diff --git a/code/include/z3D/z3Dactor.h b/code/include/z3D/z3Dactor.h index e4cc811e..763f0151 100644 --- a/code/include/z3D/z3Dactor.h +++ b/code/include/z3D/z3Dactor.h @@ -81,7 +81,7 @@ typedef struct SkelAnime { /* 0x14 */ char unk_14[0x14]; /* 0x28 */ struct SkeletonAnimationModel* unk_28; /* 0x2C */ char unk_2C[0x4]; - /* 0x30 */ s32 animationType; + /* 0x30 */ s32 animIndex; /* 0x34 */ char unk_34[0x8]; /* 0x3C */ f32 curFrame; /* 0x40 */ f32 playSpeed; @@ -381,5 +381,7 @@ void Actor_UpdateBgCheckInfo(struct GlobalContext* globalCtx, Actor* actor, f32 s32 Player_InCsMode(struct GlobalContext* globalCtx); Actor* Actor_FindNearby(struct GlobalContext* globalCtx, Actor* ref_actor, s16 actorId, u8 actor_category, f32 range); void ActorShadow_DrawFeet(Actor* actor, void* lights, struct GlobalContext* globalCtx); +void LinkAnimation_Change(SkelAnime* skelAnime, struct GlobalContext* play, u32 animation, f32 playSpeed, + f32 startFrame, f32 endFrame, u8 mode, f32 morphFrames) __attribute__((pcs("aapcs-vfp"))); #endif diff --git a/code/oot.ld b/code/oot.ld index 1c97add1..7c9ea429 100644 --- a/code/oot.ld +++ b/code/oot.ld @@ -18,6 +18,7 @@ SECTIONS .patch_ArmosPushSpeed 0x10B5C4 + _LD_OFF : { *(.patch_ArmosPushSpeed) } EnMb_ClubWaitPlayerNear = 0x10B5D0 + _LD_OFF; .patch_ShortenRainbowBridgeCS 0x10B904 + _LD_OFF : { *(.patch_ShortenRainbowBridgeCS) } + DoorShutter_Close = 0x10D030 + _LD_OFF; .patch_GrannyTextID 0x10DCD0 + _LD_OFF : { *(.patch_GrannyTextID) } OceffSpot_End = 0x10FBD0 + _LD_OFF; ObjLift_Shake = 0x110E98 + _LD_OFF; @@ -490,6 +491,7 @@ SECTIONS .patch_SkullwalltulaAttack_35F328 0x35F328 + _LD_OFF : { *(.patch_SkullwalltulaAttack_35F328) } .patch_SkullwalltulaTargetRotation 0x35F828 + _LD_OFF : { *(.patch_SkullwalltulaTargetRotation) } .patch_SkullwalltulaAttack_35F834 0x35F834 + _LD_OFF : { *(.patch_SkullwalltulaAttack_35F834) } + LinkAnimation_Change = 0x360190 + _LD_OFF; LinkAnimation_PlayOnce = 0x3604F0 + _LD_OFF; .patch_ISGCrouchStab 0x360690 + _LD_OFF : { *(.patch_ISGCrouchStab) } .patch_ForceTrailEffectUpdate 0x362108 + _LD_OFF : { *(.patch_ForceTrailEffectUpdate) } /*EffectBlure_AddVertex*/ @@ -516,6 +518,7 @@ SECTIONS .patch_IgnoreMaskReaction 0x36BBC4 + _LD_OFF : { *(.patch_IgnoreMaskReaction) } Flags_UnsetSwitch = 0x36BEAC + _LD_OFF; Matrix_Multiply = 0x36C174 + _LD_OFF; + .patch_SetupDoorShutter 0x36C3BC + _LD_OFF : { *(.patch_SetupDoorShutter) } Flags_GetClear = 0x36CF6C + _LD_OFF; Math_Vec3f_DistXZ = 0x36D260 + _LD_OFF; Math_SmoothStepToF = 0x36E168 + _LD_OFF; @@ -661,7 +664,7 @@ SECTIONS EnDoor_Open = 0x3EC04C + _LD_OFF; .patch_CowItemOverride 0x3EE378 + _LD_OFF : { *(.patch_CowItemOverride) } DoorGerudo_Unlocking = 0x3EEE38 + _LD_OFF; - DoorShutter_SlidingDoor_Open = 0x3EEE7C + _LD_OFF; + DoorShutter_Open = 0x3EEE7C + _LD_OFF; .patch_CowBottleCheck 0x3F065C + _LD_OFF : { *(.patch_CowBottleCheck) } .patch_CarpetSalesmanCheckFlagOne 0x3F0A18 + _LD_OFF : { *(.patch_CarpetSalesmanCheckFlagOne) } .patch_CarpetSalesmanCheckFlagTwo 0x3F0A64 + _LD_OFF : { *(.patch_CarpetSalesmanCheckFlagTwo) } @@ -675,7 +678,7 @@ SECTIONS .patch_FireArrowCheckChestFlagTwo 0x3F2448 + _LD_OFF : { *(.patch_FireArrowCheckChestFlagTwo) } .patch_LinkReflection 0x3F2F0C + _LD_OFF : { *(.patch_LinkReflection) } DoorGerudo_Idle = 0x3F3FA0 + _LD_OFF; - DoorShutter_SlidingDoor_Idle = 0x3F4A3C + _LD_OFF; + DoorShutter_Idle = 0x3F4A3C + _LD_OFF; .patch_SlidingDoorDestroyCustomModels 0x3F4A70 + _LD_OFF : { *(.patch_SlidingDoorDestroyCustomModels) } .patch_ChildBlueWarpOverride 0x3F5774 + _LD_OFF : { *(.patch_ChildBlueWarpOverride) } BgIceShelter_Melt = 0x3F5F00 + _LD_OFF; diff --git a/code/src/actors/dark_link.c b/code/src/actors/dark_link.c index cea78a9c..e1ea2ca2 100644 --- a/code/src/actors/dark_link.c +++ b/code/src/actors/dark_link.c @@ -8,6 +8,8 @@ void EnTorch2_Update(Actor* thisx, GlobalContext* globalCtx); u8 sPlayerWeaponClanked = FALSE; +#define IDLE_STANDING_ANIM_IDX 0x58 + void EnTorch2_rInit(Actor* thisx, GlobalContext* globalCtx) { EnTorch2_Init(thisx, globalCtx); @@ -58,6 +60,15 @@ void EnTorch2_rUpdate(Actor* thisx, GlobalContext* globalCtx) { case ENTORCH2_WAIT: // Avoid triggering fall damage effect when spawning in certain locations. this->darkPlayer.fallStartHeight = thisx->world.pos.y; + + // Sometimes during the first update cycle the animation changes to the falling one, so we need to + // restore it. Check water level in case it can raise and submerge Dark Link while idle. + if (this->darkPlayer.skelAnime.animIndex != IDLE_STANDING_ANIM_IDX && + this->darkPlayer.actor.depthInWater <= 0) { + LinkAnimation_Change(&this->darkPlayer.skelAnime, globalCtx, IDLE_STANDING_ANIM_IDX, 1.0, 0.0, 0.0, + 0, 0.0); + } + break; case ENTORCH2_ATTACK: CollisionPoly floorPoly; diff --git a/code/src/actors/door.c b/code/src/actors/door.c index 682750f3..073c5e4e 100644 --- a/code/src/actors/door.c +++ b/code/src/actors/door.c @@ -2,6 +2,7 @@ #include "models.h" #include "settings.h" #include "enemizer.h" +#include "enemy_souls.h" #include "multiplayer.h" // Certain doors can cause a crash depending on a freestanding @@ -80,14 +81,16 @@ void DoorShutter_rInit(Actor* thisx, GlobalContext* globalCtx) { void DoorShutter_Update(Actor* thisx, GlobalContext* globalCtx); -void DoorShutter_SlidingDoor_Idle(DoorShutter* this, GlobalContext* globalCtx); -void DoorShutter_SlidingDoor_Open(DoorShutter* this, GlobalContext* globalCtx); +void DoorShutter_Idle(DoorShutter* this, GlobalContext* globalCtx); +void DoorShutter_Open(DoorShutter* this, GlobalContext* globalCtx); +void DoorShutter_Close(DoorShutter* this, GlobalContext* globalCtx); + void DoorShutter_Unlocking(DoorShutter* this, GlobalContext* globalCtx); void DoorShutter_rUpdate(Actor* thisx, GlobalContext* globalCtx) { DoorShutter* this = (DoorShutter*)thisx; - DoorShutterActionFunc prev_action_fn = this->action_fn; + DoorShutterActionFunc prevActionFunc = this->actionFunc; DoorShutter_Update(thisx, globalCtx); @@ -96,9 +99,8 @@ void DoorShutter_rUpdate(Actor* thisx, GlobalContext* globalCtx) { return; } - if (this->lock_timer != 0 && prev_action_fn == DoorShutter_SlidingDoor_Idle && - this->action_fn == DoorShutter_SlidingDoor_Open) { - if (this->door_type_maybe != 5) { + if (this->unlockTimer != 0 && prevActionFunc == DoorShutter_Idle && this->actionFunc == DoorShutter_Open) { + if (this->doorType != 5) { Multiplayer_Send_UnlockedDoor(thisx->params & 0x3F); } Multiplayer_Send_ActorUpdate(thisx, NULL, 0); @@ -106,22 +108,36 @@ void DoorShutter_rUpdate(Actor* thisx, GlobalContext* globalCtx) { } void DoorShutter_Unlock(DoorShutter* this) { - if (this->action_fn != DoorShutter_SlidingDoor_Idle) { + if (this->actionFunc != DoorShutter_Idle) { return; } - this->action_fn = &DoorShutter_Unlocking; + this->actionFunc = DoorShutter_Unlocking; - u32 sfx_id = this->door_type_maybe != 5 ? NA_SE_EV_CHAIN_KEY_UNLOCK : NA_SE_EV_CHAIN_KEY_UNLOCK_B; - Audio_PlaySfxGeneral(sfx_id, &this->base.world.pos, 4, &gSfxDefaultFreqAndVolScale, &gSfxDefaultFreqAndVolScale, - &gSfxDefaultReverb); + u32 sfx_id = this->doorType != 5 ? NA_SE_EV_CHAIN_KEY_UNLOCK : NA_SE_EV_CHAIN_KEY_UNLOCK_B; + Audio_PlaySfxGeneral(sfx_id, &this->dyna.actor.world.pos, 4, &gSfxDefaultFreqAndVolScale, + &gSfxDefaultFreqAndVolScale, &gSfxDefaultReverb); } void DoorShutter_Unlocking(DoorShutter* this, GlobalContext* globalCtx) { - if (this->lock_timer > 0) { - this->lock_timer--; + if (this->unlockTimer > 0) { + this->unlockTimer--; return; } - this->action_fn = DoorShutter_SlidingDoor_Idle; + this->actionFunc = DoorShutter_Idle; +} + +u8 DoorShutter_CheckSoullessEnemies(DoorShutter* this) { + if (gSettingsContext.shuffleEnemySouls == SHUFFLEENEMYSOULS_ALL && + (this->actionFunc == DoorShutter_Close || this->actionFunc == DoorShutter_Open)) { + Actor* enemy = gGlobalContext->actorCtx.actorList[ACTORTYPE_ENEMY].first; + for (; enemy != NULL; enemy = enemy->next) { + if (enemy->room == gGlobalContext->roomNum && !EnemySouls_CheckSoulForActor(enemy)) { + this->barsClosedAmount = 0.0; + return TRUE; + } + } + } + return FALSE; } /*------------------------------ diff --git a/code/src/actors/door.h b/code/src/actors/door.h index 3a4d3ca6..0a41a082 100644 --- a/code/src/actors/door.h +++ b/code/src/actors/door.h @@ -31,15 +31,17 @@ struct DoorShutter; typedef void (*DoorShutterActionFunc)(struct DoorShutter* this, GlobalContext* globalCtx); typedef struct DoorShutter { - Actor base; - char dyna[24]; - char unk_1BC[6]; - s8 door_type_maybe; - char unk_1C3[3]; - s8 lock_timer; - char unk_1C7[9]; - DoorShutterActionFunc action_fn; + /* 0x000 */ DynaPolyActor dyna; + /* 0x1BC */ char unk_1BC[0x06]; + /* 0x1C2 */ s8 doorType; + /* 0x1C3 */ char unk_1C3[0x03]; + /* 0x1C6 */ s8 unlockTimer; + /* 0x1C7 */ char unk_1C7[0x05]; + /* 0x1CC */ f32 barsClosedAmount; + /* 0x1D0 */ DoorShutterActionFunc actionFunc; + /* 0x1D4 */ char unk_1D4[0x4C]; } DoorShutter; +_Static_assert(sizeof(DoorShutter) == 0x220, "DoorShutter size"); void DoorShutter_rInit(Actor* thisx, GlobalContext* globalCtx); void DoorShutter_rUpdate(Actor* thisx, GlobalContext* globalCtx); diff --git a/code/src/asm/hooks.s b/code/src/asm/hooks.s index 7b1362b0..60d9a922 100644 --- a/code/src/asm/hooks.s +++ b/code/src/asm/hooks.s @@ -2192,3 +2192,11 @@ HOOK BusinessScrubCheckFlags addgt lr,lr,#0x10 @ 1: kill actor cmplt r1,#0x2 @ -1: resume vanilla checks bx lr + +HOOK SetupDoorShutter + push {r0-r12, lr} + cpy r0,r4 @ actor + bl DoorShutter_CheckSoullessEnemies + cmp r0,#0x0 + pop {r0-r12, lr} + bx lr diff --git a/code/src/asm/patches.s b/code/src/asm/patches.s index 39b7d35e..5a8a2946 100644 --- a/code/src/asm/patches.s +++ b/code/src/asm/patches.s @@ -1622,3 +1622,6 @@ PATCH GanonFinalBlow PATCH PlayerBonk bl hook_PlayerBonk + +PATCH SetupDoorShutter + bleq hook_SetupDoorShutter diff --git a/code/src/enemy_souls.c b/code/src/enemy_souls.c index ee841f1c..189b1b38 100644 --- a/code/src/enemy_souls.c +++ b/code/src/enemy_souls.c @@ -98,7 +98,8 @@ void EnemySouls_SetSoulFlag(EnemySoulId soulId) { u8 EnemySouls_CheckSoulForActor(Actor* actor) { if ((gSettingsContext.shuffleEnemySouls == SHUFFLEENEMYSOULS_OFF) || (gSettingsContext.shuffleEnemySouls == SHUFFLEENEMYSOULS_BOSSES && !Actor_IsBoss(actor)) || - (actor->id == 0x054 && ((EnAm*)actor)->textureBlend == 0 /* Armos, statue or asleep */)) { + (actor->id == ACTOR_ARMOS && ((EnAm*)actor)->textureBlend == 0 /* Statue or asleep enemy */) || + (actor->id == ACTOR_DEAD_HAND && actor->shape.yOffset <= -15000.0 /* Waiting underground */)) { return TRUE; }