From 9102481fc2da8ffd4f1f7620ad18c4ed30d2927e Mon Sep 17 00:00:00 2001 From: engineer124 <47598039+engineer124@users.noreply.github.com> Date: Thu, 10 Jun 2021 11:03:42 +1000 Subject: [PATCH] Ovl_En_Minifrog OK with partial documentation (#166) * En_Minifrog first few funcs decompiled * more matching * En_Minifrog 3 non_matching functions left * two functions left * Start Documentation * Fully Matching! * Documentation * Fix merge with master * minor pr changes * Minor improvements * PR Suggestions + Minor docs * Fix bool * PR suggestions Co-authored-by: engineer124 --- include/functions.h | 5 +- include/z64.h | 4 +- linker_scripts/code_script.txt | 4 +- linker_scripts/object_script.txt | 9 + .../actors/ovl_En_Minifrog/z_en_minifrog.c | 623 +++++++++++++++++- .../actors/ovl_En_Minifrog/z_en_minifrog.h | 30 +- tables/functions.txt | 48 +- 7 files changed, 663 insertions(+), 60 deletions(-) diff --git a/include/functions.h b/include/functions.h index 0ddac8d6d6..1bb1bc51cf 100644 --- a/include/functions.h +++ b/include/functions.h @@ -601,7 +601,8 @@ void EffectSsDust_Spawn(GlobalContext* globalCtx, u16 drawFlags, Vec3f* pos, Vec // void func_800B0E48(UNK_TYPE1 param_1, UNK_TYPE1 param_2, UNK_TYPE1 param_3, UNK_TYPE1 param_4, UNK_TYPE4 param_5, UNK_TYPE4 param_6, UNK_TYPE2 param_7, UNK_TYPE2 param_8); // void func_800B0EB0(UNK_TYPE1 param_1, UNK_TYPE1 param_2, UNK_TYPE1 param_3, UNK_TYPE1 param_4, UNK_TYPE4 param_5, UNK_TYPE4 param_6, UNK_TYPE2 param_7, UNK_TYPE2 param_8, UNK_TYPE2 param_9); // void func_800B0F18(UNK_TYPE1 param_1, UNK_TYPE1 param_2, UNK_TYPE1 param_3, UNK_TYPE1 param_4, UNK_TYPE4 param_5, UNK_TYPE4 param_6, UNK_TYPE2 param_7, UNK_TYPE2 param_8, UNK_TYPE2 param_9); -// void func_800B0F80(UNK_TYPE1 param_1, UNK_TYPE1 param_2, UNK_TYPE1 param_3, UNK_TYPE1 param_4, UNK_TYPE4 param_5, UNK_TYPE4 param_6, UNK_TYPE2 param_7, UNK_TYPE2 param_8, UNK_TYPE2 param_9); +void func_800B0F80(GlobalContext* globalCtx, Vec3f* pos, Vec3f* velocity, Vec3f* accel, Color_RGBA8* primColor, + Color_RGBA8* envColor, s16 scale, s16 scaleStep, s16 life); // void func_800B0FE8(UNK_TYPE1 param_1, UNK_TYPE1 param_2, UNK_TYPE1 param_3, UNK_TYPE1 param_4, UNK_TYPE4 param_5, UNK_TYPE4 param_6, UNK_TYPE2 param_7, UNK_TYPE2 param_8); // void func_800B1054(UNK_TYPE1 param_1, UNK_TYPE1 param_2, UNK_TYPE1 param_3, UNK_TYPE1 param_4, UNK_TYPE4 param_5, UNK_TYPE4 param_6, UNK_TYPE2 param_7, UNK_TYPE2 param_8); // void func_800B10C0(void); @@ -3923,7 +3924,7 @@ void func_801A31EC(UNK_TYPE1 arg1, UNK_TYPE4 arg2, u8 arg3); // void func_801A32CC(void); // void func_801A3590(void); // void func_801A3950(void); -// void func_801A39F8(void); +u8 func_801A39F8(void); // void func_801A3A7C(void); // void func_801A3AC0(void); // void func_801A3AEC(void); diff --git a/include/z64.h b/include/z64.h index 272f858d3f..13baa1a817 100644 --- a/include/z64.h +++ b/include/z64.h @@ -1530,7 +1530,9 @@ struct GlobalContext { /* 0x17D88 */ ObjectContext objectCtx; /* 0x186E0 */ RoomContext roomContext; /* 0x18760 */ TransitionContext transitionCtx; - /* 0x18768 */ UNK_TYPE1 pad18768[0x48]; + /* 0x18768 */ UNK_TYPE1 pad18768[0x30]; + /* 0x18798 */ void (*func_18798)(struct GlobalContext* globalCtx, void* arg1, s32 arg2); + /* 0x1879C */ UNK_TYPE1 pad1879C[0x14]; /* 0x187B0 */ MtxF unk187B0; /* 0x187F0 */ UNK_TYPE1 pad187F0[0xC]; /* 0x187FC */ MtxF unk187FC; diff --git a/linker_scripts/code_script.txt b/linker_scripts/code_script.txt index 5d9e02cd16..c754affbac 100644 --- a/linker_scripts/code_script.txt +++ b/linker_scripts/code_script.txt @@ -1212,9 +1212,9 @@ SECTIONS ovl_En_Minifrog : AT(RomLocation) { build/src/overlays/actors/ovl_En_Minifrog/z_en_minifrog.o(.text) - build/asm/overlays/ovl_En_Minifrog_data.o(.data) + build/src/overlays/actors/ovl_En_Minifrog/z_en_minifrog.o(.data) build/src/overlays/actors/ovl_En_Minifrog/z_en_minifrog.o(.rodata) - build/asm/overlays/ovl_En_Minifrog_rodata.o(.rodata) + build/src/overlays/actors/ovl_En_Minifrog/z_en_minifrog_overlay.o(.ovl) } SegmentEnd = .; SegmentSize = SegmentEnd - SegmentStart; diff --git a/linker_scripts/object_script.txt b/linker_scripts/object_script.txt index 51ff58a911..25114fea89 100644 --- a/linker_scripts/object_script.txt +++ b/linker_scripts/object_script.txt @@ -1,5 +1,7 @@ /* gameplay_keep */ D_040008D0 = 0x040008D0; +D_0400DEA8 = 0x0400DEA8; +D_0400E2A8 = 0x0400E2A8; D_04029CB0 = 0x04029CB0; D_04029CF0 = 0x04029CF0; D_04058BA0 = 0x04058BA0; @@ -264,6 +266,13 @@ D_04054A90 = 0x04054A90; D_06000AD0 = 0x06000AD0; D_06000140 = 0x06000140; +/* en_minifrog */ +D_060007BC = 0x060007BC; +D_06001534 = 0x06001534; +D_060059A0 = 0x060059A0; +D_06005BA0 = 0x06005BA0; +D_0600B538 = 0x0600B538; + /* bg_lotus */ D_06000A20 = 0x06000A20; D_06000040 = 0x06000040; diff --git a/src/overlays/actors/ovl_En_Minifrog/z_en_minifrog.c b/src/overlays/actors/ovl_En_Minifrog/z_en_minifrog.c index e4ad298a4a..53aae5ea32 100644 --- a/src/overlays/actors/ovl_En_Minifrog/z_en_minifrog.c +++ b/src/overlays/actors/ovl_En_Minifrog/z_en_minifrog.c @@ -1,3 +1,9 @@ +/* + * File: z_en_minifrog.c + * Overlay: ovl_En_Minifrog + * Description: Five Frogs of the Frog Choir + */ + #include "z_en_minifrog.h" #define FLAGS 0x00000019 @@ -9,7 +15,23 @@ void EnMinifrog_Destroy(Actor* thisx, GlobalContext* globalCtx); void EnMinifrog_Update(Actor* thisx, GlobalContext* globalCtx); void EnMinifrog_Draw(Actor* thisx, GlobalContext* globalCtx); -/* +EnMinifrog* EnMinifrog_GetFrog(GlobalContext* globalCtx); + +void EnMinifrog_SpawnGrowAndShrink(EnMinifrog* this, GlobalContext* globalCtx); +void EnMinifrog_Idle(EnMinifrog* this, GlobalContext* globalCtx); +void EnMinifrog_SetupNextFrogInit(EnMinifrog* this, GlobalContext* globalCtx); +void EnMinifrog_UpdateMissingFrog(Actor* thisx, GlobalContext* globalCtx); +void EnMinifrog_YellowFrogDialog(EnMinifrog* this, GlobalContext* globalCtx); +void EnMinifrog_SetupYellowFrogDialog(EnMinifrog* this, GlobalContext* globalCtx); + +extern AnimationHeader D_060007BC; +extern AnimationHeader D_06001534; +extern FlexSkeletonHeader D_0600B538; +extern UNK_TYPE4 D_060059A0; +extern UNK_TYPE4 D_06005BA0; +extern UNK_TYPE1 D_0400DEA8; +extern UNK_TYPE1 D_0400E2A8; + const ActorInit En_Minifrog_InitVars = { ACTOR_EN_MINIFROG, ACTORCAT_NPC, @@ -21,60 +43,601 @@ const ActorInit En_Minifrog_InitVars = { (ActorFunc)EnMinifrog_Update, (ActorFunc)EnMinifrog_Draw, }; -*/ -#pragma GLOBAL_ASM("./asm/non_matchings/overlays/ovl_En_Minifrog_0x808A3670/EnMinifrog_Init.asm") +static ColliderCylinderInit sCylinderInit = { + { + COLTYPE_NONE, + AT_NONE, + AC_NONE, + OC1_ON | OC1_TYPE_ALL, + OC2_TYPE_1, + COLSHAPE_CYLINDER, + }, + { + ELEMTYPE_UNK1, + { 0xF7CFFFFF, 0x00, 0x00 }, + { 0xF7CFFFFF, 0x00, 0x00 }, + TOUCH_NONE | TOUCH_SFX_NORMAL, + BUMP_NONE, + OCELEM_ON, + }, + { 12, 14, 0, { 0, 0, 0 } }, +}; -#pragma GLOBAL_ASM("./asm/non_matchings/overlays/ovl_En_Minifrog_0x808A3670/EnMinifrog_Destroy.asm") +static CollisionCheckInfoInit sColChkInfoInit = { 1, 12, 14, MASS_IMMOVABLE }; -#pragma GLOBAL_ASM("./asm/non_matchings/overlays/ovl_En_Minifrog_0x808A3670/func_808A3930.asm") +// sEyeTextures??? +static UNK_TYPE4* D_808A4D74[] = { + &D_060059A0, + &D_06005BA0, +}; -#pragma GLOBAL_ASM("./asm/non_matchings/overlays/ovl_En_Minifrog_0x808A3670/func_808A3980.asm") +// gSaveContext.weekEventReg[KEY] = VALUE +// KEY | VALUE +static u16 isFrogReturnedFlags[] = { + (0 << 8) | 0x00, // NULL + (32 << 8) | 0x40, // Woodfall Temple Frog Returned + (32 << 8) | 0x80, // Great Bay Temple Frog Returned + (33 << 8) | 0x01, // Southern Swamp Frog Returned + (33 << 8) | 0x02, // Laundry Pool Frog Returned +}; -#pragma GLOBAL_ASM("./asm/non_matchings/overlays/ovl_En_Minifrog_0x808A3670/func_808A39EC.asm") +static s32 isInitialized = false; -#pragma GLOBAL_ASM("./asm/non_matchings/overlays/ovl_En_Minifrog_0x808A3670/func_808A3A44.asm") +static InitChainEntry sInitChain[] = { + ICHAIN_F32_DIV1000(gravity, -800, ICHAIN_STOP), +}; -#pragma GLOBAL_ASM("./asm/non_matchings/overlays/ovl_En_Minifrog_0x808A3670/func_808A3B04.asm") +void EnMinifrog_Init(Actor* thisx, GlobalContext* globalCtx) { + EnMinifrog* this = THIS; + int i; -#pragma GLOBAL_ASM("./asm/non_matchings/overlays/ovl_En_Minifrog_0x808A3670/func_808A3B3C.asm") + Actor_ProcessInitChain(&this->actor, sInitChain); + ActorShape_Init(&this->actor.shape, 0.0f, func_800B3FC0, 15.0f); + SkelAnime_InitSV(globalCtx, &this->skelAnime, &D_0600B538, &D_06001534, this->limbDrawTable, this->transitionDrawTable, 24); + CollisionCheck_SetInfo(&this->actor.colChkInfo, NULL, &sColChkInfoInit); + Collider_InitAndSetCylinder(globalCtx, &this->collider, &this->actor, &sCylinderInit); -#pragma GLOBAL_ASM("./asm/non_matchings/overlays/ovl_En_Minifrog_0x808A3670/func_808A3B74.asm") + if (!isInitialized) { + for (i = 0; i < 2; i++) { + D_808A4D74[i] = Lib_SegmentedToVirtual(D_808A4D74[i]); + } + isInitialized = true; + } -#pragma GLOBAL_ASM("./asm/non_matchings/overlays/ovl_En_Minifrog_0x808A3670/func_808A3DA8.asm") + this->frogIndex = (this->actor.params & 0xF); + if (this->frogIndex >= 5) { + this->frogIndex = MINIFROG_YELLOW; + } -#pragma GLOBAL_ASM("./asm/non_matchings/overlays/ovl_En_Minifrog_0x808A3670/func_808A3F88.asm") + this->actor.speedXZ = 0.0f; + this->actionFunc = EnMinifrog_Idle; + this->jumpState = MINIFROG_STATE_GROUND; + this->flags = 0; + this->timer = 0; -#pragma GLOBAL_ASM("./asm/non_matchings/overlays/ovl_En_Minifrog_0x808A3670/func_808A4040.asm") + if (1) {} + if (!EN_MINIFROG_IS_RETURNED(this)) { + if ((this->frogIndex == MINIFROG_YELLOW) || ((gSaveContext.weekEventReg[isFrogReturnedFlags[this->frogIndex] >> 8] & (u8)isFrogReturnedFlags[this->frogIndex]))) { + Actor_MarkForDeath(&this->actor); + } else { + this->timer = 30; + this->actionFunc = EnMinifrog_SpawnGrowAndShrink; + this->actor.textId = 0xD81; // "Ah! Don Gero! It has been so long." + this->actor.colChkInfo.mass = 30; + } + } else { // Frogs in mountain village + if (this->frogIndex == MINIFROG_YELLOW) { + this->actor.textId = 0; + this->actionFunc = EnMinifrog_SetupYellowFrogDialog; -#pragma GLOBAL_ASM("./asm/non_matchings/overlays/ovl_En_Minifrog_0x808A3670/func_808A410C.asm") + // Not spoken to MINIFROG_YELLOW + if (!(gSaveContext.weekEventReg[34] & 1)) { + this->actor.flags |= 0x10000; + } -#pragma GLOBAL_ASM("./asm/non_matchings/overlays/ovl_En_Minifrog_0x808A3670/func_808A41A0.asm") + this->actor.home.rot.x = this->actor.home.rot.z = 0; + this->frog = NULL; + } else { + this->frog = EnMinifrog_GetFrog(globalCtx); + this->actor.flags &= ~1; -#pragma GLOBAL_ASM("./asm/non_matchings/overlays/ovl_En_Minifrog_0x808A3670/func_808A4214.asm") + // Frog has been returned + if ((gSaveContext.weekEventReg[isFrogReturnedFlags[this->frogIndex] >> 8] & (u8)isFrogReturnedFlags[this->frogIndex])) { + this->actionFunc = EnMinifrog_SetupNextFrogInit; + } else { + this->actor.draw = NULL; + this->actor.update = EnMinifrog_UpdateMissingFrog; + } + } + } +} -#pragma GLOBAL_ASM("./asm/non_matchings/overlays/ovl_En_Minifrog_0x808A3670/func_808A42D8.asm") +void EnMinifrog_Destroy(Actor* thisx, GlobalContext* globalCtx) { + EnMinifrog* this = THIS; -#pragma GLOBAL_ASM("./asm/non_matchings/overlays/ovl_En_Minifrog_0x808A3670/func_808A4328.asm") + Collider_DestroyCylinder(globalCtx, &this->collider); + if (this->flags & 0x100) { + func_801A1F88(); + } +} -#pragma GLOBAL_ASM("./asm/non_matchings/overlays/ovl_En_Minifrog_0x808A3670/func_808A43A4.asm") +EnMinifrog* EnMinifrog_GetFrog(GlobalContext* globalCtx) { + EnMinifrog* frog = (EnMinifrog*)globalCtx->actorCtx.actorList[ACTORCAT_NPC].first; -#pragma GLOBAL_ASM("./asm/non_matchings/overlays/ovl_En_Minifrog_0x808A3670/func_808A44BC.asm") + while (frog != NULL) { + if ((frog->actor.id != ACTOR_EN_MINIFROG) || (frog->actor.params & 0xF)) { + frog = (EnMinifrog*)frog->actor.next; + } else { + return frog; + } + } -#pragma GLOBAL_ASM("./asm/non_matchings/overlays/ovl_En_Minifrog_0x808A3670/func_808A45A8.asm") + return NULL; +} -#pragma GLOBAL_ASM("./asm/non_matchings/overlays/ovl_En_Minifrog_0x808A3670/func_808A4634.asm") +void EnMinifrog_SetJumpState(EnMinifrog* this) { + if (this->jumpState == MINIFROG_STATE_GROUND) { + this->jumpState = MINIFROG_STATE_JUMP; + SkelAnime_ChangeAnim(&this->skelAnime, &D_060007BC, 1.0f, 0.0f, 7.0f, 2, -5.0f); + } +} -#pragma GLOBAL_ASM("./asm/non_matchings/overlays/ovl_En_Minifrog_0x808A3670/func_808A46E8.asm") +void EnMinifrog_JumpTimer(EnMinifrog* this) { + if (this->timer > 0) { + this->timer--; + } else { + this->timer = 60 + (s32)Rand_ZeroFloat(40.0f); + EnMinifrog_SetJumpState(this); + } +} -#pragma GLOBAL_ASM("./asm/non_matchings/overlays/ovl_En_Minifrog_0x808A3670/func_808A4914.asm") +void EnMinifrog_Jump(EnMinifrog* this) { + SkelAnime_FrameUpdateMatrix(&this->skelAnime); + switch (this->jumpState) { + case MINIFROG_STATE_JUMP: + if (func_801378B8(&this->skelAnime, 4.0f)) { + this->actor.bgCheckFlags &= ~1; + this->actor.velocity.y = 6.0f; + Audio_PlayActorSound2(this, 0x28B1); + this->jumpState = MINIFROG_STATE_AIR; + } + break; + case MINIFROG_STATE_AIR: + if (this->actor.bgCheckFlags & 1) { + this->jumpState = MINIFROG_STATE_GROUND; + SkelAnime_ChangeAnimTransitionRepeat(&this->skelAnime, &D_06001534, -2.5f); + SkelAnime_FrameUpdateMatrix(&this->skelAnime); + } + break; + } +} -#pragma GLOBAL_ASM("./asm/non_matchings/overlays/ovl_En_Minifrog_0x808A3670/EnMinifrog_Update.asm") +void EnMinifrog_TurnToPlayer(EnMinifrog* this) { + Math_ScaledStepToS(&this->actor.shape.rot.y, this->actor.yawTowardsPlayer, 0x400); + this->actor.world.rot.y = this->actor.shape.rot.y; +} -#pragma GLOBAL_ASM("./asm/non_matchings/overlays/ovl_En_Minifrog_0x808A3670/func_808A4AC8.asm") +void EnMinifrog_TurnToMissingFrog(EnMinifrog* this) { + Math_ScaledStepToS(&this->actor.shape.rot.y, this->actor.home.rot.y, 0x400); + this->actor.world.rot.y = this->actor.shape.rot.y; +} -#pragma GLOBAL_ASM("./asm/non_matchings/overlays/ovl_En_Minifrog_0x808A3670/func_808A4AF8.asm") +static Color_RGBA8 sPrimColor = { 255, 255, 255, 255 }; +static Color_RGBA8 sEnvColor = { 80, 80, 80, 255 }; -#pragma GLOBAL_ASM("./asm/non_matchings/overlays/ovl_En_Minifrog_0x808A3670/func_808A4B3C.asm") +void EnMinifrog_SetCamera(EnMinifrog* this, GlobalContext* globalCtx) { + Vec3f pos; + Vec3f vec5; + Vec3f vel; + Vec3f accel; + s16 yaw; + s16 pitch; + Vec3f eye; + s32 i; -#pragma GLOBAL_ASM("./asm/non_matchings/overlays/ovl_En_Minifrog_0x808A3670/EnMinifrog_Draw.asm") + eye = ACTIVE_CAM->eye; + yaw = Math_Vec3f_Yaw(&eye, &this->actor.world.pos); + pitch = -Math_Vec3f_Pitch(&eye, &this->actor.world.pos); + vec5.x = this->actor.world.pos.x - (5.0f * Math_SinS(yaw) * Math_CosS(pitch)); + vec5.y = this->actor.world.pos.y - (5.0f * Math_SinS(pitch)); + vec5.z = this->actor.world.pos.z - (5.0f * Math_CosS(yaw) * Math_CosS(pitch)); + for (i = 0; i < 5; i++) { + vel.x = randPlusMinusPoint5Scaled(4.0f); + vel.y = randPlusMinusPoint5Scaled(4.0f); + vel.z = randPlusMinusPoint5Scaled(4.0f); + accel.x = -vel.x * 0.1f; + accel.y = -vel.y * 0.1f; + accel.z = -vel.z * 0.1f; + pos.x = vec5.x + vel.x; + pos.y = vec5.y + vel.y; + pos.z = vec5.z + vel.z; + func_800B0F80(globalCtx, &pos, &vel, &accel, &sPrimColor, &sEnvColor, 300, 30, 10); + } +} + +void EnMinifrog_ReturnFrogCutscene(EnMinifrog* this, GlobalContext* globalCtx) { + u8 flag; + + EnMinifrog_TurnToPlayer(this); + EnMinifrog_Jump(this); + if ((func_80152498(&globalCtx->msgCtx) == 5) && func_80147624(globalCtx)) { + EnMinifrog_SetJumpState(this); + + switch (globalCtx->msgCtx.unk11F04) { + case 0xD81: // "Ah! Don Gero! It has been so long." + case 0xD83: // "Could it be... Has spring finally come to the mountains?" + case 0xD84: // "That look...It is true! Winter was so long that I began to lose all hope." + case 0xD86: // "Could it be... You came all this way looking for me?" + case 0xD87: // "Ah! You need not say a thing. Upon seeing that face, I understand!" ... + func_80151938(globalCtx, globalCtx->msgCtx.unk11F04 + 1); + break; + case 0xD82: // "What has brought you all this way?" + if (gSaveContext.weekEventReg[33] & 0x80) { // Mountain village is unfrozen + func_80151938(globalCtx, 0xD83); // "Could it be... Has spring finally come to the mountains?" + } else { + func_80151938(globalCtx, 0xD86); // "Could it be... You came all this way looking for me?" + } + + flag = gSaveContext.weekEventReg[isFrogReturnedFlags[this->frogIndex] >> 8]; + gSaveContext.weekEventReg[isFrogReturnedFlags[this->frogIndex] >> 8] = flag | (u8)isFrogReturnedFlags[this->frogIndex]; + break; + case 0xD85: // "I understand. I shall head for the mountains immediately." + default: + func_801477B4(globalCtx); + EnMinifrog_SetCamera(this, globalCtx); + func_800F0568(globalCtx, &this->actor.world.pos, 30, 0x3A87); + if (this->actor.cutscene != -1) { + if (ActorCutscene_GetCurrentIndex() == this->actor.cutscene) { + ActorCutscene_Stop(this->actor.cutscene); + } + } + + Actor_MarkForDeath(&this->actor); + return; + } + } + + if (this->flags & 1) { + if (ActorCutscene_GetCurrentIndex() == 0x7C) { + ActorCutscene_Stop(0x7C); + ActorCutscene_SetIntentToPlay(this->actor.cutscene); + } else if (ActorCutscene_GetCanPlayNext(this->actor.cutscene)) { + ActorCutscene_Start(this->actor.cutscene, &this->actor); + this->flags &= ~1; + } else { + ActorCutscene_SetIntentToPlay(this->actor.cutscene); + } + } +} + +// This can be seen when the Cyan and Pink frogs spawn after their respective minibosses +void EnMinifrog_SpawnGrowAndShrink(EnMinifrog* this, GlobalContext* globalCtx) { + EnMinifrog_Jump(this); + if (this->timer > 0) { + Actor_SetScale(&this->actor, (0.01f + 0.0003f * this->timer * Math_SinS(0x1000 * (this->timer & 7)))); + this->timer--; + } else { + Actor_SetScale(&this->actor, 0.01f); + this->actionFunc = EnMinifrog_Idle; + } +} + +void EnMinifrog_Idle(EnMinifrog* this, GlobalContext* globalCtx) { + EnMinifrog_TurnToPlayer(this); + EnMinifrog_Jump(this); + EnMinifrog_JumpTimer(this); + if (func_800B84D0(&this->actor, globalCtx)) { + this->actionFunc = EnMinifrog_ReturnFrogCutscene; + if (this->actor.cutscene != -1) { + this->flags |= 1; + } + } else if ((this->actor.xzDistToPlayer < 100.0f) && Actor_IsLinkFacingActor(&this->actor, 0x3000, globalCtx) && (func_8012403C(globalCtx) == 0xD)) { + func_800B8614(&this->actor, globalCtx, 110.0f); + } +} + +void EnMinifrog_SetupNextFrogInit(EnMinifrog* this, GlobalContext* globalCtx) { + EnMinifrog* nextFrog; + EnMinifrog* missingFrog; + + EnMinifrog_Jump(this); + nextFrog = this->frog; + if (nextFrog != NULL) { + missingFrog = nextFrog->frog; + if (nextFrog->frog != NULL) { + this->actor.home.rot.y = (s16)Actor_YawBetweenActors(&this->actor, &missingFrog->actor); // Set home to missing frog + EnMinifrog_TurnToMissingFrog(this); + } else { + EnMinifrog_TurnToPlayer(this); + } + + if (this->frog->actor.home.rot.z == (this->actor.params & 0xF)) { + EnMinifrog_SetJumpState(this); + this->frog->actor.home.rot.z = 0; + } + } +} + +void EnMinifrog_CheckChoirSuccess(EnMinifrog* this, GlobalContext* globalCtx) { + this->actionFunc = EnMinifrog_YellowFrogDialog; + if (this->frog != NULL) { + func_80151938(globalCtx, 0xD78); // "Unfortunately, it seems not all of our members have gathered." + } else { + func_80151938(globalCtx, 0xD7C); // "The conducting was spectacular. And all of our members rose to the occasion!" + } + + EnMinifrog_SetJumpState(this); + this->frog = NULL; + this->actor.home.rot.z = 0; +} + +void EnMinifrog_ContinueChoirCutscene(EnMinifrog* this, GlobalContext* globalCtx) { + EnMinifrog_Jump(this); + if (ActorCutscene_GetCurrentIndex() == 0x7C) { + EnMinifrog_CheckChoirSuccess(this, globalCtx); + return; // necessary to match + } else if (ActorCutscene_GetCanPlayNext(0x7C)) { + ActorCutscene_Start(0x7C, NULL); + EnMinifrog_CheckChoirSuccess(this, globalCtx); + return; // necessary to match + } else if (this->actor.cutscene != -1 && ActorCutscene_GetCurrentIndex() == this->actor.cutscene) { + ActorCutscene_Stop(this->actor.cutscene); + ActorCutscene_SetIntentToPlay(0x7C); + return; // necessary to match + } else { + ActorCutscene_SetIntentToPlay(0x7C); + } +} + +void EnMinifrog_NextFrogMissing(EnMinifrog* this, GlobalContext* globalCtx) { + EnMinifrog_TurnToMissingFrog(this); + EnMinifrog_Jump(this); + if (this->timer > 0) { + this->timer--; + } else { + this->actionFunc = EnMinifrog_ContinueChoirCutscene; + } +} + +void EnMinifrog_NextFrogReturned(EnMinifrog* this, GlobalContext* globalCtx) { + EnMinifrog_Jump(this); + if (this->timer > 0) { + this->timer--; + } else { + this->actionFunc = EnMinifrog_ContinueChoirCutscene; + this->flags &= ~(0x2 << MINIFROG_YELLOW | 0x2 << MINIFROG_CYAN | 0x2 << MINIFROG_PINK | 0x2 << MINIFROG_BLUE | + 0x2 << MINIFROG_WHITE); + globalCtx->func_18798(globalCtx, &D_0400DEA8, 0); + } +} + +void EnMinifrog_SetupNextFrogChoir(EnMinifrog* this, GlobalContext* globalCtx) { + u8 frogIndex; + + EnMinifrog_Jump(this); + frogIndex = func_801A39F8(); + if (frogIndex != MINIFROG_INVALID) { + if (frogIndex == MINIFROG_YELLOW) { + EnMinifrog_SetJumpState(this); + } else { + this->actor.home.rot.z = frogIndex; // This is strange to store the frog index in home z rotation + } + + if (!(this->flags & (0x2 << frogIndex))) { + this->flags |= (0x2 << frogIndex); + this->timer--; + } + } + + if (this->frog != NULL) { + this->actor.home.rot.z = 0; + this->actionFunc = EnMinifrog_NextFrogMissing; + this->timer = 60; + this->actor.home.rot.y = Actor_YawBetweenActors(&this->actor, &this->frog->actor); + func_801A1F88(); + this->flags &= ~0x100; + this->flags &= ~(0x2 << MINIFROG_YELLOW | 0x2 << MINIFROG_CYAN | 0x2 << MINIFROG_PINK | 0x2 << MINIFROG_BLUE | + 0x2 << MINIFROG_WHITE); + globalCtx->func_18798(globalCtx, &D_0400DEA8, 0); + } else if (this->timer <= 0) { + this->actionFunc = EnMinifrog_NextFrogReturned; + this->timer = 30; + } +} + +void EnMinifrog_BeginChoirCutscene(EnMinifrog* this, GlobalContext* globalCtx) { + EnMinifrog_Jump(this); + if (this->actor.cutscene == -1) { + this->actionFunc = EnMinifrog_SetupNextFrogChoir; + } else if (ActorCutscene_GetCurrentIndex() == 0x7C) { + ActorCutscene_Stop(0x7C); + ActorCutscene_SetIntentToPlay(this->actor.cutscene); + } else if (ActorCutscene_GetCanPlayNext(this->actor.cutscene)) { + ActorCutscene_Start(this->actor.cutscene, &this->actor); + this->actionFunc = EnMinifrog_SetupNextFrogChoir; + this->timer = 5; + func_801A1F00(3, 0x5A); + this->flags |= 0x100; + globalCtx->func_18798(globalCtx, &D_0400E2A8, 0); + } else { + ActorCutscene_SetIntentToPlay(this->actor.cutscene); + } +} + +void EnMinifrog_EndChoir(EnMinifrog* this, GlobalContext* globalCtx) { + EnMinifrog_TurnToPlayer(this); + EnMinifrog_Jump(this); + if (func_800B84D0(&this->actor, globalCtx)) { + func_801518B0(globalCtx, 0xD7E, &this->actor); // "Let us do it again sometime." + this->actionFunc = EnMinifrog_YellowFrogDialog; + } else { + func_800B8500(&this->actor, globalCtx, 1000.0f, 1000.0f, -1); + } +} + +void EnMinifrog_GetFrogHP(EnMinifrog* this, GlobalContext* globalCtx) { + EnMinifrog_TurnToPlayer(this); + EnMinifrog_Jump(this); + if (Actor_HasParent(&this->actor, globalCtx)) { + this->actor.parent = NULL; + this->actionFunc = EnMinifrog_EndChoir; + this->actor.flags |= 0x10000; + func_800B8500(&this->actor, globalCtx, 1000.0f, 1000.0f, 0); + } else { + func_800B8A1C(&this->actor, globalCtx, GI_HEART_PIECE, 10000.0f, 50.0f); + } +} + +void EnMinifrog_YellowFrogDialog(EnMinifrog* this, GlobalContext* globalCtx) { + EnMinifrog_TurnToPlayer(this); + EnMinifrog_Jump(this); + switch (func_80152498(&globalCtx->msgCtx)) { + case 4: + if (func_80147624(globalCtx)) { + switch (globalCtx->msgCtx.choiceIndex) { + case 0: // Yes + func_8019F208(); + this->actionFunc = EnMinifrog_BeginChoirCutscene; + globalCtx->msgCtx.unk11F10 = 0; + break; + case 1: // No + func_8019F230(); + func_80151938(globalCtx, 0xD7E); // "Let us do it again sometime." + break; + } + } + break; + case 5: + if (func_80147624(globalCtx)) { + EnMinifrog_SetJumpState(this); + switch (globalCtx->msgCtx.unk11F04) { + case 0xD76: // "I have been waiting for you, Don Gero. Forgive me if I'm mistaken, but it looks like + // you've lost a little weight..." + func_80151938(globalCtx, globalCtx->msgCtx.unk11F04 + 1); + this->actor.flags &= ~0x10000; + gSaveContext.weekEventReg[34] |= 1; // Spoken to MINIFROG_YELLOW + break; + case 0xD78: // "Unfortunately, it seems not all of our members have gathered." + case 0xD79: // "Perhaps it is because winter was too long? They must not have realized that spring + // has come to the mountains..." + case 0xD7A: // "And when the great Don Gero has come for us, too...What a pity." + case 0xD7F: // "Well, if it isn't the great Don Gero." + func_80151938(globalCtx, globalCtx->msgCtx.unk11F04 + 1); + break; + case 0xD77: // "Let us begin our chorus" + this->actionFunc = EnMinifrog_BeginChoirCutscene; + globalCtx->msgCtx.unk11F10 = 0; + break; + case 0xD7C: // "The conducting was spectacular. And all of our members rose to the occasion!" + if (gSaveContext.weekEventReg[35] & 0x80) { // Obtained Heart Piece + func_80151938(globalCtx, 0xD7E); + } else { + func_80151938(globalCtx, 0xD7D); // Get Heart Piece + gSaveContext.weekEventReg[35] |= 0x80; + } + break; + case 0xD7D: // "This is how deeply we were moved by your spectacular conducting..." + func_801477B4(globalCtx); + this->actionFunc = EnMinifrog_GetFrogHP; + EnMinifrog_GetFrogHP(this, globalCtx); + break; + case 0xD7B: // "Where in the world could the other members be, and what could they be doing?" + case 0xD7E: // "Let us do it again sometime." + default: + func_801477B4(globalCtx); + this->actionFunc = EnMinifrog_SetupYellowFrogDialog; + this->actor.flags &= ~0x10000; + break; + } + } + } +} + +void EnMinifrog_SetupYellowFrogDialog(EnMinifrog* this, GlobalContext* globalCtx) { + Math_ScaledStepToS(&this->actor.shape.rot.y, this->actor.yawTowardsPlayer, 0x180); + this->actor.world.rot.y = this->actor.shape.rot.y; + EnMinifrog_TurnToPlayer(this); + EnMinifrog_Jump(this); + EnMinifrog_JumpTimer(this); + if (func_800B84D0(&this->actor, globalCtx)) { + this->actionFunc = EnMinifrog_YellowFrogDialog; + if (!(gSaveContext.weekEventReg[34] & 1)) { // Not spoken with MINIFROG_YELLOW + func_801518B0(globalCtx, 0xD76, &this->actor); // "I have been waiting for you, Don Gero. Forgive me if I'm mistaken, but it + // looks like you've lost a little weight..." + } else { + func_801518B0(globalCtx, 0xD7F, &this->actor); // "Well, if it isn't the great Don Gero." + } + } else if ((this->actor.xzDistToPlayer < 150.0f) && (Actor_IsLinkFacingActor(&this->actor, 0x3000, globalCtx) || ((this->actor.flags & 0x10000) == 0x10000)) && func_8012403C(globalCtx) == 0xD) { + func_800B8614(&this->actor, globalCtx, 160.0f); + } +} + +void EnMinifrog_Update(Actor* thisx, GlobalContext* globalCtx) { + EnMinifrog* this = THIS; + s32 pad; + + this->actionFunc(this, globalCtx); + Actor_SetVelocityAndMoveYRotationAndGravity(&this->actor); + func_800B78B8(globalCtx, &this->actor, 25.0f, 12.0f, 0.0f, 0x1D); + Collider_UpdateCylinder(&this->actor, &this->collider); + CollisionCheck_SetOC(globalCtx, &globalCtx->colCheckCtx, &this->collider.base); + this->actor.focus.rot.y = this->actor.shape.rot.y; +} + +void EnMinifrog_UpdateMissingFrog(Actor* thisx, GlobalContext* globalCtx) { + EnMinifrog* this = THIS; + EnMinifrog* missingFrog; + + missingFrog = this->frog; + if ((missingFrog != NULL) && (missingFrog->actor.home.rot.z == (this->actor.params & 0xF))) { + missingFrog->frog = this; + } +} + +s32 EnMinifrog_OverrideLimbDraw(GlobalContext* globalCtx, s32 limbIndex, Gfx** dList, Vec3f* pos, Vec3s* rot, Actor* thisx) { + if (limbIndex == 1) { + pos->z -= 500.0f; + } + + if ((limbIndex == 7) || (limbIndex == 8)) { + *dList = NULL; + } + + return 0; +} + +void EnMinifrog_PostLimbDraw(GlobalContext* globalCtx, s32 limbIndex, Gfx** dList, Vec3s* rot, Actor* thisx) { + EnMinifrog* this = THIS; + + if ((limbIndex == 7) || (limbIndex == 8)) { + OPEN_DISPS(globalCtx->state.gfxCtx); + SysMatrix_NormalizeXYZ(&globalCtx->unk187FC); + gSPMatrix(POLY_OPA_DISP++, Matrix_NewMtx(globalCtx->state.gfxCtx), G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW); + gSPDisplayList(POLY_OPA_DISP++, *dList); + CLOSE_DISPS(globalCtx->state.gfxCtx); + } + + if (limbIndex == 4) { + SysMatrix_GetStateTranslation(&this->actor.focus.pos); + } +} + +static Color_RGBA8 sEnMinifrogColor[] = { + { 200, 170, 0, 255 }, { 0, 170, 200, 255 }, { 210, 120, 100, 255 }, { 120, 130, 230, 255 }, { 190, 190, 190, 255 }, +}; + +void EnMinifrog_Draw(Actor* thisx, GlobalContext* globalCtx) { + EnMinifrog* this = THIS; + Color_RGBA8* envColor; + + OPEN_DISPS(globalCtx->state.gfxCtx); + func_8012C28C(globalCtx->state.gfxCtx); + envColor = &sEnMinifrogColor[this->frogIndex]; + gSPSegment(POLY_OPA_DISP++, 0x08, D_808A4D74[0]); + gSPSegment(POLY_OPA_DISP++, 0x09, D_808A4D74[0]); + gDPSetEnvColor(POLY_OPA_DISP++, envColor->r, envColor->g, envColor->b, envColor->a); + SkelAnime_DrawSV(globalCtx, this->skelAnime.skeleton, this->skelAnime.limbDrawTbl, this->skelAnime.dListCount, + EnMinifrog_OverrideLimbDraw, EnMinifrog_PostLimbDraw, &this->actor); + CLOSE_DISPS(globalCtx->state.gfxCtx); +} diff --git a/src/overlays/actors/ovl_En_Minifrog/z_en_minifrog.h b/src/overlays/actors/ovl_En_Minifrog/z_en_minifrog.h index 0bb814b634..5b60567d41 100644 --- a/src/overlays/actors/ovl_En_Minifrog/z_en_minifrog.h +++ b/src/overlays/actors/ovl_En_Minifrog/z_en_minifrog.h @@ -5,9 +5,37 @@ struct EnMinifrog; +typedef void (*EnMinifrogActionFunc)(struct EnMinifrog*, GlobalContext*); + +#define EN_MINIFROG_IS_RETURNED(this) ((((this)->actor.params)&0xF0) >> 4) + +typedef enum { + /* 0x00 */ MINIFROG_YELLOW, // Mountain Village + /* 0x01 */ MINIFROG_CYAN, // Woodfall Temple + /* 0x02 */ MINIFROG_PINK, // Great Bay Temple + /* 0x03 */ MINIFROG_BLUE, // Southern Swamp + /* 0x04 */ MINIFROG_WHITE, // Laundry Pool + /* 0xFF */ MINIFROG_INVALID = 0xFF // -1 +} MinifrogType; + +typedef enum { + /* 0x00 */ MINIFROG_STATE_JUMP, + /* 0x01 */ MINIFROG_STATE_AIR, + /* 0x02 */ MINIFROG_STATE_GROUND +} MinifrogJumpState; + typedef struct EnMinifrog { /* 0x000 */ Actor actor; - /* 0x144 */ char unk_144[0x1C0]; + /* 0x144 */ SkelAnime skelAnime; + /* 0x188 */ Vec3s limbDrawTable[24]; + /* 0x218 */ Vec3s transitionDrawTable[24]; + /* 0x2A8 */ EnMinifrogActionFunc actionFunc; + /* 0x2AC */ struct EnMinifrog* frog; + /* 0x2B0 */ s16 frogIndex; + /* 0x2B2 */ s16 jumpState; + /* 0x2B4 */ s16 timer; + /* 0x2B6 */ u16 flags; + /* 0x2B8 */ ColliderCylinder collider; } EnMinifrog; // size = 0x304 extern const ActorInit En_Minifrog_InitVars; diff --git a/tables/functions.txt b/tables/functions.txt index 0319a07822..cd5e8a8506 100644 --- a/tables/functions.txt +++ b/tables/functions.txt @@ -5695,31 +5695,31 @@ 0x808A34B8:("EnTorch2_Draw",), 0x808A3670:("EnMinifrog_Init",), 0x808A38E4:("EnMinifrog_Destroy",), - 0x808A3930:("func_808A3930",), - 0x808A3980:("func_808A3980",), - 0x808A39EC:("func_808A39EC",), - 0x808A3A44:("func_808A3A44",), - 0x808A3B04:("func_808A3B04",), - 0x808A3B3C:("func_808A3B3C",), - 0x808A3B74:("func_808A3B74",), - 0x808A3DA8:("func_808A3DA8",), - 0x808A3F88:("func_808A3F88",), - 0x808A4040:("func_808A4040",), - 0x808A410C:("func_808A410C",), - 0x808A41A0:("func_808A41A0",), - 0x808A4214:("func_808A4214",), - 0x808A42D8:("func_808A42D8",), - 0x808A4328:("func_808A4328",), - 0x808A43A4:("func_808A43A4",), - 0x808A44BC:("func_808A44BC",), - 0x808A45A8:("func_808A45A8",), - 0x808A4634:("func_808A4634",), - 0x808A46E8:("func_808A46E8",), - 0x808A4914:("func_808A4914",), + 0x808A3930:("EnMinifrog_GetFrog",), + 0x808A3980:("EnMinifrog_SetJumpState",), + 0x808A39EC:("EnMinifrog_JumpTimer",), + 0x808A3A44:("EnMinifrog_Jump",), + 0x808A3B04:("EnMinifrog_TurnToPlayer",), + 0x808A3B3C:("EnMinifrog_TurnToMissingFrog",), + 0x808A3B74:("EnMinifrog_SetCamera",), + 0x808A3DA8:("EnMinifrog_ReturnFrogCutscene",), + 0x808A3F88:("EnMinifrog_SpawnGrowAndShrink",), + 0x808A4040:("EnMinifrog_Idle",), + 0x808A410C:("EnMinifrog_SetupNextFrogInit",), + 0x808A41A0:("EnMinifrog_CheckChoirSuccess",), + 0x808A4214:("EnMinifrog_ContinueChoirCutscene",), + 0x808A42D8:("EnMinifrog_NextFrogMissing",), + 0x808A4328:("EnMinifrog_NextFrogReturned",), + 0x808A43A4:("EnMinifrog_SetupNextFrogChoir",), + 0x808A44BC:("EnMinifrog_BeginChoirCutscene",), + 0x808A45A8:("EnMinifrog_EndChoir",), + 0x808A4634:("EnMinifrog_GetFrogHP",), + 0x808A46E8:("EnMinifrog_YellowFrogDialog",), + 0x808A4914:("EnMinifrog_SetupYellowFrogDialog",), 0x808A4A30:("EnMinifrog_Update",), - 0x808A4AC8:("func_808A4AC8",), - 0x808A4AF8:("func_808A4AF8",), - 0x808A4B3C:("func_808A4B3C",), + 0x808A4AC8:("EnMinifrog_UpdateMissingFrog",), + 0x808A4AF8:("EnMinifrog_OverrideLimbDraw",), + 0x808A4B3C:("EnMinifrog_PostLimbDraw",), 0x808A4C14:("EnMinifrog_Draw",), 0x808A5050:("func_808A5050",), 0x808A52A8:("func_808A52A8",),