From f66ef00aebc925825007d2bf4456b925b350fb3a Mon Sep 17 00:00:00 2001 From: Blythe Date: Mon, 15 Aug 2022 13:12:54 -0500 Subject: [PATCH] EnSGoro OK and documented (#895) * EnSGoro OK and documented * Format fix attempt for EnSGoro * Requested format changes * EnSGoro additional cleanup * Fixed updated names * fork merge (wip - don't review) * Misc. formatting updates Also had to un-eat some changes made upstream in functions.txt and variables.txt. * A couple minor tweaks --- spec | 3 +- src/overlays/actors/ovl_En_Jg/z_en_jg.c | 2 +- .../actors/ovl_En_S_Goro/z_en_s_goro.c | 1424 ++++++++++++++++- .../actors/ovl_En_S_Goro/z_en_s_goro.h | 55 +- tools/disasm/functions.txt | 66 +- tools/disasm/variables.txt | 12 +- 6 files changed, 1459 insertions(+), 103 deletions(-) diff --git a/spec b/spec index ecf0be8dca..6811fb622f 100644 --- a/spec +++ b/spec @@ -4363,8 +4363,7 @@ beginseg name "ovl_En_S_Goro" compress include "build/src/overlays/actors/ovl_En_S_Goro/z_en_s_goro.o" - include "build/data/ovl_En_S_Goro/ovl_En_S_Goro.data.o" - include "build/data/ovl_En_S_Goro/ovl_En_S_Goro.reloc.o" + include "build/src/overlays/actors/ovl_En_S_Goro/ovl_En_S_Goro_reloc.o" endseg beginseg diff --git a/src/overlays/actors/ovl_En_Jg/z_en_jg.c b/src/overlays/actors/ovl_En_Jg/z_en_jg.c index add52b0e40..8dd44f5f3f 100644 --- a/src/overlays/actors/ovl_En_Jg/z_en_jg.c +++ b/src/overlays/actors/ovl_En_Jg/z_en_jg.c @@ -177,7 +177,7 @@ Actor* EnJg_GetShrineGoronToFocusOn(PlayState* play, u8 focusedShrineGoronParam) while (actorIterator != NULL) { if ((actorIterator->id == ACTOR_EN_S_GORO) && - (EN_S_GORO_GET_PARAM_F(actorIterator) == focusedShrineGoronParam)) { + (EN_S_GORO_GET_MAIN_TYPE(actorIterator) == focusedShrineGoronParam)) { return actorIterator; } diff --git a/src/overlays/actors/ovl_En_S_Goro/z_en_s_goro.c b/src/overlays/actors/ovl_En_S_Goro/z_en_s_goro.c index 00637ba257..ccc11a002d 100644 --- a/src/overlays/actors/ovl_En_S_Goro/z_en_s_goro.c +++ b/src/overlays/actors/ovl_En_S_Goro/z_en_s_goro.c @@ -4,18 +4,96 @@ * Description: Goron in Goron Shrine / Bomb Shop Goron */ +/* +This actor appears to be used in three scenes. +-- Goron Shrine: Winter + Three variants (one instance of each used in game). + Main behavior determined by whether the Goron Elder's Son is asleep, and whether they themselves have been put to +sleep. One of them also has a dialogue tree that checks whether you have lit the chandelier (at least if the kid is not +crying) +-- Goron Shrine: Spring + Six variants - one instance of each appearing in a circle around the elder on the upper level of the shrine if +you've beaten Goht during that cycle. Dialogue determined by whether you have talked to elder in that context as a goron +at least once during that cycle. They have a cheering animation used while the elder is talking to you, otherwise they +stand idle. +-- Bomb Shop + Only one variant. Goron who sells you powder kegs in the bomb shop. +*/ + +/* +Week Event Flags: + 22 Bit 2 -- Goron Elder's Son has been pacified (Winter) + 77 Bit 7 -- You have spoken to the Goron Elder in goron form during spring + + 36 All Bits + 37 Bits 0 - 2 + Track whether or not you have ever spoken to each of the three winter shrine gorons + in various forms. ("Ever" being since last time reset, of course) +*/ + #include "z_en_s_goro.h" +#include "overlays/actors/ovl_En_Gk/z_en_gk.h" // Goron Elder's Son +#include "overlays/actors/ovl_En_Jg/z_en_jg.h" // Goron Elder +#include "objects/object_taisou/object_taisou.h" #define FLAGS (ACTOR_FLAG_1 | ACTOR_FLAG_8 | ACTOR_FLAG_10) - #define THIS ((EnSGoro*)thisx) +#define EN_S_GORO_ROLLEDUP_YOFFSET 14.0f +#define EN_S_GORO_OFTYPE_WSHRINE (EN_S_GORO_GET_MAIN_TYPE(&this->actor) < 3) + +#define EN_S_GORO_ACTIONFLAG_ROLLEDUP (1 << 0) +#define EN_S_GORO_ACTIONFLAG_FACEPLAYER (1 << 1) +#define EN_S_GORO_ACTIONFLAG_EYESOPEN (1 << 2) +#define EN_S_GORO_ACTIONFLAG_EARSCOVERED (1 << 3) +#define EN_S_GORO_ACTIONFLAG_ENGAGED (1 << 4) +#define EN_S_GORO_ACTIONFLAG_LASTMESSAGE (1 << 5) +#define EN_S_GORO_ACTIONFLAG_GKQUIET_ACKNOWLEDGED (1 << 6) +#define EN_S_GORO_ACTIONFLAG_SNOREPHASE (1 << 7) +#define EN_S_GORO_ACTIONFLAG_UNK0100 (1 << 8) +#define EN_S_GORO_ACTIONFLAG_HANDTAP (1 << 9) +#define EN_S_GORO_ACTIONFLAG_TIRED (1 << 10) +#define EN_S_GORO_ACTIONFLAG_SUPPRESS_SNORE (1 << 11) + +#define EN_S_GORO_BOMBBUYFLAG_TALKED_HUMAN (1 << 0) +#define EN_S_GORO_BOMBBUYFLAG_TALKED_GORONPK (1 << 1) +#define EN_S_GORO_BOMBBUYFLAG_TALKED_DEKU (1 << 2) +#define EN_S_GORO_BOMBBUYFLAG_TALKED_ZORA (1 << 3) +#define EN_S_GORO_BOMBBUYFLAG_TALKED_HUMAN_FINALNIGHT (1 << 4) +#define EN_S_GORO_BOMBBUYFLAG_TALKED_GOROKPK_FINALNIGHT (1 << 5) +#define EN_S_GORO_BOMBBUYFLAG_TALKED_DEKU_FINALNIGHT (1 << 6) +#define EN_S_GORO_BOMBBUYFLAG_TALKED_ZORA_FINALNIGHT (1 << 7) +#define EN_S_GORO_BOMBBUYFLAG_TALKED_GORON (1 << 8) +#define EN_S_GORO_BOMBBUYFLAG_TALKED_GORON_FINALNIGHT (1 << 9) +#define EN_S_GORO_BOMBBUYFLAG_YESBUY (1 << 10) + void EnSGoro_Init(Actor* thisx, PlayState* play); void EnSGoro_Destroy(Actor* thisx, PlayState* play); void EnSGoro_Update(Actor* thisx, PlayState* play); void EnSGoro_Draw(Actor* thisx, PlayState* play); -#if 0 +typedef enum EnSGoroEyeTexture { + /* 0x0 */ EN_S_GORO_EYETEX_OPEN, + /* 0x1 */ EN_S_GORO_EYETEX_HALF, + /* 0x2 */ EN_S_GORO_EYETEX_CLOSED, + /* 0x3 */ EN_S_GORO_EYETEX_CLOSED2 +} EnSGoroEyeTexture; + +typedef enum EnSGoroAnimation { + /* 0x0 */ EN_S_GORO_ANIM_IDLE_LIEDOWN_A, + /* 0x1 */ EN_S_GORO_ANIM_IDLE_LIEDOWN_B, + /* 0x2 */ EN_S_GORO_ANIM_UNROLL_A, + /* 0x3 */ EN_S_GORO_ANIM_UNROLL_B, + /* 0x4 */ EN_S_GORO_ANIM_ROLLUP, + /* 0x5 */ EN_S_GORO_ANIM_SHIVER_A, + /* 0x6 */ EN_S_GORO_ANIM_SHIVER_B, + /* 0xB */ EN_S_GORO_ANIM_COVEREARS = 11, + /* 0xC */ EN_S_GORO_ANIM_TAISOU_CHEER, + /* 0xD */ EN_S_GORO_ANIM_STAND_HANDTAP, + /* 0xE */ EN_S_GORO_ANIM_SLEEPY, + /* 0xF */ EN_S_GORO_ANIM_IDLE_STAND +} EnSGoroAnimation; + const ActorInit En_S_Goro_InitVars = { ACTOR_EN_S_GORO, ACTORCAT_NPC, @@ -28,18 +106,29 @@ const ActorInit En_S_Goro_InitVars = { (ActorFunc)EnSGoro_Draw, }; -// static ColliderCylinderInit sCylinderInit = { -static ColliderCylinderInit D_80BBF820 = { - { COLTYPE_HIT1, AT_NONE, AC_ON | AC_TYPE_PLAYER, OC1_ON | OC1_TYPE_ALL, OC2_TYPE_1, COLSHAPE_CYLINDER, }, - { ELEMTYPE_UNK1, { 0x00000000, 0x00, 0x00 }, { 0xF7CFFFFF, 0x00, 0x00 }, TOUCH_ON | TOUCH_SFX_NORMAL, BUMP_ON, OCELEM_ON, }, +static ColliderCylinderInit sCylinderInit = { + { + COLTYPE_HIT1, + AT_NONE, + AC_ON | AC_TYPE_PLAYER, + OC1_ON | OC1_TYPE_ALL, + OC2_TYPE_1, + COLSHAPE_CYLINDER, + }, + { + ELEMTYPE_UNK1, + { 0x00000000, 0x00, 0x00 }, + { 0xF7CFFFFF, 0x00, 0x00 }, + TOUCH_ON, + BUMP_ON, + OCELEM_ON, + }, { 0, 0, 0, { 0, 0, 0 } }, }; -// sColChkInfoInit -static CollisionCheckInfoInit2 D_80BBF84C = { 0, 0, 0, 0, MASS_IMMOVABLE }; +static CollisionCheckInfoInit2 sColChkInfoInit = { 0, 0, 0, 0, MASS_IMMOVABLE }; -// static DamageTable sDamageTable = { -static DamageTable D_80BBF858 = { +static DamageTable sDamageTable = { /* Deku Nut */ DMG_ENTRY(1, 0x0), /* Deku Stick */ DMG_ENTRY(1, 0x0), /* Horse trample */ DMG_ENTRY(1, 0x0), @@ -74,85 +163,1314 @@ static DamageTable D_80BBF858 = { /* Powder Keg */ DMG_ENTRY(1, 0x0), }; -#endif +static AnimationInfoS sAnimationInfo[] = { + { &gGoronLyingDownIdleAnim, 1.0f, 0, -1, ANIMMODE_LOOP, 0 }, + { &gGoronLyingDownIdleAnim, 1.0f, 0, -1, ANIMMODE_LOOP, -4 }, + { &gGoronUnrollAnim, 2.0f, 0, -1, ANIMMODE_ONCE, 0 }, + { &gGoronUnrollAnim, 2.0f, 0, -1, ANIMMODE_ONCE, -4 }, + { &gGoronUnrollAnim, -2.0f, 0, -1, ANIMMODE_ONCE, -4 }, + { &gGoronShiverAnim, 1.0f, 0, -1, ANIMMODE_LOOP, 0 }, + { &gGoronShiverAnim, 1.0f, 0, -1, ANIMMODE_LOOP, -4 }, + { &object_taisou_Anim_004DD4, 1.0f, 0, -1, ANIMMODE_LOOP, 0 }, + { &object_taisou_Anim_00283C, 1.0f, 0, -1, ANIMMODE_LOOP, 0 }, + { &object_taisou_Anim_007764, 1.0f, 0, -1, ANIMMODE_LOOP, 0 }, + { &object_taisou_Anim_005790, 1.0f, 0, -1, ANIMMODE_LOOP, 0 }, + { &gGoronCoverEarsAnim, 1.0f, 0, -1, ANIMMODE_LOOP, 0 }, + { &object_taisou_Anim_002C48, 1.0f, 0, -1, ANIMMODE_LOOP, -4 }, + { &gGoronStandingHandTappingAnim, 1.0f, 0, -1, ANIMMODE_LOOP, -4 }, + { &gGoronSleepyAnim, 1.0f, 0, -1, ANIMMODE_ONCE, -4 }, + { &gGoronStandingIdleAnim, 1.0f, 0, -1, ANIMMODE_LOOP, -8 }, +}; -extern ColliderCylinderInit D_80BBF820; -extern CollisionCheckInfoInit2 D_80BBF84C; -extern DamageTable D_80BBF858; +static TexturePtr sEyeTextures[] = { + gGoronEyeOpenTex, + gGoronEyeHalfTex, + gGoronEyeClosedTex, + gGoronEyeClosed2Tex, +}; -extern UNK_TYPE D_060091A8; -extern UNK_TYPE D_06012DE0; +u16 EnSGoro_ShrineGoron_NextTextId(EnSGoro* this, PlayState* play); +u16 EnSGoro_BombshopGoron_NextTextId(EnSGoro* this, PlayState* play); -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_S_Goro/func_80BBCA80.s") +s32 EnSGoro_FindGoronElder(EnSGoro* this, PlayState* play); +s32 EnSGoro_FindGoronChild(EnSGoro* this, PlayState* play); +s32 EnSGoro_CheckLullaby(EnSGoro* this, PlayState* play); +s32 EnSGoro_CheckGKBehavior(EnSGoro* this, PlayState* play); -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_S_Goro/func_80BBD348.s") +void EnSGoro_SetupAction(EnSGoro* this, PlayState* play); +void EnSGoro_WinterShrineGoron_Idle(EnSGoro* this, PlayState* play); +void EnSGoro_WinterShrineGoron_Talk(EnSGoro* this, PlayState* play); +void EnSGoro_SpringShrineGoron_Idle(EnSGoro* this, PlayState* play); +void EnSGoro_SpringShrineGoron_Talk(EnSGoro* this, PlayState* play); +void EnSGoro_ShopGoron_Idle(EnSGoro* this, PlayState* play); +void EnSGoro_ShopGoron_FinishUnroll(EnSGoro* this, PlayState* play); +void EnSGoro_ShopGoron_Talk(EnSGoro* this, PlayState* play); +void EnSGoro_ShopGoron_TakePayment(EnSGoro* this, PlayState* play); +void EnSGoro_ShopGoron_FinishTransaction(EnSGoro* this, PlayState* play); +void EnSGoro_Sleep(EnSGoro* this, PlayState* play); +void EnSGoro_SleepTalk(EnSGoro* this, PlayState* play); -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_S_Goro/func_80BBD8F0.s") +s32 EnSGoro_UpdateCheerAnimation(EnSGoro* this, PlayState* play); +s32 EnSGoro_UpdateRotationToPlayer(EnSGoro* this, PlayState* play); +s32 EnSGoro_UpdateAttentionTarget(EnSGoro* this, PlayState* play); +void EnSGoro_UpdateToHandtapAnimation(EnSGoro* this); +void EnSGoro_UpdateSleepyAnimation(EnSGoro* this); +void EnSGoro_UpdateToIdleAnimation(EnSGoro* this); +void EnSGoro_UpdateEyes(EnSGoro* this); +void EnSGoro_UpdateActorFocus(EnSGoro* this); +void EnSGoro_UpdateSleeping(EnSGoro* this, PlayState* play); +void EnSGoro_UpdateCollider(EnSGoro* this, PlayState* play); -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_S_Goro/func_80BBD93C.s") +s32 EnSGoro_UpdateLimb(s16 newRotZ, s16 newRotY, Vec3f* pos, Vec3s* rot, s32 stepRot, s32 overrideRot); +s32 EnSGoro_OverrideLimbDraw(PlayState* play, s32 limbIndex, Gfx** dList, Vec3f* pos, Vec3s* rot, Actor* thisx); +void EnSGoro_TransformLimbDraw(PlayState* play, s32 limbIndex, Actor* thisx); +void EnSGoro_DrawUnrolled(EnSGoro* this, PlayState* play); +void EnSGoro_DrawRolledUp(EnSGoro* this, PlayState* play); -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_S_Goro/func_80BBD98C.s") +/** + * Dialogue tree for EnSGoro when use in Goron Shrine context. Returns ID of next message to display. + */ +u16 EnSGoro_ShrineGoron_NextTextId(EnSGoro* this, PlayState* play) { + Player* player = GET_PLAYER(play); -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_S_Goro/func_80BBDACC.s") + switch (EN_S_GORO_GET_MAIN_TYPE(&this->actor)) { + case EN_S_GORO_TYPE_SHRINE_WINTER_A: + if (!(gSaveContext.save.weekEventReg[22] & 4)) { + if (player->transformation == PLAYER_FORM_GORON) { + if (!(gSaveContext.save.weekEventReg[36] & 2)) { + switch (this->textId) { + case 0xCFB: + return 0xCFC; + case 0xCFC: + return 0xCFD; + case 0xCFD: + gSaveContext.save.weekEventReg[36] |= 2; + this->actionFlags |= EN_S_GORO_ACTIONFLAG_LASTMESSAGE; + return 0xCFE; + default: + return 0xCFB; + } + } else { + this->actionFlags |= EN_S_GORO_ACTIONFLAG_LASTMESSAGE; + return 0xCFE; + } + } else { + if (!(gSaveContext.save.weekEventReg[36] & 1)) { + gSaveContext.save.weekEventReg[36] |= 1; + return 0xCF9; + } + this->actionFlags |= EN_S_GORO_ACTIONFLAG_LASTMESSAGE; + return 0xCFA; + } + } else { + // Scene flag - Checks whether the chandelier has been lit + if (!Flags_GetSwitch(play, EN_S_GORO_SCENEFLAG_INDEX(&this->actor))) { + if (player->transformation == PLAYER_FORM_GORON) { + if (!(gSaveContext.save.weekEventReg[36] & 8)) { + if (this->textId == 0xD02) { + gSaveContext.save.weekEventReg[36] |= 8; + this->actionFlags |= EN_S_GORO_ACTIONFLAG_LASTMESSAGE; + return 0xD03; + } + return 0xD02; + } + this->actionFlags |= EN_S_GORO_ACTIONFLAG_LASTMESSAGE; + return 0xD04; + } + if (!(gSaveContext.save.weekEventReg[36] & 4)) { + if (this->textId == 0xCFF) { + this->actionFlags |= EN_S_GORO_ACTIONFLAG_LASTMESSAGE; + gSaveContext.save.weekEventReg[36] |= 4; + return 0xD00; + } + return 0xCFF; + } + this->actionFlags |= EN_S_GORO_ACTIONFLAG_LASTMESSAGE; + return 0xD01; + } + if (!(gSaveContext.save.weekEventReg[36] & 0x10)) { + if (this->textId == 0xD05) { + gSaveContext.save.weekEventReg[36] |= 0x10; + this->actionFlags |= EN_S_GORO_ACTIONFLAG_LASTMESSAGE; + return 0xD06; + } + return 0xD05; + } + this->actionFlags |= EN_S_GORO_ACTIONFLAG_LASTMESSAGE; + return 0xD07; + } + break; -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_S_Goro/func_80BBDC34.s") + case EN_S_GORO_TYPE_SHRINE_WINTER_B: + if (!(gSaveContext.save.weekEventReg[22] & 4)) { + if (player->transformation == PLAYER_FORM_GORON) { + if (!(gSaveContext.save.weekEventReg[36] & 0x40)) { + switch (this->textId) { + case 0xD15: + return 0xD16; + case 0xD16: + gSaveContext.save.weekEventReg[36] |= 0x40; + this->actionFlags |= EN_S_GORO_ACTIONFLAG_LASTMESSAGE; + return 0xD17; + default: + return 0xD15; + } + } else { + this->actionFlags |= EN_S_GORO_ACTIONFLAG_LASTMESSAGE; + return 0xD17; + } + } else { + if (!(gSaveContext.save.weekEventReg[36] & 0x20)) { + gSaveContext.save.weekEventReg[36] |= 0x20; + return 0xD13; + } + this->actionFlags |= EN_S_GORO_ACTIONFLAG_LASTMESSAGE; + return 0xD14; + } + } else if (player->transformation == PLAYER_FORM_GORON) { + if (!(gSaveContext.save.weekEventReg[37] & 1)) { + switch (this->textId) { + case 0xD1E: + return 0xD1F; + case 0xD1F: + gSaveContext.save.weekEventReg[37] |= 1; + this->actionFlags |= EN_S_GORO_ACTIONFLAG_LASTMESSAGE; + return 0xD20; + default: + return 0xD1E; + } + } else { + this->actionFlags |= EN_S_GORO_ACTIONFLAG_LASTMESSAGE; + return 0xD21; + } + } else { + if (!(gSaveContext.save.weekEventReg[36] & 0x80)) { + switch (this->textId) { + case 0xD18: + return 0xD19; + case 0xD19: + return 0xD1A; + case 0xD1A: + return 0xD1B; + case 0xD1B: + gSaveContext.save.weekEventReg[36] |= 0x80; + this->actionFlags |= EN_S_GORO_ACTIONFLAG_LASTMESSAGE; + return 0xD1C; + default: + return 0xD18; + } + } else { + this->actionFlags |= EN_S_GORO_ACTIONFLAG_LASTMESSAGE; + return 0xD1D; + } + } + break; -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_S_Goro/func_80BBDCFC.s") + case EN_S_GORO_TYPE_SHRINE_WINTER_C: + if (!(gSaveContext.save.weekEventReg[22] & 4)) { + if (player->transformation == PLAYER_FORM_GORON) { + if (!(gSaveContext.save.weekEventReg[37] & 2)) { + switch (this->textId) { + case 0xD09: + return 0xD0A; + case 0xD0A: + return 0xD0B; + case 0xD0B: + gSaveContext.save.weekEventReg[37] |= 2; + this->actionFlags |= EN_S_GORO_ACTIONFLAG_LASTMESSAGE; + return 0xD0C; + default: + return 0xD09; + } + } else { + this->actionFlags |= EN_S_GORO_ACTIONFLAG_LASTMESSAGE; + return 0xD0D; + } + } else { + this->actionFlags |= EN_S_GORO_ACTIONFLAG_LASTMESSAGE; + return 0xD08; + } + } else if (player->transformation == PLAYER_FORM_GORON) { + if (!(gSaveContext.save.weekEventReg[37] & 4)) { + switch (this->textId) { + case 0xD0E: + return 0xD0F; + case 0xD0F: + gSaveContext.save.weekEventReg[37] |= 4; + this->actionFlags |= EN_S_GORO_ACTIONFLAG_LASTMESSAGE; + return 0xD10; + default: + return 0xD0E; + } + } else { + this->actionFlags |= EN_S_GORO_ACTIONFLAG_LASTMESSAGE; + return 0xD11; + } + } else { + this->actionFlags |= EN_S_GORO_ACTIONFLAG_LASTMESSAGE; + return 0xD12; + } + break; -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_S_Goro/func_80BBDDF8.s") + case EN_S_GORO_TYPE_SHRINE_SPRING_A: + if (player->transformation == PLAYER_FORM_GORON) { + if (gSaveContext.save.weekEventReg[77] & 0x80) { + if (this->textId == 0xDE3) { + this->actionFlags |= EN_S_GORO_ACTIONFLAG_LASTMESSAGE; + return 0xDE4; + } + return 0xDE3; + } + this->actionFlags |= EN_S_GORO_ACTIONFLAG_LASTMESSAGE; + return 0xDE2; + } + this->actionFlags |= EN_S_GORO_ACTIONFLAG_LASTMESSAGE; + return 0xDE1; -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_S_Goro/func_80BBDE78.s") + case EN_S_GORO_TYPE_SHRINE_SPRING_B: + if (player->transformation == PLAYER_FORM_GORON) { + if (gSaveContext.save.weekEventReg[77] & 0x80) { + if (this->textId == 0xDE7) { + this->actionFlags |= EN_S_GORO_ACTIONFLAG_LASTMESSAGE; + return 0xDE8; + } + return 0xDE7; + } + this->actionFlags |= EN_S_GORO_ACTIONFLAG_LASTMESSAGE; + return 0xDE6; + } + this->actionFlags |= EN_S_GORO_ACTIONFLAG_LASTMESSAGE; + return 0xDE5; -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_S_Goro/func_80BBDF28.s") + case EN_S_GORO_TYPE_SHRINE_SPRING_C: + if (player->transformation == PLAYER_FORM_GORON) { + if (gSaveContext.save.weekEventReg[77] & 0x80) { + if (this->textId == 0xDEB) { + this->actionFlags |= EN_S_GORO_ACTIONFLAG_LASTMESSAGE; + return 0xDEC; + } + return 0xDEB; + } + this->actionFlags |= EN_S_GORO_ACTIONFLAG_LASTMESSAGE; + return 0xDEA; + } + this->actionFlags |= EN_S_GORO_ACTIONFLAG_LASTMESSAGE; + return 0xDE9; -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_S_Goro/func_80BBDFA8.s") + case EN_S_GORO_TYPE_SHRINE_SPRING_D: + if (player->transformation == PLAYER_FORM_GORON) { + if (gSaveContext.save.weekEventReg[77] & 0x80) { + if (this->textId == 0xDF1) { + this->actionFlags |= EN_S_GORO_ACTIONFLAG_LASTMESSAGE; + return 0xDF2; + } + return 0xDF1; + } + this->actionFlags |= EN_S_GORO_ACTIONFLAG_LASTMESSAGE; + return 0xDF0; + } + switch (this->textId) { + case 0xDED: + return 0xDEE; + case 0xDEE: + this->actionFlags |= EN_S_GORO_ACTIONFLAG_LASTMESSAGE; + return 0xDEF; + default: + return 0xDED; + } + break; -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_S_Goro/func_80BBE05C.s") + case EN_S_GORO_TYPE_SHRINE_SPRING_E: + if (player->transformation == PLAYER_FORM_GORON) { + if (gSaveContext.save.weekEventReg[77] & 0x80) { + if (this->textId == 0xDF6) { + this->actionFlags |= EN_S_GORO_ACTIONFLAG_LASTMESSAGE; + return 0xDF7; + } + return 0xDF6; + } + this->actionFlags |= EN_S_GORO_ACTIONFLAG_LASTMESSAGE; + return 0xDF5; + } + if (this->textId == 0xDF3) { + this->actionFlags |= EN_S_GORO_ACTIONFLAG_LASTMESSAGE; + return 0xDF4; + } + return 0xDF3; -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_S_Goro/func_80BBE0E4.s") + case EN_S_GORO_TYPE_SHRINE_SPRING_F: + if (player->transformation == PLAYER_FORM_GORON) { + if (gSaveContext.save.weekEventReg[77] & 0x80) { + switch (this->textId) { + case 0xDFB: + return 0xDFC; + case 0xDFC: + this->actionFlags |= EN_S_GORO_ACTIONFLAG_LASTMESSAGE; + return 0xDFD; + default: + return 0xDFB; + } + } else { + this->actionFlags |= EN_S_GORO_ACTIONFLAG_LASTMESSAGE; + return 0xDFA; + } + } else { + if (this->textId == 0xDF8) { + this->actionFlags |= EN_S_GORO_ACTIONFLAG_LASTMESSAGE; + return 0xDF9; + } + return 0xDF8; + } + break; -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_S_Goro/func_80BBE144.s") + default: + return 0; + } +} -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_S_Goro/func_80BBE374.s") +/** + * Dialogue tree for bomb shop goron. Returns ID of next message to display. + */ +u16 EnSGoro_BombshopGoron_NextTextId(EnSGoro* this, PlayState* play) { + Player* player = GET_PLAYER(play); -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_S_Goro/func_80BBE498.s") + switch (this->textId) { + case 0x0: + switch (player->transformation) { + case PLAYER_FORM_GORON: + // Check if Powder Keg is in Powder Key slot. + if (INV_CONTENT(ITEM_POWDER_KEG) == ITEM_POWDER_KEG) { + if ((gSaveContext.save.day == 3) && gSaveContext.save.isNight) { + if (!(this->bombbuyFlags & EN_S_GORO_BOMBBUYFLAG_TALKED_GOROKPK_FINALNIGHT)) { + this->bombbuyFlags |= EN_S_GORO_BOMBBUYFLAG_TALKED_GOROKPK_FINALNIGHT; + this->actionFlags |= EN_S_GORO_ACTIONFLAG_HANDTAP; + return 0x677; + } + return 0x67A; + } + if (!(this->bombbuyFlags & EN_S_GORO_BOMBBUYFLAG_TALKED_GORONPK)) { + this->bombbuyFlags |= EN_S_GORO_BOMBBUYFLAG_TALKED_GORONPK; + this->actionFlags |= EN_S_GORO_ACTIONFLAG_HANDTAP; + return 0x66E; + } + return 0x679; + } -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_S_Goro/func_80BBE73C.s") + // No powder keg + if ((gSaveContext.save.day == 3) && gSaveContext.save.isNight) { + if (!(this->bombbuyFlags & EN_S_GORO_BOMBBUYFLAG_TALKED_GORON_FINALNIGHT)) { + this->bombbuyFlags |= EN_S_GORO_BOMBBUYFLAG_TALKED_GORON_FINALNIGHT; + this->actionFlags |= EN_S_GORO_ACTIONFLAG_HANDTAP; + return 0x67E; + } + return 0x683; + } + if (!(this->bombbuyFlags & EN_S_GORO_BOMBBUYFLAG_TALKED_GORON)) { + this->bombbuyFlags |= EN_S_GORO_BOMBBUYFLAG_TALKED_GORON; + this->actionFlags |= EN_S_GORO_ACTIONFLAG_HANDTAP; + return 0x67B; + } + return 0x681; -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_S_Goro/func_80BBE844.s") + case PLAYER_FORM_ZORA: + if ((gSaveContext.save.day == 3) && gSaveContext.save.isNight) { + if (!(this->bombbuyFlags & EN_S_GORO_BOMBBUYFLAG_TALKED_ZORA_FINALNIGHT)) { + this->bombbuyFlags |= EN_S_GORO_BOMBBUYFLAG_TALKED_ZORA_FINALNIGHT; + return 0x668; + } + this->actionFlags |= EN_S_GORO_ACTIONFLAG_LASTMESSAGE; + this->actionFlags |= EN_S_GORO_ACTIONFLAG_TIRED; + return 0x66D; + } + if (!(this->bombbuyFlags & EN_S_GORO_BOMBBUYFLAG_TALKED_ZORA)) { + this->bombbuyFlags |= EN_S_GORO_BOMBBUYFLAG_TALKED_ZORA; + return 0x664; + } + this->actionFlags |= EN_S_GORO_ACTIONFLAG_LASTMESSAGE; + this->actionFlags |= EN_S_GORO_ACTIONFLAG_TIRED; + return 0x66C; -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_S_Goro/func_80BBE904.s") + case PLAYER_FORM_DEKU: + if ((gSaveContext.save.day == 3) && gSaveContext.save.isNight) { + if (!(this->bombbuyFlags & EN_S_GORO_BOMBBUYFLAG_TALKED_DEKU_FINALNIGHT)) { + this->bombbuyFlags |= EN_S_GORO_BOMBBUYFLAG_TALKED_DEKU_FINALNIGHT; + return 0x668; + } + this->actionFlags |= EN_S_GORO_ACTIONFLAG_LASTMESSAGE; + return 0x66D; + } + if (!(this->bombbuyFlags & EN_S_GORO_BOMBBUYFLAG_TALKED_DEKU)) { + this->bombbuyFlags |= EN_S_GORO_BOMBBUYFLAG_TALKED_DEKU; + return 0x664; + } + this->actionFlags |= EN_S_GORO_ACTIONFLAG_LASTMESSAGE; + return 0x66C; -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_S_Goro/func_80BBE9F8.s") + case PLAYER_FORM_HUMAN: + if ((gSaveContext.save.day == 3) && gSaveContext.save.isNight) { + if (!(this->bombbuyFlags & EN_S_GORO_BOMBBUYFLAG_TALKED_HUMAN_FINALNIGHT)) { + this->bombbuyFlags |= EN_S_GORO_BOMBBUYFLAG_TALKED_HUMAN_FINALNIGHT; + return 0x668; + } + this->actionFlags |= EN_S_GORO_ACTIONFLAG_LASTMESSAGE; + return 0x66D; + } + if (!(this->bombbuyFlags & EN_S_GORO_BOMBBUYFLAG_TALKED_HUMAN)) { + this->bombbuyFlags |= EN_S_GORO_BOMBBUYFLAG_TALKED_HUMAN; + return 0x664; + } + this->actionFlags |= EN_S_GORO_ACTIONFLAG_LASTMESSAGE; + return 0x66C; + } -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_S_Goro/func_80BBEAD8.s") + case 0x664: + this->actionFlags |= EN_S_GORO_ACTIONFLAG_HANDTAP; + return 0x665; -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_S_Goro/func_80BBEBF8.s") + case 0x665: + this->actionFlags &= ~EN_S_GORO_ACTIONFLAG_HANDTAP; + return 0x666; -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_S_Goro/func_80BBECBC.s") + case 0x666: + this->actionFlags |= EN_S_GORO_ACTIONFLAG_LASTMESSAGE; + this->actionFlags |= EN_S_GORO_ACTIONFLAG_TIRED; + return 0x667; -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_S_Goro/func_80BBEEB4.s") + case 0x668: + this->actionFlags |= EN_S_GORO_ACTIONFLAG_HANDTAP; + return 0x669; -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_S_Goro/func_80BBEF34.s") + case 0x669: + this->actionFlags &= ~EN_S_GORO_ACTIONFLAG_HANDTAP; + return 0x66A; -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_S_Goro/func_80BBEFA0.s") + case 0x66A: + this->actionFlags |= EN_S_GORO_ACTIONFLAG_LASTMESSAGE; + this->actionFlags |= EN_S_GORO_ACTIONFLAG_TIRED; + return 0x66B; -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_S_Goro/func_80BBF01C.s") + case 0x677: + this->actionFlags &= ~EN_S_GORO_ACTIONFLAG_HANDTAP; + return 0x678; -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_S_Goro/EnSGoro_Init.s") + case 0x678: + return 0x670; -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_S_Goro/EnSGoro_Destroy.s") + case 0x66E: + this->actionFlags &= ~EN_S_GORO_ACTIONFLAG_HANDTAP; + return 0x66F; -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_S_Goro/EnSGoro_Update.s") + case 0x66F: + return 0x670; -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_S_Goro/func_80BBF298.s") + case 0x679: + return 0x670; -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_S_Goro/func_80BBF3D0.s") + case 0x67A: + return 0x670; -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_S_Goro/func_80BBF3EC.s") + case 0x67E: + this->actionFlags &= ~EN_S_GORO_ACTIONFLAG_HANDTAP; + return 0x67F; -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_S_Goro/func_80BBF5F0.s") + case 0x67F: + this->actionFlags |= EN_S_GORO_ACTIONFLAG_LASTMESSAGE; + return 0x680; -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_S_Goro/func_80BBF6BC.s") + case 0x67B: + this->actionFlags &= ~EN_S_GORO_ACTIONFLAG_HANDTAP; + return 0x67C; -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_S_Goro/EnSGoro_Draw.s") + case 0x67C: + this->actionFlags |= EN_S_GORO_ACTIONFLAG_LASTMESSAGE; + return 0x67D; + + case 0x681: + this->actionFlags |= EN_S_GORO_ACTIONFLAG_LASTMESSAGE; + return 0x682; + + case 0x683: + this->actionFlags |= EN_S_GORO_ACTIONFLAG_LASTMESSAGE; + return 0x684; + + case 0x670: + if (this->bombbuyFlags & EN_S_GORO_BOMBBUYFLAG_YESBUY) { + if (AMMO(ITEM_POWDER_KEG) != 0) { + this->actionFlags |= EN_S_GORO_ACTIONFLAG_LASTMESSAGE; + play_sound(NA_SE_SY_ERROR); + return 0x673; + } + this->powderKegPrice = play->msgCtx.unk1206C; + if (gSaveContext.save.playerData.rupees < this->powderKegPrice) { + this->actionFlags |= EN_S_GORO_ACTIONFLAG_LASTMESSAGE; + this->actionFlags |= EN_S_GORO_ACTIONFLAG_TIRED; + play_sound(NA_SE_SY_ERROR); + return 0x674; + } + if ((gSaveContext.save.day == 3) && gSaveContext.save.isNight) { + this->actionFlags |= EN_S_GORO_ACTIONFLAG_LASTMESSAGE; + func_8019F208(); + return 0x676; + } + this->actionFlags |= EN_S_GORO_ACTIONFLAG_LASTMESSAGE; + func_8019F208(); + return 0x675; + } + if ((gSaveContext.save.day == 3) && gSaveContext.save.isNight) { + this->actionFlags |= EN_S_GORO_ACTIONFLAG_LASTMESSAGE; + return 0x672; + } + this->actionFlags |= EN_S_GORO_ACTIONFLAG_LASTMESSAGE; + return 0x671; + } + return 0; +} + +/** + * Links to actor of type EN_JG (Goron Elder), returns whether operation successful. + */ +s32 EnSGoro_FindGoronElder(EnSGoro* this, PlayState* play) { + this->otherGoron = SubS_FindActor(play, this->otherGoron, ACTORCAT_NPC, ACTOR_EN_JG); + if (this->otherGoron != NULL) { + return true; + } + return false; +} + +/** + * Links to actor of type EN_GK (Goron Elder's Son), returns whether operation successful. + */ +s32 EnSGoro_FindGoronChild(EnSGoro* this, PlayState* play) { + this->otherGoron = NULL; + this->otherGoron = SubS_FindActor(play, this->otherGoron, ACTORCAT_NPC, ACTOR_EN_GK); + if (this->otherGoron != NULL) { + return true; + } + return false; +} + +/** + * Looks like it manages the snoring cycle for when rolled up and asleep. + */ +void EnSGoro_UpdateSleeping(EnSGoro* this, PlayState* play) { + s16 curFrame = this->skelAnime.curFrame; + + this->snorePhase += 0x400; + this->scaleFactor = Math_SinS(this->snorePhase) * 0.01f * 0.1f; + this->actor.scale.y = 0.01f - this->scaleFactor; + this->actor.scale.z = 0.01f - this->scaleFactor; + this->actor.scale.x = 0.01f + this->scaleFactor; + + if (!(this->actionFlags & EN_S_GORO_ACTIONFLAG_SUPPRESS_SNORE)) { + if (this->snorePhase == 0) { + if (this->actionFlags & EN_S_GORO_ACTIONFLAG_SNOREPHASE) { + this->actionFlags &= ~EN_S_GORO_ACTIONFLAG_SNOREPHASE; + Actor_PlaySfxAtPos(&this->actor, NA_SE_EN_GOLON_SNORE2); + } else { + this->actionFlags |= EN_S_GORO_ACTIONFLAG_SNOREPHASE; + Actor_PlaySfxAtPos(&this->actor, NA_SE_EN_GOLON_SNORE1); + } + } + } else if (gSaveContext.save.weekEventReg[22] & 4) { + this->actionFlags &= ~EN_S_GORO_ACTIONFLAG_SUPPRESS_SNORE; + } + + if (!(this->actionFlags & EN_S_GORO_ACTIONFLAG_ROLLEDUP) && (curFrame == 0)) { + this->actionFlags |= EN_S_GORO_ACTIONFLAG_ROLLEDUP; + this->actor.shape.yOffset = EN_S_GORO_ROLLEDUP_YOFFSET; + } + + this->actor.shape.yOffset = (this->actor.scale.y / 0.01f) * EN_S_GORO_ROLLEDUP_YOFFSET; +} + +s32 EnSGoro_UpdateCheerAnimation(EnSGoro* this, PlayState* play) { + if (this->animInfoIndex == EN_S_GORO_ANIM_IDLE_STAND) { + if (((EnJg*)this->otherGoron)->flags & 1) { + this->loadedObjIndex = Object_GetIndex(&play->objectCtx, OBJECT_TAISOU); + if (this->loadedObjIndex >= 0) { + gSegments[6] = PHYSICAL_TO_VIRTUAL(play->objectCtx.status[this->loadedObjIndex].segment); + this->animInfoIndex = EN_S_GORO_ANIM_TAISOU_CHEER; + SubS_ChangeAnimationByInfoS(&this->skelAnime, sAnimationInfo, this->animInfoIndex); + return true; + } + } + } else if ((this->animInfoIndex == EN_S_GORO_ANIM_TAISOU_CHEER) && !(((EnJg*)this->otherGoron)->flags & 1)) { + this->loadedObjIndex = Object_GetIndex(&play->objectCtx, OBJECT_OF1D_MAP); + if (this->loadedObjIndex >= 0) { + gSegments[6] = PHYSICAL_TO_VIRTUAL(play->objectCtx.status[this->loadedObjIndex].segment); + this->animInfoIndex = EN_S_GORO_ANIM_IDLE_STAND; + SubS_ChangeAnimationByInfoS(&this->skelAnime, sAnimationInfo, this->animInfoIndex); + this->skelAnime.curFrame = this->skelAnime.endFrame; + return true; + } + } + return false; +} + +s32 EnSGoro_CheckLullaby(EnSGoro* this, PlayState* play) { + s32 actorType; + Player* player = GET_PLAYER(play); + + if ((player->transformation == PLAYER_FORM_GORON) && (play->msgCtx.ocarinaMode == 3)) { + if (play->msgCtx.lastPlayedSong == OCARINA_SONG_GORON_LULLABY) { + this->animInfoIndex = EN_S_GORO_ANIM_ROLLUP; + SubS_ChangeAnimationByInfoS(&this->skelAnime, sAnimationInfo, this->animInfoIndex); + + actorType = EN_S_GORO_GET_MAIN_TYPE(&this->actor); + this->snorePhase = 0x400 << (actorType + 1); + + /* + * Should be: + * if ((actorType % 2) == 0) + * However, the original code checks the negative case whereas the above does not. + * So unfortunately, this is the only way to get it to match. + */ + if (!(actorType % 2)) { + this->actionFlags |= EN_S_GORO_ACTIONFLAG_SNOREPHASE; + } + this->actionFunc = EnSGoro_Sleep; + return true; + } + } + return false; +} + +s32 EnSGoro_CheckGKBehavior(EnSGoro* this, PlayState* play) { + s32 actorType; + + if (!EnSGoro_FindGoronChild(this, play)) { + return false; + } + if ((!(this->actionFlags & EN_S_GORO_ACTIONFLAG_GKQUIET_ACKNOWLEDGED)) && + ((((EnGk*)this->otherGoron)->unk_1E4 & 0x80) || (gSaveContext.save.weekEventReg[22] & 4))) { + + this->actionFlags |= EN_S_GORO_ACTIONFLAG_GKQUIET_ACKNOWLEDGED; + this->animInfoIndex = EN_S_GORO_ANIM_ROLLUP; + SubS_ChangeAnimationByInfoS(&this->skelAnime, sAnimationInfo, this->animInfoIndex); + + actorType = EN_S_GORO_GET_MAIN_TYPE(&this->actor); + this->snorePhase = 0x400 << (actorType + 1); + + /* + * Should be: + * if ((actorType % 2) == 0) + * However, the original code checks the negative case whereas the above does not. + * So unfortunately, this is the only way to get it to match. + */ + if (!(actorType % 2)) { + this->actionFlags |= EN_S_GORO_ACTIONFLAG_SNOREPHASE; + } + this->actionFlags |= EN_S_GORO_ACTIONFLAG_SUPPRESS_SNORE; + this->actionFunc = EnSGoro_Sleep; + return true; + } + return false; +} + +void EnSGoro_UpdateToHandtapAnimation(EnSGoro* this) { + s16 curFrame = this->skelAnime.curFrame; + s16 lastFrame = Animation_GetLastFrame(sAnimationInfo[this->animInfoIndex].animation); + + if ((this->animInfoIndex != EN_S_GORO_ANIM_STAND_HANDTAP) && (curFrame == lastFrame)) { + this->animInfoIndex = EN_S_GORO_ANIM_STAND_HANDTAP; + SubS_ChangeAnimationByInfoS(&this->skelAnime, sAnimationInfo, this->animInfoIndex); + } +} + +void EnSGoro_UpdateSleepyAnimation(EnSGoro* this) { + s16 curFrame = this->skelAnime.curFrame; + s16 lastFrame = Animation_GetLastFrame(sAnimationInfo[this->animInfoIndex].animation); + + if (this->animInfoIndex != EN_S_GORO_ANIM_SLEEPY) { + if (curFrame == lastFrame) { + this->animInfoIndex = EN_S_GORO_ANIM_SLEEPY; + SubS_ChangeAnimationByInfoS(&this->skelAnime, sAnimationInfo, this->animInfoIndex); + } + } else if (curFrame == lastFrame) { + this->actionFlags &= ~EN_S_GORO_ACTIONFLAG_TIRED; + this->animInfoIndex = EN_S_GORO_ANIM_IDLE_STAND; + SubS_ChangeAnimationByInfoS(&this->skelAnime, sAnimationInfo, this->animInfoIndex); + } +} + +void EnSGoro_UpdateToIdleAnimation(EnSGoro* this) { + s16 curFrame = this->skelAnime.curFrame; + s16 lastFrame = Animation_GetLastFrame(sAnimationInfo[this->animInfoIndex].animation); + + if ((this->animInfoIndex != EN_S_GORO_ANIM_IDLE_STAND) && (curFrame == lastFrame)) { + this->animInfoIndex = EN_S_GORO_ANIM_IDLE_STAND; + SubS_ChangeAnimationByInfoS(&this->skelAnime, sAnimationInfo, this->animInfoIndex); + } +} + +void EnSGoro_UpdateCollider(EnSGoro* this, PlayState* play) { + Vec3f world_pos = this->actor.world.pos; + f32 radius = 24.0f; + f32 height = 62.0f; + + this->collider.dim.pos.x = world_pos.x; + this->collider.dim.pos.y = world_pos.y; + this->collider.dim.pos.z = world_pos.z; + this->collider.dim.radius = radius; + this->collider.dim.height = height; + + //! @bug: It is not clear what this is for. + if ((s32)this != -0x190) { + CollisionCheck_SetOC(play, &play->colChkCtx, &this->collider.base); + } +} + +void EnSGoro_UpdateEyes(EnSGoro* this) { + if (this->actionFlags & EN_S_GORO_ACTIONFLAG_EYESOPEN) { + if (DECR(this->eyeTimer) == 0) { + this->eyeTexIndex++; + if (this->eyeTexIndex > EN_S_GORO_EYETEX_CLOSED) { + this->eyeTimer = Rand_S16Offset(30, 30); + this->eyeTexIndex = EN_S_GORO_EYETEX_OPEN; + } + } + } +} + +void EnSGoro_UpdateActorFocus(EnSGoro* this) { + f32 yDelta; + + if (this->actionFlags & EN_S_GORO_ACTIONFLAG_ROLLEDUP) { + yDelta = this->actor.shape.yOffset; + } else { + yDelta = 58.0f; + } + + this->actor.focus.pos.x = this->actor.world.pos.x; + this->actor.focus.pos.y = this->actor.world.pos.y + yDelta; + this->actor.focus.pos.z = this->actor.world.pos.z; + this->actor.focus.rot.x = this->actor.world.rot.x; + this->actor.focus.rot.y = this->actor.world.rot.y; + this->actor.focus.rot.z = this->actor.world.rot.z; +} + +s32 EnSGoro_UpdateRotationToPlayer(EnSGoro* this, PlayState* play) { + Player* player = GET_PLAYER(play); + Vec3f playerPos; + Vec3f thisPos; + s16 target = (this->actor.yawTowardsPlayer - this->bodyRotY) - this->actor.shape.rot.y; + + Math_SmoothStepToS(&this->headRotY, target, 4, 0x2AA8, 1); + this->headRotY = CLAMP(this->headRotY, -0x1FFE, 0x1FFE); + + target = (this->actor.yawTowardsPlayer - this->headRotY) - this->actor.shape.rot.y; + Math_SmoothStepToS(&this->bodyRotY, target, 4, 0x2AA8, 1); + this->bodyRotY = CLAMP(this->bodyRotY, -0x1C70, 0x1C70); + + playerPos = player->actor.world.pos; + playerPos.y = player->bodyPartsPos[7].y + 3.0f; + thisPos = this->actor.world.pos; + thisPos.y += 70.0f; + + target = Math_Vec3f_Pitch(&thisPos, &playerPos) - this->bodyRotZ; + Math_SmoothStepToS(&this->headRotZ, target, 4, 0x2AA8, 1); + this->headRotZ = CLAMP(this->headRotZ, -0x1C70, 0x1C70); + + target = Math_Vec3f_Pitch(&thisPos, &playerPos) - this->headRotZ; + Math_SmoothStepToS(&this->bodyRotZ, target, 4, 0x2AA8, 1); + this->bodyRotZ = CLAMP(this->bodyRotZ, -0x1C70, 0x1C70); + + return true; +} + +s32 EnSGoro_UpdateAttentionTarget(EnSGoro* this, PlayState* play) { + if (DECR(this->loseAttentionTimer) != 0) { + // EnSGoro is in the process of returning to idle position from previously looking at the player. + if ((this->actionFlags & EN_S_GORO_ACTIONFLAG_EARSCOVERED) && + (this->actionFlags & EN_S_GORO_ACTIONFLAG_EYESOPEN)) { + // If ears are covered, but eyes are open, close eyes. + this->actionFlags &= ~EN_S_GORO_ACTIONFLAG_EYESOPEN; + this->eyeTexIndex = EN_S_GORO_EYETEX_CLOSED2; + } + // Reset position to idle. EnSGoro cannot return attention to player until the timer is up. + this->actionFlags &= ~EN_S_GORO_ACTIONFLAG_FACEPLAYER; + this->headRotZ = 0; + this->headRotY = 0; + this->bodyRotZ = 0; + this->bodyRotY = 0; + return true; + } + + // Turn to face player if either player has engaged EnSGoro or if player is in range and EnSGoro isn't covering his + // ears. + if (this->actionFlags & EN_S_GORO_ACTIONFLAG_ENGAGED) { + this->actionFlags |= EN_S_GORO_ACTIONFLAG_FACEPLAYER; + EnSGoro_UpdateRotationToPlayer(this, play); + } else if (!(this->actionFlags & EN_S_GORO_ACTIONFLAG_EARSCOVERED) && + Actor_IsFacingAndNearPlayer(&this->actor, 120.0f, 0x3FFC)) { + this->actionFlags |= EN_S_GORO_ACTIONFLAG_FACEPLAYER; + EnSGoro_UpdateRotationToPlayer(this, play); + } else { + // Unengaged or player out of range. + if (this->actionFlags & EN_S_GORO_ACTIONFLAG_FACEPLAYER) { + // Previously facing player, but now player out of range. + // Start counter for frames/function calls to ignore player while in process of returning to idle. + this->loseAttentionTimer = 20; + } + // Start animation to return to idle position. + this->actionFlags &= ~EN_S_GORO_ACTIONFLAG_FACEPLAYER; + this->headRotZ = 0; + this->headRotY = 0; + this->bodyRotZ = 0; + this->bodyRotY = 0; + } + return true; +} + +void EnSGoro_SetupAction(EnSGoro* this, PlayState* play) { + if (Object_IsLoaded(&play->objectCtx, this->loadedObjIndex)) { + this->actionFlags = 0; + if (EN_S_GORO_OFTYPE_WSHRINE) { + if (gSaveContext.save.weekEventReg[22] & 4) { + this->actionFlags |= EN_S_GORO_ACTIONFLAG_GKQUIET_ACKNOWLEDGED; + this->actionFlags |= EN_S_GORO_ACTIONFLAG_EYESOPEN; + this->animInfoIndex = EN_S_GORO_ANIM_SHIVER_A; + SubS_ChangeAnimationByInfoS(&this->skelAnime, sAnimationInfo, this->animInfoIndex); + } else { + this->eyeTexIndex = EN_S_GORO_EYETEX_CLOSED2; + this->actionFlags |= EN_S_GORO_ACTIONFLAG_EARSCOVERED; + this->animInfoIndex = EN_S_GORO_ANIM_COVEREARS; + SubS_ChangeAnimationByInfoS(&this->skelAnime, sAnimationInfo, this->animInfoIndex); + } + } else { + this->actionFlags |= EN_S_GORO_ACTIONFLAG_EYESOPEN; + this->animInfoIndex = EN_S_GORO_ANIM_IDLE_STAND; + SubS_ChangeAnimationByInfoS(&this->skelAnime, sAnimationInfo, this->animInfoIndex); + } + + this->scaleFactor = 0.01f; + Actor_SetScale(&this->actor, 0.01f); + this->actor.gravity = -1.0f; + this->actor.flags |= ACTOR_FLAG_10; + this->actor.flags |= ACTOR_FLAG_2000000; + this->actor.targetMode = 1; + + switch (EN_S_GORO_GET_MAIN_TYPE(&this->actor)) { + case EN_S_GORO_TYPE_SHRINE_WINTER_A: + this->actionFunc = EnSGoro_WinterShrineGoron_Idle; + break; + case EN_S_GORO_TYPE_SHRINE_WINTER_B: + this->actionFunc = EnSGoro_WinterShrineGoron_Idle; + break; + case EN_S_GORO_TYPE_SHRINE_WINTER_C: + this->actionFunc = EnSGoro_WinterShrineGoron_Idle; + break; + case EN_S_GORO_TYPE_SHRINE_SPRING_A: + if (EnSGoro_FindGoronElder(this, play)) { + this->actionFunc = EnSGoro_SpringShrineGoron_Idle; + } + break; + case EN_S_GORO_TYPE_SHRINE_SPRING_B: + if (EnSGoro_FindGoronElder(this, play)) { + this->actionFunc = EnSGoro_SpringShrineGoron_Idle; + } + break; + case EN_S_GORO_TYPE_SHRINE_SPRING_C: + if (EnSGoro_FindGoronElder(this, play)) { + this->actionFunc = EnSGoro_SpringShrineGoron_Idle; + } + break; + case EN_S_GORO_TYPE_SHRINE_SPRING_D: + if (EnSGoro_FindGoronElder(this, play)) { + this->actionFunc = EnSGoro_SpringShrineGoron_Idle; + } + break; + case EN_S_GORO_TYPE_SHRINE_SPRING_E: + if (EnSGoro_FindGoronElder(this, play)) { + this->actionFunc = EnSGoro_SpringShrineGoron_Idle; + } + break; + case EN_S_GORO_TYPE_SHRINE_SPRING_F: + if (EnSGoro_FindGoronElder(this, play)) { + this->actionFunc = EnSGoro_SpringShrineGoron_Idle; + } + break; + case EN_S_GORO_TYPE_BOMBSHOP: + this->actionFlags |= EN_S_GORO_ACTIONFLAG_ROLLEDUP; + this->actionFunc = EnSGoro_ShopGoron_Idle; + this->actor.shape.yOffset = EN_S_GORO_ROLLEDUP_YOFFSET; + break; + default: + Actor_MarkForDeath(&this->actor); + break; + } + } +} + +void EnSGoro_WinterShrineGoron_Idle(EnSGoro* this, PlayState* play) { + if (!EnSGoro_CheckLullaby(this, play) && !EnSGoro_CheckGKBehavior(this, play)) { + if (Actor_ProcessTalkRequest(&this->actor, &play->state)) { + this->actionFlags |= EN_S_GORO_ACTIONFLAG_ENGAGED; + if (this->actionFlags & EN_S_GORO_ACTIONFLAG_EARSCOVERED) { + this->actionFlags |= EN_S_GORO_ACTIONFLAG_EYESOPEN; + this->eyeTexIndex = EN_S_GORO_EYETEX_OPEN; + } + this->textId = EnSGoro_ShrineGoron_NextTextId(this, play); + Message_StartTextbox(play, this->textId, &this->actor); + this->actionFunc = EnSGoro_WinterShrineGoron_Talk; + } else if ((this->actor.xzDistToPlayer < 250.0f) || this->actor.isTargeted) { + func_800B863C(&this->actor, play); + } + Math_SmoothStepToS(&this->actor.shape.rot.y, this->actor.home.rot.y, 5, 0x1000, 0x100); + this->actor.world.rot.y = this->actor.shape.rot.y; + } +} + +void EnSGoro_WinterShrineGoron_Talk(EnSGoro* this, PlayState* play) { + if ((Message_GetState(&play->msgCtx) == TEXT_STATE_DONE) && (Message_ShouldAdvance(play))) { + if (this->actionFlags & EN_S_GORO_ACTIONFLAG_LASTMESSAGE) { + this->actionFlags &= ~EN_S_GORO_ACTIONFLAG_LASTMESSAGE; + this->actionFlags &= ~EN_S_GORO_ACTIONFLAG_ENGAGED; + this->actionFunc = EnSGoro_WinterShrineGoron_Idle; + return; + } + this->textId = EnSGoro_ShrineGoron_NextTextId(this, play); + Message_StartTextbox(play, this->textId, &this->actor); + } + Math_SmoothStepToS(&this->actor.shape.rot.y, this->actor.yawTowardsPlayer, 5, 0x1000, 0x100); + this->actor.world.rot.y = this->actor.shape.rot.y; +} + +void EnSGoro_SpringShrineGoron_Idle(EnSGoro* this, PlayState* play) { + if ((EN_S_GORO_GET_MAIN_TYPE(&this->actor) == EN_S_GORO_TYPE_SHRINE_SPRING_F) || + !EnSGoro_UpdateCheerAnimation(this, play)) { + if (Actor_ProcessTalkRequest(&this->actor, &play->state)) { + this->actionFlags |= EN_S_GORO_ACTIONFLAG_ENGAGED; + this->textId = EnSGoro_ShrineGoron_NextTextId(this, play); + Message_StartTextbox(play, this->textId, &this->actor); + this->actionFunc = EnSGoro_SpringShrineGoron_Talk; + } else if ((this->actor.xzDistToPlayer < 250.0f) || (this->actor.isTargeted)) { + func_800B863C(&this->actor, play); + } + Math_SmoothStepToS(&this->actor.shape.rot.y, this->actor.home.rot.y, 5, 0x1000, 0x100); + this->actor.world.rot.y = this->actor.shape.rot.y; + } +} + +void EnSGoro_SpringShrineGoron_Talk(EnSGoro* this, PlayState* play) { + if ((Message_GetState(&play->msgCtx) == TEXT_STATE_5) && Message_ShouldAdvance(play)) { + if (this->actionFlags & EN_S_GORO_ACTIONFLAG_LASTMESSAGE) { + this->actionFlags &= ~EN_S_GORO_ACTIONFLAG_LASTMESSAGE; + this->actionFlags &= ~EN_S_GORO_ACTIONFLAG_ENGAGED; + play->msgCtx.msgMode = 0x43; + play->msgCtx.stateTimer = 4; + this->actionFunc = EnSGoro_SpringShrineGoron_Idle; + return; + } + this->textId = EnSGoro_ShrineGoron_NextTextId(this, play); + Message_StartTextbox(play, this->textId, &this->actor); + } + Math_SmoothStepToS(&this->actor.shape.rot.y, this->actor.yawTowardsPlayer, 5, 0x1000, 0x100); + this->actor.world.rot.y = this->actor.shape.rot.y; +} + +void EnSGoro_ShopGoron_Idle(EnSGoro* this, PlayState* play) { + if (!(this->actionFlags & EN_S_GORO_ACTIONFLAG_ROLLEDUP)) { + EnSGoro_UpdateToIdleAnimation(this); + } + if (Actor_ProcessTalkRequest(&this->actor, &play->state)) { + this->actionFlags |= EN_S_GORO_ACTIONFLAG_ENGAGED; + this->textId = EnSGoro_BombshopGoron_NextTextId(this, play); + if (this->actionFlags & EN_S_GORO_ACTIONFLAG_ROLLEDUP) { + this->actionFlags &= ~EN_S_GORO_ACTIONFLAG_ROLLEDUP; + this->animInfoIndex = EN_S_GORO_ANIM_UNROLL_A; + SubS_ChangeAnimationByInfoS(&this->skelAnime, sAnimationInfo, this->animInfoIndex); + this->actionFunc = EnSGoro_ShopGoron_FinishUnroll; + } else { + Message_StartTextbox(play, this->textId, &this->actor); + this->actionFunc = EnSGoro_ShopGoron_Talk; + } + } else if ((this->actor.xzDistToPlayer < 250.0f) || this->actor.isTargeted) { + func_800B863C(&this->actor, play); + } + Math_SmoothStepToS(&this->actor.shape.rot.y, this->actor.home.rot.y, 5, 0x1000, 0x100); + this->actor.world.rot.y = this->actor.shape.rot.y; +} + +void EnSGoro_ShopGoron_FinishUnroll(EnSGoro* this, PlayState* play) { + s16 curFrame = this->skelAnime.curFrame; + s16 lastFrame = Animation_GetLastFrame(sAnimationInfo[this->animInfoIndex].animation); + + if ((this->animInfoIndex == EN_S_GORO_ANIM_UNROLL_A) && (curFrame == lastFrame)) { + this->animInfoIndex = EN_S_GORO_ANIM_IDLE_STAND; + SubS_ChangeAnimationByInfoS(&this->skelAnime, sAnimationInfo, this->animInfoIndex); + Message_StartTextbox(play, this->textId, &this->actor); + this->actionFunc = EnSGoro_ShopGoron_Talk; + } + + Math_SmoothStepToS(&this->actor.shape.rot.y, this->actor.yawTowardsPlayer, 5, 0x1000, 0x100); + this->actor.world.rot.y = this->actor.shape.rot.y; +} + +void EnSGoro_ShopGoron_Talk(EnSGoro* this, PlayState* play) { + u8 talkState = Message_GetState(&play->msgCtx); + + if (this->actionFlags & EN_S_GORO_ACTIONFLAG_HANDTAP) { + EnSGoro_UpdateToHandtapAnimation(this); + } else if (this->actionFlags & EN_S_GORO_ACTIONFLAG_TIRED) { + EnSGoro_UpdateSleepyAnimation(this); + } else { + EnSGoro_UpdateToIdleAnimation(this); + } + + if (talkState == TEXT_STATE_DONE) { + if (Message_ShouldAdvance(play)) { + if (this->actionFlags & EN_S_GORO_ACTIONFLAG_LASTMESSAGE) { + this->actionFlags &= ~EN_S_GORO_ACTIONFLAG_LASTMESSAGE; + this->actionFlags &= ~EN_S_GORO_ACTIONFLAG_ENGAGED; + this->textId = 0; + this->actionFunc = EnSGoro_ShopGoron_Idle; + return; + } + this->textId = EnSGoro_BombshopGoron_NextTextId(this, play); + Message_StartTextbox(play, this->textId, &this->actor); + } + } else if ((talkState == TEXT_STATE_CHOICE) && (Message_ShouldAdvance(play))) { + switch (play->msgCtx.choiceIndex) { + case 0: + this->bombbuyFlags |= EN_S_GORO_BOMBBUYFLAG_YESBUY; + break; + case 1: + func_8019F230(); + this->bombbuyFlags &= ~EN_S_GORO_BOMBBUYFLAG_YESBUY; + break; + } + + this->textId = EnSGoro_BombshopGoron_NextTextId(this, play); + if ((this->textId == 0x675) || (this->textId == 0x676)) { + play->msgCtx.msgMode = 0x43; + play->msgCtx.stateTimer = 4; + Actor_PickUp(&this->actor, play, GI_POWDER_KEG, 300.0f, 300.0f); + this->actionFunc = EnSGoro_ShopGoron_TakePayment; + } else { + Message_StartTextbox(play, this->textId, &this->actor); + } + } + + Math_SmoothStepToS(&this->actor.shape.rot.y, this->actor.yawTowardsPlayer, 5, 0x1000, 0x100); + this->actor.world.rot.y = this->actor.shape.rot.y; +} + +void EnSGoro_ShopGoron_TakePayment(EnSGoro* this, PlayState* play) { + if (Actor_HasParent(&this->actor, play)) { + this->actor.parent = NULL; + Rupees_ChangeBy(-this->powderKegPrice); + this->actionFunc = EnSGoro_ShopGoron_FinishTransaction; + } else { + Actor_PickUp(&this->actor, play, GI_POWDER_KEG, 300.0f, 300.0f); + } +} + +void EnSGoro_ShopGoron_FinishTransaction(EnSGoro* this, PlayState* play) { + if (Actor_ProcessTalkRequest(&this->actor, &play->state)) { + Message_StartTextbox(play, this->textId, &this->actor); + this->actionFunc = EnSGoro_ShopGoron_Talk; + } else { + func_800B85E0(&this->actor, play, 400.0f, -1); + } +} + +void EnSGoro_Sleep(EnSGoro* this, PlayState* play) { + if (Actor_ProcessTalkRequest(&this->actor, &play->state)) { + Message_StartTextbox(play, 0x23A, &this->actor); + this->actionFunc = EnSGoro_SleepTalk; + } else if (this->actor.isTargeted) { + func_800B863C(&this->actor, play); + } + EnSGoro_UpdateSleeping(this, play); +} + +void EnSGoro_SleepTalk(EnSGoro* this, PlayState* play) { + if (Message_GetState(&play->msgCtx) == TEXT_STATE_DONE) { + if (Message_ShouldAdvance(play)) { + play->msgCtx.msgMode = 0x43; + play->msgCtx.stateTimer = 4; + this->actionFunc = EnSGoro_Sleep; + } + } + EnSGoro_UpdateSleeping(this, play); +} + +void EnSGoro_Init(Actor* thisx, PlayState* play) { + s32 pad; + EnSGoro* this = THIS; + + ActorShape_Init(&this->actor.shape, 0.0f, ActorShadow_DrawCircle, 20.0f); + SkelAnime_InitFlex(play, &this->skelAnime, &gGoronSkel, &gGoronUnrollAnim, this->jointTable, this->morphTable, + GORON_LIMB_MAX); + Collider_InitCylinder(play, &this->collider); + Collider_SetCylinder(play, &this->collider, &this->actor, &sCylinderInit); + CollisionCheck_SetInfo2(&this->actor.colChkInfo, &sDamageTable, &sColChkInfoInit); + if (this->actor.update != NULL) { + s32 objIndex = Object_GetIndex(&play->objectCtx, OBJECT_OF1D_MAP); + + this->loadedObjIndex = objIndex; + if (objIndex < 0) { + Actor_MarkForDeath(&this->actor); + } + } + this->actor.draw = EnSGoro_Draw; + this->actionFunc = EnSGoro_SetupAction; +} + +void EnSGoro_Destroy(Actor* thisx, PlayState* play) { + EnSGoro* this = THIS; + + Collider_DestroyCylinder(play, &this->collider); +} + +void EnSGoro_Update(Actor* thisx, PlayState* play) { + EnSGoro* this = (EnSGoro*)thisx; + + this->actionFunc(this, play); + Actor_UpdateBgCheckInfo(play, &this->actor, 30.0f, 12.0f, 0.0f, 5); + gSegments[6] = PHYSICAL_TO_VIRTUAL(play->objectCtx.status[this->loadedObjIndex].segment); + SkelAnime_Update(&this->skelAnime); + if (this->animInfoIndex != EN_S_GORO_ANIM_SLEEPY) { + EnSGoro_UpdateAttentionTarget(this, play); + } + EnSGoro_UpdateEyes(this); + EnSGoro_UpdateActorFocus(this); + EnSGoro_UpdateCollider(this, play); +} + +/** + * This function appears to be identical to SubS_UpdateLimb. But it's here! + */ +s32 EnSGoro_UpdateLimb(s16 newRotZ, s16 newRotY, Vec3f* pos, Vec3s* rot, s32 stepRot, s32 overrideRot) { + Vec3f newPos; + Vec3f zeroVec = gZeroVec3f; + Vec3s newRot; + MtxF curState; + + Matrix_MultVec3f(&zeroVec, &newPos); + Matrix_Get(&curState); + Matrix_MtxFToYXZRot(&curState, &newRot, MTXMODE_NEW); + + *pos = newPos; + + if (!stepRot && !overrideRot) { + rot->x = newRot.x; + rot->y = newRot.y; + rot->z = newRot.z; + return true; + } + + if (overrideRot) { + newRot.z = newRotZ; + newRot.y = newRotY; + } + + Math_SmoothStepToS(&rot->x, newRot.x, 3, 0x2AA8, 0xB6); + Math_SmoothStepToS(&rot->y, newRot.y, 3, 0x2AA8, 0xB6); + Math_SmoothStepToS(&rot->z, newRot.z, 3, 0x2AA8, 0xB6); + return true; +} + +s32 EnSGoro_OverrideLimbDraw(PlayState* play, s32 limbIndex, Gfx** dList, Vec3f* pos, Vec3s* rot, Actor* thisx) { + return false; +} + +void EnSGoro_TransformLimbDraw(PlayState* play, s32 limbIndex, Actor* thisx) { + s32 stepRot; + s32 overrideRot; + EnSGoro* this = THIS; + + if (limbIndex != GORON_LIMB_BODY) { + if ((limbIndex == GORON_LIMB_HEAD) && (this->animInfoIndex != EN_S_GORO_ANIM_SLEEPY)) { + if (this->actionFlags & EN_S_GORO_ACTIONFLAG_FACEPLAYER) { + overrideRot = true; + } else { + overrideRot = false; + } + if (this->loseAttentionTimer != 0) { + stepRot = true; + } else { + stepRot = false; + } + + EnSGoro_UpdateLimb(this->headRotZ + this->bodyRotZ + 0x4000, + this->headRotY + this->bodyRotY + this->actor.shape.rot.y + 0x4000, &this->headTranslate, + &this->headRotate, stepRot, overrideRot); + + Matrix_Pop(); + Matrix_Translate(this->headTranslate.x, this->headTranslate.y, this->headTranslate.z, MTXMODE_NEW); + Matrix_Scale(this->actor.scale.x, this->actor.scale.y, this->actor.scale.z, MTXMODE_APPLY); + Matrix_RotateYS(this->headRotate.y, MTXMODE_APPLY); + Matrix_RotateXS(this->headRotate.x, MTXMODE_APPLY); + Matrix_RotateZS(this->headRotate.z, MTXMODE_APPLY); + Matrix_Push(); + } + } else if (this->animInfoIndex != EN_S_GORO_ANIM_SLEEPY) { + if (this->actionFlags & EN_S_GORO_ACTIONFLAG_FACEPLAYER) { + overrideRot = true; + } else { + overrideRot = false; + } + if (this->loseAttentionTimer != 0) { + stepRot = true; + } else { + stepRot = false; + } + + EnSGoro_UpdateLimb(this->bodyRotZ + 0x4000, this->bodyRotY + this->actor.shape.rot.y + 0x4000, + &this->bodyTranslate, &this->bodyRotate, stepRot, overrideRot); + + Matrix_Pop(); + Matrix_Translate(this->bodyTranslate.x, this->bodyTranslate.y, this->bodyTranslate.z, MTXMODE_NEW); + Matrix_Scale(this->actor.scale.x, this->actor.scale.y, this->actor.scale.z, MTXMODE_APPLY); + Matrix_RotateYS(this->bodyRotate.y, MTXMODE_APPLY); + Matrix_RotateXS(this->bodyRotate.x, MTXMODE_APPLY); + Matrix_RotateZS(this->bodyRotate.z, MTXMODE_APPLY); + Matrix_Push(); + } +} + +void EnSGoro_DrawUnrolled(EnSGoro* this, PlayState* play) { + s32 pad; + + OPEN_DISPS(play->state.gfxCtx); + func_8012C28C(play->state.gfxCtx); + + gSPSegment(POLY_OPA_DISP++, 0x8, Lib_SegmentedToVirtual(sEyeTextures[this->eyeTexIndex])); + gDPPipeSync(POLY_OPA_DISP++); + + SkelAnime_DrawTransformFlexOpa(play, this->skelAnime.skeleton, this->skelAnime.jointTable, + this->skelAnime.dListCount, EnSGoro_OverrideLimbDraw, NULL, + EnSGoro_TransformLimbDraw, &this->actor); + + CLOSE_DISPS(play->state.gfxCtx); +} + +void EnSGoro_DrawRolledUp(EnSGoro* this, PlayState* play) { + OPEN_DISPS(play->state.gfxCtx); + func_8012C28C(play->state.gfxCtx); + + Matrix_Translate(this->actor.world.pos.x, this->actor.world.pos.y + this->actor.shape.yOffset, + this->actor.world.pos.z, MTXMODE_NEW); + Matrix_RotateYS(this->actor.shape.rot.y, MTXMODE_APPLY); + Matrix_Translate(0.0f, -this->actor.shape.yOffset, 0.0f, MTXMODE_APPLY); + Matrix_RotateZS(this->actor.shape.rot.z, MTXMODE_APPLY); + Matrix_Translate(0.0f, this->actor.shape.yOffset, 0.0f, MTXMODE_APPLY); + Matrix_Scale(this->actor.scale.x, this->actor.scale.y, this->actor.scale.z, MTXMODE_APPLY); + + gSPMatrix(POLY_OPA_DISP++, Matrix_NewMtx(play->state.gfxCtx), G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW); + gSPDisplayList(POLY_OPA_DISP++, gGoronRolledUpDL); + + CLOSE_DISPS(play->state.gfxCtx); +} + +void EnSGoro_Draw(Actor* thisx, PlayState* play) { + EnSGoro* this = (EnSGoro*)thisx; + + if (this->actionFlags & EN_S_GORO_ACTIONFLAG_ROLLEDUP) { + EnSGoro_DrawRolledUp(this, play); + } else { + EnSGoro_DrawUnrolled(this, play); + } +} diff --git a/src/overlays/actors/ovl_En_S_Goro/z_en_s_goro.h b/src/overlays/actors/ovl_En_S_Goro/z_en_s_goro.h index 7d8e7627f0..0d7ac9edb9 100644 --- a/src/overlays/actors/ovl_En_S_Goro/z_en_s_goro.h +++ b/src/overlays/actors/ovl_En_S_Goro/z_en_s_goro.h @@ -2,20 +2,59 @@ #define Z_EN_S_GORO_H #include "global.h" +#include "objects/object_oF1d_map/object_oF1d_map.h" -#define EN_S_GORO_GET_PARAM_F(thisx) ((thisx)->params & 0xF) +#define EN_S_GORO_GET_MAIN_TYPE(thisx) ((thisx)->params & 0xF) +#define EN_S_GORO_SCENEFLAG_INDEX(thisx) (((thisx)->params & 0x7F0) >> 4) struct EnSGoro; typedef void (*EnSGoroActionFunc)(struct EnSGoro*, PlayState*); -typedef struct EnSGoro { - /* 0x000 */ Actor actor; - /* 0x144 */ char unk_144[0x48]; - /* 0x18C */ EnSGoroActionFunc actionFunc; - /* 0x190 */ char unk_190[0x180]; -} EnSGoro; // size = 0x310 - extern const ActorInit En_S_Goro_InitVars; +typedef struct EnSGoro { + /* 0x000 */ Actor actor; + /* 0x144 */ Actor* otherGoron; + /* 0x148 */ SkelAnime skelAnime; + /* 0x18C */ EnSGoroActionFunc actionFunc; + /* 0x190 */ ColliderCylinder collider; + /* 0x1DC */ u16 actionFlags; + /* 0x1DE */ u16 bombbuyFlags; + /* 0x1E0 */ UNK_TYPE1 unk_1E0[0xC]; + /* 0x1EC */ s16 eyeTexIndex; + /* 0x1EE */ s16 eyeTimer; + /* 0x1F0 */ s16 loseAttentionTimer; + /* 0x1F4 */ s32 loadedObjIndex; + /* 0x1F8 */ Vec3s jointTable[GORON_LIMB_MAX]; + /* 0x264 */ Vec3s morphTable[GORON_LIMB_MAX]; + /* 0x2D0 */ f32 scaleFactor; + /* 0x2D4 */ s16 headRotZ; + /* 0x2D6 */ s16 headRotY; + /* 0x2D8 */ s16 bodyRotZ; + /* 0x2DA */ s16 bodyRotY; + /* 0x2DC */ Vec3f headTranslate; + /* 0x2E8 */ Vec3s headRotate; + /* 0x2F0 */ Vec3f bodyTranslate; + /* 0x2FC */ Vec3s bodyRotate; + /* 0x302 */ UNK_TYPE1 unk_302[2]; + /* 0x304 */ u16 textId; + /* 0x306 */ s16 snorePhase; + /* 0x308 */ s32 animInfoIndex; + /* 0x30C */ s16 powderKegPrice; +} EnSGoro; // size = 0x310 + +typedef enum EnSGoroType { + /* 0x0 */ EN_S_GORO_TYPE_SHRINE_WINTER_A, + /* 0x1 */ EN_S_GORO_TYPE_SHRINE_WINTER_B, + /* 0x2 */ EN_S_GORO_TYPE_SHRINE_WINTER_C, + /* 0x3 */ EN_S_GORO_TYPE_SHRINE_SPRING_A, + /* 0x4 */ EN_S_GORO_TYPE_SHRINE_SPRING_B, + /* 0x5 */ EN_S_GORO_TYPE_SHRINE_SPRING_C, + /* 0x6 */ EN_S_GORO_TYPE_SHRINE_SPRING_D, + /* 0x7 */ EN_S_GORO_TYPE_SHRINE_SPRING_E, + /* 0x8 */ EN_S_GORO_TYPE_SHRINE_SPRING_F, + /* 0x9 */ EN_S_GORO_TYPE_BOMBSHOP +} EnSGoroType; + #endif // Z_EN_S_GORO_H diff --git a/tools/disasm/functions.txt b/tools/disasm/functions.txt index 722faab561..0b79b37be2 100644 --- a/tools/disasm/functions.txt +++ b/tools/disasm/functions.txt @@ -15414,42 +15414,42 @@ 0x80BBC4E4:("func_80BBC4E4",), 0x80BBC500:("func_80BBC500",), 0x80BBC540:("EnZos_Draw",), - 0x80BBCA80:("func_80BBCA80",), - 0x80BBD348:("func_80BBD348",), - 0x80BBD8F0:("func_80BBD8F0",), - 0x80BBD93C:("func_80BBD93C",), - 0x80BBD98C:("func_80BBD98C",), - 0x80BBDACC:("func_80BBDACC",), - 0x80BBDC34:("func_80BBDC34",), - 0x80BBDCFC:("func_80BBDCFC",), - 0x80BBDDF8:("func_80BBDDF8",), - 0x80BBDE78:("func_80BBDE78",), - 0x80BBDF28:("func_80BBDF28",), - 0x80BBDFA8:("func_80BBDFA8",), - 0x80BBE05C:("func_80BBE05C",), - 0x80BBE0E4:("func_80BBE0E4",), - 0x80BBE144:("func_80BBE144",), - 0x80BBE374:("func_80BBE374",), - 0x80BBE498:("func_80BBE498",), - 0x80BBE73C:("func_80BBE73C",), - 0x80BBE844:("func_80BBE844",), - 0x80BBE904:("func_80BBE904",), - 0x80BBE9F8:("func_80BBE9F8",), - 0x80BBEAD8:("func_80BBEAD8",), - 0x80BBEBF8:("func_80BBEBF8",), - 0x80BBECBC:("func_80BBECBC",), - 0x80BBEEB4:("func_80BBEEB4",), - 0x80BBEF34:("func_80BBEF34",), - 0x80BBEFA0:("func_80BBEFA0",), - 0x80BBF01C:("func_80BBF01C",), + 0x80BBCA80:("EnSGoro_ShrineGoron_NextTextId",), + 0x80BBD348:("EnSGoro_BombshopGoron_NextTextId",), + 0x80BBD8F0:("EnSGoro_FindGoronElder",), + 0x80BBD93C:("EnSGoro_FindGoronChild",), + 0x80BBD98C:("EnSGoro_UpdateSleeping",), + 0x80BBDACC:("EnSGoro_UpdateCheerAnimation",), + 0x80BBDC34:("EnSGoro_CheckLullaby",), + 0x80BBDCFC:("EnSGoro_CheckGKBehavior",), + 0x80BBDDF8:("EnSGoro_UpdateToHandtapAnimation",), + 0x80BBDE78:("EnSGoro_UpdateSleepyAnimation",), + 0x80BBDF28:("EnSGoro_UpdateToIdleAnimation",), + 0x80BBDFA8:("EnSGoro_UpdateCollider",), + 0x80BBE05C:("EnSGoro_UpdateEyes",), + 0x80BBE0E4:("EnSGoro_UpdateActorFocus",), + 0x80BBE144:("EnSGoro_UpdateRotationToPlayer",), + 0x80BBE374:("EnSGoro_UpdateAttentionTarget",), + 0x80BBE498:("EnSGoro_SetupAction",), + 0x80BBE73C:("EnSGoro_WinterShrineGoron_Idle",), + 0x80BBE844:("EnSGoro_WinterShrineGoron_Talk",), + 0x80BBE904:("EnSGoro_SpringShrineGoron_Idle",), + 0x80BBE9F8:("EnSGoro_SpringShrineGoron_Talk",), + 0x80BBEAD8:("EnSGoro_ShopGoron_Idle",), + 0x80BBEBF8:("EnSGoro_ShopGoron_FinishUnroll",), + 0x80BBECBC:("EnSGoro_ShopGoron_Talk",), + 0x80BBEEB4:("EnSGoro_ShopGoron_TakePayment",), + 0x80BBEF34:("EnSGoro_ShopGoron_FinishTransaction",), + 0x80BBEFA0:("EnSGoro_Sleep",), + 0x80BBF01C:("EnSGoro_SleepTalk",), 0x80BBF09C:("EnSGoro_Init",), 0x80BBF198:("EnSGoro_Destroy",), 0x80BBF1C4:("EnSGoro_Update",), - 0x80BBF298:("func_80BBF298",), - 0x80BBF3D0:("func_80BBF3D0",), - 0x80BBF3EC:("func_80BBF3EC",), - 0x80BBF5F0:("func_80BBF5F0",), - 0x80BBF6BC:("func_80BBF6BC",), + 0x80BBF298:("EnSGoro_UpdateLimb",), + 0x80BBF3D0:("EnSGoro_OverrideLimbDraw",), + 0x80BBF3EC:("EnSGoro_TransformLimbDraw",), + 0x80BBF5F0:("EnSGoro_DrawUnrolled",), + 0x80BBF6BC:("EnSGoro_DrawRolledUp",), 0x80BBF7BC:("EnSGoro_Draw",), 0x80BBFDB0:("func_80BBFDB0",), 0x80BBFE60:("func_80BBFE60",), diff --git a/tools/disasm/variables.txt b/tools/disasm/variables.txt index 407b746ca0..e04bc46f09 100644 --- a/tools/disasm/variables.txt +++ b/tools/disasm/variables.txt @@ -15610,12 +15610,12 @@ 0x80BBC75C:("D_80BBC75C","UNK_TYPE1","",0x1), 0x80BBC770:("D_80BBC770","f32","",0x4), 0x80BBC774:("jtbl_80BBC774","UNK_PTR","",0x4), - 0x80BBF800:("En_S_Goro_InitVars","UNK_TYPE1","",0x1), - 0x80BBF820:("D_80BBF820","UNK_TYPE1","",0x1), - 0x80BBF84C:("D_80BBF84C","UNK_TYPE1","",0x1), - 0x80BBF858:("D_80BBF858","UNK_TYPE1","",0x1), - 0x80BBF878:("D_80BBF878","UNK_TYPE1","",0x1), - 0x80BBF978:("D_80BBF978","UNK_TYPE1","",0x1), + 0x80BBF800:("En_S_Goro_InitVars","ActorInit","",0x20), + 0x80BBF820:("sCylinderInit","ColliderCylinderInit","",0x2C), + 0x80BBF84C:("sColChkInfoInit","CollisionCheckInfoInit2","",0xC), + 0x80BBF858:("sDamageTable","DamageTable","",0x20), + 0x80BBF878:("sAnimationInfo","AnimationInfoS","[16]",0x100), + 0x80BBF978:("sEyeTextures","TexturePtr","[4]",0x18), 0x80BBF990:("jtbl_80BBF990","UNK_PTR","",0x4), 0x80BBF9B4:("jtbl_80BBF9B4","UNK_PTR","",0x4), 0x80BBFA34:("D_80BBFA34","f32","",0x4),