diff --git a/include/functions.h b/include/functions.h index 6bb0c03cc5..80e48e256a 100644 --- a/include/functions.h +++ b/include/functions.h @@ -1736,7 +1736,7 @@ void Font_LoadOrderedFont(Font* font); // void func_800F50D4(void); void Kankyo_Init(GlobalContext* globalCtx, EnvironmentContext* envCtx); u32 func_800F5954(u8* param_1, u32 param_2, u32 param_3, u8 param_4, u8 param_5); -// void func_800F5A8C(void); +f32 func_800F5A8C(u16 arg0, u16 arg1, u16 arg2, GlobalContext* globalContext); // void func_800F5B10(UNK_TYPE1 param_1, UNK_TYPE1 param_2, UNK_TYPE1 param_3, UNK_TYPE1 param_4, UNK_TYPE2 param_5); // void func_800F5CD0(void); // void func_800F6834(void); diff --git a/include/z64cutscene.h b/include/z64cutscene.h index 3629aba74a..51e60799e0 100644 --- a/include/z64cutscene.h +++ b/include/z64cutscene.h @@ -29,7 +29,11 @@ typedef struct { /* 0x00 */ u16 unk0; // action; // "dousa" /* 0x02 */ u16 startFrame; /* 0x04 */ u16 endFrame; - /* 0x06 */ UNK_TYPE1 pad6[0x2A]; + /* 0x06 */ UNK_TYPE1 pad6[0xA]; + /* 0x10 */ s32 unk10; + /* 0x14 */ UNK_TYPE1 pad14[0x8]; + /* 0x1C */ s32 unk1C; + /* 0x20 */ UNK_TYPE1 pad20[0x10]; } CsCmdActorAction; // size = 0x30 typedef struct { diff --git a/spec b/spec index 40a76a93f9..697971ff1d 100644 --- a/spec +++ b/spec @@ -3889,8 +3889,7 @@ beginseg name "ovl_En_Giant" compress include "build/src/overlays/actors/ovl_En_Giant/z_en_giant.o" - include "build/data/ovl_En_Giant/ovl_En_Giant.data.o" - include "build/data/ovl_En_Giant/ovl_En_Giant.reloc.o" + include "build/src/overlays/actors/ovl_En_Giant/ovl_En_Giant_reloc.o" endseg beginseg diff --git a/src/overlays/actors/ovl_En_Giant/z_en_giant.c b/src/overlays/actors/ovl_En_Giant/z_en_giant.c index 2bf3bbd53b..62da9b9f6b 100644 --- a/src/overlays/actors/ovl_En_Giant/z_en_giant.c +++ b/src/overlays/actors/ovl_En_Giant/z_en_giant.c @@ -1,3 +1,9 @@ +/* + * File: z_en_giant.c + * Overlay: ovl_En_Giant + * Description: Giant + */ + #include "z_en_giant.h" #define FLAGS 0x00000030 @@ -9,11 +15,10 @@ void EnGiant_Destroy(Actor* thisx, GlobalContext* globalCtx); void EnGiant_Update(Actor* thisx, GlobalContext* globalCtx); void EnGiant_Draw(Actor* thisx, GlobalContext* globalCtx); -void func_80B023D0(EnGiant* this, GlobalContext* globalCtx); -void func_80B024AC(EnGiant* this, GlobalContext* globalCtx); -void func_80B024D8(EnGiant* this, GlobalContext* globalCtx); +void EnGiant_PerformClockTowerSuccessActions(EnGiant* this, GlobalContext* globalCtx); +void EnGiant_PlayClockTowerFailureAnimation(EnGiant* this, GlobalContext* globalCtx); +void EnGiant_PerformCutsceneActions(EnGiant* this, GlobalContext* globalCtx); -#if 0 const ActorInit En_Giant_InitVars = { ACTOR_EN_GIANT, ACTORCAT_NPC, @@ -26,42 +31,460 @@ const ActorInit En_Giant_InitVars = { (ActorFunc)EnGiant_Draw, }; -#endif +extern AnimationHeader D_06002168; +extern Gfx D_06005A80[]; +extern Gfx D_06006280[]; +extern Gfx D_06007610[]; +extern Gfx D_06006A80[]; +extern FlexSkeletonHeader D_060079B0; +extern AnimationHeader D_06008394; +extern AnimationHeader D_060096E4; +extern AnimationHeader D_0600A1C4; +extern AnimationHeader D_0600ACA4; +extern AnimationHeader D_0600B784; +extern AnimationHeader D_0600C5D4; +extern AnimationHeader D_0600D040; +extern AnimationHeader D_0600DE84; +extern AnimationHeader D_060102A4; +extern AnimationHeader D_060116E4; +extern AnimationHeader D_06012A38; +extern AnimationHeader D_06013004; +extern AnimationHeader D_06013FE8; +extern AnimationHeader D_06015334; +extern AnimationHeader D_06017944; -extern UNK_TYPE D_06002168; -extern UNK_TYPE D_06007610; -extern UNK_TYPE D_060116E4; +static AnimationHeader* sAnimationTable[] = { + &D_06008394, &D_060096E4, &D_060102A4, &D_060116E4, &D_06012A38, &D_06013004, &D_06013FE8, &D_06015334, + &D_06017944, &D_0600A1C4, &D_0600D040, &D_0600DE84, &D_0600ACA4, &D_0600B784, &D_0600C5D4, +}; -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Giant/func_80B01990.s") +void EnGiant_ChangeAnimation(EnGiant* this, s16 newAnimationId) { + if (newAnimationId >= GIANT_ANIMATION_LOOK_UP_START && newAnimationId < GIANT_ANIMATION_MAX) { + if ((this->animationId == GIANT_ANIMATION_WALKING_LOOP && newAnimationId != GIANT_ANIMATION_WALKING_LOOP) || + (newAnimationId == GIANT_ANIMATION_WALKING_LOOP && this->animationId != GIANT_ANIMATION_WALKING_LOOP)) { + Animation_Change(&this->skelAnime, sAnimationTable[newAnimationId], 1.0f, 0.0f, + Animation_GetLastFrame(&sAnimationTable[newAnimationId]->common), 2, 10.0f); + } else { + Animation_PlayOnce(&this->skelAnime, sAnimationTable[newAnimationId]); + } + this->animationId = newAnimationId; + } +} -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Giant/func_80B01A74.s") +s32 EnGiant_IsImprisoned(EnGiant* this) { + switch (GIANT_TYPE(&this->actor)) { + case GIANT_TYPE_SWAMP_TERMINA_FIELD: + case GIANT_TYPE_SWAMP_CLOCK_TOWER_SUCCESS: + case GIANT_TYPE_SWAMP_GIANTS_CHAMBER_AND_ENDING: + case GIANT_TYPE_SWAMP_CLOCK_TOWER_FAILURE: + if (!CHECK_QUEST_ITEM(0)) { + return true; + } + break; + case GIANT_TYPE_MOUNTAIN_TERMINA_FIELD: + case GIANT_TYPE_MOUNTAIN_CLOCK_TOWER_SUCCESS: + case GIANT_TYPE_MOUNTAIN_GIANTS_CHAMBER_AND_ENDING: + case GIANT_TYPE_MOUNTAIN_CLOCK_TOWER_FAILURE: + if (!CHECK_QUEST_ITEM(1)) { + return true; + } + break; + case GIANT_TYPE_OCEAN_TERMINA_FIELD: + case GIANT_TYPE_OCEAN_CLOCK_TOWER_SUCCESS: + case GIANT_TYPE_OCEAN_GIANTS_CHAMBER_AND_ENDING: + case GIANT_TYPE_OCEAN_CLOCK_TOWER_FAILURE: + if (!CHECK_QUEST_ITEM(2)) { + return true; + } + break; + case GIANT_TYPE_CANYON_TERMINA_FIELD: + case GIANT_TYPE_CANYON_CLOCK_TOWER_SUCCESS: + case GIANT_TYPE_CANYON_GIANTS_CHAMBER_AND_ENDING: + case GIANT_TYPE_CANYON_CLOCK_TOWER_FAILURE: + if (!CHECK_QUEST_ITEM(3)) { + return true; + } + break; + } -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Giant/EnGiant_Init.s") + return false; +} -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Giant/EnGiant_Destroy.s") +void EnGiant_Init(Actor* thisx, GlobalContext* globalCtx) { + EnGiant* this = THIS; + s32 type = GIANT_TYPE(thisx); -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Giant/func_80B01E84.s") + this->actor.uncullZoneForward = 4000.0f; + this->actor.uncullZoneScale = 2000.0f; + this->actor.uncullZoneDownward = 2400.0f; + Actor_SetScale(&this->actor, 0.32f); + SkelAnime_InitFlex(globalCtx, &this->skelAnime, &D_060079B0, &D_06002168, this->jointTable, this->morphTable, 16); + EnGiant_ChangeAnimation(this, GIANT_ANIMATION_IDLE_LOOP); + this->csAction = GIANT_CS_ACTION_NONE; + this->actionFunc = EnGiant_PerformCutsceneActions; + this->actor.draw = NULL; + this->alpha = 0; + this->actor.velocity.y = -10.0f; + this->actor.minVelocityY = -10.0f; + this->actor.gravity = -5.0f; + switch (type) { + case GIANT_TYPE_CANYON_TERMINA_FIELD: + case GIANT_TYPE_CANYON_CLOCK_TOWER_SUCCESS: + case GIANT_TYPE_CANYON_GIANTS_CHAMBER_AND_ENDING: + this->unk_24A = 0x1C6; + break; + case GIANT_TYPE_SWAMP_TERMINA_FIELD: + case GIANT_TYPE_SWAMP_CLOCK_TOWER_SUCCESS: + case GIANT_TYPE_SWAMP_GIANTS_CHAMBER_AND_ENDING: + this->unk_24A = 0x1C7; + break; + case GIANT_TYPE_OCEAN_TERMINA_FIELD: + case GIANT_TYPE_OCEAN_CLOCK_TOWER_SUCCESS: + case GIANT_TYPE_OCEAN_GIANTS_CHAMBER_AND_ENDING: + this->unk_24A = 0x1C8; + break; + default: + this->unk_24A = 0x1C5; + break; + } -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Giant/func_80B01EE8.s") + if (GIANT_TYPE_IS_CLOCK_TOWER_SUCCESS(type)) { + if (!(gSaveContext.weekEventReg[0x19] & 2)) { + Actor_MarkForDeath(&this->actor); + return; + } + this->unk_24A = 0x1C5; + Actor_SetScale(&this->actor, 0.32f); + this->actionFunc = EnGiant_PerformClockTowerSuccessActions; + Animation_Change(&this->skelAnime, &D_060116E4, 0.0f, Animation_GetLastFrame(&D_060116E4) - 1.0f, + Animation_GetLastFrame(&D_060116E4), 2, 0.0f); + this->actor.draw = EnGiant_Draw; + this->actor.velocity.y = 0.0f; + this->actor.minVelocityY = 0.0f; + this->actor.gravity = 0.0f; + } -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Giant/func_80B020A0.s") + if (GIANT_TYPE_IS_CLOCK_TOWER_FAILURE(type)) { + Actor_SetScale(&this->actor, 0.32f); + this->actionFunc = EnGiant_PlayClockTowerFailureAnimation; + Animation_Change(&this->skelAnime, &D_06013FE8, 1.0f, 0.0f, Animation_GetLastFrame(&D_06013004), 0, 0.0f); + this->actor.draw = EnGiant_Draw; + this->actor.velocity.y = 0.0f; + this->actor.minVelocityY = 0.0f; + this->actor.gravity = 0.0f; + if (EnGiant_IsImprisoned(this)) { + Actor_MarkForDeath(&this->actor); + } + } -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Giant/func_80B0211C.s") + if (GIANT_TYPE_IS_NOT_TERMINA_FIELD(type)) { + this->alpha = 255; + } -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Giant/func_80B02234.s") + this->sfxId = 0xFFFF; + if (GIANT_TYPE_IS_CHAMBER_OR_ENDING(type)) { + switch (gSaveContext.sceneSetupIndex) { + case 0: + case 10: + this->sfxId = NA_SE_EV_KYOJIN_GRATITUDE2 - SFX_FLAG; + break; + case 1: + case 2: + case 3: + this->sfxId = NA_SE_EV_KYOJIN_GRATITUDE1 - SFX_FLAG; + break; + default: + this->sfxId = NA_SE_EV_KYOJIN_GRATITUDE0 - SFX_FLAG; + break; + } + } +} -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Giant/func_80B02354.s") +void EnGiant_Destroy(Actor* thisx, GlobalContext* globalCtx) { +} -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Giant/func_80B023D0.s") +/** + * The animations in sAnimationTable are organized such that looping animations + * appear immediately after their respective starting animations. The point of + * this function is to play the requested start animation if it has not been + * played yet and play the respetive looping animation otherwise. + */ +void EnGiant_ChangeToStartOrLoopAnimation(EnGiant* this, s16 requestedAnimationId) { + s16 nextAnimationId = requestedAnimationId + 1; -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Giant/func_80B024AC.s") + if (this->animationId != nextAnimationId) { + if (this->animationId != requestedAnimationId) { + EnGiant_ChangeAnimation(this, requestedAnimationId); + } else { + EnGiant_ChangeAnimation(this, nextAnimationId); + } + } +} -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Giant/func_80B024D8.s") +/** + * Immediately switches to the specified animation for this cutscene action. + */ +void EnGiant_ChangeAnimationBasedOnCsAction(EnGiant* this) { + switch (this->csAction) { + case GIANT_CS_ACTION_IDLE: + EnGiant_ChangeAnimation(this, GIANT_ANIMATION_IDLE_LOOP); + break; + case GIANT_CS_ACTION_WALKING: + EnGiant_ChangeAnimation(this, GIANT_ANIMATION_WALKING_LOOP); + break; + case GIANT_CS_ACTION_STRUGGLING: + EnGiant_ChangeAnimation(this, GIANT_ANIMATION_STRUGGLE_START); + break; + case GIANT_CS_ACTION_FALLING_OVER: + EnGiant_ChangeAnimation(this, GIANT_ANIMATION_FALLING_OVER); + break; + case GIANT_CS_ACTION_IDLE_FADE_IN: + EnGiant_ChangeAnimation(this, GIANT_ANIMATION_IDLE_LOOP); + this->alpha = 0; + break; + case GIANT_CS_ACTION_TALKING: + EnGiant_ChangeAnimation(this, GIANT_ANIMATION_BIG_CALL_START); + break; + case GIANT_CS_ACTION_DONE_TALKING: + EnGiant_ChangeAnimation(this, GIANT_ANIMATION_BIG_CALL_END); + break; + case GIANT_CS_ACTION_TEACHING_OATH_TO_ORDER: + EnGiant_ChangeAnimation(this, GIANT_ANIMATION_SMALL_CALL_START); + break; + case GIANT_CS_ACTION_PLAYER_LEARNED_OATH_TO_ORDER: + EnGiant_ChangeAnimation(this, GIANT_ANIMATION_SMALL_CALL_END); + break; + case GIANT_CS_ACTION_UNKNOWN_12: + EnGiant_ChangeAnimation(this, GIANT_ANIMATION_IDLE_LOOP); + break; + case GIANT_CS_ACTION_UNKNOWN_13: + EnGiant_ChangeAnimation(this, GIANT_ANIMATION_WALKING_LOOP); + break; + case GIANT_CS_ACTION_UNKNOWN_14: + if (this->animationId != GIANT_ANIMATION_WALKING_LOOP) { + EnGiant_ChangeAnimation(this, GIANT_ANIMATION_WALKING_LOOP); + } + break; + case GIANT_CS_ACTION_HOLDING_UP_MOON_IN_CLOCK_TOWER: + Animation_Change(&this->skelAnime, &D_060116E4, 0.0f, Animation_GetLastFrame(&D_060116E4) - 1.0f, + Animation_GetLastFrame(&D_060116E4), 2, 0.0f); + break; + } +} -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Giant/EnGiant_Update.s") +void EnGiant_UpdateAlpha(EnGiant* this) { + switch (this->csAction) { + case GIANT_CS_ACTION_FALLING_OVER: + if (this->skelAnime.curFrame >= 90.0f && this->alpha > 0) { + this->alpha -= 12; + } + break; + case GIANT_CS_ACTION_UNKNOWN_14: + this->alpha -= 12; + break; + default: + if (this->alpha < 255) { + this->alpha += 8; + } + break; + } +} -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Giant/func_80B02688.s") +/** + * Plays the currently specified animation and, if the animation is done playing, + * switches to the animation appropriate for the current cutscene action. This + * function can be used to play the appropriate starting or looping animation for + * a given cutscene action, depending on what animation has already been played. + */ +void EnGiant_PlayAndUpdateAnimation(EnGiant* this) { + if (SkelAnime_Update(&this->skelAnime) && + (this->animationId != GIANT_ANIMATION_FALLING_OVER || this->csAction != GIANT_CS_ACTION_FALLING_OVER)) { + EnGiant_ChangeAnimation(this, this->animationId); + switch (this->csAction) { + case GIANT_CS_ACTION_LOOKING_UP: + EnGiant_ChangeToStartOrLoopAnimation(this, GIANT_ANIMATION_LOOK_UP_START); + break; + case GIANT_CS_ACTION_RAISING_ARMS: + EnGiant_ChangeToStartOrLoopAnimation(this, GIANT_ANIMATION_RAISED_ARMS_START); + break; + case GIANT_CS_ACTION_STRUGGLING: + EnGiant_ChangeToStartOrLoopAnimation(this, GIANT_ANIMATION_STRUGGLE_START); + break; + case GIANT_CS_ACTION_FALLING_OVER: + // Unused + EnGiant_ChangeToStartOrLoopAnimation(this, GIANT_ANIMATION_FALLING_OVER); + break; + case GIANT_CS_ACTION_TALKING: + EnGiant_ChangeAnimation(this, GIANT_ANIMATION_BIG_CALL_LOOP); + break; + case GIANT_CS_ACTION_DONE_TALKING: + case GIANT_CS_ACTION_PLAYER_LEARNED_OATH_TO_ORDER: + EnGiant_ChangeAnimation(this, GIANT_ANIMATION_IDLE_LOOP); + break; + case GIANT_CS_ACTION_TEACHING_OATH_TO_ORDER: + EnGiant_ChangeAnimation(this, GIANT_ANIMATION_SMALL_CALL_LOOP); + break; + } + SkelAnime_Update(&this->skelAnime); + } +} -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Giant/func_80B026C4.s") +void EnGiant_PlaySound(EnGiant* this) { + if (this->actor.draw != NULL && this->alpha > 0) { + if (this->animationId == GIANT_ANIMATION_WALKING_LOOP && + (Animation_OnFrame(&this->skelAnime, 40.0f) || Animation_OnFrame(&this->skelAnime, 100.0f))) { + Audio_PlayActorSound2(&this->actor, NA_SE_EV_KYOJIN_WALK); + } + if (this->animationId == GIANT_ANIMATION_FALLING_OVER && Animation_OnFrame(&this->skelAnime, 40.0f)) { + Audio_PlayActorSound2(&this->actor, NA_SE_EV_KYOJIN_VOICE_FAIL); + } + if (this->sfxId != 0xFFFF && + ((this->animationId == GIANT_ANIMATION_BIG_CALL_START && this->skelAnime.curFrame >= 18.0f) || + this->animationId == GIANT_ANIMATION_BIG_CALL_LOOP)) { + func_800B9010(&this->actor, this->sfxId); + } + if ((this->animationId == GIANT_ANIMATION_SMALL_CALL_START && this->skelAnime.curFrame >= 18.0f) || + this->animationId == GIANT_ANIMATION_SMALL_CALL_LOOP) { + func_800B9010(&this->actor, NA_SE_EV_KYOJIN_SIGN - SFX_FLAG); + } + } +} -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Giant/EnGiant_Draw.s") +void EnGiant_UpdatePosition(EnGiant* this, GlobalContext* globalCtx, u32 actionIndex) { + CsCmdActorAction* actorAction = globalCtx->csCtx.npcActions[actionIndex]; + f32 floatUnk10 = actorAction->unk10; + s32 pad[2]; + f32 floatUnk1C = actorAction->unk1C; + f32 functionTemp; + + functionTemp = func_800F5A8C(actorAction->endFrame, actorAction->startFrame, globalCtx->csCtx.frames, globalCtx); + this->actor.world.pos.y = ((floatUnk1C - floatUnk10) * functionTemp) + floatUnk10; +} + +void EnGiant_PerformClockTowerSuccessActions(EnGiant* this, GlobalContext* globalCtx) { + if (func_800EE29C(globalCtx, this->unk_24A)) { + EnGiant_UpdatePosition(this, globalCtx, func_800EE200(globalCtx, this->unk_24A)); + if (this->csAction != globalCtx->csCtx.npcActions[func_800EE200(globalCtx, this->unk_24A)]->unk0) { + this->csAction = globalCtx->csCtx.npcActions[func_800EE200(globalCtx, this->unk_24A)]->unk0; + EnGiant_ChangeAnimationBasedOnCsAction(this); + } + EnGiant_UpdateAlpha(this); + } + + EnGiant_PlaySound(this); + if (this->csAction == GIANT_CS_ACTION_STRUGGLING) { + func_800B9010(&this->actor, NA_SE_IT_KYOJIN_BEARING - SFX_FLAG); + } + EnGiant_PlayAndUpdateAnimation(this); +} + +void EnGiant_PlayClockTowerFailureAnimation(EnGiant* this, GlobalContext* globalCtx) { + SkelAnime_Update(&this->skelAnime); +} + +void EnGiant_PerformCutsceneActions(EnGiant* this, GlobalContext* globalCtx) { + this->actor.draw = EnGiant_Draw; + + if (func_800EE29C(globalCtx, this->unk_24A)) { + func_800EDF24(&this->actor, globalCtx, func_800EE200(globalCtx, this->unk_24A)); + if (this->csAction != globalCtx->csCtx.npcActions[func_800EE200(globalCtx, this->unk_24A)]->unk0) { + this->csAction = globalCtx->csCtx.npcActions[func_800EE200(globalCtx, this->unk_24A)]->unk0; + EnGiant_ChangeAnimationBasedOnCsAction(this); + } + EnGiant_UpdateAlpha(this); + } + + if (GIANT_TYPE_IS_TERMINA_FIELD(GIANT_TYPE(&this->actor)) && EnGiant_IsImprisoned(this)) { + this->actor.draw = NULL; + } + + EnGiant_PlaySound(this); + EnGiant_PlayAndUpdateAnimation(this); +} + +void EnGiant_Update(Actor* thisx, GlobalContext* globalCtx) { + EnGiant* this = THIS; + s32 blinkTimerTemp; + + this->actionFunc(this, globalCtx); + Actor_SetVelocityAndMoveYRotationAndGravity(&this->actor); + Actor_UpdateBgCheckInfo(globalCtx, &this->actor, 0.0f, 0.0f, 0.0f, 4); + + if (this->blinkTimer == 0) { + blinkTimerTemp = 0; + } else { + this->blinkTimer--; + blinkTimerTemp = this->blinkTimer; + } + + if (!blinkTimerTemp) { + this->blinkTimer = Rand_S16Offset(60, 60); + } + this->faceIndex = this->blinkTimer; + if (this->faceIndex >= 3) { + this->faceIndex = 0; + } +} + +void EnGiant_PostLimbDrawOpa(GlobalContext* globalCtx, s32 limbIndex, Gfx** dList, Vec3s* rot, Actor* thisx) { + if (limbIndex == 1) { + OPEN_DISPS(globalCtx->state.gfxCtx); + + gSPDisplayList(POLY_OPA_DISP++, D_06007610); + + CLOSE_DISPS(globalCtx->state.gfxCtx); + } +} + +void EnGiant_PostLimbDrawXlu(GlobalContext* globalCtx, s32 limbIndex, Gfx** dList, Vec3s* rot, Actor* thisx, + Gfx** gfx) { + EnGiant* this = THIS; + + if (limbIndex == 1) { + Matrix_CopyCurrentState(&this->unk_254); + } +} + +void EnGiant_Draw(Actor* thisx, GlobalContext* globalCtx) { + s32 pad; + EnGiant* this = THIS; + + /** + * 0 = eyes fully open face + * 1 = eyes half-closed face + * 2 = eyes fully closed face + */ + static TexturePtr sFaceTextures[] = { D_06005A80, D_06006280, D_06006A80 }; + + if (this->alpha > 0) { + OPEN_DISPS(globalCtx->state.gfxCtx); + + if (this->alpha >= 255) { + func_8012C28C(globalCtx->state.gfxCtx); + gSPSegment(POLY_OPA_DISP++, 0x08, Lib_SegmentedToVirtual(sFaceTextures[this->faceIndex])); + gDPSetEnvColor(POLY_OPA_DISP++, 0, 0, 0, 255); + Scene_SetRenderModeXlu(globalCtx, 0, 1); + SkelAnime_DrawFlexOpa(globalCtx, this->skelAnime.skeleton, this->skelAnime.jointTable, + this->skelAnime.dListCount, NULL, EnGiant_PostLimbDrawOpa, thisx); + } else if (this->alpha > 0) { + if (this->alpha >= 129) { + func_8012C2B4(POLY_XLU_DISP++); + Scene_SetRenderModeXlu(globalCtx, 2, 2); + } else { + func_8012C304(POLY_XLU_DISP++); + Scene_SetRenderModeXlu(globalCtx, 1, 2); + } + gSPSegment(POLY_XLU_DISP++, 0x08, Lib_SegmentedToVirtual(sFaceTextures[this->faceIndex])); + gDPSetEnvColor(POLY_XLU_DISP++, 0, 0, 0, this->alpha); + POLY_XLU_DISP = + SkelAnime_DrawFlex(globalCtx, this->skelAnime.skeleton, this->skelAnime.jointTable, + this->skelAnime.dListCount, NULL, EnGiant_PostLimbDrawXlu, thisx, POLY_XLU_DISP); + Matrix_InsertMatrix(&this->unk_254, MTXMODE_NEW); + gSPMatrix(POLY_XLU_DISP++, Matrix_NewMtx(globalCtx->state.gfxCtx), + G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW); + gSPDisplayList(POLY_XLU_DISP++, D_06007610); + } + + CLOSE_DISPS(globalCtx->state.gfxCtx); + } +} diff --git a/src/overlays/actors/ovl_En_Giant/z_en_giant.h b/src/overlays/actors/ovl_En_Giant/z_en_giant.h index 9c75272fac..6f50370f7b 100644 --- a/src/overlays/actors/ovl_En_Giant/z_en_giant.h +++ b/src/overlays/actors/ovl_En_Giant/z_en_giant.h @@ -3,14 +3,107 @@ #include "global.h" +#define GIANT_TYPE(thisx) ((thisx)->params & 0xF) +#define GIANT_TYPE_IS_NOT_TERMINA_FIELD(type) (type > GIANT_TYPE_OCEAN_TERMINA_FIELD) +#define GIANT_TYPE_IS_TERMINA_FIELD(type) (type <= GIANT_TYPE_OCEAN_TERMINA_FIELD) +#define GIANT_TYPE_IS_CLOCK_TOWER_SUCCESS(type) (type >= GIANT_TYPE_MOUNTAIN_CLOCK_TOWER_SUCCESS && type <= GIANT_TYPE_OCEAN_CLOCK_TOWER_SUCCESS) +#define GIANT_TYPE_IS_CHAMBER_OR_ENDING(type) (type >= GIANT_TYPE_MOUNTAIN_GIANTS_CHAMBER_AND_ENDING && type <= GIANT_TYPE_OCEAN_GIANTS_CHAMBER_AND_ENDING) +#define GIANT_TYPE_IS_CLOCK_TOWER_FAILURE(type) (type >= GIANT_TYPE_MOUNTAIN_CLOCK_TOWER_FAILURE && type <= GIANT_TYPE_OCEAN_CLOCK_TOWER_FAILURE) + +/** + * The giants are divided into types based on where in the game they appear. + * - TERMINA_FIELD: These appear in all non-ending cutscenes that take place in Termina Field. + * - CLOCK_TOWER_SUCCESS: These appear in the Clock Tower when the Oath to Order is played and all giants are freed. + * - GIANTS_CHAMBER_AND_ENDING: These giants appear in the Giant's Chamber or in all cutscenes that play after defeating Majora. + * - CLOCK_TOWER_FAILURE: These appear in the Clock Tower when the Oath to Order is played and all giants are NOT freed. + * + * The SWAMP, MOUNTAIN, OCEAN, and CANYON signifiers are used to identify which of the four giants it is, + * but the devs were not always consistent about this. For example, the giants in the Giant's Chamber are + * always GIANT_TYPE_MOUNTAIN_GIANTS_CHAMBER_AND_ENDING, regardless of which boss was just defeated. These + * are named such that EnGiant_IsImprisoned has the expected behavior; the devs were only inconsistent in + * the cases where they weren't calling this function. + */ +typedef enum { + /* 0 */ GIANT_TYPE_MOUNTAIN_TERMINA_FIELD, + /* 1 */ GIANT_TYPE_CANYON_TERMINA_FIELD, + /* 2 */ GIANT_TYPE_SWAMP_TERMINA_FIELD, + /* 3 */ GIANT_TYPE_OCEAN_TERMINA_FIELD, + /* 4 */ GIANT_TYPE_MOUNTAIN_CLOCK_TOWER_SUCCESS, + /* 5 */ GIANT_TYPE_CANYON_CLOCK_TOWER_SUCCESS, + /* 6 */ GIANT_TYPE_SWAMP_CLOCK_TOWER_SUCCESS, + /* 7 */ GIANT_TYPE_OCEAN_CLOCK_TOWER_SUCCESS, + /* 8 */ GIANT_TYPE_MOUNTAIN_GIANTS_CHAMBER_AND_ENDING, + /* 9 */ GIANT_TYPE_CANYON_GIANTS_CHAMBER_AND_ENDING, + /* 10 */ GIANT_TYPE_SWAMP_GIANTS_CHAMBER_AND_ENDING, + /* 11 */ GIANT_TYPE_OCEAN_GIANTS_CHAMBER_AND_ENDING, + /* 12 */ GIANT_TYPE_MOUNTAIN_CLOCK_TOWER_FAILURE, + /* 13 */ GIANT_TYPE_CANYON_CLOCK_TOWER_FAILURE, + /* 14 */ GIANT_TYPE_SWAMP_CLOCK_TOWER_FAILURE, + /* 15 */ GIANT_TYPE_OCEAN_CLOCK_TOWER_FAILURE, +} GiantType; + +/** + * These values are used to index into sAnimationTable to pick the appropriate animation. + */ +typedef enum { + /* 0 */ GIANT_ANIMATION_LOOK_UP_START, + /* 1 */ GIANT_ANIMATION_LOOK_UP_LOOP, + /* 2 */ GIANT_ANIMATION_FALLING_OVER, + /* 3 */ GIANT_ANIMATION_RAISED_ARMS_START, + /* 4 */ GIANT_ANIMATION_RAISED_ARMS_LOOP, + /* 5 */ GIANT_ANIMATION_STRUGGLE_START, + /* 6 */ GIANT_ANIMATION_STRUGGLE_LOOP, + /* 7 */ GIANT_ANIMATION_IDLE_LOOP, + /* 8 */ GIANT_ANIMATION_WALKING_LOOP, + /* 9 */ GIANT_ANIMATION_BIG_CALL_START, + /* 10 */ GIANT_ANIMATION_BIG_CALL_LOOP, + /* 11 */ GIANT_ANIMATION_BIG_CALL_END, + /* 12 */ GIANT_ANIMATION_SMALL_CALL_START, + /* 13 */ GIANT_ANIMATION_SMALL_CALL_LOOP, + /* 14 */ GIANT_ANIMATION_SMALL_CALL_END, + /* 15 */ GIANT_ANIMATION_MAX +} GiantAnimationIndex; + +/** + * Used as values for csAction. The UNKNOWN ones are never used in-game. + */ +typedef enum { + /* 0 */ GIANT_CS_ACTION_NONE, + /* 1 */ GIANT_CS_ACTION_IDLE, + /* 2 */ GIANT_CS_ACTION_WALKING, + /* 3 */ GIANT_CS_ACTION_LOOKING_UP, + /* 4 */ GIANT_CS_ACTION_RAISING_ARMS, + /* 5 */ GIANT_CS_ACTION_STRUGGLING, + /* 6 */ GIANT_CS_ACTION_FALLING_OVER, + /* 7 */ GIANT_CS_ACTION_IDLE_FADE_IN, + /* 8 */ GIANT_CS_ACTION_TALKING, + /* 9 */ GIANT_CS_ACTION_DONE_TALKING, + /* 10 */ GIANT_CS_ACTION_TEACHING_OATH_TO_ORDER, + /* 11 */ GIANT_CS_ACTION_PLAYER_LEARNED_OATH_TO_ORDER, + /* 12 */ GIANT_CS_ACTION_UNKNOWN_12, + /* 13 */ GIANT_CS_ACTION_UNKNOWN_13, + /* 14 */ GIANT_CS_ACTION_UNKNOWN_14, + /* 15 */ GIANT_CS_ACTION_HOLDING_UP_MOON_IN_CLOCK_TOWER +} GiantCsActionIndex; + struct EnGiant; typedef void (*EnGiantActionFunc)(struct EnGiant*, GlobalContext*); typedef struct EnGiant { - /* 0x0000 */ Actor actor; - /* 0x0144 */ char unk_144[0x154]; - /* 0x0298 */ EnGiantActionFunc actionFunc; + /* 0x000 */ Actor actor; + /* 0x144 */ SkelAnime skelAnime; + /* 0x188 */ Vec3s jointTable[16]; + /* 0x1E8 */ Vec3s morphTable[16]; + /* 0x248 */ s16 animationId; + /* 0x24A */ u16 unk_24A; + /* 0x24C */ u16 csAction; + /* 0x24E */ s16 alpha; + /* 0x250 */ u16 sfxId; + /* 0x254 */ MtxF unk_254; + /* 0x294 */ s16 faceIndex; + /* 0x296 */ s16 blinkTimer; + /* 0x298 */ EnGiantActionFunc actionFunc; } EnGiant; // size = 0x29C extern const ActorInit En_Giant_InitVars; diff --git a/tools/disasm/functions.txt b/tools/disasm/functions.txt index cf6076b7fb..e77e59ad0a 100644 --- a/tools/disasm/functions.txt +++ b/tools/disasm/functions.txt @@ -12869,22 +12869,22 @@ 0x80B00F08:("func_80B00F08",), 0x80B00F64:("func_80B00F64",), 0x80B01040:("EnTalkGibud_Draw",), - 0x80B01990:("func_80B01990",), - 0x80B01A74:("func_80B01A74",), + 0x80B01990:("EnGiant_ChangeAnimation",), + 0x80B01A74:("EnGiant_IsImprisoned",), 0x80B01B30:("EnGiant_Init",), 0x80B01E74:("EnGiant_Destroy",), - 0x80B01E84:("func_80B01E84",), - 0x80B01EE8:("func_80B01EE8",), - 0x80B020A0:("func_80B020A0",), - 0x80B0211C:("func_80B0211C",), - 0x80B02234:("func_80B02234",), - 0x80B02354:("func_80B02354",), - 0x80B023D0:("func_80B023D0",), - 0x80B024AC:("func_80B024AC",), - 0x80B024D8:("func_80B024D8",), + 0x80B01E84:("EnGiant_ChangeToStartOrLoopAnimation",), + 0x80B01EE8:("EnGiant_ChangeAnimationBasedOnCsAction",), + 0x80B020A0:("EnGiant_UpdateAlpha",), + 0x80B0211C:("EnGiant_PlayAndUpdateAnimation",), + 0x80B02234:("EnGiant_PlaySound",), + 0x80B02354:("EnGiant_UpdatePosition",), + 0x80B023D0:("EnGiant_PerformClockTowerSuccessActions",), + 0x80B024AC:("EnGiant_PlayClockTowerFailureAnimation",), + 0x80B024D8:("EnGiant_PerformCutsceneActions",), 0x80B025CC:("EnGiant_Update",), - 0x80B02688:("func_80B02688",), - 0x80B026C4:("func_80B026C4",), + 0x80B02688:("EnGiant_PostLimbDrawOpa",), + 0x80B026C4:("EnGiant_PostLimbDrawXlu",), 0x80B026FC:("EnGiant_Draw",), 0x80B02CD0:("func_80B02CD0",), 0x80B02D58:("func_80B02D58",), diff --git a/undefined_syms.txt b/undefined_syms.txt index d6a0e05ee6..2b5e232578 100644 --- a/undefined_syms.txt +++ b/undefined_syms.txt @@ -2321,11 +2321,26 @@ D_0600F6C0 = 0x0600F6C0; // ovl_En_Giant D_06002168 = 0x06002168; +D_06005A80 = 0x06005A80; +D_06006280 = 0x06006280; +D_06006A80 = 0x06006A80; D_06007610 = 0x06007610; D_060079B0 = 0x060079B0; +D_06008394 = 0x06008394; +D_060096E4 = 0x060096E4; +D_0600A1C4 = 0x0600A1C4; +D_0600ACA4 = 0x0600ACA4; +D_0600B784 = 0x0600B784; +D_0600C5D4 = 0x0600C5D4; +D_0600D040 = 0x0600D040; +D_0600DE84 = 0x0600DE84; +D_060102A4 = 0x060102A4; D_060116E4 = 0x060116E4; +D_06012A38 = 0x06012A38; D_06013004 = 0x06013004; D_06013FE8 = 0x06013FE8; +D_06015334 = 0x06015334; +D_06017944 = 0x06017944; // ovl_En_Ginko_Man