Add actor update/init events and save init event (#536)

This commit is contained in:
Garrett Cox 2025-02-16 22:51:04 -06:00 committed by GitHub
parent b3aad6420c
commit d49228691d
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 193 additions and 2 deletions

View File

@ -1,6 +1,7 @@
#include "patches.h"
#include "fault.h"
#include "transform_ids.h"
#include "z64actor.h"
u16 next_actor_transform = 0;
@ -47,6 +48,11 @@ u32 create_actor_transform_id() {
return ret;
}
RECOMP_DECLARE_EVENT(recomp_should_actor_init(PlayState* play, Actor* actor, bool* should));
RECOMP_DECLARE_EVENT(recomp_after_actor_init(PlayState* play, Actor* actor));
RECOMP_DECLARE_EVENT(recomp_should_actor_update(PlayState* play, Actor* actor, bool* should));
RECOMP_DECLARE_EVENT(recomp_after_actor_update(PlayState* play, Actor* actor));
RECOMP_PATCH void Actor_Init(Actor* actor, PlayState* play) {
Actor_SetWorldToHome(actor);
Actor_SetShapeRotToWorld(actor);
@ -69,8 +75,18 @@ RECOMP_PATCH void Actor_Init(Actor* actor, PlayState* play) {
ActorShape_Init(&actor->shape, 0.0f, NULL, 0.0f);
if (Object_IsLoaded(&play->objectCtx, actor->objectSlot)) {
Actor_SetObjectDependency(play, actor);
// @recomp Augmented, allowing us to prevent actor init and hook into after init
bool shouldInit = true;
recomp_should_actor_init(play, actor, &shouldInit);
if (shouldInit) {
actor->init(actor, play);
actor->init = NULL;
recomp_after_actor_init(play, actor);
} else {
actor->init = NULL;
Actor_Kill(actor);
}
}
// @recomp Pick a transform ID for this actor and encode it into struct padding
@ -79,6 +95,108 @@ RECOMP_PATCH void Actor_Init(Actor* actor, PlayState* play) {
actorIdByte1(actor) = (cur_transform_id >> 8) & 0xFF;;
}
// @recomp Copied from z_actor.c
typedef struct {
/* 0x00 */ PlayState* play;
/* 0x04 */ Actor* actor;
/* 0x08 */ u32 freezeExceptionFlag;
/* 0x0C */ u32 canFreezeCategory;
/* 0x10 */ Actor* talkActor;
/* 0x14 */ Player* player;
/* 0x18 */ u32 updateActorFlagsMask; // Actor will update only if at least 1 actor flag is set in this bitmask
} UpdateActor_Params; // size = 0x1C
void Actor_Destroy(Actor* actor, PlayState* play);
RECOMP_PATCH Actor* Actor_UpdateActor(UpdateActor_Params* params) {
PlayState* play = params->play;
Actor* actor = params->actor;
Actor* nextActor;
if (actor->world.pos.y < -25000.0f) {
actor->world.pos.y = -25000.0f;
}
actor->sfxId = 0;
actor->audioFlags &= ~(((1 << 4) | (1 << 3) | (1 << 2) | (1 << 1) | (1 << 0)) | ((1 << 6) | (1 << 5))); // ACTOR_AUDIO_FLAG_ALL
if (actor->init != NULL) {
if (Object_IsLoaded(&play->objectCtx, actor->objectSlot)) {
Actor_SetObjectDependency(play, actor);
// @recomp Augmented, allowing us to prevent actor init and hook into after init
bool shouldInit = true;
recomp_should_actor_init(play, actor, &shouldInit);
if (shouldInit) {
actor->init(actor, play);
actor->init = NULL;
recomp_after_actor_init(play, actor);
} else {
actor->init = NULL;
Actor_Kill(actor);
}
}
nextActor = actor->next;
} else if (actor->update == NULL) {
if (!actor->isDrawn) {
nextActor = Actor_Delete(&play->actorCtx, actor, play);
} else {
Actor_Destroy(actor, play);
nextActor = actor->next;
}
} else {
if (!Object_IsLoaded(&play->objectCtx, actor->objectSlot)) {
Actor_Kill(actor);
} else if (((params->freezeExceptionFlag != 0) && !(actor->flags & params->freezeExceptionFlag)) ||
(((!params->freezeExceptionFlag) != 0) &&
(!(actor->flags & (1 << 20)) ||
((actor->category == ACTORCAT_EXPLOSIVES) && (params->player->stateFlags1 & PLAYER_STATE1_200))) &&
params->canFreezeCategory && (actor != params->talkActor) && (actor != params->player->heldActor) &&
(actor->parent != &params->player->actor))) {
CollisionCheck_ResetDamage(&actor->colChkInfo);
} else {
Math_Vec3f_Copy(&actor->prevPos, &actor->world.pos);
actor->xzDistToPlayer = Actor_WorldDistXZToActor(actor, &params->player->actor);
actor->playerHeightRel = Actor_HeightDiff(actor, &params->player->actor);
actor->xyzDistToPlayerSq = SQ(actor->xzDistToPlayer) + SQ(actor->playerHeightRel);
actor->yawTowardsPlayer = Actor_WorldYawTowardActor(actor, &params->player->actor);
actor->flags &= ~(1 << 24);
if ((DECR(actor->freezeTimer) == 0) && (actor->flags & params->updateActorFlagsMask)) {
if (actor == params->player->lockOnActor) {
actor->isLockedOn = true;
} else {
actor->isLockedOn = false;
}
if ((actor->targetPriority != 0) && (params->player->lockOnActor == NULL)) {
actor->targetPriority = 0;
}
Actor_SetObjectDependency(play, actor);
if (actor->colorFilterTimer != 0) {
actor->colorFilterTimer--;
}
// @recomp Augmented, allowing us to prevent actor update and hook into after update
bool shouldUpdate = true;
recomp_should_actor_update(play, actor, &shouldUpdate);
if (shouldUpdate) {
actor->update(actor, play);
recomp_after_actor_update(play, actor);
}
DynaPoly_UnsetAllInteractFlags(play, &play->colCtx.dyna, actor);
}
CollisionCheck_ResetDamage(&actor->colChkInfo);
}
nextActor = actor->next;
}
return nextActor;
}
// Extract the transform ID for this actor, add the limb index and write that as the matrix group to POLY_OPA_DISP.
Gfx* push_limb_matrix_group(Gfx* dlist, Actor* actor, u32 limb_index) {
if (actor != NULL) {

View File

@ -2,10 +2,14 @@
#include "sys_flashrom.h"
#include "PR/os_internal_flash.h"
#include "fault.h"
#include "overlays/gamestates/ovl_file_choose/z_file_select.h"
#include "overlays/kaleido_scope/ovl_kaleido_scope/z_kaleido_scope.h"
extern OSMesgQueue sFlashromMesgQueue;
s32 SysFlashrom_IsInit(void);
void Sleep_Msec(u32 ms);
extern u16 D_801F6AF0;
extern u8 D_801F6AF2;
// @recomp Patched to not wait a hardcoded amount of time for the save to complete.
RECOMP_PATCH void Sram_UpdateWriteToFlashDefault(SramContext* sramCtx) {
@ -56,3 +60,72 @@ RECOMP_PATCH void Sram_UpdateWriteToFlashOwlSave(SramContext* sramCtx) {
Lib_MemCpy(&gSaveContext, sramCtx->saveBuf, offsetof(SaveContext, fileNum));
}
}
RECOMP_DECLARE_EVENT(recomp_after_init_save(FileSelectState* fileSelect, SramContext* sramCtx));
// @recomp Patched to expose recomp_on_save_init event
RECOMP_PATCH void Sram_InitSave(FileSelectState* fileSelect2, SramContext* sramCtx) {
s32 phi_v0;
u16 i;
FileSelectState* fileSelect = fileSelect2;
s16 maskCount;
if (gSaveContext.flashSaveAvailable) {
Sram_InitNewSave();
if (fileSelect->buttonIndex == 0) {
gSaveContext.save.cutsceneIndex = 0xFFF0;
}
for (phi_v0 = 0; phi_v0 < ARRAY_COUNT(gSaveContext.save.saveInfo.playerData.playerName); phi_v0++) {
gSaveContext.save.saveInfo.playerData.playerName[phi_v0] =
fileSelect->fileNames[fileSelect->buttonIndex][phi_v0];
}
gSaveContext.save.saveInfo.playerData.newf[0] = 'Z';
gSaveContext.save.saveInfo.playerData.newf[1] = 'E';
gSaveContext.save.saveInfo.playerData.newf[2] = 'L';
gSaveContext.save.saveInfo.playerData.newf[3] = 'D';
gSaveContext.save.saveInfo.playerData.newf[4] = 'A';
gSaveContext.save.saveInfo.playerData.newf[5] = '3';
recomp_after_init_save(fileSelect, sramCtx);
gSaveContext.save.saveInfo.checksum = Sram_CalcChecksum(&gSaveContext.save, sizeof(Save));
Lib_MemCpy(sramCtx->saveBuf, &gSaveContext.save, sizeof(Save));
Lib_MemCpy(&sramCtx->saveBuf[0x2000], &gSaveContext.save, sizeof(Save));
for (i = 0; i < ARRAY_COUNT(gSaveContext.save.saveInfo.playerData.newf); i++) {
fileSelect->newf[fileSelect->buttonIndex][i] = gSaveContext.save.saveInfo.playerData.newf[i];
}
fileSelect->threeDayResetCount[fileSelect->buttonIndex] =
gSaveContext.save.saveInfo.playerData.threeDayResetCount;
for (i = 0; i < ARRAY_COUNT(gSaveContext.save.saveInfo.playerData.playerName); i++) {
fileSelect->fileNames[fileSelect->buttonIndex][i] = gSaveContext.save.saveInfo.playerData.playerName[i];
}
fileSelect->healthCapacity[fileSelect->buttonIndex] = gSaveContext.save.saveInfo.playerData.healthCapacity;
fileSelect->health[fileSelect->buttonIndex] = gSaveContext.save.saveInfo.playerData.health;
fileSelect->defenseHearts[fileSelect->buttonIndex] = gSaveContext.save.saveInfo.inventory.defenseHearts;
fileSelect->questItems[fileSelect->buttonIndex] = gSaveContext.save.saveInfo.inventory.questItems;
fileSelect->time[fileSelect->buttonIndex] = CURRENT_TIME;
fileSelect->day[fileSelect->buttonIndex] = gSaveContext.save.day;
fileSelect->isOwlSave[fileSelect->buttonIndex] = gSaveContext.save.isOwlSave;
fileSelect->rupees[fileSelect->buttonIndex] = gSaveContext.save.saveInfo.playerData.rupees;
fileSelect->walletUpgrades[fileSelect->buttonIndex] = CUR_UPG_VALUE(UPG_WALLET);
for (i = 0, maskCount = 0; i < MASK_NUM_SLOTS; i++) {
if (gSaveContext.save.saveInfo.inventory.items[i + ITEM_NUM_SLOTS] != ITEM_NONE) {
maskCount++;
}
}
fileSelect->maskCount[fileSelect->buttonIndex] = maskCount;
fileSelect->heartPieceCount[fileSelect->buttonIndex] = GET_QUEST_HEART_PIECE_COUNT;
}
gSaveContext.save.time = D_801F6AF0;
gSaveContext.flashSaveAvailable = D_801F6AF2;
}