diff --git a/include/z64.h b/include/z64.h index d5df3d2e02..8e90281a8e 100644 --- a/include/z64.h +++ b/include/z64.h @@ -1590,7 +1590,7 @@ struct ActorContext { /* 0x1FC */ Vec3f unk1FC; /* 0x208 */ UNK_TYPE1 pad208[0x48]; /* 0x250 */ void* unk250; // allocation of 0x20f0 bytes? - /* 0x254 */ UNK_TYPE1 pad254[0x14]; + /* 0x254 */ u32 unk254[5]; /* 0x268 */ u8 unk268; /* 0x269 */ UNK_TYPE1 pad269[0x1B]; }; // size = 0x284 diff --git a/linker_scripts/code_script.txt b/linker_scripts/code_script.txt index fdb3d7429a..c78e37e0b1 100644 --- a/linker_scripts/code_script.txt +++ b/linker_scripts/code_script.txt @@ -1196,9 +1196,9 @@ SECTIONS ovl_En_Torch2 : AT(RomLocation) { build/src/overlays/actors/ovl_En_Torch2/z_en_torch2.o(.text) - build/asm/overlays/ovl_En_Torch2_data.o(.data) + build/src/overlays/actors/ovl_En_Torch2/z_en_torch2.o(.data) build/src/overlays/actors/ovl_En_Torch2/z_en_torch2.o(.rodata) - build/asm/overlays/ovl_En_Torch2_rodata.o(.rodata) + build/src/overlays/actors/ovl_En_Torch2/z_en_torch2_overlay.o(.ovl) } SegmentEnd = .; SegmentSize = SegmentEnd - SegmentStart; diff --git a/linker_scripts/object_script.txt b/linker_scripts/object_script.txt index 2a5f047b9c..48c8242143 100644 --- a/linker_scripts/object_script.txt +++ b/linker_scripts/object_script.txt @@ -236,3 +236,9 @@ D_06000958 = 0x06000958; /* z_en_jc_mato */ D_06000390 = 0x06000390; + +/* z_en_torch2 */ +D_0401C430 = 0x0401C430; +D_04048DF0 = 0x04048DF0; +D_04057B10 = 0x04057B10; +D_04089070 = 0x04089070; diff --git a/src/overlays/actors/ovl_En_Torch2/z_en_torch2.c b/src/overlays/actors/ovl_En_Torch2/z_en_torch2.c index 40a1d18341..14c5aadf72 100644 --- a/src/overlays/actors/ovl_En_Torch2/z_en_torch2.c +++ b/src/overlays/actors/ovl_En_Torch2/z_en_torch2.c @@ -1,5 +1,10 @@ -#include "z_en_torch2.h" +/* + * File: z_en_torch2.c + * Overlay: ovl_En_Torch2 + * Description: Elegy of Emptiness Shell + */ +#include "z_en_torch2.h" #define FLAGS 0x00000010 #define THIS ((EnTorch2*)thisx) @@ -9,7 +14,14 @@ void EnTorch2_Destroy(Actor* thisx, GlobalContext* globalCtx); void EnTorch2_Update(Actor* thisx, GlobalContext* globalCtx); void EnTorch2_Draw(Actor* thisx, GlobalContext* globalCtx); -/* +void EnTorch2_UpdateIdle(Actor* thisx, GlobalContext* globalCtx); +void EnTorch2_UpdateDeath(Actor* thisx, GlobalContext* globalCtx); + +extern Gfx D_0401C430[]; +extern Gfx D_04048DF0[]; +extern Gfx D_04057B10[]; +extern Gfx D_04089070[]; + const ActorInit En_Torch2_InitVars = { ACTOR_EN_TORCH2, ACTORCAT_ITEMACTION, @@ -21,16 +33,137 @@ const ActorInit En_Torch2_InitVars = { (ActorFunc)EnTorch2_Update, (ActorFunc)EnTorch2_Draw, }; -*/ -#pragma GLOBAL_ASM("./asm/non_matchings/overlays/ovl_En_Torch2_0x808A31B0/EnTorch2_Init.asm") +static ColliderCylinderInit sCylinderInit = { + { COLTYPE_METAL, AT_NONE, AC_ON | AC_HARD | AC_TYPE_PLAYER, OC1_ON | OC1_TYPE_PLAYER | OC1_TYPE_1 | OC1_TYPE_2, + OC2_TYPE_2, COLSHAPE_CYLINDER }, + { ELEMTYPE_UNK2, { 0x00100000, 0, 0 }, { 0xF7CFFFFF, 0, 0 }, TOUCH_NONE, BUMP_ON | BUMP_HOOKABLE, OCELEM_ON }, + { 20, 60, 0, { 0, 0, 0 } }, +}; -#pragma GLOBAL_ASM("./asm/non_matchings/overlays/ovl_En_Torch2_0x808A31B0/EnTorch2_Destroy.asm") +static InitChainEntry sInitChain[] = { + ICHAIN_S8(colChkInfo.mass, MASS_IMMOVABLE, ICHAIN_STOP), +}; -#pragma GLOBAL_ASM("./asm/non_matchings/overlays/ovl_En_Torch2_0x808A31B0/EnTorch2_Update.asm") +// Shells for each of Link's different forms +// (Playing elegy as Fierce Deity puts down a human shell) +static Gfx* sShellDLists[] = { + D_0401C430, // Human + D_04048DF0, // Zora + D_04089070, // Deku + D_04057B10, // Goron + D_0401C430, // Human +}; -#pragma GLOBAL_ASM("./asm/non_matchings/overlays/ovl_En_Torch2_0x808A31B0/func_808A3428.asm") +void EnTorch2_Init(Actor* thisx, GlobalContext* globalCtx) { + EnTorch2* this = THIS; + s16 params; -#pragma GLOBAL_ASM("./asm/non_matchings/overlays/ovl_En_Torch2_0x808A31B0/func_808A3458.asm") + Actor_ProcessInitChain(&this->actor, sInitChain); + Collider_InitAndSetCylinder(globalCtx, &this->collider, &this->actor, &sCylinderInit); -#pragma GLOBAL_ASM("./asm/non_matchings/overlays/ovl_En_Torch2_0x808A31B0/EnTorch2_Draw.asm") + // params: which form Link is in (e.g. human, deku, etc.) + params = this->actor.params; + if (params != TORCH2_PARAM_DEKU) { + this->actor.flags |= 0x4000000; // Can press switch + if (params == TORCH2_PARAM_GORON) { + this->actor.flags |= 0x20000; // Can press heavy switches + } + } + this->framesUntilNextState = 20; +} + +void EnTorch2_Destroy(Actor* thisx, GlobalContext* globalCtx) { + EnTorch2* this = THIS; + + Collider_DestroyCylinder(globalCtx, &this->collider); + func_80169DCC(globalCtx, this->actor.params + 3, 0xFF, 0, 0xBFF, &this->actor.world, this->actor.shape.rot.y); + globalCtx->actorCtx.unk254[this->actor.params] = 0; +} + +void EnTorch2_Update(Actor* thisx, GlobalContext* globalCtx) { + EnTorch2* this = THIS; + u16 targetAlpha; + u16 remainingFrames; + s32 pad[2]; + + if (this->state == TORCH2_STATE_IDLE) { + this->actor.update = EnTorch2_UpdateIdle; + return; + } + + this->actor.gravity = -1.0f; + Actor_SetVelocityAndMoveYRotationAndGravity(&this->actor); + func_800B78B8(globalCtx, &this->actor, 30.0f, 20.0f, 70.0f, 0x05); + + if (this->framesUntilNextState == 0) { + remainingFrames = 0; + } else { + remainingFrames = --this->framesUntilNextState; + } + + if (remainingFrames == 0) { + if (this->state == TORCH2_STATE_INITIALIZED) { + // Spawn in + if (this->alpha == 0) { + Math_Vec3f_Copy(&this->actor.world.pos, &this->actor.home.pos); + this->actor.shape.rot.y = this->actor.home.rot.y; + this->state = TORCH2_STATE_FADING_IN; + } + targetAlpha = 0; + } else if (this->state == TORCH2_STATE_FADING_IN) { + // Stay semitransparent until the player moves away + if ((this->actor.xzDistToPlayer > 32.0f) || (fabsf(this->actor.yDistToPlayer) > 70.0f)) { + this->state = TORCH2_STATE_SOLID; + } + targetAlpha = 60; + } else { + // Once the player has moved away, update collision and become opaque + Collider_UpdateCylinder(&this->actor, &this->collider); + CollisionCheck_SetOC(globalCtx, &globalCtx->colCheckCtx, &this->collider.base); + targetAlpha = 255; + } + Math_StepToS(&this->alpha, targetAlpha, 8); + } +} + +void EnTorch2_UpdateIdle(Actor* thisx, GlobalContext* globalCtx) { + EnTorch2* this = THIS; + + if (this->state == TORCH2_STATE_DYING) { + // Start death animation + this->actor.update = EnTorch2_UpdateDeath; + this->actor.velocity.y = 0.0f; + } +} + +void EnTorch2_UpdateDeath(Actor* thisx, GlobalContext* globalCtx) { + EnTorch2* this = THIS; + + // Fall down and become transparent, then delete once invisible + if (Math_StepToS(&this->alpha, 0, 8)) { + Actor_MarkForDeath(&this->actor); + } else { + this->actor.gravity = -1.0f; + Actor_SetVelocityAndMoveYRotationAndGravity(&this->actor); + } +} + +void EnTorch2_Draw(Actor* thisx, GlobalContext* globalCtx) { + EnTorch2* this = THIS; + + GlobalContext* unused = globalCtx; + Gfx* gfx = sShellDLists[thisx->params]; + + OPEN_DISPS(globalCtx->state.gfxCtx); + if (this->alpha == 0xFF) { + Scene_SetRenderModeXlu(globalCtx, 0, 0x01); + gDPSetEnvColor(POLY_OPA_DISP++, 255, 255, 255, 255); + func_800BDFC0(globalCtx, gfx); + } else { + Scene_SetRenderModeXlu(globalCtx, 1, 0x02); + gDPSetEnvColor(POLY_XLU_DISP++, 255, 255, 255, this->alpha); + func_800BE03C(globalCtx, gfx); + } + CLOSE_DISPS(globalCtx->state.gfxCtx); +} diff --git a/src/overlays/actors/ovl_En_Torch2/z_en_torch2.h b/src/overlays/actors/ovl_En_Torch2/z_en_torch2.h index 0381de1434..68a2b2c406 100644 --- a/src/overlays/actors/ovl_En_Torch2/z_en_torch2.h +++ b/src/overlays/actors/ovl_En_Torch2/z_en_torch2.h @@ -7,9 +7,28 @@ struct EnTorch2; typedef struct EnTorch2 { /* 0x000 */ Actor actor; - /* 0x144 */ char unk_144[0x50]; + /* 0x144 */ ColliderCylinder collider; + /* 0x190 */ u8 state; + /* 0x191 */ u8 framesUntilNextState; + /* 0x192 */ s16 alpha; } EnTorch2; // size = 0x194 +typedef enum { + TORCH2_PARAM_HUMAN, + TORCH2_PARAM_GORON, + TORCH2_PARAM_ZORA, + TORCH2_PARAM_DEKU, + TORCH2_PARAM_FIERCE_DEITY, +} EnTorch2Param; + +typedef enum { + TORCH2_STATE_INITIALIZED, + TORCH2_STATE_FADING_IN, + TORCH2_STATE_SOLID, + TORCH2_STATE_IDLE, + TORCH2_STATE_DYING, +} EnTorch2State; + extern const ActorInit En_Torch2_InitVars; #endif // Z_EN_TORCH2_H diff --git a/tables/functions.txt b/tables/functions.txt index d75205e1a1..7ba2fd31cd 100644 --- a/tables/functions.txt +++ b/tables/functions.txt @@ -5690,8 +5690,8 @@ 0x808A31B0:("EnTorch2_Init",), 0x808A323C:("EnTorch2_Destroy",), 0x808A32B0:("EnTorch2_Update",), - 0x808A3428:("func_808A3428",), - 0x808A3458:("func_808A3458",), + 0x808A3428:("EnTorch2_UpdateIdle",), + 0x808A3458:("EnTorch2_UpdateDeath",), 0x808A34B8:("EnTorch2_Draw",), 0x808A3670:("EnMinifrog_Init",), 0x808A38E4:("EnMinifrog_Destroy",),