diff --git a/assets/xml/objects/object_hakugin_demo.xml b/assets/xml/objects/object_hakugin_demo.xml index 24c7a2ba2a..8c8b5837c2 100644 --- a/assets/xml/objects/object_hakugin_demo.xml +++ b/assets/xml/objects/object_hakugin_demo.xml @@ -1,8 +1,9 @@  + - - - - + + + + diff --git a/assets/xml/objects/object_taisou.xml b/assets/xml/objects/object_taisou.xml index 696285927f..0143f24442 100644 --- a/assets/xml/objects/object_taisou.xml +++ b/assets/xml/objects/object_taisou.xml @@ -1,12 +1,13 @@  + - - - - - - - - + + + + + + + + diff --git a/include/z64save.h b/include/z64save.h index 01acfed0eb..fdb99fea04 100644 --- a/include/z64save.h +++ b/include/z64save.h @@ -695,7 +695,9 @@ typedef enum { #define WEEKEVENTREG_18_10 PACK_WEEKEVENTREG_FLAG(18, 0x10) #define WEEKEVENTREG_18_20 PACK_WEEKEVENTREG_FLAG(18, 0x20) #define WEEKEVENTREG_18_40 PACK_WEEKEVENTREG_FLAG(18, 0x40) -#define WEEKEVENTREG_18_80 PACK_WEEKEVENTREG_FLAG(18, 0x80) + +// Player has Powder Keg purchasing privileges. +#define WEEKEVENTREG_HAS_POWDERKEG_PRIVILEGES PACK_WEEKEVENTREG_FLAG(18, 0x80) #define WEEKEVENTREG_19_01 PACK_WEEKEVENTREG_FLAG(19, 0x01) #define WEEKEVENTREG_19_02 PACK_WEEKEVENTREG_FLAG(19, 0x02) #define WEEKEVENTREG_19_04 PACK_WEEKEVENTREG_FLAG(19, 0x04) @@ -717,8 +719,12 @@ typedef enum { #define WEEKEVENTREG_20_80 PACK_WEEKEVENTREG_FLAG(20, 0x80) #define WEEKEVENTREG_21_01 PACK_WEEKEVENTREG_FLAG(21, 0x01) #define WEEKEVENTREG_21_02 PACK_WEEKEVENTREG_FLAG(21, 0x02) -#define WEEKEVENTREG_21_04 PACK_WEEKEVENTREG_FLAG(21, 0x04) -#define WEEKEVENTREG_21_08 PACK_WEEKEVENTREG_FLAG(21, 0x08) + +// Player has spoken to Goron Graveyard's gravemaker while in Goron form. +#define WEEKEVENTREG_TALKED_GORON_GRAVEMAKER_AS_GORON PACK_WEEKEVENTREG_FLAG(21, 0x04) +// Player has spoken to formerly frozen Goron outside Goron Graveyard. +#define WEEKEVENTREG_TALKED_THAWED_GRAVEYARD_GORON PACK_WEEKEVENTREG_FLAG(21, 0x08) + #define WEEKEVENTREG_21_10 PACK_WEEKEVENTREG_FLAG(21, 0x10) #define WEEKEVENTREG_21_20 PACK_WEEKEVENTREG_FLAG(21, 0x20) #define WEEKEVENTREG_21_40 PACK_WEEKEVENTREG_FLAG(21, 0x40) @@ -729,7 +735,10 @@ typedef enum { #define WEEKEVENTREG_22_01 PACK_WEEKEVENTREG_FLAG(22, 0x01) #define WEEKEVENTREG_22_02 PACK_WEEKEVENTREG_FLAG(22, 0x02) -#define WEEKEVENTREG_22_04 PACK_WEEKEVENTREG_FLAG(22, 0x04) + +// Goron Elder's son has been calmed from Goron's Lullaby. +#define WEEKEVENTREG_CALMED_GORON_ELDERS_SON PACK_WEEKEVENTREG_FLAG(22, 0x04) + #define WEEKEVENTREG_22_08 PACK_WEEKEVENTREG_FLAG(22, 0x08) #define WEEKEVENTREG_22_10 PACK_WEEKEVENTREG_FLAG(22, 0x10) #define WEEKEVENTREG_22_20 PACK_WEEKEVENTREG_FLAG(22, 0x20) @@ -1293,11 +1302,17 @@ typedef enum { #define WEEKEVENTREG_88_08 PACK_WEEKEVENTREG_FLAG(88, 0x08) #define WEEKEVENTREG_88_10 PACK_WEEKEVENTREG_FLAG(88, 0x10) #define WEEKEVENTREG_88_20 PACK_WEEKEVENTREG_FLAG(88, 0x20) -#define WEEKEVENTREG_88_40 PACK_WEEKEVENTREG_FLAG(88, 0x40) -#define WEEKEVENTREG_88_80 PACK_WEEKEVENTREG_FLAG(88, 0x80) -#define WEEKEVENTREG_89_01 PACK_WEEKEVENTREG_FLAG(89, 0x01) -#define WEEKEVENTREG_89_02 PACK_WEEKEVENTREG_FLAG(89, 0x02) -#define WEEKEVENTREG_89_04 PACK_WEEKEVENTREG_FLAG(89, 0x04) + +// Goron shrine Gatekeeper has opened shrine. +#define WEEKEVENTREG_GATEKEEPER_OPENED_GORON_SHRINE PACK_WEEKEVENTREG_FLAG(88, 0x40) +// Goron shrine Gatekeeper has opened shrine for player in Human form. +#define WEEKEVENTREG_GATEKEEPER_OPENED_GORON_SHRINE_FOR_HUMAN PACK_WEEKEVENTREG_FLAG(88, 0x80) +// Goron shrine Gatekeeper has opened shrine for player in Deku form. +#define WEEKEVENTREG_GATEKEEPER_OPENED_GORON_SHRINE_FOR_DEKU PACK_WEEKEVENTREG_FLAG(89, 0x01) +// Goron shrine Gatekeeper has opened shrine for player in Zora form. +#define WEEKEVENTREG_GATEKEEPER_OPENED_GORON_SHRINE_FOR_ZORA PACK_WEEKEVENTREG_FLAG(89, 0x02) +// Goron shrine Gatekeeper has opened shrine for player in Goron form. +#define WEEKEVENTREG_GATEKEEPER_OPENED_GORON_SHRINE_FOR_GORON PACK_WEEKEVENTREG_FLAG(89, 0x04) // Unconfirmed: "Postman has delivered priority mail" #define WEEKEVENTREG_89_08 PACK_WEEKEVENTREG_FLAG(89, 0x08) diff --git a/spec b/spec index 05cd8d6340..a9d627634f 100644 --- a/spec +++ b/spec @@ -2402,11 +2402,7 @@ beginseg name "ovl_En_Go" compress include "build/src/overlays/actors/ovl_En_Go/z_en_go.o" -#ifdef NON_MATCHING include "build/src/overlays/actors/ovl_En_Go/ovl_En_Go_reloc.o" -#else - include "build/data/ovl_En_Go/ovl_En_Go.reloc.o" -#endif endseg beginseg diff --git a/src/overlays/actors/ovl_Bg_Tobira01/z_bg_tobira01.c b/src/overlays/actors/ovl_Bg_Tobira01/z_bg_tobira01.c index 920842b0b9..5302c6a903 100644 --- a/src/overlays/actors/ovl_Bg_Tobira01/z_bg_tobira01.c +++ b/src/overlays/actors/ovl_Bg_Tobira01/z_bg_tobira01.c @@ -38,12 +38,12 @@ void BgTobira01_Action(BgTobira01* this, PlayState* play) { CutsceneManager_Stop(CS_ID_GLOBAL_TALK); } else if (CutsceneManager_IsNext(csId)) { CutsceneManager_StartWithPlayerCs(csId, &this->dyna.actor); - SET_WEEKEVENTREG(WEEKEVENTREG_88_40); + SET_WEEKEVENTREG(WEEKEVENTREG_GATEKEEPER_OPENED_GORON_SHRINE); this->cutsceneRequested = false; } else { CutsceneManager_Queue(csId); } - } else if (!CHECK_WEEKEVENTREG(WEEKEVENTREG_88_40) && (this->posYTick == 0) && + } else if (!CHECK_WEEKEVENTREG(WEEKEVENTREG_GATEKEEPER_OPENED_GORON_SHRINE) && (this->posYTick == 0) && (play->actorCtx.playerImpact.timer != 0) && (play->actorCtx.playerImpact.type == PLAYER_IMPACT_GORON_GROUND_POUND) && (SurfaceType_GetSceneExitIndex(&play->colCtx, player->actor.floorPoly, player->actor.floorBgId) == 6)) { @@ -52,7 +52,7 @@ void BgTobira01_Action(BgTobira01* this, PlayState* play) { } prevPosYTick = this->posYTick; - if (CHECK_WEEKEVENTREG(WEEKEVENTREG_88_40)) { + if (CHECK_WEEKEVENTREG(WEEKEVENTREG_GATEKEEPER_OPENED_GORON_SHRINE)) { this->posYTick++; } else { this->posYTick--; @@ -65,9 +65,9 @@ void BgTobira01_Action(BgTobira01* this, PlayState* play) { this->timer = 180; } - if (!(player->stateFlags1 & PLAYER_STATE1_40) && CHECK_WEEKEVENTREG(WEEKEVENTREG_88_40) && + if (!(player->stateFlags1 & PLAYER_STATE1_40) && CHECK_WEEKEVENTREG(WEEKEVENTREG_GATEKEEPER_OPENED_GORON_SHRINE) && (DECR(this->timer) == 0)) { - CLEAR_WEEKEVENTREG(WEEKEVENTREG_88_40); + CLEAR_WEEKEVENTREG(WEEKEVENTREG_GATEKEEPER_OPENED_GORON_SHRINE); } } @@ -76,7 +76,7 @@ void BgTobira01_Init(Actor* thisx, PlayState* play) { DynaPolyActor_Init(&this->dyna, DYNA_TRANSFORM_POS); DynaPolyActor_LoadMesh(play, &this->dyna, &gGoronDoorCol); - CLEAR_WEEKEVENTREG(WEEKEVENTREG_88_40); + CLEAR_WEEKEVENTREG(WEEKEVENTREG_GATEKEEPER_OPENED_GORON_SHRINE); Actor_SetScale(&this->dyna.actor, 1.0f); this->timer = gSaveContext.save.isNight; this->posYTick = 0; diff --git a/src/overlays/actors/ovl_En_Geg/z_en_geg.c b/src/overlays/actors/ovl_En_Geg/z_en_geg.c index 0362fb4e30..6621ecc935 100644 --- a/src/overlays/actors/ovl_En_Geg/z_en_geg.c +++ b/src/overlays/actors/ovl_En_Geg/z_en_geg.c @@ -135,17 +135,17 @@ static AnimationInfoS sAnimationInfo[] = { { &gGoronShiverAnim, 1.0f, 0, -1, ANIMMODE_LOOP, 0 }, { &gGoronShiverAnim, 1.0f, 0, -1, ANIMMODE_LOOP, -4 }, { &gGoronDropKegAnim, 1.0f, 0, -1, ANIMMODE_ONCE, -4 }, - { &object_taisou_Anim_0016C8, 1.0f, 0, -1, ANIMMODE_LOOP, 0 }, - { &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_005EE0, 1.0f, 0, -1, ANIMMODE_LOOP, 0 }, - { &object_taisou_Anim_002C48, 1.0f, 0, -1, ANIMMODE_LOOP, 0 }, - { &object_taisou_Anim_0031D8, 1.0f, 0, -1, ANIMMODE_LOOP, 0 }, - { &object_taisou_Anim_005790, 1.0f, 0, -1, ANIMMODE_LOOP, 0 }, + { &gGoronAthleticsSquatSideToSideAnim, 1.0f, 0, -1, ANIMMODE_LOOP, 0 }, + { &gGoronAthleticsDoubleArmSideBendAnim, 1.0f, 0, -1, ANIMMODE_LOOP, 0 }, + { &gGoronAthleticsShakeLimbsAnim, 1.0f, 0, -1, ANIMMODE_LOOP, 0 }, + { &gGoronAthleticsSingleArmSideBendAnim, 1.0f, 0, -1, ANIMMODE_LOOP, 0 }, + { &gGoronAthleticsHamstringStretchSittingAnim, 1.0f, 0, -1, ANIMMODE_LOOP, 0 }, + { &gGoronAthleticsCheerAnim, 1.0f, 0, -1, ANIMMODE_LOOP, 0 }, + { &gGoronAthleticsShoutAnim, 1.0f, 0, -1, ANIMMODE_LOOP, 0 }, + { &gGoronAthleticsHamstringStretchStandingAnim, 1.0f, 0, -1, ANIMMODE_LOOP, 0 }, { &gGoronCoverEarsAnim, 1.0f, 0, -1, ANIMMODE_LOOP, 0 }, - { &object_hakugin_demo_Anim_002704, 1.0f, 0, -1, ANIMMODE_ONCE, 0 }, - { &object_hakugin_demo_Anim_003378, 1.0f, 0, -1, ANIMMODE_LOOP, -4 }, + { &gGoronSpringLookAroundAnim, 1.0f, 0, -1, ANIMMODE_ONCE, 0 }, + { &gGoronSpringLookAroundLoopAnim, 1.0f, 0, -1, ANIMMODE_LOOP, -4 }, { &gGoronShiveringSurprisedAnim, 1.0f, 0, -1, ANIMMODE_ONCE, 0 }, { &gGoronStandingIdleAnim, 1.0f, 0, -1, ANIMMODE_LOOP, 0 }, }; diff --git a/src/overlays/actors/ovl_En_Gk/z_en_gk.c b/src/overlays/actors/ovl_En_Gk/z_en_gk.c index c561035aa9..28d5c344df 100644 --- a/src/overlays/actors/ovl_En_Gk/z_en_gk.c +++ b/src/overlays/actors/ovl_En_Gk/z_en_gk.c @@ -830,7 +830,7 @@ void func_80B51EA4(EnGk* this, PlayState* play) { } void func_80B51FD0(EnGk* this, PlayState* play) { - if (!CHECK_WEEKEVENTREG(WEEKEVENTREG_22_04)) { + if (!CHECK_WEEKEVENTREG(WEEKEVENTREG_CALMED_GORON_ELDERS_SON)) { if (this->unk_1E4 & 2) { func_801A4748(&this->actor.projectedPos, NA_SE_EN_GOLON_KID_CRY - SFX_FLAG); } else { @@ -897,7 +897,7 @@ void func_80B5227C(EnGk* this, PlayState* play) { func_800B14D4(play, 20.0f, &this->actor.home.pos); this->unk_350 = 60; if (!(this->unk_1E4 & 0x80)) { - SET_WEEKEVENTREG(WEEKEVENTREG_22_04); + SET_WEEKEVENTREG(WEEKEVENTREG_CALMED_GORON_ELDERS_SON); } Actor_PlaySfx(&this->actor, NA_SE_EN_GOLON_SIT_IMT); this->unk_350 = 0x4000; @@ -987,7 +987,7 @@ void func_80B525E0(EnGk* this, PlayState* play) { void func_80B52654(EnGk* this, PlayState* play) { this->unk_350 += 0x400; if ((this->unk_1E4 & 0x80) && (play->csCtx.curFrame == 250)) { - SET_WEEKEVENTREG(WEEKEVENTREG_22_04); + SET_WEEKEVENTREG(WEEKEVENTREG_CALMED_GORON_ELDERS_SON); } this->unk_354 = Math_SinS(this->unk_350) * 0.006f * 0.06f; @@ -1044,7 +1044,7 @@ void EnGk_Init(Actor* thisx, PlayState* play) { Actor_Kill(&this->actor); } } else if (ENGK_GET_F(&this->actor) == ENGK_F_2) { - if (!CHECK_WEEKEVENTREG(WEEKEVENTREG_22_04)) { + if (!CHECK_WEEKEVENTREG(WEEKEVENTREG_CALMED_GORON_ELDERS_SON)) { this->actionFunc = func_80B51FD0; this->actor.draw = NULL; this->actor.flags |= ACTOR_FLAG_10; @@ -1052,7 +1052,7 @@ void EnGk_Init(Actor* thisx, PlayState* play) { } else { Actor_Kill(&this->actor); } - } else if (!CHECK_WEEKEVENTREG(WEEKEVENTREG_22_04)) { + } else if (!CHECK_WEEKEVENTREG(WEEKEVENTREG_CALMED_GORON_ELDERS_SON)) { this->unk_2E4 = 0; this->csId = this->actor.csId; this->actor.flags |= ACTOR_FLAG_10; @@ -1076,7 +1076,7 @@ void EnGk_Update(Actor* thisx, PlayState* play) { this->actionFunc(this, play); if ((ENGK_GET_F(&this->actor) == ENGK_F_1) || - ((ENGK_GET_F(&this->actor) == ENGK_F_0) && !CHECK_WEEKEVENTREG(WEEKEVENTREG_22_04))) { + ((ENGK_GET_F(&this->actor) == ENGK_F_0) && !CHECK_WEEKEVENTREG(WEEKEVENTREG_CALMED_GORON_ELDERS_SON))) { func_80B507A0(this, play); SkelAnime_Update(&this->skelAnime); Actor_TrackPlayer(play, &this->actor, &this->unk_1D8, &this->unk_1DE, this->actor.focus.pos); @@ -1235,7 +1235,7 @@ void EnGk_Draw(Actor* thisx, PlayState* play) { Gfx_SetupDL25_Opa(play->state.gfxCtx); - if ((ENGK_GET_F(&this->actor) == ENGK_F_0) && CHECK_WEEKEVENTREG(WEEKEVENTREG_22_04)) { + if ((ENGK_GET_F(&this->actor) == ENGK_F_0) && CHECK_WEEKEVENTREG(WEEKEVENTREG_CALMED_GORON_ELDERS_SON)) { Matrix_RotateXS(-0x4000, MTXMODE_APPLY); gSPMatrix(POLY_OPA_DISP++, Matrix_NewMtx(play->state.gfxCtx), G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW); diff --git a/src/overlays/actors/ovl_En_Go/z_en_go.c b/src/overlays/actors/ovl_En_Go/z_en_go.c index 67cbf327a2..f706289304 100644 --- a/src/overlays/actors/ovl_En_Go/z_en_go.c +++ b/src/overlays/actors/ovl_En_Go/z_en_go.c @@ -2,42 +2,208 @@ * File: z_en_go.c * Overlay: ovl_En_Go * Description: Goron + * + * This actor handles multiple (but not all) Gorons. The Gorons included are: + * - Athletics Goron: Gorons in the racetrack performing stretches before/after a race. + * - Spectator Goron: Gorons scattered throughout the racetrack watching the race. + * - Gatekeeper Goron: The Gatekeeper of the Goron Shrine. + * - Graveyard Goron: Both Gorons outside the Goron Graveyard (one of which is initially frozen). + * - Shrine Goron: Gorons in the Goron Shrine (specifically, one in the elders room, one outside the elder's room, and + * one outside the shop, not all Gorons in the Goron Shrine are covered by this actor). + * - Medigoron: The Powder Keg making Medigoron in Goron Village. */ - #include "z_en_go.h" #include "z64quake.h" #include "overlays/actors/ovl_En_Bom/z_en_bom.h" -#include "objects/object_oF1d_map/object_oF1d_map.h" #include "objects/object_hakugin_demo/object_hakugin_demo.h" #include "objects/object_taisou/object_taisou.h" #include "objects/gameplay_keep/gameplay_keep.h" +#include "overlays/actors/ovl_Obj_Aqua/z_obj_aqua.h" #define FLAGS (ACTOR_FLAG_1 | ACTOR_FLAG_8 | ACTOR_FLAG_10 | ACTOR_FLAG_2000000) - #define THIS ((EnGo*)thisx) +#define ENGO_STANDING_Y_OFFSET 0.0f // Actor shape offset in use when a Goron is in any standing state. +#define ENGO_ROLLEDUP_Y_OFFSET 14.0f // Actor shape offset in use when a Goron is "rolled up". +#define ENGO_SNOWBALL_Y_OFFSET 46.0f // Actor shape offset in use when a Goron is in a snowball. + +#define ENGO_NORMAL_SCALE 0.01f // "Unit Scale" of a normal Goron. +#define ENGO_MEDIGORON_SCALE_MULTIPLIER 5.0f // Scale factor for the Medigoron in the Powder Keg Shop. + +#define ENGO_POUND_INITIAL_RISE_VEL 10.0f // Velocity at which the Gatekeeper's pound surges into the air. +#define ENGO_POUND_INITIAL_FALL_VEL -6.0f // Velocity at which the Gatekeeper's pound surges to the ground. + +#define ENGO_DUST_STEAM_LIFETIME 16 // Lifetime in frames of the Dust and Steam effects. + +#define ENGO_FLAG_ENGAGED (1 << 3) +#define ENGO_FLAG_FACE_TARGET (1 << 4) +#define ENGO_FLAG_EYES_OPEN (1 << 5) +#define ENGO_FLAG_LOST_ATTENTION (1 << 6) +#define ENGO_FLAG_STANDING (1 << 7) +#define ENGO_FLAG_SNOWBALLED (1 << 8) +#define ENGO_FLAG_ROLLED_UP (1 << 9) +#define ENGO_FLAG_FROZEN (1 << 10) +#define ENGO_FLAG_HIT_OTHER (1 << 11) +#define ENGO_FLAG_HIT_BY_OTHER (1 << 12) +#define ENGO_FLAG_HIT_OBJ (1 << 13) +#define ENGO_FLAG_ROLLING_UP (1 << 14) +#define ENGO_FLAG_UNROLLING (1 << 15) + void EnGo_Init(Actor* thisx, PlayState* play); void EnGo_Destroy(Actor* thisx, PlayState* play); void EnGo_Update(Actor* thisx, PlayState* play); +void EnGo_Draw(Actor* thisx, PlayState* play); -void func_80A14798(EnGo* this, PlayState* play); -void func_80A149B0(EnGo* this, PlayState* play); -void func_80A14B30(EnGo* this, PlayState* play); -void func_80A14E14(EnGo* this, PlayState* play); -void func_80A14E74(EnGo* this, PlayState* play); -void func_80A14EB0(EnGo* this, PlayState* play); -void func_80A14FC8(EnGo* this, PlayState* play); -void func_80A153FC(EnGo* this, PlayState* play); -void func_80A157C4(EnGo* this, PlayState* play); -void func_80A15FEC(Actor* thisx, PlayState* play); +typedef enum EnGoEyeTexture { + /* 0 */ ENGO_EYETEX_OPEN, + /* 1 */ ENGO_EYETEX_HALF, + /* 2 */ ENGO_EYETEX_CLOSED, + /* 3 */ ENGO_EYETEX_HALF2, + /* 4 */ ENGO_EYETEX_CLOSED2 +} EnGoEyeTexture; -static s32 D_80A16100[] = { +typedef enum EnGoSleepState { + /* -1 */ ENGO_ASLEEP_NEG = -1, + /* 0 */ ENGO_AWAKE, + /* 1 */ ENGO_ASLEEP_POS +} EnGoSleepState; + +typedef enum EnGoEffectType { + /* 0 */ ENGO_EFFECT_NONE, + /* 1 */ ENGO_EFFECT_SNOW1, + /* 2 */ ENGO_EFFECT_SNOW2, + /* 3 */ ENGO_EFFECT_SNOW3, + /* 4 */ ENGO_EFFECT_DUST_MIN, + /* 4 */ ENGO_EFFECT_DUST1 = ENGO_EFFECT_DUST_MIN, + /* 5 */ ENGO_EFFECT_DUST2, + /* 6 */ ENGO_EFFECT_DUST3, + /* 7 */ ENGO_EFFECT_STEAM_MIN, + /* 7 */ ENGO_EFFECT_STEAM = ENGO_EFFECT_STEAM_MIN +} EnGoEffectType; + +typedef enum EnGoAnimationIndex { + /* -1 */ ENGO_ANIM_INVALID = -1, + /* 0 */ ENGO_ANIM_GORON_MIN, + /* 0 */ ENGO_ANIM_LYINGDOWNIDLE = ENGO_ANIM_GORON_MIN, + /* 1 */ ENGO_ANIM_LYINGDOWNIDLE_IMM, + /* 2 */ ENGO_ANIM_UNROLL, + /* 3 */ ENGO_ANIM_UNROLL_IMM, + /* 4 */ ENGO_ANIM_ROLL, + /* 5 */ ENGO_ANIM_SHIVER, + /* 6 */ ENGO_ANIM_SHIVER_IMM, + /* 7 */ ENGO_ANIM_DROPKEG, + /* 8 */ ENGO_ANIM_COVEREARS, + /* 9 */ ENGO_ANIM_SHIVERINGSURPRISED, + /* 10 */ ENGO_ANIM_ATHLETICS_MIN, + /* 10 */ ENGO_ANIM_DOUBLE_ARM_SIDEBEND = ENGO_ANIM_ATHLETICS_MIN, + /* 11 */ ENGO_ANIM_SQUAT_SIDE_TO_SIDE, + /* 12 */ ENGO_ANIM_SHAKE_LIMBS, + /* 13 */ ENGO_ANIM_SINGLE_ARM_SIDEBEND, + /* 14 */ ENGO_ANIM_SITTING_STRETCH, + /* 15 */ ENGO_ANIM_CHEER, + /* 16 */ ENGO_ANIM_SHOUT, + /* 17 */ ENGO_ANIM_HELP_SITTING_STRETCH, + /* 18 */ ENGO_ANIM_SPRING_MIN, + /* 18 */ ENGO_ANIM_SHOW = ENGO_ANIM_SPRING_MIN, + /* 19 */ ENGO_ANIM_SHOW_LOOPED, + /* 20 */ ENGO_ANIM_LOOK_AROUND, + /* 21 */ ENGO_ANIM_LOOK_AROUND_LOOPED +} EnGoAnimationIndex; + +EnGoEffect* EnGo_InitSteam(EnGoEffect effect[], Vec3f pos, Vec3f accel, Vec3f velocity, f32 scale, f32 deltaScale, + s32 maxFrames); +void EnGo_DrawSteam(EnGoEffect effect[], PlayState* play2); + +void EnGo_InitDust(EnGoEffect effect[], Vec3f pos, Vec3f accel, Vec3f vel, f32 scale, f32 deltaScale, s32 maxFrames, + EnGoEffectType parentEffectType); +void EnGo_DrawDust(EnGoEffect effect[], PlayState* play2); + +void EnGo_InitSnow(EnGoEffect effect[], Vec3f pos); +void EnGo_UpdateSnow(EnGoEffect* effect, f32 dustConversionHeight); +void EnGo_DrawSnow(EnGoEffect effect[], PlayState* play, Gfx* material, Gfx* model, u8 effectType); + +void EnGo_UpdateEffects(EnGo* this); +void EnGo_DrawEffects(EnGo* this, PlayState* play); + +s32 EnGo_CanSnowballHurtPlayer(PlayState* play); +s32 EnGo_IsFallingAsleep(EnGo* this, PlayState* play); + +s32 EnGo_UpdateFocus(EnGo* this); + +void EnGo_UpdateSnowballCollider(EnGo* this, PlayState* play); +void EnGo_UpdateMedigoronCollider(EnGo* this, PlayState* play); +void EnGo_UpdateRolledUpCollider(EnGo* this, PlayState* play); +void EnGo_UpdateFrozenCollider(EnGo* this, PlayState* play); +void EnGo_UpdateStandingCollider(EnGo* this, PlayState* play); +void EnGo_UpdateCollider(EnGo* this, PlayState* play); + +s32 EnGo_UpdateTalking(EnGo* this, PlayState* play); +s32 EnGo_DetectCollisions(EnGo* this, PlayState* play); +s32 EnGo_UpdateSpringArrivalCutscene(EnGo* this, PlayState* play); +s32 EnGo_UpdateAnimationToCurrent(EnGo* this, PlayState* play); +s32 EnGo_UpdateSfx(EnGo* this, PlayState* play); +s32 EnGo_ChangeAnim(EnGo* this, PlayState* play, EnGoAnimationIndex animIndex); +void EnGo_UpdateEyes(EnGo* this); + +void EnGo_UpdateShiverSurprisedAnimation(EnGo* this, PlayState* play); +s32 EnGo_UpdateGraveyardAttentionTargetAndReactions(EnGo* this, PlayState* play); +s32 EnGo_UpdateRotationToTarget(EnGo* this, PlayState* play); +s32 EnGo_UpdateAttentionTargetAndReactions(EnGo* this, PlayState* play); + +void EnGo_GravemakerIdle(EnGo* this, PlayState* play); +void EnGo_FrozenIdle(EnGo* this, PlayState* play); +Actor* EnGo_FindGravemaker(EnGo* this, PlayState* play); + +void EnGo_UpdateMedigoronColliderRadius(EnGo* this, PlayState* play, s32 isGivenPowderKeg); +s32 EnGo_ChangeCutscene(EnGo* this, s16 csId); + +s32 EnGo_HandleGatekeeperPoundCutscene(EnGo* this, f32 initialVelocity, f32 maxDistortion, s32 maxHangtime); +void EnGo_AddGatekeeperPoundQuake(PlayState* play, s16 speed, s16 verticalMag, s16 countdown); +void EnGo_CreateGatekeeperPoundEffects(EnGo* this, PlayState* play); +void EnGo_DrawIceBlockWhenFrozen(EnGo* this, PlayState* play, f32 scale, f32 alpha); +void EnGo_MakeSteam(EnGo* this); + +s32 EnGo_HandleOpenShrineCutscene(Actor* thisx, PlayState* play); +s32 EnGo_HandleGivePowderKegCutscene(Actor* thisx, PlayState* play); + +void EnGo_ChangeToStretchingAnimation(EnGo* this, PlayState* play); +void EnGo_ChangeToSpectatingAnimation(EnGo* this, PlayState* play); +void EnGo_ChangeToFrozenAnimation(EnGo* this, PlayState* play); +void EnGo_ChangeToSnowballAnimation(EnGo* this, PlayState* play); +void EnGo_ChangeToCoveringEarsAnimation(EnGo* this, PlayState* play); +void EnGo_ChangeToShiveringAnimation(EnGo* this, PlayState* play); + +void EnGo_SetupAthletic(EnGo* this, PlayState* play); +void EnGo_SetupSpectator(EnGo* this, PlayState* play); +void EnGo_SetupGatekeeper(EnGo* this, PlayState* play); +void EnGo_SetupGraveyardGoron(EnGo* this, PlayState* play); +void EnGo_SetupShrineGoron(EnGo* this, PlayState* play); +void EnGo_SetupMedigoron(EnGo* this, PlayState* play); +void EnGo_SetupInitialAction(EnGo* this, PlayState* play); + +void EnGo_Idle(EnGo* this, PlayState* play); +void EnGo_Sleep(EnGo* this, PlayState* play); +void EnGo_Frozen(EnGo* this, PlayState* play); +void EnGo_AwaitThaw(EnGo* this, PlayState* play); +void EnGo_Thaw(EnGo* this, PlayState* play); + +void EnGo_HandleSpringArrivalCutscene(EnGo* this, PlayState* play); + +void EnGo_Snowball(EnGo* this, PlayState* play); + +s32* EnGo_GetMsgEventScript(EnGo* this, PlayState* play); + +void EnGo_Talk(EnGo* this, PlayState* play); + +// MsgEvent script for the Goron who made Darmani's grave in the mountain village. +static s32 sMsgScriptGoronGravemaker[] = { 0x00150800, 0x40010022, 0x00150200, 0x180E0E10, 0x0C0F0E11, 0x0C0F0E12, 0x0C0F0E13, 0x0C0F0E14, 0x0C111502, 0x100E0E15, 0x0C100015, 0x0400110E, 0x0E160C0F, 0x0E170C0F, 0x0E180C11, 0x15041610, 0x0E0E190C, 0x10001504, 0x000D0100, 0x050E0E31, 0x0C100E0E, 0x2F0C1001, 0x00050E0E, 0x2D0C100E, 0x0E2B0C10, }; -static s32 D_80A16164[] = { +// MsgEvent script for the frozen Goron aside the gravemaker in the mountain village. +static s32 sMsgScriptGoronFrozen[] = { 0x00150800, 0x7E01004D, 0x00150400, 0x180E0E1A, 0x0C170F0E, 0x230C180F, 0x0E240C0F, 0x0E250C12, 0x16111508, 0x100E0E1A, 0x0C170F0E, 0x230C180F, 0x0E240C0F, 0x0E250C17, 0x0F0E260C, 0x180F0E27, 0x0C170F0E, 0x280C180F, 0x0E290C17, 0x0F0E2A0C, 0x16111508, 0x100E0E1A, 0x0C170F0E, 0x1B0C180F, 0x0E1C0C0F, 0x0E1D0C0F, 0x0E1E0C17, @@ -45,19 +211,23 @@ static s32 D_80A16164[] = { 0x0E0E300C, 0x10010005, 0x0E0E2E0C, 0x100E0E2C, 0x0C100000, }; -static s32 D_80A16208[2] = { 0xE0E520C, 0x10000000 }; +// MsgEvent script for the shrine Goron standing aside the store. +static s32 sMsgScriptGoronAsideStore[] = { 0xE0E520C, 0x10000000 }; -static s32 D_80A16210[17] = { +// MsgEvent script for the shrine Goron standing aside the Elder's son. +static s32 sMsgScriptGoronAsideEldersSon[] = { 0x160400, 0x38010010, 0xE0E430C, 0xF0E440C, 0xF0E450C, 0x11188010, 0x160800, 0x1B0E0E46, 0xC0F0E47, 0xC0F0E48, 0xC0F0E49, 0xC0F0E4A, 0xC111608, 0x11188010, 0xE0E4B0C, 0x100E0E42, 0xC100000, }; -static s32 D_80A16254[11] = { +// MsgEvent script for the shrine Goron standing aside the Elder's room. +static s32 sMsgScriptGoronAsideEldersRoom[] = { 0x160400, 0x22010009, 0xE0E4D0C, 0xF0E4E0C, 0x10001701, 0xC0E0E, 0x4F0C0F0E, 0x500C1117, 0x1100E0E, 0x510C100E, 0xE4C0C10, }; -static s32 D_80A16280[52] = { +// MsgEvent script for the Goron in Goron Village who sells Powder Kegs. +static s32 sMsgScriptGoronMedigoron[] = { 0x1001200, 0x12200008, 0xE0C8E0C, 0x11122010, 0xE0C8F0C, 0x10001240, 0x1D0E0C, 0x800C1112, 0x40001280, 0x742500, 0xC006F00, 0x13010045, 0xF0C810C, 0x19001300, 0x1280005E, 0x25000C00, 0x59001301, 0x2F0E0C, 0x810C0F0C, 0x820C0500, 0x1A00, 0x1A300E0C, 0x830C1209, 0x700, 0xE0C84, 0x160C1113, 0x1100E0C, @@ -66,18 +236,30 @@ static s32 D_80A16280[52] = { 0x14FF9C12, 0x6003400, 0x130034, 0x700000E, 0xC870C16, 0x100E0C8B, 0xC100000, }; -static s32 D_80A16350[27] = { +// MsgEvent script for the gatekeeper Goron in Goron Village who opens the shrine gate. +static s32 sMsgScriptGoronGatekeeper[] = { 0x584000, 0x2903000E, 0x2001301, 0x180058, 0x80005119, 0x1E0059, 0x1004919, 0x160059, 0x2004119, 0xE0059, 0x4003919, 0x2F0E0D, 0x4D0C1210, 0xE0D480C, 0xF0D490C, 0xF0D4A0C, 0x5000000, 0xF000F30, 0xE0D4B0C, 0x15090000, 0xE0D4D0C, 0x1210310E, 0xD4C0C12, 0x100E0D4E, 0xC19FFD8, 0xE0D4F0C, 0x19FFD500, }; -static s32 D_80A163BC[4] = { 0x100060E, 0xDFE0C12, 0x100E0DFF, 0xC121000 }; -static s32 D_80A163CC[4] = { 0x100060E, 0xE000C12, 0x100E0E01, 0xC121000 }; -static s32 D_80A163DC[4] = { 0x100060E, 0xE020C12, 0x100E0E03, 0xC121000 }; -static s32 D_80A163EC[4] = { 0x100060E, 0xE040C12, 0x100E0E05, 0xC121000 }; -static s32 D_80A163FC[4] = { 0x100060E, 0xE060C12, 0x100E0E07, 0xC121000 }; -static s32 D_80A1640C[2] = { 0xE023A0C, 0x12100000 }; +// MsgEvent script for one of the Goron stretchers at the racetrack (Initially stretching side to side while squatting). +static s32 sMsgScriptGoronAthleticA[] = { 0x100060E, 0xDFE0C12, 0x100E0DFF, 0xC121000 }; + +// MsgEvent script for one of the Goron stretchers at the racetrack (Initially doing sidebend stretches with one arm). +static s32 sMsgScriptGoronAthleticB[] = { 0x100060E, 0xE000C12, 0x100E0E01, 0xC121000 }; + +// MsgEvent script for one of the Goron stretchers at the racetrack (Initially shaking out their limbs). +static s32 sMsgScriptGoronAthleticC[] = { 0x100060E, 0xE020C12, 0x100E0E03, 0xC121000 }; + +// MsgEvent script for one of the Goron stretchers (Initially doing sidebend stretches with both arms). +static s32 sMsgScriptGoronAthleticD[] = { 0x100060E, 0xE040C12, 0x100E0E05, 0xC121000 }; + +// MsgEvent script for the pair of Gorons stretching one Goron's hamstrings. +static s32 sMsgScriptGoronAthleticHamstring[] = { 0x100060E, 0xE060C12, 0x100E0E07, 0xC121000 }; + +// MsgEvent script for any sleeping Goron. +static s32 sMsgScriptGoronSleeping[] = { 0xE023A0C, 0x12100000 }; ActorInit En_Go_InitVars = { ACTOR_EN_GO, @@ -111,7 +293,8 @@ static ColliderSphereInit sSphereInit = { { 0, { { 0, 0, 0 }, 0 }, 100 }, }; -static ColliderCylinderInit sCylinderInit1 = { +// Collider for the frozen solid Gorons. +static ColliderCylinderInit sCylinderInitFrozen = { { COLTYPE_METAL, AT_ON | AT_TYPE_ENEMY, @@ -131,7 +314,8 @@ static ColliderCylinderInit sCylinderInit1 = { { 0, 0, 0, { 0, 0, 0 } }, }; -static ColliderCylinderInit sCylinderInit2 = { +// Collider for normal Gorons. +static ColliderCylinderInit sCylinderInit = { { COLTYPE_HIT1, AT_NONE, @@ -153,42 +337,55 @@ static ColliderCylinderInit sCylinderInit2 = { static CollisionCheckInfoInit2 sColChkInfoInit = { 0, 0, 0, 0, MASS_IMMOVABLE }; +typedef enum { + /* 0x0 */ ENGO_DMGEFF_NONE, + /* 0x2 */ ENGO_DMGEFF_FIRE = 0x2, + /* 0xF */ ENGO_DMGEFF_BREAK = 0xF +} EnGoDamageEffect; + static DamageTable sDamageTable = { - /* Deku Nut */ DMG_ENTRY(1, 0x0), - /* Deku Stick */ DMG_ENTRY(1, 0x0), - /* Horse trample */ DMG_ENTRY(1, 0x0), - /* Explosives */ DMG_ENTRY(1, 0x0), - /* Zora boomerang */ DMG_ENTRY(1, 0x0), - /* Normal arrow */ DMG_ENTRY(1, 0x0), - /* UNK_DMG_0x06 */ DMG_ENTRY(1, 0x0), - /* Hookshot */ DMG_ENTRY(1, 0x0), - /* Goron punch */ DMG_ENTRY(1, 0xF), - /* Sword */ DMG_ENTRY(1, 0x0), - /* Goron pound */ DMG_ENTRY(1, 0xF), - /* Fire arrow */ DMG_ENTRY(1, 0x2), - /* Ice arrow */ DMG_ENTRY(1, 0x0), - /* Light arrow */ DMG_ENTRY(1, 0x0), - /* Goron spikes */ DMG_ENTRY(1, 0xF), - /* Deku spin */ DMG_ENTRY(1, 0x0), - /* Deku bubble */ DMG_ENTRY(1, 0x0), - /* Deku launch */ DMG_ENTRY(1, 0x0), - /* UNK_DMG_0x12 */ DMG_ENTRY(1, 0x0), - /* Zora barrier */ DMG_ENTRY(1, 0x0), - /* Normal shield */ DMG_ENTRY(1, 0x0), - /* Light ray */ DMG_ENTRY(1, 0x0), - /* Thrown object */ DMG_ENTRY(1, 0x0), - /* Zora punch */ DMG_ENTRY(1, 0x0), - /* Spin attack */ DMG_ENTRY(1, 0x0), - /* Sword beam */ DMG_ENTRY(1, 0x0), - /* Normal Roll */ DMG_ENTRY(1, 0x0), - /* UNK_DMG_0x1B */ DMG_ENTRY(1, 0x0), - /* UNK_DMG_0x1C */ DMG_ENTRY(1, 0x0), - /* Unblockable */ DMG_ENTRY(1, 0x0), - /* UNK_DMG_0x1E */ DMG_ENTRY(1, 0x0), - /* Powder Keg */ DMG_ENTRY(1, 0x0), + /* Deku Nut */ DMG_ENTRY(1, ENGO_DMGEFF_NONE), + /* Deku Stick */ DMG_ENTRY(1, ENGO_DMGEFF_NONE), + /* Horse trample */ DMG_ENTRY(1, ENGO_DMGEFF_NONE), + /* Explosives */ DMG_ENTRY(1, ENGO_DMGEFF_NONE), + /* Zora boomerang */ DMG_ENTRY(1, ENGO_DMGEFF_NONE), + /* Normal arrow */ DMG_ENTRY(1, ENGO_DMGEFF_NONE), + /* UNK_DMG_0x06 */ DMG_ENTRY(1, ENGO_DMGEFF_NONE), + /* Hookshot */ DMG_ENTRY(1, ENGO_DMGEFF_NONE), + /* Goron punch */ DMG_ENTRY(1, ENGO_DMGEFF_BREAK), + /* Sword */ DMG_ENTRY(1, ENGO_DMGEFF_NONE), + /* Goron pound */ DMG_ENTRY(1, ENGO_DMGEFF_BREAK), + /* Fire arrow */ DMG_ENTRY(1, ENGO_DMGEFF_FIRE), + /* Ice arrow */ DMG_ENTRY(1, ENGO_DMGEFF_NONE), + /* Light arrow */ DMG_ENTRY(1, ENGO_DMGEFF_NONE), + /* Goron spikes */ DMG_ENTRY(1, ENGO_DMGEFF_BREAK), + /* Deku spin */ DMG_ENTRY(1, ENGO_DMGEFF_NONE), + /* Deku bubble */ DMG_ENTRY(1, ENGO_DMGEFF_NONE), + /* Deku launch */ DMG_ENTRY(1, ENGO_DMGEFF_NONE), + /* UNK_DMG_0x12 */ DMG_ENTRY(1, ENGO_DMGEFF_NONE), + /* Zora barrier */ DMG_ENTRY(1, ENGO_DMGEFF_NONE), + /* Normal shield */ DMG_ENTRY(1, ENGO_DMGEFF_NONE), + /* Light ray */ DMG_ENTRY(1, ENGO_DMGEFF_NONE), + /* Thrown object */ DMG_ENTRY(1, ENGO_DMGEFF_NONE), + /* Zora punch */ DMG_ENTRY(1, ENGO_DMGEFF_NONE), + /* Spin attack */ DMG_ENTRY(1, ENGO_DMGEFF_NONE), + /* Sword beam */ DMG_ENTRY(1, ENGO_DMGEFF_NONE), + /* Normal Roll */ DMG_ENTRY(1, ENGO_DMGEFF_NONE), + /* UNK_DMG_0x1B */ DMG_ENTRY(1, ENGO_DMGEFF_NONE), + /* UNK_DMG_0x1C */ DMG_ENTRY(1, ENGO_DMGEFF_NONE), + /* Unblockable */ DMG_ENTRY(1, ENGO_DMGEFF_NONE), + /* UNK_DMG_0x1E */ DMG_ENTRY(1, ENGO_DMGEFF_NONE), + /* Powder Keg */ DMG_ENTRY(1, ENGO_DMGEFF_NONE), }; +/** + * Animations used in the actor. + * + * @see EnGoAnimationIndex + */ static AnimationInfoS sAnimationInfo[] = { + + /* Animations for generic Goron actions */ { &gGoronLyingDownIdleAnim, 1.0f, 0, -1, ANIMMODE_LOOP, 0 }, { &gGoronLyingDownIdleAnim, 1.0f, 0, -1, ANIMMODE_LOOP, -4 }, { &gGoronUnrollAnim, 2.0f, 0, -1, ANIMMODE_ONCE, 0 }, @@ -200,366 +397,453 @@ static AnimationInfoS sAnimationInfo[] = { { &gGoronCoverEarsAnim, 1.0f, 0, -1, ANIMMODE_LOOP, 0 }, { &gGoronShiveringSurprisedAnim, 1.0f, 0, -1, ANIMMODE_ONCE, -4 }, - { &object_taisou_Anim_004DD4, 1.0f, 0, -1, ANIMMODE_LOOP, 0 }, - { &object_taisou_Anim_0016C8, 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_005EE0, 1.0f, 0, -1, ANIMMODE_LOOP, 0 }, - { &object_taisou_Anim_002C48, 1.0f, 0, -1, ANIMMODE_LOOP, 0 }, - { &object_taisou_Anim_0031D8, 1.0f, 0, -1, ANIMMODE_LOOP, 0 }, - { &object_taisou_Anim_005790, 1.0f, 0, -1, ANIMMODE_LOOP, 0 }, + /* Animations for stretching Gorons at the racetrack */ + { &gGoronAthleticsDoubleArmSideBendAnim, 1.0f, 0, -1, ANIMMODE_LOOP, 0 }, + { &gGoronAthleticsSquatSideToSideAnim, 1.0f, 0, -1, ANIMMODE_LOOP, 0 }, + { &gGoronAthleticsShakeLimbsAnim, 1.0f, 0, -1, ANIMMODE_LOOP, 0 }, + { &gGoronAthleticsSingleArmSideBendAnim, 1.0f, 0, -1, ANIMMODE_LOOP, 0 }, + { &gGoronAthleticsHamstringStretchSittingAnim, 1.0f, 0, -1, ANIMMODE_LOOP, 0 }, + { &gGoronAthleticsCheerAnim, 1.0f, 0, -1, ANIMMODE_LOOP, 0 }, + { &gGoronAthleticsShoutAnim, 1.0f, 0, -1, ANIMMODE_LOOP, 0 }, + { &gGoronAthleticsHamstringStretchStandingAnim, 1.0f, 0, -1, ANIMMODE_LOOP, 0 }, - { &object_hakugin_demo_Anim_001420, 1.0f, 0, -1, ANIMMODE_ONCE, 0 }, - { &object_hakugin_demo_Anim_001A4C, 1.0f, 0, -1, ANIMMODE_LOOP, -4 }, - { &object_hakugin_demo_Anim_002704, 1.0f, 0, -1, ANIMMODE_ONCE, 0 }, - { &object_hakugin_demo_Anim_003378, 1.0f, 0, -1, ANIMMODE_LOOP, -4 }, + /* Animations for the Goron during the spring arrival cutscene */ + { &gGoronSpringShowAnim, 1.0f, 0, -1, ANIMMODE_ONCE, 0 }, + { &gGoronSpringShowLoopAnim, 1.0f, 0, -1, ANIMMODE_LOOP, -4 }, + { &gGoronSpringLookAroundAnim, 1.0f, 0, -1, ANIMMODE_ONCE, 0 }, + { &gGoronSpringLookAroundLoopAnim, 1.0f, 0, -1, ANIMMODE_LOOP, -4 }, }; -EnGoStruct* func_80A10FD0(EnGoStruct* ptr, Vec3f arg1, Vec3f arg2, Vec3f arg3, f32 arg4, f32 arg5, s32 arg6) { +/** + * Initialize the latter section of the effects in 'effectTable' to be of type ENGO_EFFECT_STEAM. + * + * @param effect Latter section of the EnGoEffect table (&effectTable[ENGO_SNOW_EFFECT_COUNT]) + * @param pos Initial pos + * @param accel Initial acceleration + * @param velocity Initial velocity + * @param scale Initial scale + * @param deltaScale How much the effect scales per frame (additive) + * @param maxFrames Maximum number of frames the effect will last. Actual lifetime will be between 'maxFrames / 3' and + * 'maxFrames' + */ +EnGoEffect* EnGo_InitSteam(EnGoEffect effect[ENGO_OTHER_EFFECT_COUNT], Vec3f pos, Vec3f accel, Vec3f velocity, + f32 scale, f32 deltaScale, s32 maxFrames) { s32 i; - for (i = 16; i < 32; i++, ptr++) { - if (ptr->unk_00 == 0) { - ptr->unk_00 = 7; - ptr->unk_01 = (Rand_ZeroOne() * (2.0f * (arg6 / 3.0f))) + (arg6 / 3.0f); - ptr->unk_02 = ptr->unk_01; - ptr->unk_10 = arg1; - ptr->unk_1C = arg2; - ptr->unk_28 = arg3; - ptr->unk_34 = arg4; - ptr->unk_38 = arg5; - break; + // Steam effects are from the end of the snow effects to the end of all effects + for (i = ENGO_SNOW_EFFECT_COUNT; i < ENGO_EFFECT_COUNT; i++, effect++) { + if (effect->type != ENGO_EFFECT_NONE) { + continue; } - } - return ptr; + effect->type = ENGO_EFFECT_STEAM; + effect->alphaDenom = (Rand_ZeroOne() * (2.0f * (maxFrames / 3.0f))) + (maxFrames / 3.0f); + effect->alphaNumer = effect->alphaDenom; + effect->pos = pos; + effect->accel = accel; + effect->velocity = velocity; + effect->scaleXY = scale; + effect->scaleXYDelta = deltaScale; + break; + } + return effect; } -void func_80A11144(EnGoStruct* ptr, PlayState* play) { - s32 pad; +/** + * Draw all effects of type ENGO_EFFECT_STEAM. + * + * @param effect The EnGoEffect table + */ +void EnGo_DrawSteam(EnGoEffect effect[ENGO_EFFECT_COUNT], PlayState* play2) { + PlayState* play = play2; s32 i; - s32 flag = false; - f32 temp; + s32 isMaterialSet = false; + f32 alpha; OPEN_DISPS(play->state.gfxCtx); - Gfx_SetupDL25_Xlu(play->state.gfxCtx); - - for (i = 0; i < 32; i++, ptr++) { - - if (ptr->unk_00 == 7) { - gDPPipeSync(POLY_XLU_DISP++); - - if (!flag) { - gSPDisplayList(POLY_XLU_DISP++, gGoronSteamMaterialDL); - flag = true; - } - - Matrix_Push(); - - temp = ((f32)ptr->unk_02 / ptr->unk_01); - temp *= 255; - - gDPSetPrimColor(POLY_XLU_DISP++, 0, 0, 195, 225, 235, (u8)temp); - gSPSegment(POLY_XLU_DISP++, 0x08, - Gfx_TwoTexScroll(play->state.gfxCtx, 0, (ptr->unk_02 + (i * 3)) * 3, - (ptr->unk_02 + (i * 3)) * 15, 0x20, 0x40, 1, 0, 0, 0x20, 0x20)); - - Matrix_Translate(ptr->unk_10.x, ptr->unk_10.y, ptr->unk_10.z, MTXMODE_NEW); - Matrix_ReplaceRotation(&play->billboardMtxF); - Matrix_Scale(ptr->unk_34, ptr->unk_34, 1.0f, MTXMODE_APPLY); - - gSPMatrix(POLY_XLU_DISP++, Matrix_NewMtx(play->state.gfxCtx), G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW); - gSPDisplayList(POLY_XLU_DISP++, gGoronSteamModelDL); - - Matrix_Pop(); - if (play->state.gfxCtx) {} + for (i = 0; i < ENGO_EFFECT_COUNT; i++, effect++) { + if (effect->type != ENGO_EFFECT_STEAM) { + continue; } + + gDPPipeSync(POLY_XLU_DISP++); + if (!isMaterialSet) { + gSPDisplayList(POLY_XLU_DISP++, gGoronSteamMaterialDL); + isMaterialSet = true; + } + + Matrix_Push(); + + alpha = (f32)effect->alphaNumer / effect->alphaDenom; + alpha *= 255.0f; + gDPSetPrimColor(POLY_XLU_DISP++, 0, 0, 195, 225, 235, (u8)alpha); + gSPSegment(POLY_XLU_DISP++, 0x08, + Gfx_TwoTexScroll(play->state.gfxCtx, 0, (effect->alphaNumer + (i * 3)) * 3, + (effect->alphaNumer + (i * 3)) * 15, 0x20, 0x40, 1, 0, 0, 0x20, 0x20)); + + Matrix_Translate(effect->pos.x, effect->pos.y, effect->pos.z, MTXMODE_NEW); + Matrix_ReplaceRotation(&play->billboardMtxF); + Matrix_Scale(effect->scaleXY, effect->scaleXY, 1.0f, MTXMODE_APPLY); + + gSPMatrix(POLY_XLU_DISP++, Matrix_NewMtx(play->state.gfxCtx), G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW); + gSPDisplayList(POLY_XLU_DISP++, gGoronSteamModelDL); + + Matrix_Pop(); } CLOSE_DISPS(play->state.gfxCtx); } -void func_80A1143C(EnGoStruct* ptr, Vec3f arg1, Vec3f arg2, Vec3f arg3, f32 arg4, f32 arg5, s32 arg6, s32 arg7) { +/** + * Initialize the first available effect to be of type 'ENGO_EFFECT_DUST1'/'2'/'3'. + * + * @param effect Latter section of the EnGoEffect table (&effectTable[ENGO_SNOW_EFFECT_COUNT]) + * @param pos Initial pos + * @param accel Initial acceleration + * @param velocity Initial velocity + * @param scale Initial scale + * @param deltaScale How much the effect scales per frame (additive) + * @param maxFrames Maximum number of frames the effect will last. Actual lifetime will be 1/3 * maxFrames -> maxFrames + * @param parentEffectType Type of the parent effect, determines which of the possible dust effects correspond + */ +void EnGo_InitDust(EnGoEffect effect[ENGO_OTHER_EFFECT_COUNT], Vec3f pos, Vec3f accel, Vec3f vel, f32 scale, + f32 deltaScale, s32 maxFrames, EnGoEffectType parentEffectType) { s32 i; - for (i = 16; i < 32; i++, ptr++) { - if (ptr->unk_00 == 0) { - ptr->unk_00 = arg7 + 4; - - ptr->unk_01 = (Rand_ZeroOne() * (2.0f * (arg6 / 3.0f))) + (arg6 / 3.0f); - ptr->unk_02 = ptr->unk_01; - - ptr->unk_10 = arg1; - ptr->unk_1C = arg2; - ptr->unk_28 = arg3; - ptr->unk_34 = arg4; - ptr->unk_38 = arg5; - break; + // Dust effects are from the end of the snow effects to the end of all effects. + for (i = ENGO_SNOW_EFFECT_COUNT; i < ENGO_EFFECT_COUNT; i++, effect++) { + if (effect->type != ENGO_EFFECT_NONE) { + continue; } + + effect->type = parentEffectType + ENGO_EFFECT_DUST_MIN; + effect->alphaDenom = (Rand_ZeroOne() * (2.0f * (maxFrames / 3.0f))) + (maxFrames / 3.0f); + effect->alphaNumer = effect->alphaDenom; + effect->pos = pos; + effect->accel = accel; + effect->velocity = vel; + effect->scaleXY = scale; + effect->scaleXYDelta = deltaScale; + break; } } -void func_80A115B4(EnGoStruct* ptr, PlayState* play) { +/** + * Draw all effects of type 'ENGO_EFFECT_DUST1'/'2'/'3'. + * + * @param effect The EnGoEffect table + */ +void EnGo_DrawDust(EnGoEffect effect[ENGO_EFFECT_COUNT], PlayState* play2) { static TexturePtr sDustTextures[] = { gEffDust8Tex, gEffDust7Tex, gEffDust6Tex, gEffDust5Tex, gEffDust4Tex, gEffDust3Tex, gEffDust2Tex, gEffDust1Tex, }; - static Color_RGBA8 D_80A16664[] = { - { 255, 255, 255, 0 }, - { 170, 130, 90, 0 }, - { 0, 0, 0, 0 }, + static Color_RGBA8 sEnGoDustPrimColor[] = { + { 255, 255, 255, 0 }, // White + { 170, 130, 90, 0 }, // Light Brown + { 0, 0, 0, 0 }, // Black }; - static Color_RGBA8 D_80A16670[] = { - { 255, 255, 255, 0 }, - { 100, 60, 20, 0 }, - { 0, 0, 0, 0 }, + static Color_RGBA8 sEnGoDustEnvColor[] = { + { 255, 255, 255, 0 }, // White + { 100, 60, 20, 0 }, // Dark Brown + { 0, 0, 0, 0 }, // Black }; + PlayState* play = play2; s32 i; - u8 flag = false; - f32 temp; + u8 isMaterialSet = false; + f32 alpha; OPEN_DISPS(play->state.gfxCtx); - Gfx_SetupDL25_Xlu(play->state.gfxCtx); - - for (i = 0; i < 32; i++, ptr++) { - if ((ptr->unk_00 >= 4) && (ptr->unk_00 < 7)) { - if (!flag) { - POLY_XLU_DISP = Gfx_SetupDL(POLY_XLU_DISP, SETUPDL_0); - gSPDisplayList(POLY_XLU_DISP++, gGoronDustMaterialDL); - flag = true; - } - Matrix_Push(); - - temp = (f32)ptr->unk_02 / ptr->unk_01; - - gDPSetPrimColor(POLY_XLU_DISP++, 0, 0, D_80A16664[(s32)ptr->unk_00 - 4].r, - D_80A16664[(s32)ptr->unk_00 - 4].g, D_80A16664[(s32)ptr->unk_00 - 4].b, (u8)(temp * 255)); - gDPSetEnvColor(POLY_XLU_DISP++, D_80A16670[(s32)ptr->unk_00 - 4].r, D_80A16670[(s32)ptr->unk_00 - 4].g, - D_80A16670[(s32)ptr->unk_00 - 4].b, 0); - - Matrix_Translate(ptr->unk_10.x, ptr->unk_10.y, ptr->unk_10.z, MTXMODE_NEW); - Matrix_Scale(ptr->unk_34, ptr->unk_34, 1.0f, MTXMODE_APPLY); - Matrix_ReplaceRotation(&play->billboardMtxF); - - gSPMatrix(POLY_XLU_DISP++, Matrix_NewMtx(play->state.gfxCtx), G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW); - gSPSegment(POLY_XLU_DISP++, 0x08, Lib_SegmentedToVirtual(sDustTextures[(s32)(temp * 7.0f)])); - gSPDisplayList(POLY_XLU_DISP++, gGoronDustModelDL); - - Matrix_Pop(); + for (i = 0; i < ENGO_EFFECT_COUNT; i++, effect++) { + if ((effect->type < ENGO_EFFECT_DUST_MIN) || (effect->type >= ENGO_EFFECT_STEAM_MIN)) { + continue; } - if (play->state.gfxCtx) {} + + if (!isMaterialSet) { + POLY_XLU_DISP = Gfx_SetupDL(POLY_XLU_DISP, SETUPDL_0); + gSPDisplayList(POLY_XLU_DISP++, gGoronDustMaterialDL); + isMaterialSet = true; + } + + Matrix_Push(); + + alpha = (f32)effect->alphaNumer / effect->alphaDenom; + gDPSetPrimColor(POLY_XLU_DISP++, 0, 0, sEnGoDustPrimColor[(s32)effect->type - ENGO_EFFECT_DUST_MIN].r, + sEnGoDustPrimColor[(s32)effect->type - ENGO_EFFECT_DUST_MIN].g, + sEnGoDustPrimColor[(s32)effect->type - ENGO_EFFECT_DUST_MIN].b, (u8)(alpha * UINT8_MAX)); + gDPSetEnvColor(POLY_XLU_DISP++, sEnGoDustEnvColor[(s32)effect->type - ENGO_EFFECT_DUST_MIN].r, + sEnGoDustEnvColor[(s32)effect->type - ENGO_EFFECT_DUST_MIN].g, + sEnGoDustEnvColor[(s32)effect->type - ENGO_EFFECT_DUST_MIN].b, 0); + + Matrix_Translate(effect->pos.x, effect->pos.y, effect->pos.z, MTXMODE_NEW); + Matrix_Scale(effect->scaleXY, effect->scaleXY, 1.0f, MTXMODE_APPLY); + Matrix_ReplaceRotation(&play->billboardMtxF); + + gSPMatrix(POLY_XLU_DISP++, Matrix_NewMtx(play->state.gfxCtx), G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW); + gSPSegment(POLY_XLU_DISP++, 0x08, Lib_SegmentedToVirtual(sDustTextures[(s32)(alpha * 7.0f)])); + gSPDisplayList(POLY_XLU_DISP++, gGoronDustModelDL); + + Matrix_Pop(); } CLOSE_DISPS(play->state.gfxCtx); } -#ifdef NON_MATCHING -void func_80A118F8(EnGoStruct* ptr, Vec3f arg1) { - static u8 D_80A1667C[] = { - 3, 1, 1, 2, 3, 1, 1, 2, 3, 1, 1, 2, 3, 1, 1, 2, +/** + * Initialize the snowball break effects. + * + * Half of the elements will be 'ENGO_EFFECT_SNOW1'/'2'/'3' randomly generated around the character. The second half + * will be dedicated 'ENGO_EFFECT_DUST1'/'2'/'3' paired with the snow. + * + * @param effect The EnGoEffect table + * @param pos Position around which the effects appear + */ +void EnGo_InitSnow(EnGoEffect effect[ENGO_EFFECT_COUNT], Vec3f pos) { + static u8 effectIndexToSnowEffectTable[] = { + ENGO_EFFECT_SNOW3, ENGO_EFFECT_SNOW1, ENGO_EFFECT_SNOW1, ENGO_EFFECT_SNOW2, + ENGO_EFFECT_SNOW3, ENGO_EFFECT_SNOW1, ENGO_EFFECT_SNOW1, ENGO_EFFECT_SNOW2, + ENGO_EFFECT_SNOW3, ENGO_EFFECT_SNOW1, ENGO_EFFECT_SNOW1, ENGO_EFFECT_SNOW2, + ENGO_EFFECT_SNOW3, ENGO_EFFECT_SNOW1, ENGO_EFFECT_SNOW1, ENGO_EFFECT_SNOW2, }; - EnGoStruct* ptr2 = &ptr[16]; + + EnGoEffect* dustEffects = &effect[ENGO_SNOW_EFFECT_COUNT]; s32 i; - Vec3f spB4; - Vec3f spA8; - f32 temp_f20; + Vec3f randRelativeToWorldPos; + Vec3f randYOneToFour; + f32 velMagnitude; - for (i = 0; i < 16; i++, ptr++) { - if (ptr->unk_00 == 0) { - ptr->unk_10 = arg1; - ptr->unk_10.y += 56.0f; - - ptr->unk_04.x = (Rand_ZeroOne() - 0.5f) * 5460.0f; - ptr->unk_04.y = (Rand_ZeroOne() - 0.5f) * 5460.0f; - ptr->unk_04.z = (Rand_ZeroOne() - 0.5f) * 5460.0f; - - temp_f20 = (Rand_ZeroOne() * 4.0f) + 6.0f; - ptr->unk_28.x = Math_SinS(i * 0x1000) * temp_f20; - ptr->unk_28.z = Math_CosS(i * 0x1000) * temp_f20; - ptr->unk_28.y = (Rand_ZeroOne() * 3.0f) + 6.0f; - - ptr->unk_1C = gZeroVec3f; - ptr->unk_1C.y = -0.8f; - - ptr->unk_01 = ptr->unk_02 = 1; - ptr->unk_00 = D_80A1667C[i]; - - spB4.x = ((Rand_ZeroOne() - 0.5f) * 80.0f) + ptr->unk_10.x; - spB4.y = ((Rand_ZeroOne() - 0.5f) * 40.0f) + ptr->unk_10.y; - spB4.z = ((Rand_ZeroOne() - 0.5f) * 80.0f) + ptr->unk_10.z; - - spA8 = gZeroVec3f; - spA8.y = (Rand_ZeroOne() * 3.0f) + 1.0f; - - func_80A1143C(ptr2, spB4, gZeroVec3f, spA8, 0.6f, 0.2f, 16, 0); + // Snow effects consume the first part of the effects table, and are paired with dust effects in the latter part + for (i = 0; i < ENGO_SNOW_EFFECT_COUNT; i++, effect++) { + if (effect->type != ENGO_EFFECT_NONE) { + continue; } + + effect->pos = pos; + effect->pos.y += 56.0f; + + // Generate a +-15 degree rotational velocity + effect->rotVelocity.x = (Rand_ZeroOne() - 0.5f) * (f32)0x1554; + effect->rotVelocity.y = (Rand_ZeroOne() - 0.5f) * (f32)0x1554; + effect->rotVelocity.z = (Rand_ZeroOne() - 0.5f) * (f32)0x1554; + + // Generate a radially outward velocity for each of the effects + velMagnitude = (Rand_ZeroOne() * 4.0f) + 6.0f; + effect->velocity.x = Math_SinS(i * (0x10000 / ENGO_SNOW_EFFECT_COUNT)) * velMagnitude; + effect->velocity.z = Math_CosS(i * (0x10000 / ENGO_SNOW_EFFECT_COUNT)) * velMagnitude; + effect->velocity.y = (Rand_ZeroOne() * 3.0f) + 6.0f; + + // No acceleration on the X,Z axis, negative acceleration on the Y axis + effect->accel = gZeroVec3f; + effect->accel.y = -0.8f; + + // Full visibility (1/1) + effect->alphaDenom = effect->alphaNumer = 1; + + // Assign a snow effect value of 'ENGO_EFFECT_SNOW1'/'2'/'3' + effect->type = effectIndexToSnowEffectTable[i]; + + // Initialize the parameters for the paired element + randRelativeToWorldPos.x = ((Rand_ZeroOne() - 0.5f) * 80.0f) + effect->pos.x; + randRelativeToWorldPos.y = ((Rand_ZeroOne() - 0.5f) * 40.0f) + effect->pos.y; + randRelativeToWorldPos.z = ((Rand_ZeroOne() - 0.5f) * 80.0f) + effect->pos.z; + + randYOneToFour = gZeroVec3f; + randYOneToFour.y = (Rand_ZeroOne() * 3.0f) + 1.0f; + + // Initialize the paired element. + EnGo_InitDust(dustEffects, randRelativeToWorldPos, gZeroVec3f, randYOneToFour, 0.6f, 0.2f, + ENGO_DUST_STEAM_LIFETIME, 0); } } -#else -static u8 D_80A1667C[] = { - 3, 1, 1, 2, 3, 1, 1, 2, 3, 1, 1, 2, 3, 1, 1, 2, -}; -void func_80A118F8(EnGoStruct* ptr, Vec3f arg1); -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Go/func_80A118F8.s") -#endif -void func_80A11BF8(EnGoStruct* ptr, f32 arg1) { - f32 test; - f32 test2; +/** + * Update the snow effect's movement. + * + * When the snow drops to the ground, it is converted to dust. + * + * @param effect Pointer to the effect to update + * @param dustConversionHeight Height above the ground at which to convert the effect to dust + */ +void EnGo_UpdateSnow(EnGoEffect* effect, f32 dustConversionHeight) { f32 x; f32 z; - ptr->unk_10.x += ptr->unk_28.x; - ptr->unk_10.y += ptr->unk_28.y; - ptr->unk_10.z += ptr->unk_28.z; + effect->pos.x += effect->velocity.x; + effect->pos.y += effect->velocity.y; + effect->pos.z += effect->velocity.z; - ptr->unk_28.y += ptr->unk_1C.y; - ptr->unk_34 += ptr->unk_38; + effect->velocity.y += effect->accel.y; + effect->scaleXY += effect->scaleXYDelta; - if (ptr->unk_10.y < arg1) { - ptr->unk_10.y = arg1; + if (effect->pos.y < dustConversionHeight) { + effect->pos.y = dustConversionHeight; - ptr->unk_00 = 4; - ptr->unk_01 = (Rand_ZeroOne() * 8.0f) + 4.0f; - ptr->unk_02 = ptr->unk_01; + effect->type = ENGO_EFFECT_DUST1; + effect->alphaDenom = (Rand_ZeroOne() * 8.0f) + 4.0f; + effect->alphaNumer = effect->alphaDenom; - ptr->unk_28 = gZeroVec3f; - ptr->unk_28.y = (Rand_ZeroOne() * 3.0f) + 1.0f; + effect->velocity = gZeroVec3f; + effect->velocity.y = (Rand_ZeroOne() * 3.0f) + 1.0f; - ptr->unk_34 = 0.4f; - ptr->unk_38 = 0.1f; + effect->scaleXY = 0.4f; + effect->scaleXYDelta = 0.1f; return; } - if (ptr->unk_28.x != 0.0f) { - x = ptr->unk_28.x / fabsf(ptr->unk_28.x); - x *= ((sREG(13) + 140) * 0.01f); - Math_StepToF(&ptr->unk_28.x, x, (sREG(14) + 40) * 0.01f); + if (effect->velocity.x != 0.0f) { + x = effect->velocity.x / fabsf(effect->velocity.x); + x *= (sREG(13) + 140) * 0.01f; + Math_StepToF(&effect->velocity.x, x, (sREG(14) + 40) * 0.01f); } - if (ptr->unk_28.z != 0.0f) { - z = ptr->unk_28.z / fabsf(ptr->unk_28.z); + if (effect->velocity.z != 0.0f) { + z = effect->velocity.z / fabsf(effect->velocity.z); z *= ((sREG(13) + 140) * 0.01f); - Math_StepToF(&ptr->unk_28.z, z, (sREG(14) + 40) * 0.01f); + Math_StepToF(&effect->velocity.z, z, (sREG(14) + 40) * 0.01f); } - ptr->unk_0A.x += ptr->unk_04.x; - ptr->unk_0A.y += ptr->unk_04.y; - ptr->unk_0A.z += ptr->unk_04.z; + effect->rotAngle.x += effect->rotVelocity.x; + effect->rotAngle.y += effect->rotVelocity.y; + effect->rotAngle.z += effect->rotVelocity.z; } -#ifdef NON_MATCHING -void func_80A11EC0(EnGoStruct* ptr, PlayState* play, Gfx* arg2, Gfx* arg3, u8 arg4) { +/** + * Draw all effects of type 'ENGO_EFFECT_SNOW1'/'2'/'3'. + * + * @param effect The EnGoEffect table + * @param material Snow Material + * @param model Snow Model + * @param type Snow Effect type to draw + */ +void EnGo_DrawSnow(EnGoEffect effect[ENGO_SNOW_EFFECT_COUNT], PlayState* play, Gfx* material, Gfx* model, + u8 effectType) { s32 i; - u8 flag = false; + u8 isMaterialSet = false; OPEN_DISPS(play->state.gfxCtx); - Gfx_SetupDL25_Opa(play->state.gfxCtx); - - for (i = 0; i < 16; i++, ptr++) { - if (ptr->unk_00 == arg4) { - if (!flag) { - gSPDisplayList(POLY_OPA_DISP++, arg2); - flag = true; - } - - Matrix_Push(); - Matrix_Translate(ptr->unk_10.x, ptr->unk_10.y, ptr->unk_10.z, MTXMODE_NEW); - Matrix_Scale(0.08f, 0.08f, 0.08f, MTXMODE_APPLY); - Matrix_RotateZS(ptr->unk_0A.z, MTXMODE_APPLY); - Matrix_RotateXS(ptr->unk_0A.x, MTXMODE_APPLY); - Matrix_RotateYS(ptr->unk_0A.y, MTXMODE_APPLY); - - if (1) { - gSPMatrix(POLY_OPA_DISP++, Matrix_NewMtx(play->state.gfxCtx), - G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW); - gSPDisplayList(POLY_OPA_DISP++, arg3); - } - - Matrix_Pop(); + for (i = 0; i < ENGO_SNOW_EFFECT_COUNT; i++, effect++) { + if (effect->type != effectType) { + continue; } + + if (!isMaterialSet) { + gSPDisplayList(POLY_OPA_DISP++, material); + isMaterialSet = true; + } + + Matrix_Push(); + Matrix_Translate(effect->pos.x, effect->pos.y, effect->pos.z, MTXMODE_NEW); + Matrix_Scale(0.08f, 0.08f, 0.08f, MTXMODE_APPLY); + Matrix_RotateZS(effect->rotAngle.z, MTXMODE_APPLY); + Matrix_RotateXS(effect->rotAngle.x, MTXMODE_APPLY); + Matrix_RotateYS(effect->rotAngle.y, MTXMODE_APPLY); + + gSPMatrix(POLY_OPA_DISP++, Matrix_NewMtx(play->state.gfxCtx), G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW); + gSPDisplayList(POLY_OPA_DISP++, model); + + Matrix_Pop(); } CLOSE_DISPS(play->state.gfxCtx); } -#else -void func_80A11EC0(EnGoStruct* ptr, PlayState* play, Gfx* arg2, Gfx* arg3, u8 arg4); -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Go/func_80A11EC0.s") -#endif -void func_80A1203C(EnGo* this) { - EnGoStruct* ptr = this->unk_3F8; +/** + * Update all effects, potentially fading them away to nothing. + */ +void EnGo_UpdateEffects(EnGo* this) { + EnGoEffect* effect = this->effectTable; s32 i; - for (i = 0; i < ARRAY_COUNT(this->unk_3F8); i++, ptr++) { - if (ptr->unk_00 != 0) { - if (ptr->unk_02 == 0) { - ptr->unk_00 = 0; - } else if ((ptr->unk_00 > 0) && (ptr->unk_00 < 4)) { - func_80A11BF8(ptr, this->actor.world.pos.y); - } else { - ptr->unk_10.x += ptr->unk_28.x; - ptr->unk_10.y += ptr->unk_28.y; - ptr->unk_10.z += ptr->unk_28.z; + for (i = 0; i < ENGO_EFFECT_COUNT; i++, effect++) { + if (effect->type == ENGO_EFFECT_NONE) { + continue; + } - ptr->unk_28.x += ptr->unk_1C.x; - ptr->unk_28.y += ptr->unk_1C.y; - ptr->unk_28.z += ptr->unk_1C.z; + if (effect->alphaNumer == 0) { + // End usage of the effect + effect->type = ENGO_EFFECT_NONE; + } else if ((effect->type > ENGO_EFFECT_NONE) && (effect->type < ENGO_EFFECT_DUST_MIN)) { + // Snow rotates, and changes to dust upon dropping below the actor position + EnGo_UpdateSnow(effect, this->actor.world.pos.y); + } else { + // Dust and steam move according to their initial values + effect->pos.x += effect->velocity.x; + effect->pos.y += effect->velocity.y; + effect->pos.z += effect->velocity.z; - ptr->unk_34 += ptr->unk_38; - ptr->unk_02--; - } + effect->velocity.x += effect->accel.x; + effect->velocity.y += effect->accel.y; + effect->velocity.z += effect->accel.z; + + effect->scaleXY += effect->scaleXYDelta; + effect->alphaNumer--; } } } -void func_80A1213C(EnGo* this, PlayState* play) { - func_80A11EC0(this->unk_3F8, play, gGoronLargeSnowballFragmentMaterialDL, gGoronLargeSnowballFragmentModelDL, 1); - func_80A11EC0(this->unk_3F8, play, gGoronMediumSnowballFragmentMaterialDL, gGoronMediumSnowballFragmentModelDL, 2); - func_80A11EC0(this->unk_3F8, play, gGoronSmallSnowballFragmentMaterialDL, gGoronSmallSnowballFragmentModelDL, 3); - func_80A11144(this->unk_3F8, play); - func_80A115B4(this->unk_3F8, play); +/** + * Draw all effects. + */ +void EnGo_DrawEffects(EnGo* this, PlayState* play) { + EnGo_DrawSnow(this->effectTable, play, gGoronLargeSnowballFragmentMaterialDL, gGoronLargeSnowballFragmentModelDL, + ENGO_EFFECT_SNOW1); + EnGo_DrawSnow(this->effectTable, play, gGoronMediumSnowballFragmentMaterialDL, gGoronMediumSnowballFragmentModelDL, + ENGO_EFFECT_SNOW2); + EnGo_DrawSnow(this->effectTable, play, gGoronSmallSnowballFragmentMaterialDL, gGoronSmallSnowballFragmentModelDL, + ENGO_EFFECT_SNOW3); + EnGo_DrawSteam(this->effectTable, play); + EnGo_DrawDust(this->effectTable, play); } -s32 func_80A121F4(PlayState* play) { +/** + * Check if the Goron can hurt the player. + */ +s32 EnGo_CanSnowballHurtPlayer(PlayState* play) { Player* player = GET_PLAYER(play); if ((player->transformation == PLAYER_FORM_GORON) && (player->stateFlags3 & PLAYER_STATE3_2000000)) { return false; + } else { + return true; } - return true; } -s32 func_80A1222C(EnGo* this, PlayState* play) { +/** + * Check if the Goron is falling asleep. + */ +s32 EnGo_IsFallingAsleep(EnGo* this, PlayState* play) { Player* player = GET_PLAYER(play); - s32 ret = false; + s32 isFallingAsleep = false; if (((player->transformation == PLAYER_FORM_GORON) && (play->msgCtx.ocarinaMode == 3) && - (play->msgCtx.lastPlayedSong == OCARINA_SONG_GORON_LULLABY) && (this->unk_3EC == 0) && + (play->msgCtx.lastPlayedSong == OCARINA_SONG_GORON_LULLABY) && (this->sleepState == ENGO_AWAKE) && (this->actor.xzDistToPlayer < 400.0f)) || - (!CHECK_WEEKEVENTREG(WEEKEVENTREG_22_04) && (play->sceneId == SCENE_16GORON_HOUSE) && - (gSaveContext.sceneLayer == 0) && (this->unk_3EC == 0) && (play->csCtx.scriptIndex == 1))) { - ret = true; + (!CHECK_WEEKEVENTREG(WEEKEVENTREG_CALMED_GORON_ELDERS_SON) && (play->sceneId == SCENE_16GORON_HOUSE) && + (gSaveContext.sceneLayer == 0) && (this->sleepState == ENGO_AWAKE) && (play->csCtx.scriptIndex == 1))) { + isFallingAsleep = true; } - return ret; + return isFallingAsleep; } -s32 func_80A122EC(EnGo* this) { - static Vec3f D_80A1668C = { 0.0f, 100.0f, 160.0f }; +/** + * Update the actor's focus. + */ +s32 EnGo_UpdateFocus(EnGo* this) { + static Vec3f sMedigoronPos = { 0.0f, 100.0f, 160.0f }; s32 pad; - f32 sp20 = 58.0f; + f32 yAxisOffsetToFocusPoint = 58.0f; - if (ENGO_GET_F(&this->actor) == ENGO_F_8) { - Lib_Vec3f_TranslateAndRotateY(&this->actor.world.pos, this->actor.shape.rot.y, &D_80A1668C, + if (ENGO_GET_TYPE(&this->actor) == ENGO_MEDIGORON) { + Lib_Vec3f_TranslateAndRotateY(&this->actor.world.pos, this->actor.shape.rot.y, &sMedigoronPos, &this->actor.focus.pos); } else { - if ((this->unk_390 & 0x200) || (this->unk_390 & 0x100)) { - sp20 = this->actor.shape.yOffset; + if ((this->actionFlags & ENGO_FLAG_ROLLED_UP) || (this->actionFlags & ENGO_FLAG_SNOWBALLED)) { + yAxisOffsetToFocusPoint = this->actor.shape.yOffset; } Math_Vec3f_Copy(&this->actor.focus.pos, &this->actor.world.pos); - this->actor.focus.pos.y += sp20; + this->actor.focus.pos.y += yAxisOffsetToFocusPoint; } this->actor.focus.rot.x = this->actor.world.rot.x; @@ -568,21 +852,24 @@ s32 func_80A122EC(EnGo* this) { return false; } -void func_80A123A0(EnGo* this, PlayState* play) { - Vec3f sp2C; +/** + * Update the collider for the snowball form of the Goron Shrine gatekeeper. + */ +void EnGo_UpdateSnowballCollider(EnGo* this, PlayState* play) { + Vec3f worldPos; - Math_Vec3f_Copy(&sp2C, &this->actor.world.pos); + Math_Vec3f_Copy(&worldPos, &this->actor.world.pos); - this->colliderSphere.dim.worldSphere.center.x = sp2C.x; - this->colliderSphere.dim.worldSphere.center.y = sp2C.y; + this->colliderSphere.dim.worldSphere.center.x = worldPos.x; + this->colliderSphere.dim.worldSphere.center.y = worldPos.y; this->colliderSphere.dim.worldSphere.center.y += (s16)this->actor.shape.yOffset; - this->colliderSphere.dim.worldSphere.center.z = sp2C.z; + this->colliderSphere.dim.worldSphere.center.z = worldPos.z; this->colliderSphere.dim.modelSphere.radius = 48; this->colliderSphere.dim.worldSphere.radius = this->colliderSphere.dim.modelSphere.radius * this->colliderSphere.dim.scale; - if (func_80A121F4(play)) { + if (EnGo_CanSnowballHurtPlayer(play)) { CollisionCheck_SetAT(play, &play->colChkCtx, &this->colliderSphere.base); } @@ -590,175 +877,203 @@ void func_80A123A0(EnGo* this, PlayState* play) { CollisionCheck_SetOC(play, &play->colChkCtx, &this->colliderSphere.base); } -void func_80A124A0(EnGo* this, PlayState* play) { +/** + * Update the collider for the Medigoron in the Powder Keg Shop. + */ +void EnGo_UpdateMedigoronCollider(EnGo* this, PlayState* play) { this->colliderSphere.dim.worldSphere.radius = this->colliderSphere.dim.modelSphere.radius * this->colliderSphere.dim.scale; CollisionCheck_SetOC(play, &play->colChkCtx, &this->colliderSphere.base); } -void func_80A124FC(EnGo* this, PlayState* play) { - Vec3f sp1C; +/** + * Update the collider for the rolled up form of a Goron. + */ +void EnGo_UpdateRolledUpCollider(EnGo* this, PlayState* play) { + Vec3f worldPos; - Math_Vec3f_Copy(&sp1C, &this->actor.world.pos); - - this->colliderSphere.dim.worldSphere.center.x = sp1C.x; - this->colliderSphere.dim.worldSphere.center.y = sp1C.y; + Math_Vec3f_Copy(&worldPos, &this->actor.world.pos); + this->colliderSphere.dim.worldSphere.center.x = worldPos.x; + this->colliderSphere.dim.worldSphere.center.y = worldPos.y; this->colliderSphere.dim.worldSphere.center.y += (s16)this->actor.shape.yOffset; - this->colliderSphere.dim.worldSphere.center.z = sp1C.z; - + this->colliderSphere.dim.worldSphere.center.z = worldPos.z; this->colliderSphere.dim.modelSphere.radius = 20; this->colliderSphere.dim.worldSphere.radius = this->colliderSphere.dim.modelSphere.radius * this->colliderSphere.dim.scale; - CollisionCheck_SetOC(play, &play->colChkCtx, &this->colliderSphere.base); } -void func_80A125BC(EnGo* this, PlayState* play) { +/** + * Update the collider for the frozen form of a Goron. + */ +void EnGo_UpdateFrozenCollider(EnGo* this, PlayState* play) { s32 pad; Math_Vec3f_ToVec3s(&this->colliderCylinder.dim.pos, &this->actor.world.pos); - this->colliderCylinder.dim.radius = 46; this->colliderCylinder.dim.height = 78; - - if (this->unk_3C6 == 0) { + if (this->harmlessTimer == 0) { CollisionCheck_SetAT(play, &play->colChkCtx, &this->colliderCylinder.base); } CollisionCheck_SetAC(play, &play->colChkCtx, &this->colliderCylinder.base); CollisionCheck_SetOC(play, &play->colChkCtx, &this->colliderCylinder.base); } -void func_80A12660(EnGo* this, PlayState* play) { +/** + * Update the collider for all standing forms of a Goron. + */ +void EnGo_UpdateStandingCollider(EnGo* this, PlayState* play) { Math_Vec3f_ToVec3s(&this->colliderCylinder.dim.pos, &this->actor.world.pos); this->colliderCylinder.dim.radius = 24; this->colliderCylinder.dim.height = 62; CollisionCheck_SetOC(play, &play->colChkCtx, &this->colliderCylinder.base); } -void func_80A126BC(EnGo* this, PlayState* play) { +/** + * Update the collider for the Goron. + * + * Both the rolling snowball and frozen forms can hurt Player on collision, others do not. + */ +void EnGo_UpdateCollider(EnGo* this, PlayState* play) { Player* player = GET_PLAYER(play); if (!(player->stateFlags2 & PLAYER_STATE2_4000)) { - if (this->unk_3C6 != 0) { - this->unk_3C6--; - } + DECR(this->harmlessTimer); } - - if (ENGO_GET_F(&this->actor) == ENGO_F_8) { - func_80A124A0(this, play); - } else if (this->unk_390 & 0x100) { - func_80A123A0(this, play); - } else if (this->unk_390 & 0x200) { - func_80A124FC(this, play); - } else if (this->unk_390 & 0x400) { - func_80A125BC(this, play); + if (ENGO_GET_TYPE(&this->actor) == ENGO_MEDIGORON) { + EnGo_UpdateMedigoronCollider(this, play); + } else if (this->actionFlags & ENGO_FLAG_SNOWBALLED) { + EnGo_UpdateSnowballCollider(this, play); + } else if (this->actionFlags & ENGO_FLAG_ROLLED_UP) { + EnGo_UpdateRolledUpCollider(this, play); + } else if (this->actionFlags & ENGO_FLAG_FROZEN) { + EnGo_UpdateFrozenCollider(this, play); } else { - func_80A12660(this, play); + EnGo_UpdateStandingCollider(this, play); } } -s32 func_80A12774(EnGo* this, PlayState* play) { - if (!(this->unk_390 & 7) || !Actor_ProcessTalkRequest(&this->actor, &play->state)) { +/** + * Check if the actor is talking, and if so set the action function to handle it. + * + * @return True if talking + */ +s32 EnGo_UpdateTalking(EnGo* this, PlayState* play) { + if (!(this->actionFlags & 7) || !Actor_ProcessTalkRequest(&this->actor, &play->state)) { return false; } - if ((ENGO_GET_F(&this->actor) != ENGO_F_8) && (ENGO_GET_F(&this->actor) != ENGO_F_1)) { - if (!(this->unk_390 & 0x200)) { - this->unk_390 |= 8; + if ((ENGO_GET_TYPE(&this->actor) != ENGO_MEDIGORON) && (ENGO_GET_TYPE(&this->actor) != ENGO_ATHLETIC)) { + if (!(this->actionFlags & ENGO_FLAG_ROLLED_UP)) { + this->actionFlags |= ENGO_FLAG_ENGAGED; } } - if ((ENGO_GET_F(&this->actor) == ENGO_F_5) || (ENGO_GET_F(&this->actor) == ENGO_F_6) || - (ENGO_GET_F(&this->actor) == ENGO_F_7)) { - this->unk_3BC = 0; - this->unk_3BE = 0; - this->unk_390 |= 0x20; + if ((ENGO_GET_TYPE(&this->actor) == ENGO_ASIDE_STORE) || (ENGO_GET_TYPE(&this->actor) == ENGO_ASIDE_ELDERSROOM) || + (ENGO_GET_TYPE(&this->actor) == ENGO_ASIDE_ELDERSSON)) { + this->blinkTimer = 0; + this->eyeTexIndex = ENGO_EYETEX_OPEN; + this->actionFlags |= ENGO_FLAG_EYES_OPEN; } - SubS_UpdateFlags(&this->unk_390, 0, 7); - this->unk_3C0 = 0; - this->unk_3C4 = 0; - this->unk_18C = this->actionFunc; - this->actionFunc = func_80A157C4; + SubS_UpdateFlags(&this->actionFlags, 0, 7); + this->cutsceneState = 0; + this->gatekeeperAnimState = 0; + this->interruptedActionFunc = this->actionFunc; + this->actionFunc = EnGo_Talk; return true; } -s32 func_80A12868(EnGo* this, PlayState* play) { - this->unk_390 &= ~0x800; - this->unk_390 &= ~0x1000; - this->unk_390 &= ~0x2000; +/** + * Detect any collisions, and convert detections to object specific 'actionFlags'. + */ +s32 EnGo_DetectCollisions(EnGo* this, PlayState* play) { + this->actionFlags &= ~ENGO_FLAG_HIT_OTHER; + this->actionFlags &= ~ENGO_FLAG_HIT_BY_OTHER; + this->actionFlags &= ~ENGO_FLAG_HIT_OBJ; if ((this->colliderCylinder.base.atFlags & AT_HIT) || (this->colliderSphere.base.atFlags & AT_HIT)) { this->colliderCylinder.base.atFlags &= ~AT_HIT; this->colliderSphere.base.atFlags &= ~AT_HIT; - this->unk_390 |= 0x800; - this->unk_3C6 = 0x28; + this->actionFlags |= ENGO_FLAG_HIT_OTHER; + this->harmlessTimer = 40; } if ((this->colliderCylinder.base.acFlags & AC_HIT) || (this->colliderSphere.base.acFlags & AC_HIT)) { this->colliderCylinder.base.acFlags &= ~AC_HIT; this->colliderSphere.base.acFlags &= ~AC_HIT; - this->unk_390 |= 0x1000; + this->actionFlags |= ENGO_FLAG_HIT_BY_OTHER; } if ((this->colliderCylinder.base.ocFlags1 & OC1_HIT) || (this->colliderSphere.base.ocFlags1 & OC1_HIT)) { this->colliderCylinder.base.ocFlags1 &= ~OC1_HIT; this->colliderSphere.base.ocFlags1 &= ~OC1_HIT; - this->unk_390 |= 0x2000; + this->actionFlags |= ENGO_FLAG_HIT_OBJ; } return false; } -s32 func_80A12954(EnGo* this, PlayState* play) { - if ((ENGO_GET_F(&this->actor) == ENGO_F_4) && (play->csCtx.state != CS_STATE_IDLE) && (this->actor.draw != NULL) && - (play->sceneId == SCENE_10YUKIYAMANOMURA2) && (gSaveContext.sceneLayer == 1) && +/** + * Start, or finish, the cutscene for the arrival of springtime. + */ +s32 EnGo_UpdateSpringArrivalCutscene(EnGo* this, PlayState* play) { + if ((ENGO_GET_TYPE(&this->actor) == ENGO_GRAVEYARD) && (play->csCtx.state != CS_STATE_IDLE) && + (this->actor.draw != NULL) && (play->sceneId == SCENE_10YUKIYAMANOMURA2) && (gSaveContext.sceneLayer == 1) && (play->csCtx.scriptIndex == 0)) { - if (this->unk_3F0 == 0) { + if (this->springArrivalCutsceneActive == false) { this->actor.flags &= ~ACTOR_FLAG_1; - this->cueId = 255; - this->unk_3F0 = 1; - this->unk_18C = this->actionFunc; + this->springArrivalCueId = 255; + this->springArrivalCutsceneActive = true; + this->interruptedActionFunc = this->actionFunc; } - SubS_UpdateFlags(&this->unk_390, 0, 7); - this->actionFunc = func_80A14FC8; - } else if (this->unk_3F0 != 0) { + SubS_UpdateFlags(&this->actionFlags, 0, 7); + this->actionFunc = EnGo_HandleSpringArrivalCutscene; + } else if (this->springArrivalCutsceneActive) { this->actor.flags |= ACTOR_FLAG_1; - this->cueId = 255; - this->unk_3F0 = 0; - SubS_UpdateFlags(&this->unk_390, 3, 7); - this->actionFunc = this->unk_18C; + this->springArrivalCueId = 255; + this->springArrivalCutsceneActive = false; + SubS_UpdateFlags(&this->actionFlags, 3, 7); + this->actionFunc = this->interruptedActionFunc; } return false; } -s32 func_80A12A64(EnGo* this, PlayState* play) { - s8 objIdx = this->actor.objBankIndex; - s8 objIdx2 = -1; - s32 ret = 0; +/** + * Update the animation to the actor's currently set value. + * + * @return True if non-repeating animation has finished + */ +s32 EnGo_UpdateAnimationToCurrent(EnGo* this, PlayState* play) { + s8 objIndex = this->actor.objBankIndex; + s8 extraObjIndex = -1; + s32 ret = false; - if ((this->unk_3DC >= 18) && (this->unk_289 >= 0)) { - objIdx2 = this->unk_289; - } else if ((this->unk_3DC >= 10) && (this->unk_288 >= 0)) { - objIdx2 = this->unk_288; - } else if (this->unk_3DC < 10) { - objIdx2 = this->actor.objBankIndex; + if ((this->curAnimIndex >= ENGO_ANIM_SPRING_MIN) && (this->hakuginDemoObjIndex >= 0)) { + extraObjIndex = this->hakuginDemoObjIndex; + } else if ((this->curAnimIndex >= ENGO_ANIM_ATHLETICS_MIN) && (this->taisouObjIndex >= 0)) { + extraObjIndex = this->taisouObjIndex; + } else if (this->curAnimIndex < ENGO_ANIM_ATHLETICS_MIN) { + extraObjIndex = this->actor.objBankIndex; } - if (objIdx2 >= 0) { - gSegments[6] = VIRTUAL_TO_PHYSICAL(play->objectCtx.status[objIdx2].segment); - this->skelAnime.playSpeed = this->unk_398; + if (extraObjIndex >= 0) { + gSegments[6] = VIRTUAL_TO_PHYSICAL(play->objectCtx.status[extraObjIndex].segment); + this->skelAnime.playSpeed = this->curAnimPlaySpeed; ret = SkelAnime_Update(&this->skelAnime); - gSegments[6] = VIRTUAL_TO_PHYSICAL(play->objectCtx.status[objIdx].segment); + gSegments[6] = VIRTUAL_TO_PHYSICAL(play->objectCtx.status[objIndex].segment); } return ret; } -s32 func_80A12B78(EnGo* this, PlayState* play) { +/** + * Update sound effects based on animation. + */ +s32 EnGo_UpdateSfx(EnGo* this, PlayState* play) { if (play->csCtx.state == CS_STATE_IDLE) { - if (this->unk_3DC == 4) { + if (this->curAnimIndex == ENGO_ANIM_ROLL) { if (Animation_OnFrame(&this->skelAnime, 2.0f)) { Actor_PlaySfx(&this->actor, NA_SE_EN_GOLON_CIRCLE); } @@ -766,7 +1081,7 @@ s32 func_80A12B78(EnGo* this, PlayState* play) { if (Animation_OnFrame(&this->skelAnime, 22.0f)) { Actor_PlaySfx(&this->actor, NA_SE_EN_GOLON_SIT_IMT); } - } else if ((this->unk_3DC == 2) || (this->unk_3DC == 3)) { + } else if ((this->curAnimIndex == ENGO_ANIM_UNROLL) || (this->curAnimIndex == ENGO_ANIM_UNROLL_IMM)) { if (Animation_OnFrame(&this->skelAnime, 2.0f)) { Actor_PlaySfx(&this->actor, NA_SE_EN_GOLON_CIRCLE_OFF); } @@ -779,189 +1094,231 @@ s32 func_80A12B78(EnGo* this, PlayState* play) { return 0; } -s32 func_80A12C48(EnGo* this, PlayState* play, s32 arg2) { - s8 objIdx = this->actor.objBankIndex; - s8 objIdx2 = -1; +/** + * Change the Goron's animation. + * + * Goron animations come from one of three categories: + * - Basic Goron animations + * - Goron athletics like stretches, cheers, etc... + * - Spring arrival cutscene animations + * Changing animations with this function handles the transitions between the three categories. + * + * @return True if animation was changed + */ +s32 EnGo_ChangeAnim(EnGo* this, PlayState* play, EnGoAnimationIndex animIndex) { + s8 objIndex = this->actor.objBankIndex; + s8 extraObjIndex = -1; s32 ret = false; - if ((arg2 >= 18) && (this->unk_289 >= 0)) { - objIdx2 = this->unk_289; - } else if ((arg2 >= 10) && (this->unk_288 >= 0)) { - objIdx2 = this->unk_288; - } else if (arg2 < 10) { - objIdx2 = this->actor.objBankIndex; + if ((animIndex >= ENGO_ANIM_SPRING_MIN) && (this->hakuginDemoObjIndex >= 0)) { + extraObjIndex = this->hakuginDemoObjIndex; + } else if ((animIndex >= ENGO_ANIM_ATHLETICS_MIN) && (this->taisouObjIndex >= 0)) { + extraObjIndex = this->taisouObjIndex; + } else if (animIndex < ENGO_ANIM_ATHLETICS_MIN) { + extraObjIndex = this->actor.objBankIndex; } - if (objIdx2 >= 0) { - gSegments[6] = VIRTUAL_TO_PHYSICAL(play->objectCtx.status[objIdx2].segment); - this->unk_3DC = arg2; - ret = SubS_ChangeAnimationByInfoS(&this->skelAnime, sAnimationInfo, arg2); - this->unk_398 = this->skelAnime.playSpeed; - gSegments[6] = VIRTUAL_TO_PHYSICAL(play->objectCtx.status[objIdx].segment); + if (extraObjIndex >= 0) { + gSegments[6] = VIRTUAL_TO_PHYSICAL(play->objectCtx.status[extraObjIndex].segment); + this->curAnimIndex = animIndex; + ret = SubS_ChangeAnimationByInfoS(&this->skelAnime, sAnimationInfo, animIndex); + this->curAnimPlaySpeed = this->skelAnime.playSpeed; + gSegments[6] = VIRTUAL_TO_PHYSICAL(play->objectCtx.status[objIndex].segment); } return ret; } -void func_80A12D6C(EnGo* this) { - if ((this->unk_390 & 0x20) && (DECR(this->unk_3BC) == 0)) { - this->unk_3BE++; - if (this->unk_3BE >= 4) { - this->unk_3BC = Rand_S16Offset(30, 30); - this->unk_3BE = 0; +/** + * Update the eye textures to blink. + */ +void EnGo_UpdateEyes(EnGo* this) { + if (this->actionFlags & ENGO_FLAG_EYES_OPEN) { + if (DECR(this->blinkTimer) == 0) { + this->eyeTexIndex++; + if (this->eyeTexIndex >= ENGO_EYETEX_CLOSED2) { + this->blinkTimer = Rand_S16Offset(30, 30); + this->eyeTexIndex = ENGO_EYETEX_OPEN; + } } } } -void func_80A12DF4(EnGo* this, PlayState* play) { - if (this->unk_3D4 == 0) { - func_80A12C48(this, play, 9); - this->unk_3D4++; - } else if ((this->unk_3D4 == 1) && Animation_OnFrame(&this->skelAnime, this->skelAnime.endFrame)) { - func_80A12C48(this, play, 6); - this->unk_3D4++; +/** + * Play the surprise animation then return to shivering. + */ +void EnGo_UpdateShiverSurprisedAnimation(EnGo* this, PlayState* play) { + if (this->surprisePhase == 0) { + EnGo_ChangeAnim(this, play, ENGO_ANIM_SHIVERINGSURPRISED); + this->surprisePhase++; + } else if ((this->surprisePhase == 1) && Animation_OnFrame(&this->skelAnime, this->skelAnime.endFrame)) { + EnGo_ChangeAnim(this, play, ENGO_ANIM_SHIVER_IMM); + this->surprisePhase++; } } -s32 func_80A12E80(EnGo* this, PlayState* play) { - u16 temp = play->msgCtx.currentTextId; +/** + * Change the attention target, and dialog reactions of the Gorons outside Darmani's grave. + */ +s32 EnGo_UpdateGraveyardAttentionTargetAndReactions(EnGo* this, PlayState* play) { + u16 textId = play->msgCtx.currentTextId; Player* player = GET_PLAYER(play); - if (ENGO_GET_F(&this->actor) != ENGO_F_4) { + if (ENGO_GET_TYPE(&this->actor) != ENGO_GRAVEYARD) { return false; } if (player->stateFlags1 & PLAYER_STATE1_40) { - if (this->unk_392 != temp) { - switch (temp) { - case 0xE1A: - this->unk_390 |= 8; - this->unk_38C = this->actor.child; + if (this->lastTextId != textId) { + switch (textId) { + case 0xE1A: // Awakening from frozen form, confused, turn to other Goron + this->actionFlags |= ENGO_FLAG_ENGAGED; + this->attentionTarget = this->actor.child; break; - case 0xE1D: - case 0xE25: - if (ENGO_GET_70(&this->actor) == ENGO_70_1) { - this->unk_38C = &GET_PLAYER(play)->actor; + case 0xE1D: // Turn to player (Goron form) while stating Darmani is dead + case 0xE25: // Turn to player (Other form) while thanking player + if (ENGO_GET_SUBTYPE(&this->actor) == ENGO_GRAVEYARD_FROZEN) { + this->attentionTarget = &GET_PLAYER(play)->actor; } break; - case 0xE27: - if (ENGO_GET_70(&this->actor) == ENGO_70_1) { - this->unk_38C = this->actor.child; + case 0xE27: // (spoken) "What's this?..." + if (ENGO_GET_SUBTYPE(&this->actor) == ENGO_GRAVEYARD_FROZEN) { + this->attentionTarget = this->actor.child; } - case 0xE16: - case 0xE1E: - this->unk_190 = func_80A12DF4; + case 0xE16: // Surprised, questioning if player is Darmani + case 0xE1E: // Surprised, seeing Darmani + this->graveyardDialogActionFunc = EnGo_UpdateShiverSurprisedAnimation; break; - case 0xE1F: - if (ENGO_GET_70(&this->actor) == ENGO_70_0) { - this->unk_38C = &GET_PLAYER(play)->actor; + case 0xE1F: // Turn to player stating Darmani is not dead + if (ENGO_GET_SUBTYPE(&this->actor) == ENGO_GRAVEYARD_GRAVEMAKER) { + this->attentionTarget = &GET_PLAYER(play)->actor; } break; + + default: + break; } } - this->unk_3F4 = 1; - this->unk_392 = temp; - } else if (this->unk_3F4 != 0) { - this->unk_3F4 = 0; - this->unk_190 = NULL; - this->unk_392 = 0; - func_80A12C48(this, play, 5); - this->unk_390 &= ~8; + this->changedText = true; + this->lastTextId = textId; + } else if (this->changedText) { + // If the player isn't talking, and the text has changed, its the last text. + // Set everything back to the "Idle" behavior. + this->changedText = false; + this->graveyardDialogActionFunc = NULL; + this->lastTextId = 0; + EnGo_ChangeAnim(this, play, ENGO_ANIM_SHIVER); + this->actionFlags &= ~ENGO_FLAG_ENGAGED; } - if (this->unk_190 != NULL) { - this->unk_190(this, play); + if (this->graveyardDialogActionFunc != NULL) { + this->graveyardDialogActionFunc(this, play); } return false; } -s32 func_80A12FE8(EnGo* this, PlayState* play) { +/** + * Update the actor's rotation to point towards the target. + */ +s32 EnGo_UpdateRotationToTarget(EnGo* this, PlayState* play) { s32 pad; - Vec3f sp40; - Vec3f sp34; - s16 sp32; + Vec3f targetPos; + Vec3f thisPos; + s16 desiredYaw; - Math_Vec3f_Copy(&sp40, &this->unk_38C->world.pos); - Math_Vec3f_Copy(&sp34, &this->actor.world.pos); - sp32 = Math_Vec3f_Yaw(&sp34, &sp40); + Math_Vec3f_Copy(&targetPos, &this->attentionTarget->world.pos); + Math_Vec3f_Copy(&thisPos, &this->actor.world.pos); + desiredYaw = Math_Vec3f_Yaw(&thisPos, &targetPos); - Math_ApproachS(&this->unk_3B2, (sp32 - this->unk_3B6) - this->actor.shape.rot.y, 4, 0x2AA8); - this->unk_3B2 = CLAMP(this->unk_3B2, -0x1FFE, 0x1FFE); + Math_ApproachS(&this->headRotY, (desiredYaw - this->bodyRotY) - this->actor.shape.rot.y, 4, 0x2AA8); + this->headRotY = CLAMP(this->headRotY, -0x1FFE, 0x1FFE); - Math_ApproachS(&this->unk_3B6, (sp32 - this->unk_3B2) - this->actor.shape.rot.y, 4, 0x2AA8); - this->unk_3B6 = CLAMP(this->unk_3B6, -0x1C70, 0x1C70); + Math_ApproachS(&this->bodyRotY, (desiredYaw - this->headRotY) - this->actor.shape.rot.y, 4, 0x2AA8); + this->bodyRotY = CLAMP(this->bodyRotY, -0x1C70, 0x1C70); - Math_Vec3f_Copy(&sp34, &this->actor.focus.pos); - - if (this->unk_38C->id == ACTOR_PLAYER) { - sp40.y = ((Player*)this->unk_38C)->bodyPartsPos[7].y + 3.0f; + Math_Vec3f_Copy(&thisPos, &this->actor.focus.pos); + if (this->attentionTarget->id == ACTOR_PLAYER) { + targetPos.y = ((Player*)this->attentionTarget)->bodyPartsPos[7].y + 3.0f; } else { - Math_Vec3f_Copy(&sp40, &this->unk_38C->focus.pos); + Math_Vec3f_Copy(&targetPos, &this->attentionTarget->focus.pos); } - Math_ApproachS(&this->unk_3B0, Math_Vec3f_Pitch(&sp34, &sp40) - this->unk_3B4, 4, 0x2AA8); - this->unk_3B0 = CLAMP(this->unk_3B0, -0x1554, 0x1554); + Math_ApproachS(&this->headRotZ, Math_Vec3f_Pitch(&thisPos, &targetPos) - this->bodyRotZ, 4, 0x2AA8); + this->headRotZ = CLAMP(this->headRotZ, -0x1554, 0x1554); - Math_ApproachS(&this->unk_3B4, Math_Vec3f_Pitch(&sp34, &sp40) - this->unk_3B0, 4, 0x2AA8); - this->unk_3B4 = CLAMP(this->unk_3B4, -0xE38, 0xE38); + Math_ApproachS(&this->bodyRotZ, Math_Vec3f_Pitch(&thisPos, &targetPos) - this->headRotZ, 4, 0x2AA8); + this->bodyRotZ = CLAMP(this->bodyRotZ, -0xE38, 0xE38); return false; } -s32 func_80A131F8(EnGo* this, PlayState* play) { - if (this->unk_3F4 == 0) { - this->unk_38C = &GET_PLAYER(play)->actor; +/** + * Handle updating of Goron's attention target, and reactions during dialog. + */ +s32 EnGo_UpdateAttentionTargetAndReactions(EnGo* this, PlayState* play) { + if (!this->changedText) { + this->attentionTarget = &GET_PLAYER(play)->actor; } - func_80A12E80(this, play); + EnGo_UpdateGraveyardAttentionTargetAndReactions(this, play); - if (this->unk_390 & 8) { - this->unk_390 &= ~0x40; - this->unk_390 |= 0x10; - func_80A12FE8(this, play); - } else if (this->unk_390 & 0x10) { - this->unk_390 &= ~0x10; - this->unk_3B0 = 0; - this->unk_3B2 = 0; - this->unk_3B4 = 0; - this->unk_3B6 = 0; - this->unk_3BA = 0x14; - } else if (DECR(this->unk_3BA) == 0) { - this->unk_390 |= 0x40; - this->unk_3BA = 0x14; + if (this->actionFlags & ENGO_FLAG_ENGAGED) { + this->actionFlags &= ~ENGO_FLAG_LOST_ATTENTION; + this->actionFlags |= ENGO_FLAG_FACE_TARGET; + EnGo_UpdateRotationToTarget(this, play); + } else if (this->actionFlags & ENGO_FLAG_FACE_TARGET) { + this->actionFlags &= ~ENGO_FLAG_FACE_TARGET; + this->headRotZ = 0; + this->headRotY = 0; + this->bodyRotZ = 0; + this->bodyRotY = 0; + this->loseAttentionTimer = 20; + } else if (DECR(this->loseAttentionTimer) == 0) { + this->actionFlags |= ENGO_FLAG_LOST_ATTENTION; + this->loseAttentionTimer = 20; } return true; } -void func_80A132C8(EnGo* this, PlayState* play) { +/** + * Idle action function for the gravemaker at the Goron Graveyard. + */ +void EnGo_GravemakerIdle(EnGo* this, PlayState* play) { Player* player = GET_PLAYER(play); - s16 temp_v1 = BINANG_SUB(this->actor.yawTowardsPlayer, this->actor.shape.rot.y); + s16 deltaYaw = BINANG_SUB(this->actor.yawTowardsPlayer, this->actor.shape.rot.y); if ((fabsf(this->actor.playerHeightRel) > 20.0f) || (this->actor.xzDistToPlayer > 300.0f)) { - SubS_UpdateFlags(&this->unk_390, 3, 7); - } else if ((player->transformation != PLAYER_FORM_GORON) || (ABS_ALT(temp_v1) >= 0x1C70) || - CHECK_WEEKEVENTREG(WEEKEVENTREG_21_04) || CHECK_WEEKEVENTREG(WEEKEVENTREG_21_08)) { - SubS_UpdateFlags(&this->unk_390, 3, 7); + SubS_UpdateFlags(&this->actionFlags, 3, 7); + } else if ((player->transformation != PLAYER_FORM_GORON) || (ABS_ALT(deltaYaw) >= 0x1C70) || + CHECK_WEEKEVENTREG(WEEKEVENTREG_TALKED_GORON_GRAVEMAKER_AS_GORON) || + CHECK_WEEKEVENTREG(WEEKEVENTREG_TALKED_THAWED_GRAVEYARD_GORON)) { + SubS_UpdateFlags(&this->actionFlags, 3, 7); } else { - SubS_UpdateFlags(&this->unk_390, 4, 7); + SubS_UpdateFlags(&this->actionFlags, 4, 7); } } -void func_80A133A8(EnGo* this, PlayState* play) { - if (CHECK_WEEKEVENTREG(WEEKEVENTREG_21_08)) { - SubS_UpdateFlags(&this->unk_390, 3, 7); +/** + * Idle action function for the Goron frozen at the Goron Graveyard + */ +void EnGo_FrozenIdle(EnGo* this, PlayState* play) { + if (CHECK_WEEKEVENTREG(WEEKEVENTREG_TALKED_THAWED_GRAVEYARD_GORON)) { + SubS_UpdateFlags(&this->actionFlags, 3, 7); } else { - SubS_UpdateFlags(&this->unk_390, 4, 7); + SubS_UpdateFlags(&this->actionFlags, 4, 7); } } -Actor* func_80A13400(EnGo* this, PlayState* play) { +/** + * Obtain a pointer to the gravemaker at the Goron Graveyard. + */ +Actor* EnGo_FindGravemaker(EnGo* this, PlayState* play) { Actor* actor; Actor* retActor = NULL; @@ -969,8 +1326,8 @@ Actor* func_80A13400(EnGo* this, PlayState* play) { actor = SubS_FindActor(play, retActor, ACTORCAT_NPC, ACTOR_EN_GO); retActor = actor; - if ((actor != NULL) && ((EnGo*)actor != this) && (ENGO_GET_F(actor) == ENGO_F_4) && - (ENGO_GET_70(actor) == ENGO_70_0)) { + if ((actor != NULL) && ((EnGo*)actor != this) && (ENGO_GET_TYPE(actor) == ENGO_GRAVEYARD) && + (ENGO_GET_SUBTYPE(actor) == ENGO_GRAVEYARD_GRAVEMAKER)) { return retActor; } @@ -988,15 +1345,27 @@ Actor* func_80A13400(EnGo* this, PlayState* play) { return NULL; } -void func_80A134B0(EnGo* this, PlayState* play, s32 arg2) { - if (CHECK_WEEKEVENTREG(WEEKEVENTREG_18_80) || (play->actorCtx.flags & ACTORCTX_FLAG_0) || arg2) { +/** + * The Medigoron's collider radius is greater when it needs to be able to drop the Powder Keg in front of the player. + */ +void EnGo_UpdateMedigoronColliderRadius(EnGo* this, PlayState* play, s32 isGivenPowderKeg) { + if (CHECK_WEEKEVENTREG(WEEKEVENTREG_HAS_POWDERKEG_PRIVILEGES) || + (play->actorCtx.flags & ACTORCTX_FLAG_0) // Same check occurs in Powder Keg ammo check MsgScript Command + || isGivenPowderKeg) { this->colliderSphere.dim.modelSphere.radius = 300; } else { this->colliderSphere.dim.modelSphere.radius = 380; } } -s32 func_80A134F4(EnGo* this, s16 csId) { +/** + * Helper to change a cutscene. + * + * @returns Status of cutscene change + * @retval true Cutscene has started + * @retval false Cutscene is queued to start + */ +s32 EnGo_ChangeCutscene(EnGo* this, s16 csId) { if (CutsceneManager_GetCurrentCsId() == CS_ID_GLOBAL_TALK) { CutsceneManager_Stop(CS_ID_GLOBAL_TALK); } else if (CutsceneManager_IsNext(csId)) { @@ -1007,44 +1376,66 @@ s32 func_80A134F4(EnGo* this, s16 csId) { return false; } -s32 func_80A13564(EnGo* this, f32 arg1, f32 arg2, s32 arg3) { +/** + * Handle the animation of the "Goron Pound". + * + * There are Several Phases to the pound: + * - Phase 1: (Once in Rolled-Up form) the pound starts by leaping into the air. + * - The Goron rotates until its back faces the ground at its peak. + * - The Goron distorts shape until at its peak. + * - Transition: At the peak, all movement is halted. + * - Phase 2: While hanging, the Goron reverts back to normal shape. + * - Transition: At reaching maxHangTime, ENGO_POUND_INITIAL_FALL_VEL is applied. + * - Phase 3: The Goron falls to the ground. + * - Transition: At reaching the ground. + * + * @param initialVelocity Initial +Y velocity of the pound. + * @param maxDistortion Maximum distortion of the Goron's shape. + * @param maxHangtime Maximum hangtime at the peak of the pound. + * @returns True when pound finishes. + */ +s32 EnGo_HandleGatekeeperPoundCutscene(EnGo* this, f32 initialVelocity, f32 maxDistortion, s32 maxHangtime) { s32 pad; - f32 temp_f0 = 1.0f; - f32 temp_f14 = this->actor.velocity.y + this->actor.gravity; - s32 ret; + f32 rotAndDistortFactor = 1.0f; + f32 velocity = this->actor.velocity.y + this->actor.gravity; + s32 isFinished; if (this->actor.bgCheckFlags & BGCHECKFLAG_GROUND_TOUCH) { - ret = true; + // Transition 3->DONE + isFinished = true; } else { - if (temp_f14 > 0.0f) { - temp_f0 = temp_f14 / arg1; - this->actor.shape.rot.x += (s16)(9100.0f * temp_f0); - this->unk_3AE = 0; + if (velocity > 0.0f) { + // PHASE 1: Goron is rising + rotAndDistortFactor = velocity / initialVelocity; + this->actor.shape.rot.x += (s16)(0x238C * rotAndDistortFactor); + this->elapsedHangtime = 0; } else if ((s32)this->actor.velocity.y == 0) { - if (arg3 >= this->unk_3AE) { - temp_f0 = (f32)this->unk_3AE / arg3; + if (maxHangtime >= this->elapsedHangtime) { + // PHASE 2: Goron is hanging in the air + rotAndDistortFactor = (f32)this->elapsedHangtime / maxHangtime; } else { - this->actor.gravity = -6.0f; + // Transition 2->3: Hanging is complete + this->actor.gravity = ENGO_POUND_INITIAL_FALL_VEL; } - this->unk_3AE++; - } else if (this->unk_3AE == 0) { + this->elapsedHangtime++; + } else if (this->elapsedHangtime == 0) { + // Transition 1->2: Goron has reached the peak this->actor.velocity.y = 0.0f; this->actor.gravity = 0.0f; - temp_f0 = temp_f14 / arg1; + rotAndDistortFactor = velocity / initialVelocity; + } else { + // PHASE 3: Goron is falling (Just letting gravity take effect) } - ret = false; + isFinished = false; } - this->unk_3A8 = (1.0f - temp_f0) * arg2; - this->actor.scale.x = this->unk_3A4 - this->unk_3A8; - this->actor.scale.y = this->unk_3A4 + this->unk_3A8; + // Handle shape distortions + this->scaleFactorPoundDistortion = (1.0f - rotAndDistortFactor) * maxDistortion; + this->actor.scale.x = this->scaleFactor - this->scaleFactorPoundDistortion; + this->actor.scale.y = this->scaleFactor + this->scaleFactorPoundDistortion; + this->actor.scale.z = MAX(this->actor.scale.x, this->actor.scale.y); - if (this->actor.scale.y < this->actor.scale.x) { - this->actor.scale.z = this->actor.scale.x; - } else { - this->actor.scale.z = this->actor.scale.y; - } - return ret; + return isFinished; } void EnGo_RequestQuake(PlayState* play, s16 speed, s16 y, s16 duration) { @@ -1055,7 +1446,10 @@ void EnGo_RequestQuake(PlayState* play, s16 speed, s16 y, s16 duration) { Quake_SetPerturbations(quakeIndex, y, 0, 0, 0); } -void func_80A13728(EnGo* this, PlayState* play) { +/** + * Create the visual effects caused by the gatekeeper's pound. + */ +void EnGo_CreateGatekeeperPoundEffects(EnGo* this, PlayState* play) { EnGo_RequestQuake(play, 27767, 7, 20); play->actorCtx.unk2 = 4; Actor_Spawn(&play->actorCtx, play, ACTOR_EN_TEST, this->actor.world.pos.x, this->actor.world.pos.y, @@ -1063,11 +1457,14 @@ void func_80A13728(EnGo* this, PlayState* play) { EffectSsBlast_SpawnWhiteShockwave(play, &this->actor.world.pos, &gZeroVec3f, &gZeroVec3f); } -void func_80A137C0(EnGo* this, PlayState* play, f32 arg2, f32 arg3) { - u32 frames1; - u32 frames2; +/** + * Draw the ice encasing a frozen Goron. + */ +void EnGo_DrawIceBlockWhenFrozen(EnGo* this, PlayState* play, f32 scale, f32 alpha) { + u32 y1; + u32 y2; - if (this->unk_390 & 0x400) { + if (this->actionFlags & ENGO_FLAG_FROZEN) { Matrix_Push(); OPEN_DISPS(play->state.gfxCtx); @@ -1075,15 +1472,15 @@ void func_80A137C0(EnGo* this, PlayState* play, f32 arg2, f32 arg3) { Gfx_SetupDL25_Xlu(play->state.gfxCtx); Matrix_Translate(this->actor.world.pos.x, this->actor.world.pos.y, this->actor.world.pos.z, MTXMODE_NEW); - Matrix_Scale(arg2 * 0.7f, arg2 * 0.8f, arg2, MTXMODE_APPLY); + Matrix_Scale(scale * 0.7f, scale * 0.8f, scale, MTXMODE_APPLY); func_800B8118(&this->actor, play, 0); gSPMatrix(POLY_XLU_DISP++, Matrix_NewMtx(play->state.gfxCtx), G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW); - frames1 = play->gameplayFrames % 256; - frames2 = (play->gameplayFrames * 2) % 256; + y1 = play->gameplayFrames % 256; + y2 = (play->gameplayFrames * 2) % 256; gSPSegment(POLY_XLU_DISP++, 0x08, - Gfx_TwoTexScroll(play->state.gfxCtx, 0, 0, frames1, 0x20, 0x10, 1, 0, frames2, 0x40, 0x20)); - gDPSetEnvColor(POLY_XLU_DISP++, 0, 50, 100, (u8)arg3); + Gfx_TwoTexScroll(play->state.gfxCtx, 0, 0, y1, 0x20, 0x10, 1, 0, y2, 0x40, 0x20)); + gDPSetEnvColor(POLY_XLU_DISP++, 0, 50, 100, (u8)alpha); gSPDisplayList(POLY_XLU_DISP++, gEffIceFragment3DL); CLOSE_DISPS(play->state.gfxCtx); @@ -1092,154 +1489,172 @@ void func_80A137C0(EnGo* this, PlayState* play, f32 arg2, f32 arg3) { } } -void func_80A139E4(EnGo* this) { - static Vec3f D_80A16698 = { 0.0f, 0.06f, 0.0f }; - Vec3f sp54; - Vec3f sp48; - s16 sp46 = Rand_ZeroOne() * 360.0f * 182.0f; +/** + * Initialize the steam effect used for melting ice. + */ +void EnGo_MakeSteam(EnGo* this) { + static Vec3f sAccel = { 0.0f, 0.06f, 0.0f }; + Vec3f tempPos; + Vec3f effectPos; + s16 rotAngle = Rand_ZeroOne() * 360.0f * 182.0f; - Math_Vec3f_Copy(&sp54, &gZeroVec3f); - sp54.z = 28.0f; - Lib_Vec3f_TranslateAndRotateY(&this->actor.world.pos, sp46, &sp54, &sp48); - sp48.y = (Rand_ZeroOne() * 10.0f) + 4.0f; - sp48.y += this->actor.floorHeight; - func_80A10FD0(&this->unk_3F8[16], sp48, D_80A16698, gZeroVec3f, 0.01f, 0.002f, 16); + Math_Vec3f_Copy(&tempPos, &gZeroVec3f); + tempPos.z = 28.0f; + Lib_Vec3f_TranslateAndRotateY(&this->actor.world.pos, rotAngle, &tempPos, &effectPos); + effectPos.y = (Rand_ZeroOne() * 10.0f) + 4.0f; + effectPos.y += this->actor.floorHeight; + EnGo_InitSteam(&this->effectTable[ENGO_SNOW_EFFECT_COUNT], effectPos, sAccel, gZeroVec3f, ENGO_NORMAL_SCALE, + (0.2f * ENGO_NORMAL_SCALE), ENGO_DUST_STEAM_LIFETIME); } -s32 func_80A13B1C(EnGo* this, PlayState* play) { +/** + * Transition through the cutscenes when the gatekeeper is opening the shrine. + * + * @return True when cutscenes end. + */ +s32 EnGo_HandleOpenShrineCutscene(Actor* thisx, PlayState* play) { Player* player = GET_PLAYER(play); - s32 pad; + EnGo* this = THIS; s32 ret = false; - switch (this->unk_3C0) { + switch (this->cutsceneState) { case 0: this->csId = CutsceneManager_GetAdditionalCsId(this->actor.csId); - if (func_80A134F4(this, this->csId)) { - this->unk_3C4 = 1; - this->unk_3C0 = 1; - } else { + if (!EnGo_ChangeCutscene(this, this->csId)) { break; } - + this->gatekeeperAnimState = 1; + this->cutsceneState = 1; + // fallthrough case 1: - if (CutsceneManager_GetCurrentCsId() != this->csId) { - this->csId = CutsceneManager_GetAdditionalCsId(this->csId); - this->unk_3C0 = 2; - } else { + if (CutsceneManager_GetCurrentCsId() == this->csId) { break; } - + this->csId = CutsceneManager_GetAdditionalCsId(this->csId); + this->cutsceneState = 2; + // fallthrough case 2: - if (func_80A134F4(this, this->csId)) { - this->unk_3C0 = 3; - } else { + if (!EnGo_ChangeCutscene(this, this->csId)) { break; } - + this->cutsceneState = 3; + // fallthrough case 3: if (CutsceneManager_IsNext(CS_ID_GLOBAL_TALK)) { CutsceneManager_StartWithPlayerCs(CS_ID_GLOBAL_TALK, NULL); - this->unk_3C0 = 4; + this->cutsceneState = 4; } else if (CutsceneManager_GetCurrentCsId() == this->csId) { CutsceneManager_Queue(CS_ID_GLOBAL_TALK); } + // fallthrough + default: + break; } - switch (this->unk_3C4) { + switch (this->gatekeeperAnimState) { case 1: - func_80A12C48(this, play, 4); - this->unk_390 |= 0x4000; - this->unk_3C4++; + EnGo_ChangeAnim(this, play, ENGO_ANIM_ROLL); + this->actionFlags |= ENGO_FLAG_ROLLING_UP; + this->gatekeeperAnimState++; break; case 2: if (Animation_OnFrame(&this->skelAnime, this->skelAnime.endFrame)) { - this->unk_390 &= ~0x4000; - this->unk_390 &= ~0x80; - this->unk_390 |= 0x200; - this->unk_3C4++; - this->unk_3C2 = 0; - this->actor.shape.yOffset = 14.0f; + this->actionFlags &= ~ENGO_FLAG_ROLLING_UP; + this->actionFlags &= ~ENGO_FLAG_STANDING; + this->actionFlags |= ENGO_FLAG_ROLLED_UP; + this->gatekeeperAnimState++; + this->cutsceneDelayTimer = 0; + this->actor.shape.yOffset = ENGO_ROLLEDUP_Y_OFFSET; } break; case 3: - this->unk_3C2++; - if (this->unk_3C2 >= 10) { + this->cutsceneDelayTimer++; + if (this->cutsceneDelayTimer >= 10) { Actor_PlaySfx(&this->actor, NA_SE_EN_GOLON_JUMP); - this->actor.velocity.y = 10.0f; + this->actor.velocity.y = ENGO_POUND_INITIAL_RISE_VEL; this->actor.gravity = -1.0f; - this->unk_3C4++; + this->gatekeeperAnimState++; } break; case 4: - if (func_80A13564(this, 10.0f, 0.004f, 6)) { + if (EnGo_HandleGatekeeperPoundCutscene(this, ENGO_POUND_INITIAL_RISE_VEL, (0.4f) * ENGO_NORMAL_SCALE, 6)) { Actor_PlaySfx(&this->actor, NA_SE_EN_GOLON_LAND_BIG); - func_80A13728(this, play); - this->unk_3C4++; - this->unk_3C2 = 0; - SET_WEEKEVENTREG(WEEKEVENTREG_88_40); + EnGo_CreateGatekeeperPoundEffects(this, play); + this->gatekeeperAnimState++; + this->cutsceneDelayTimer = 0; + SET_WEEKEVENTREG(WEEKEVENTREG_GATEKEEPER_OPENED_GORON_SHRINE); } break; case 5: - this->unk_3C2++; - if (this->unk_3C2 >= 10) { - func_80A12C48(this, play, 5); + this->cutsceneDelayTimer++; + if (this->cutsceneDelayTimer >= 10) { + EnGo_ChangeAnim(this, play, ENGO_ANIM_SHIVER); this->actor.shape.rot.x = 0; - this->unk_390 &= ~0x200; - this->unk_390 |= 0x80; - this->unk_3C4++; + this->actionFlags &= ~ENGO_FLAG_ROLLED_UP; + this->actionFlags |= ENGO_FLAG_STANDING; + this->gatekeeperAnimState++; } break; case 6: - this->unk_3C0++; - if (this->unk_3C0 >= 65) { + this->cutsceneState++; + if (this->cutsceneState >= 65) { switch (player->transformation) { case PLAYER_FORM_HUMAN: - SET_WEEKEVENTREG(WEEKEVENTREG_88_80); + SET_WEEKEVENTREG(WEEKEVENTREG_GATEKEEPER_OPENED_GORON_SHRINE_FOR_HUMAN); break; case PLAYER_FORM_GORON: - SET_WEEKEVENTREG(WEEKEVENTREG_89_04); + SET_WEEKEVENTREG(WEEKEVENTREG_GATEKEEPER_OPENED_GORON_SHRINE_FOR_GORON); break; case PLAYER_FORM_ZORA: - SET_WEEKEVENTREG(WEEKEVENTREG_89_02); + SET_WEEKEVENTREG(WEEKEVENTREG_GATEKEEPER_OPENED_GORON_SHRINE_FOR_ZORA); break; case PLAYER_FORM_DEKU: - SET_WEEKEVENTREG(WEEKEVENTREG_89_01); + SET_WEEKEVENTREG(WEEKEVENTREG_GATEKEEPER_OPENED_GORON_SHRINE_FOR_DEKU); + break; + + default: break; } ret = true; } break; + + default: + break; } Actor_MoveWithGravity(&this->actor); return ret; } -s32 func_80A13E80(EnGo* this, PlayState* play) { - static Vec3f D_80A166A4 = { 0.0f, 200.0f, 280.0f }; - s32 pad; - Vec3f sp48; +/** + * Medigoron's MsgEvent callback to give the Powder Keg for the test. + */ +s32 EnGo_HandleGivePowderKegCutscene(Actor* thisx, PlayState* play) { + static Vec3f sPowderKegSpawnOffset = { 0.0f, 200.0f, 280.0f }; + EnGo* this = THIS; + Vec3f powderKegSpawnPos; s32 ret = false; - switch (this->unk_3C0) { + switch (this->cutsceneState) { case 0: this->csId = this->actor.csId; - if (func_80A134F4(this, this->csId)) { - this->unk_3C0++; + if (EnGo_ChangeCutscene(this, this->csId)) { + this->cutsceneState++; } break; case 1: - func_80A12C48(this, play, 7); - this->unk_3C0++; + EnGo_ChangeAnim(this, play, ENGO_ANIM_DROPKEG); + this->cutsceneState++; case 2: if (Animation_OnFrame(&this->skelAnime, 16.0f)) { @@ -1247,263 +1662,348 @@ s32 func_80A13E80(EnGo* this, PlayState* play) { } if (Animation_OnFrame(&this->skelAnime, this->skelAnime.endFrame)) { - func_80A12C48(this, play, 1); - Lib_Vec3f_TranslateAndRotateY(&this->actor.world.pos, this->actor.shape.rot.y, &D_80A166A4, &sp48); + EnGo_ChangeAnim(this, play, ENGO_ANIM_LYINGDOWNIDLE_IMM); + Lib_Vec3f_TranslateAndRotateY(&this->actor.world.pos, this->actor.shape.rot.y, &sPowderKegSpawnOffset, + &powderKegSpawnPos); gSaveContext.powderKegTimer = 2400; - Actor_Spawn(&play->actorCtx, play, ACTOR_EN_BOM, sp48.x, sp48.y, sp48.z, BOMB_EXPLOSIVE_TYPE_POWDER_KEG, - 0, 0, BOMB_TYPE_BODY); - func_80A134B0(this, play, 1); - this->unk_3C2 = 0; - this->unk_3C0++; + Actor_Spawn(&play->actorCtx, play, ACTOR_EN_BOM, powderKegSpawnPos.x, powderKegSpawnPos.y, + powderKegSpawnPos.z, BOMB_EXPLOSIVE_TYPE_POWDER_KEG, 0, 0, BOMB_TYPE_BODY); + EnGo_UpdateMedigoronColliderRadius(this, play, true); + this->cutsceneDelayTimer = 0; + this->cutsceneState++; } break; case 3: - if (this->unk_3C2 >= 60) { + if (this->cutsceneDelayTimer >= 60) { CutsceneManager_Stop(this->csId); - this->unk_3C2 = 0; - this->unk_3C0 = 0; + this->cutsceneDelayTimer = 0; + this->cutsceneState = 0; ret = true; } else { - this->unk_3C2++; + this->cutsceneDelayTimer++; } break; + + default: + break; } return ret; } -void func_80A14018(EnGo* this, PlayState* play) { - static Vec3f D_80A166B0 = { 0.0f, 0.0f, 40.0f }; - static s32 D_80A166BC[] = { 11, 10, 12, 13, 14, 17 }; - Vec3f sp2C; - s32 phi_v0 = ENGO_GET_70(&this->actor) % 6; +/** + * Update the stretching racer's animation and actionFlags. + * + * 'ENGO_ATHLETIC_A' through 'ENGO_ATHLETIC_D' exchange animations before and after the race, while the hamstring + * stretchers have the same animation every time. + * + * @see EnGo_Idle + */ +void EnGo_ChangeToStretchingAnimation(EnGo* this, PlayState* play) { + static Vec3f sStretchingGoronOffset = { 0.0f, 0.0f, 40.0f }; + static s32 sSubtypeToAnimIndex[] = { + ENGO_ANIM_SQUAT_SIDE_TO_SIDE, ENGO_ANIM_DOUBLE_ARM_SIDEBEND, ENGO_ANIM_SHAKE_LIMBS, + ENGO_ANIM_SINGLE_ARM_SIDEBEND, ENGO_ANIM_SITTING_STRETCH, ENGO_ANIM_HELP_SITTING_STRETCH, + }; + Vec3f newSittingStretcherPos; - if (phi_v0 < 4) { - phi_v0 = ((gSaveContext.eventInf[2] & 0xF) + phi_v0) % 4; + // The first four Racer Gorons have different stretches depending on context + // The last two remain the same (since they are dependent on one-another) + s32 subtypeLookup = ENGO_GET_SUBTYPE(&this->actor) % 6; + + if (subtypeLookup < 4) { + subtypeLookup = ((gSaveContext.eventInf[2] & 0xF) + subtypeLookup) % 4; } - func_80A12C48(this, play, D_80A166BC[phi_v0]); + EnGo_ChangeAnim(this, play, sSubtypeToAnimIndex[subtypeLookup]); - if (this->unk_3DC == 14) { - Lib_Vec3f_TranslateAndRotateY(&this->actor.world.pos, this->actor.shape.rot.y, &D_80A166B0, &sp2C); - Math_Vec3f_Copy(&this->actor.world.pos, &sp2C); + // Move the sitting Goron forward, since their spawn location is the same as their standing counterpart. + if (this->curAnimIndex == ENGO_ANIM_SITTING_STRETCH) { + + Lib_Vec3f_TranslateAndRotateY(&this->actor.world.pos, this->actor.shape.rot.y, &sStretchingGoronOffset, + &newSittingStretcherPos); + Math_Vec3f_Copy(&this->actor.world.pos, &newSittingStretcherPos); } + this->actor.flags &= ~ACTOR_FLAG_1; - Actor_SetScale(&this->actor, this->unk_3A4); - this->unk_3EC = 0; - this->unk_390 = 0; - this->unk_390 |= (0x40 | 0x20); + Actor_SetScale(&this->actor, this->scaleFactor); + this->sleepState = ENGO_AWAKE; + this->actionFlags = 0; + this->actionFlags |= (ENGO_FLAG_LOST_ATTENTION | ENGO_FLAG_EYES_OPEN); this->actor.gravity = 0.0f; } -void func_80A14104(EnGo* this, PlayState* play) { - static s32 D_80A166D4[] = { 15, 16 }; - s16 temp; +/** + * Update the Goron's animation and actionFlags to 'spectating'. + * + * Spectators engage in one of two cheering animations. Either cheering with their hands above their head, or + * cupping their hands infront of their face and shouting. + * + * @see EnGo_Idle + */ +void EnGo_ChangeToSpectatingAnimation(EnGo* this, PlayState* play) { + static s32 sSubtypeToAnimIndex[] = { ENGO_ANIM_CHEER, ENGO_ANIM_SHOUT }; + s16 animFrame; + + EnGo_ChangeAnim(this, play, sSubtypeToAnimIndex[ENGO_GET_SUBTYPE(&this->actor) % 2]); + animFrame = Rand_ZeroOne() * this->skelAnime.endFrame; + this->skelAnime.curFrame = animFrame; - func_80A12C48(this, play, D_80A166D4[ENGO_GET_70(&this->actor) % 2]); - temp = Rand_ZeroOne() * this->skelAnime.endFrame; - this->skelAnime.curFrame = temp; this->actor.flags &= ~ACTOR_FLAG_1; - Actor_SetScale(&this->actor, this->unk_3A4); - this->unk_3EC = 0; - this->unk_390 = 0; - this->unk_390 |= 0x40; - this->unk_390 |= 0x20; + Actor_SetScale(&this->actor, this->scaleFactor); + this->sleepState = ENGO_AWAKE; + this->actionFlags = 0; + this->actionFlags |= ENGO_FLAG_LOST_ATTENTION; + this->actionFlags |= ENGO_FLAG_EYES_OPEN; this->actor.gravity = 0.0f; } -void func_80A141D4(EnGo* this, PlayState* play) { - Collider_InitAndSetCylinder(play, &this->colliderCylinder, &this->actor, &sCylinderInit1); +/** + * Update the Goron's animation and actionFlags to 'frozen'. + * + * The Goron will shiver upon awakening, but is otherwise encased in a block of ice which deals damage upon contact. + * + * @see EnGo_Frozen + */ +void EnGo_ChangeToFrozenAnimation(EnGo* this, PlayState* play) { + Collider_InitAndSetCylinder(play, &this->colliderCylinder, &this->actor, &sCylinderInitFrozen); CollisionCheck_SetInfo2(&this->actor.colChkInfo, &sDamageTable, &sColChkInfoInit); - this->unk_3DC = -1; - func_80A12C48(this, play, 5); - this->unk_3EC = 0; - this->unk_39C = (this->unk_3A4 / 0.01f) * 0.9f; - this->unk_3BE = 2; - this->unk_390 = 0; - this->unk_390 |= 0x40; - this->unk_390 |= 0x400; - this->unk_3A0 = 100.0f; + this->curAnimIndex = -1; + EnGo_ChangeAnim(this, play, ENGO_ANIM_SHIVER); + this->sleepState = ENGO_AWAKE; + this->iceBlockScale = (this->scaleFactor / 0.01f) * 0.9f; + this->eyeTexIndex = ENGO_EYETEX_CLOSED; + this->actionFlags = 0; + this->actionFlags |= ENGO_FLAG_LOST_ATTENTION; + this->actionFlags |= ENGO_FLAG_FROZEN; + this->iceBlockAlpha = 100.0f; } -void func_80A1428C(EnGo* this, PlayState* play) { - s16 temp; - Vec3f sp30; - Vec3f sp24; +/** + * Update the Goron Gatekeeper's animation and actionFlags to 'snowball'. + * + * @see EnGo_Snowball + */ +void EnGo_ChangeToSnowballAnimation(EnGo* this, PlayState* play) { + s16 yawToPathPoint; + Vec3f currentPos; + Vec3f startingPathPoint; - Math_Vec3f_Copy(&sp30, &this->actor.world.pos); - if (this->unk_284 != NULL) { + Math_Vec3f_Copy(¤tPos, &this->actor.world.pos); + if (this->gatekeeperPath != NULL) { this->actor.flags &= ~ACTOR_FLAG_2000000; - SubS_CopyPointFromPathCheckBounds(this->unk_284, 0, &sp24); - temp = Math_Vec3f_Yaw(&sp30, &sp24); - this->actor.shape.rot.y = temp; - this->actor.world.rot.y = temp; + SubS_CopyPointFromPathCheckBounds(this->gatekeeperPath, 0, &startingPathPoint); + yawToPathPoint = Math_Vec3f_Yaw(¤tPos, &startingPathPoint); + this->actor.shape.rot.y = yawToPathPoint; + this->actor.world.rot.y = yawToPathPoint; } - this->unk_390 = 0; - this->unk_390 |= 0x100; - this->actor.shape.yOffset = 46.0f; + this->actionFlags = 0; + this->actionFlags |= ENGO_FLAG_SNOWBALLED; + this->actor.shape.yOffset = ENGO_SNOWBALL_Y_OFFSET; this->actor.gravity = -1.0f; } -void func_80A14324(EnGo* this, PlayState* play) { - func_80A12C48(this, play, 8); - Actor_SetScale(&this->actor, this->unk_3A4); - this->unk_390 = 0; +/** + * Update the Goron's animation and actionFlags to 'covering ears'. + * + * @see EnGo_Idle + */ +void EnGo_ChangeToCoveringEarsAnimation(EnGo* this, PlayState* play) { + EnGo_ChangeAnim(this, play, ENGO_ANIM_COVEREARS); + Actor_SetScale(&this->actor, this->scaleFactor); + this->actionFlags = 0; this->actor.gravity = -1.0f; - SubS_UpdateFlags(&this->unk_390, 3, 7); - this->unk_3EC = 0; - this->unk_390 |= 0x40; - this->unk_3BC = 0; - this->unk_3BE = 4; - this->unk_39C = 0.0f; - this->unk_3A0 = 0.0f; + SubS_UpdateFlags(&this->actionFlags, 3, 7); + this->sleepState = ENGO_AWAKE; + this->actionFlags |= ENGO_FLAG_LOST_ATTENTION; + this->blinkTimer = 0; + this->eyeTexIndex = ENGO_EYETEX_CLOSED2; + this->iceBlockScale = 0.0f; + this->iceBlockAlpha = 0.0f; } -void func_80A143A8(EnGo* this, PlayState* play) { - func_80A12C48(this, play, 5); - Actor_SetScale(&this->actor, this->unk_3A4); - this->unk_390 = 0; +/** + * Update the Goron's animation and actionFlags to 'shivering'. + * + * @see EnGo_Idle + */ +void EnGo_ChangeToShiveringAnimation(EnGo* this, PlayState* play) { + EnGo_ChangeAnim(this, play, ENGO_ANIM_SHIVER); + Actor_SetScale(&this->actor, this->scaleFactor); + this->actionFlags = 0; this->actor.gravity = -1.0f; - SubS_UpdateFlags(&this->unk_390, 3, 7); - this->unk_3EC = 0; - this->unk_390 |= 0x40; - this->unk_390 |= 0x20; - this->unk_3BC = 0; - this->unk_3BE = 0; - this->unk_39C = 0.0f; - this->unk_3A0 = 0.0f; + SubS_UpdateFlags(&this->actionFlags, 3, 7); + this->sleepState = ENGO_AWAKE; + this->actionFlags |= ENGO_FLAG_LOST_ATTENTION; + this->actionFlags |= ENGO_FLAG_EYES_OPEN; + this->blinkTimer = 0; + this->eyeTexIndex = ENGO_EYETEX_OPEN; + this->iceBlockScale = 0.0f; + this->iceBlockAlpha = 0.0f; } -void func_80A14430(EnGo* this, PlayState* play) { +/** + * Setup a Goron stretching at the racetrack. + * + * Stretching Gorons placed in the starting area of the racetrack doing various stretches. + */ +void EnGo_SetupAthletic(EnGo* this, PlayState* play) { if (((gSaveContext.save.entrance == ENTRANCE(GORON_RACETRACK, 0)) || (gSaveContext.save.entrance == ENTRANCE(GORON_RACETRACK, 2))) && (CHECK_WEEKEVENTREG(WEEKEVENTREG_CLEARED_SNOWHEAD_TEMPLE))) { - func_80A14018(this, play); - this->actionFunc = func_80A149B0; + EnGo_ChangeToStretchingAnimation(this, play); + this->actionFunc = EnGo_Idle; } else { Actor_Kill(&this->actor); } } -void func_80A1449C(EnGo* this, PlayState* play) { +/** + * Setup a Goron spectating at the racetrack. + * + * Spectators to the Goron races cannot be engaged, they simply stand idle and cheer. + */ +void EnGo_SetupSpectator(EnGo* this, PlayState* play) { if ((gSaveContext.save.entrance == ENTRANCE(GORON_RACETRACK, 1)) || (gSaveContext.save.entrance == ENTRANCE(CUTSCENE, 0))) { - func_80A14104(this, play); - this->actionFunc = func_80A149B0; + EnGo_ChangeToSpectatingAnimation(this, play); + this->actionFunc = EnGo_Idle; } else { Actor_Kill(&this->actor); } } -void func_80A144F4(EnGo* this, PlayState* play) { +/** + * Setup the Goron Shrine's Gatekeeper. + * + * When spoken to, can open the Goron Shrine for the player. + * - On Day 1: Can be found in the open, shivering. + * - On Days 2,3: Can be found in a snowball. + */ +void EnGo_SetupGatekeeper(EnGo* this, PlayState* play) { if (gSaveContext.save.day >= 2) { - this->unk_284 = SubS_GetDayDependentPath(play, ENGO_GET_7F80(&this->actor), 0xFF, &this->unk_3E4); - if (this->unk_284 != NULL) { - this->unk_3E4 = 1; + this->gatekeeperPath = SubS_GetDayDependentPath(play, ENGO_GET_PATH(&this->actor), 0xFF, &this->indexPathPoint); + if (this->gatekeeperPath != NULL) { + this->indexPathPoint = 1; } - func_80A1428C(this, play); - this->actionFunc = func_80A153FC; - this->unk_3D8 = func_80A13B1C; + EnGo_ChangeToSnowballAnimation(this, play); + this->actionFunc = EnGo_Snowball; + this->msgEventFunc = EnGo_HandleOpenShrineCutscene; } else { - func_80A143A8(this, play); - this->actionFunc = func_80A149B0; - this->unk_3D8 = func_80A13B1C; + EnGo_ChangeToShiveringAnimation(this, play); + this->actionFunc = EnGo_Idle; + this->msgEventFunc = EnGo_HandleOpenShrineCutscene; } } -void func_80A145AC(EnGo* this, PlayState* play) { - if ((ENGO_GET_70(&this->actor) == ENGO_70_1) && +/** + * Setup a Goron at the graveyard + * + * The Gorons are together, one shivering from the cold, another frozen solid. + */ +void EnGo_SetupGraveyardGoron(EnGo* this, PlayState* play) { + if ((ENGO_GET_SUBTYPE(&this->actor) == ENGO_GRAVEYARD_FROZEN) && (((play->sceneId == SCENE_10YUKIYAMANOMURA2) && (gSaveContext.sceneLayer == 1) && (play->csCtx.scriptIndex == 0)) || - !CHECK_WEEKEVENTREG(WEEKEVENTREG_21_08))) { - this->actor.child = func_80A13400(this, play); + !CHECK_WEEKEVENTREG(WEEKEVENTREG_TALKED_THAWED_GRAVEYARD_GORON))) { + this->actor.child = EnGo_FindGravemaker(this, play); this->actor.child->child = &this->actor; - func_80A141D4(this, play); - this->actionFunc = func_80A14E14; + EnGo_ChangeToFrozenAnimation(this, play); + this->actionFunc = EnGo_Frozen; } else { - func_80A143A8(this, play); - this->actionFunc = func_80A149B0; + EnGo_ChangeToShiveringAnimation(this, play); + this->actionFunc = EnGo_Idle; } } -void func_80A14668(EnGo* this, PlayState* play) { - if (!CHECK_WEEKEVENTREG(WEEKEVENTREG_22_04)) { - func_80A14324(this, play); - this->actionFunc = func_80A149B0; +/** + * Setup a shrine Goron. + * + * There are three, but they all behave the same way aside from dialog. + */ +void EnGo_SetupShrineGoron(EnGo* this, PlayState* play) { + if (!CHECK_WEEKEVENTREG(WEEKEVENTREG_CALMED_GORON_ELDERS_SON)) { + EnGo_ChangeToCoveringEarsAnimation(this, play); + this->actionFunc = EnGo_Idle; } else { - func_80A143A8(this, play); - this->actionFunc = func_80A149B0; + EnGo_ChangeToShiveringAnimation(this, play); + this->actionFunc = EnGo_Idle; } } -void func_80A146CC(EnGo* this, PlayState* play) { - func_80A134B0(this, play, 0); - func_80A12C48(this, play, 0); - this->unk_3A4 *= 5.0f; - Actor_SetScale(&this->actor, this->unk_3A4); +/** + * Setup the Medigoron in the Powder Keg Shop. + * + * This Goron sells Powder Kegs, and gives the player a Powder Keg as part of a challenge to gain + * the privilege to buy them. + */ +void EnGo_SetupMedigoron(EnGo* this, PlayState* play) { + EnGo_UpdateMedigoronColliderRadius(this, play, false); + EnGo_ChangeAnim(this, play, ENGO_ANIM_LYINGDOWNIDLE); + this->scaleFactor *= ENGO_MEDIGORON_SCALE_MULTIPLIER; + Actor_SetScale(&this->actor, this->scaleFactor); this->actor.flags &= ~ACTOR_FLAG_1; this->actor.targetMode = 3; - this->unk_390 = 0; + this->actionFlags = 0; this->actor.gravity = -1.0f; - SubS_UpdateFlags(&this->unk_390, 3, 7); - this->unk_390 |= 0x40; - this->unk_390 |= 0x20; - this->unk_3D8 = func_80A13E80; - this->actionFunc = func_80A149B0; + SubS_UpdateFlags(&this->actionFlags, 3, 7); + this->actionFlags |= ENGO_FLAG_LOST_ATTENTION; + this->actionFlags |= ENGO_FLAG_EYES_OPEN; + this->msgEventFunc = EnGo_HandleGivePowderKegCutscene; + this->actionFunc = EnGo_Idle; } -void func_80A14798(EnGo* this, PlayState* play) { - EffectTireMarkInit sp38 = { - 0, - 62, - { 0, 0, 15, 100 }, - }; +/** + * Default setup function as the initial action function. + */ +void EnGo_SetupInitialAction(EnGo* this, PlayState* play) { + EffectTireMarkInit tireMarkInit = { 0, 62, { 0, 0, 15, 100 } }; - if ((this->unk_288 < 0) || SubS_IsObjectLoaded(this->unk_288, play) || (this->unk_289 < 0) || - SubS_IsObjectLoaded(this->unk_289, play)) { + if (((this->taisouObjIndex < 0) || SubS_IsObjectLoaded(this->taisouObjIndex, play)) || + ((this->hakuginDemoObjIndex < 0) || SubS_IsObjectLoaded(this->hakuginDemoObjIndex, play))) { ActorShape_Init(&this->actor.shape, 0.0f, ActorShadow_DrawCircle, 20.0f); SkelAnime_InitFlex(play, &this->skelAnime, &gGoronSkel, NULL, this->jointTable, this->morphTable, GORON_LIMB_MAX); - this->unk_3DC = -1; - func_80A12C48(this, play, 2); - this->actor.draw = func_80A15FEC; + this->curAnimIndex = ENGO_ANIM_INVALID; + EnGo_ChangeAnim(this, play, ENGO_ANIM_UNROLL); + this->actor.draw = EnGo_Draw; Collider_InitAndSetSphere(play, &this->colliderSphere, &this->actor, &sSphereInit); - Collider_InitAndSetCylinder(play, &this->colliderCylinder, &this->actor, &sCylinderInit2); + Collider_InitAndSetCylinder(play, &this->colliderCylinder, &this->actor, &sCylinderInit); CollisionCheck_SetInfo2(&this->actor.colChkInfo, &sDamageTable, &sColChkInfoInit); - Effect_Add(play, &this->unk_3E8, EFFECT_TIRE_MARK, 0, 0, &sp38); + Effect_Add(play, &this->indexEffect, EFFECT_TIRE_MARK, 0, 0, &tireMarkInit); this->actor.targetMode = 1; - this->unk_3A4 = 0.01f; - this->unk_3D8 = NULL; + this->scaleFactor = ENGO_NORMAL_SCALE; + this->msgEventFunc = NULL; - switch (ENGO_GET_F(&this->actor)) { - case ENGO_F_1: - func_80A14430(this, play); + switch (ENGO_GET_TYPE(&this->actor)) { + case ENGO_ATHLETIC: + EnGo_SetupAthletic(this, play); break; - case ENGO_F_2: - func_80A1449C(this, play); + case ENGO_SPECTATOR: + EnGo_SetupSpectator(this, play); break; - case ENGO_F_3: - func_80A144F4(this, play); + case ENGO_GATEKEEPER: + EnGo_SetupGatekeeper(this, play); break; - case ENGO_F_4: - func_80A145AC(this, play); + case ENGO_GRAVEYARD: + EnGo_SetupGraveyardGoron(this, play); break; - case ENGO_F_5: - case ENGO_F_6: - case ENGO_F_7: - func_80A14668(this, play); + case ENGO_ASIDE_STORE: + case ENGO_ASIDE_ELDERSROOM: + case ENGO_ASIDE_ELDERSSON: + EnGo_SetupShrineGoron(this, play); break; - case ENGO_F_8: - func_80A146CC(this, play); + case ENGO_MEDIGORON: + EnGo_SetupMedigoron(this, play); break; default: @@ -1513,147 +2013,192 @@ void func_80A14798(EnGo* this, PlayState* play) { } } -void func_80A149B0(EnGo* this, PlayState* play) { - s16 sp26 = this->actor.world.rot.y; +/** + * Default action for the Gorons. Different types have different default actions. + * + * The default action possibilities include: + * - Shivering + * - Covering ears + * - Spectating (cheering or shouting) + * - Stretching (side-to-side squatting, two-arm side bend, limb shake, one-arm side bend, hamstring stretching while + * sitting, and helping the hamstring stretching Goron.) + */ +void EnGo_Idle(EnGo* this, PlayState* play) { + s16 targetRot = this->actor.world.rot.y; - if ((ENGO_GET_F(&this->actor) == ENGO_F_2) && (gSaveContext.save.entrance == ENTRANCE(GORON_RACETRACK, 1))) { + if ((ENGO_GET_TYPE(&this->actor) == ENGO_SPECTATOR) && + (gSaveContext.save.entrance == ENTRANCE(GORON_RACETRACK, 1))) { + // Spectators only cheer. No other interactions Actor_PlaySfx(&this->actor, NA_SE_EV_GORON_CHEER - SFX_FLAG); - } else if (ENGO_GET_F(&this->actor) != ENGO_F_8) { - if (func_80A1222C(this, play)) { - SubS_UpdateFlags(&this->unk_390, 0, 7); - this->unk_3EC = 1; - this->actionFunc = func_80A14B30; - } else if (ENGO_GET_F(&this->actor) == ENGO_F_4) { - switch (ENGO_GET_70(&this->actor)) { - case ENGO_70_0: - func_80A132C8(this, play); + } else if (ENGO_GET_TYPE(&this->actor) != ENGO_MEDIGORON) { + // All others besides the Medigoron in the Powder Keg Shop can fall asleep + if (EnGo_IsFallingAsleep(this, play)) { + SubS_UpdateFlags(&this->actionFlags, 0, 7); + this->sleepState = ENGO_ASLEEP_POS; + this->actionFunc = EnGo_Sleep; + } else if (ENGO_GET_TYPE(&this->actor) == ENGO_GRAVEYARD) { + switch (ENGO_GET_SUBTYPE(&this->actor)) { + case ENGO_GRAVEYARD_GRAVEMAKER: + EnGo_GravemakerIdle(this, play); break; - case ENGO_70_1: - func_80A133A8(this, play); + case ENGO_GRAVEYARD_FROZEN: + EnGo_FrozenIdle(this, play); + break; + + default: break; } - } else if (ENGO_GET_F(&this->actor) == ENGO_F_1) { + } else if (ENGO_GET_TYPE(&this->actor) == ENGO_ATHLETIC) { if (ABS_ALT(BINANG_SUB(this->actor.yawTowardsPlayer, this->actor.shape.rot.y)) < 0x3FFC) { - SubS_UpdateFlags(&this->unk_390, 3, 7); + SubS_UpdateFlags(&this->actionFlags, 3, 7); } else { - SubS_UpdateFlags(&this->unk_390, 0, 7); + SubS_UpdateFlags(&this->actionFlags, 0, 7); } } } - Math_ApproachS(&this->actor.shape.rot.y, sp26, 4, 0x2AA8); + Math_ApproachS(&this->actor.shape.rot.y, targetRot, 4, 0x2AA8); } -void func_80A14B30(EnGo* this, PlayState* play) { - s16 sp26 = this->actor.world.rot.y; +/** + * Handles falling asleep, as well as snoring while asleep. + */ +void EnGo_Sleep(EnGo* this, PlayState* play) { + s16 targetRot = this->actor.world.rot.y; u16 sfxId; - if (func_80A1222C(this, play)) { - this->unk_3EC = 1; + if (EnGo_IsFallingAsleep(this, play)) { + this->sleepState = ENGO_ASLEEP_POS; } - if (this->unk_390 & 0x4000) { + if (this->actionFlags & ENGO_FLAG_ROLLING_UP) { if (Animation_OnFrame(&this->skelAnime, this->skelAnime.endFrame)) { - this->unk_390 &= ~0x4000; - this->unk_390 |= 0x200; - if (this->unk_3EC != 0) { - this->unk_3AE = 0; + this->actionFlags &= ~ENGO_FLAG_ROLLING_UP; + this->actionFlags |= ENGO_FLAG_ROLLED_UP; + if (this->sleepState != ENGO_AWAKE) { + this->snorePhase = 0; } - this->actor.shape.yOffset = 14.0f; + this->actor.shape.yOffset = ENGO_ROLLEDUP_Y_OFFSET; } - } else if (this->unk_390 & 0x8000) { + } else if (this->actionFlags & ENGO_FLAG_UNROLLING) { if (Animation_OnFrame(&this->skelAnime, this->skelAnime.endFrame)) { - this->unk_390 |= 0x80; - this->unk_390 &= ~0x8000; + this->actionFlags |= ENGO_FLAG_STANDING; + this->actionFlags &= ~ENGO_FLAG_UNROLLING; } - } else if (this->unk_390 & 0x200) { - if ((this->actor.xzDistToPlayer < 160.0f) && (this->actor.playerHeightRel < 20.0f) && (this->unk_3EC == 0)) { - func_80A12C48(this, play, 3); - this->unk_390 &= ~0x80; - this->unk_390 &= ~0x200; - this->unk_390 |= 0x8000; - this->actor.shape.yOffset = 0.0f; - } else if ((this->unk_3EC != 0) && CHECK_WEEKEVENTREG(WEEKEVENTREG_22_04)) { - this->actor.scale.x = this->unk_3A4 - (Math_SinS(this->unk_3AE) * 0.001f); - this->actor.scale.y = (Math_SinS(this->unk_3AE) * 0.001f) + this->unk_3A4; - this->actor.scale.z = (Math_SinS(this->unk_3AE) * 0.001f) + this->unk_3A4; - if (this->unk_3AE == 0) { - this->unk_3EC = -this->unk_3EC; - if (this->unk_3EC > 0) { - sfxId = NA_SE_EN_GOLON_SNORE1; - } else { - sfxId = NA_SE_EN_GOLON_SNORE2; - } + } else if (this->actionFlags & ENGO_FLAG_ROLLED_UP) { + if ((this->actor.xzDistToPlayer < 160.0f) && (this->actor.playerHeightRel < 20.0f) && + (this->sleepState == ENGO_AWAKE)) { + EnGo_ChangeAnim(this, play, ENGO_ANIM_UNROLL_IMM); + this->actionFlags &= ~ENGO_FLAG_STANDING; + this->actionFlags &= ~ENGO_FLAG_ROLLED_UP; + this->actionFlags |= ENGO_FLAG_UNROLLING; + this->actor.shape.yOffset = ENGO_STANDING_Y_OFFSET; + } else if ((this->sleepState != ENGO_AWAKE) && CHECK_WEEKEVENTREG(WEEKEVENTREG_CALMED_GORON_ELDERS_SON)) { + // While asleep, rhythmicallly snore and change shape to show breathing. + this->actor.scale.x = this->scaleFactor - (Math_SinS(this->snorePhase) * (0.1f * ENGO_NORMAL_SCALE)); + this->actor.scale.y = this->scaleFactor + (Math_SinS(this->snorePhase) * (0.1f * ENGO_NORMAL_SCALE)); + this->actor.scale.z = this->scaleFactor + (Math_SinS(this->snorePhase) * (0.1f * ENGO_NORMAL_SCALE)); + + if (this->snorePhase == 0) { + this->sleepState = -this->sleepState; + sfxId = (this->sleepState > ENGO_AWAKE) ? NA_SE_EN_GOLON_SNORE1 : NA_SE_EN_GOLON_SNORE2; Actor_PlaySfx(&this->actor, sfxId); } - this->unk_3AE += 0x400; - this->actor.shape.yOffset = (this->actor.scale.y / this->unk_3A4) * 14.0f; - SubS_UpdateFlags(&this->unk_390, 3, 7); + this->snorePhase += 0x400; + this->actor.shape.yOffset = (this->actor.scale.y / this->scaleFactor) * ENGO_ROLLEDUP_Y_OFFSET; + SubS_UpdateFlags(&this->actionFlags, 3, 7); } } else if ((this->actor.xzDistToPlayer >= 240.0f) || (this->actor.playerHeightRel >= 20.0f) || - (this->unk_3EC != 0)) { - func_80A12C48(this, play, 4); - this->unk_390 &= ~0x80; - this->unk_390 &= ~0x200; - this->unk_390 |= 0x4000; - this->actor.shape.yOffset = 0.0f; + (this->sleepState != ENGO_AWAKE)) { + EnGo_ChangeAnim(this, play, ENGO_ANIM_ROLL); + this->actionFlags &= ~ENGO_FLAG_STANDING; + this->actionFlags &= ~ENGO_FLAG_ROLLED_UP; + this->actionFlags |= ENGO_FLAG_ROLLING_UP; + this->actor.shape.yOffset = ENGO_STANDING_Y_OFFSET; } - SubS_FillLimbRotTables(play, this->unk_3CE, this->unk_3C8, ARRAY_COUNT(this->unk_3CE)); - Math_ApproachS(&this->actor.shape.rot.y, sp26, 4, 0x2AA8); + SubS_FillLimbRotTables(play, this->limbRotTableY, this->limbRotTableZ, ARRAY_COUNT(this->limbRotTableY)); + Math_ApproachS(&this->actor.shape.rot.y, targetRot, 4, 0x2AA8); } -void func_80A14E14(EnGo* this, PlayState* play) { - Actor* actor = this->colliderCylinder.base.ac; +/** + * Action function for a frozen Goron. + * + * Transitions to the thawing cutscene when colliding with hot water or fire effect. + */ +void EnGo_Frozen(EnGo* this, PlayState* play) { + Actor* actorCollidedWith = this->colliderCylinder.base.ac; - if ((this->unk_390 & 0x1000) && (((actor != NULL) && (actor->id == ACTOR_OBJ_AQUA) && (actor->params & 1)) || - (this->actor.colChkInfo.damageEffect == 2))) { - this->actionFunc = func_80A14E74; + if ((this->actionFlags & ENGO_FLAG_HIT_BY_OTHER) && + (((actorCollidedWith != NULL) && (actorCollidedWith->id == ACTOR_OBJ_AQUA) && AQUA_HOT(actorCollidedWith)) || + (this->actor.colChkInfo.damageEffect == ENGO_DMGEFF_FIRE))) { + this->actionFunc = EnGo_AwaitThaw; } } -void func_80A14E74(EnGo* this, PlayState* play) { - if (func_80A134F4(this, this->actor.csId)) { - this->actionFunc = func_80A14EB0; +/** + * Action function for transitioning to thawing. + */ +void EnGo_AwaitThaw(EnGo* this, PlayState* play) { + if (EnGo_ChangeCutscene(this, this->actor.csId)) { + this->actionFunc = EnGo_Thaw; } } -void func_80A14EB0(EnGo* this, PlayState* play) { - EnGo* sp24 = (EnGo*)this->actor.child; +/** + * Action function for thawing of the Goron, melting sounds, and steam. + */ +void EnGo_Thaw(EnGo* this, PlayState* play) { + EnGo* otherGoron = (EnGo*)this->actor.child; - if ((s32)(this->unk_39C * 3.0f) != 0) { + if ((s32)(this->iceBlockScale * 3.0f) != 0) { Actor_PlaySfx(&this->actor, NA_SE_EV_ICE_MELT_LEVEL - SFX_FLAG); - Math_ApproachF(&this->unk_39C, 0.0f, 0.02f, 1.0f); - this->unk_3A0 = (this->unk_39C / 0.9f) * 100.0f; - func_80A139E4(this); + Math_ApproachF(&this->iceBlockScale, 0.0f, 0.02f, 1.0f); + this->iceBlockAlpha = (this->iceBlockScale / 0.9f) * 100.0f; + EnGo_MakeSteam(this); } else { CutsceneManager_Stop(this->actor.csId); - func_80A143A8(this, play); - if ((ENGO_GET_F(&this->actor) == ENGO_F_4) && (ENGO_GET_70(&this->actor) == ENGO_70_1)) { - SubS_UpdateFlags(&this->unk_390, 4, 7); - func_80A143A8(sp24, play); - sp24->actionFunc = func_80A149B0; + EnGo_ChangeToShiveringAnimation(this, play); + if ((ENGO_GET_TYPE(&this->actor) == ENGO_GRAVEYARD) && + (ENGO_GET_SUBTYPE(&this->actor) == ENGO_GRAVEYARD_FROZEN)) { + SubS_UpdateFlags(&this->actionFlags, 4, 7); + EnGo_ChangeToShiveringAnimation(otherGoron, play); + otherGoron->actionFunc = EnGo_Idle; } - this->actionFunc = func_80A149B0; + this->actionFunc = EnGo_Idle; } } -void func_80A14FC8(EnGo* this, PlayState* play) { - s32 sp38[] = { - 0, 2, 6, 20, 18, 5, 5, 15, +/** + * Cutscene action function for the arrival of springtime. + * + * This cutscene consists of: + * - The gravemaker stops shivering and looks around. + * - The other Goron thaws and shivers briefly. + * - The gravemaker pats the other's back and gestures broadly. + * - They both look around. + * - They both cheer. + */ +void EnGo_HandleSpringArrivalCutscene(EnGo* this, PlayState* play) { + s32 animationIndices[] = { + ENGO_ANIM_LYINGDOWNIDLE, ENGO_ANIM_UNROLL, ENGO_ANIM_SHIVER_IMM, ENGO_ANIM_LOOK_AROUND, + ENGO_ANIM_SHOW, ENGO_ANIM_SHIVER, ENGO_ANIM_SHIVER, ENGO_ANIM_CHEER, }; u16 cueType = 0; s32 cueId; s32 cueChannel; - switch (ENGO_GET_70(&this->actor)) { - case ENGO_70_0: + switch (ENGO_GET_SUBTYPE(&this->actor)) { + case ENGO_GRAVEYARD_GRAVEMAKER: cueType = CS_CMD_ACTOR_CUE_128; break; - case ENGO_70_1: + case ENGO_GRAVEYARD_FROZEN: cueType = CS_CMD_ACTOR_CUE_129; break; + + default: + break; } if ((cueType == CS_CMD_ACTOR_CUE_128) || (cueType == CS_CMD_ACTOR_CUE_129)) { @@ -1661,51 +2206,59 @@ void func_80A14FC8(EnGo* this, PlayState* play) { cueChannel = Cutscene_GetCueChannel(play, cueType); cueId = play->csCtx.actorCues[cueChannel]->id; - if (this->cueId != (u8)cueId) { - this->cueId = cueId; - func_80A12C48(this, play, sp38[cueId]); - this->unk_390 = 0; - this->unk_390 |= 0x20; - this->unk_3BE = 0; - this->unk_39C = 0.0f; - this->unk_3A0 = 0.0f; + if (this->springArrivalCueId != (u8)cueId) { + this->springArrivalCueId = cueId; + EnGo_ChangeAnim(this, play, animationIndices[cueId]); + this->actionFlags = 0; + this->actionFlags |= ENGO_FLAG_EYES_OPEN; + this->eyeTexIndex = ENGO_EYETEX_OPEN; + this->iceBlockScale = 0.0f; + this->iceBlockAlpha = 0.0f; switch (cueId) { case 1: - this->unk_390 |= 0x80; + this->actionFlags |= ENGO_FLAG_STANDING; this->skelAnime.curFrame = this->skelAnime.endFrame; break; case 5: case 6: - func_80A141D4(this, play); + EnGo_ChangeToFrozenAnimation(this, play); + break; + + default: break; } } - switch (this->cueId) { + switch (this->springArrivalCueId) { case 3: - if (Animation_OnFrame(&this->skelAnime, this->skelAnime.endFrame) && (this->unk_3DC == 20)) { - func_80A12C48(this, play, 21); + if (Animation_OnFrame(&this->skelAnime, this->skelAnime.endFrame) && + (this->curAnimIndex == ENGO_ANIM_LOOK_AROUND)) { + EnGo_ChangeAnim(this, play, ENGO_ANIM_LOOK_AROUND_LOOPED); } break; case 4: - if (Animation_OnFrame(&this->skelAnime, this->skelAnime.endFrame) && (this->unk_3DC == 18)) { - func_80A12C48(this, play, 19); + if (Animation_OnFrame(&this->skelAnime, this->skelAnime.endFrame) && + (this->curAnimIndex == ENGO_ANIM_SHOW)) { + EnGo_ChangeAnim(this, play, ENGO_ANIM_SHOW_LOOPED); } break; case 6: - if ((s32)(this->unk_39C * 3.0f) != 0) { + if ((s32)(this->iceBlockScale * 3.0f) != 0) { Actor_PlaySfx(&this->actor, NA_SE_EV_ICE_MELT_LEVEL - SFX_FLAG); - Math_ApproachF(&this->unk_39C, 0.0f, 0.02f, 1.0f); - this->unk_3A0 = (this->unk_39C / 0.9f) * 100.0f; - func_80A139E4(this); - } else if (this->unk_390 & 0x400) { - func_80A143A8(this, play); + Math_ApproachF(&this->iceBlockScale, 0.0f, 0.02f, 1.0f); + this->iceBlockAlpha = (this->iceBlockScale / 0.9f) * 100.0f; + EnGo_MakeSteam(this); + } else if (this->actionFlags & ENGO_FLAG_FROZEN) { + EnGo_ChangeToShiveringAnimation(this, play); } break; + + default: + break; } if (cueType == 128) { @@ -1731,6 +2284,9 @@ void func_80A14FC8(EnGo* this, PlayState* play) { case 490: Actor_PlaySfx(&this->actor, NA_SE_EN_GOLON_VOICE_EATFULL); break; + + default: + break; } } else if (cueType == 129) { switch (play->csCtx.curFrame) { @@ -1750,65 +2306,72 @@ void func_80A14FC8(EnGo* this, PlayState* play) { case 480: Actor_PlaySfx(&this->actor, NA_SE_EN_GOLON_VOICE_EATFULL); break; + + default: + break; } } - SubS_FillLimbRotTables(play, this->unk_3CE, this->unk_3C8, ARRAY_COUNT(this->unk_3CE)); + SubS_FillLimbRotTables(play, this->limbRotTableY, this->limbRotTableZ, ARRAY_COUNT(this->limbRotTableY)); Cutscene_ActorTranslateAndYaw(&this->actor, play, cueChannel); } } } -void func_80A153FC(EnGo* this, PlayState* play) { - Vec3s* sp5C; - Vec3f sp50; - Vec3f sp44; +/** + * Action function for the Gatekeeper while they're in a snowball. + * + * On Day 2, they'll roll along a set path, and can be halted with certain attacks. + * On Day 3, they're frozen solid. + */ +void EnGo_Snowball(EnGo* this, PlayState* play) { + Vec3s* pathPoints; + Vec3f currentPos; + Vec3f currentPathPoint; - if ((this->unk_390 & 0x1000) && (this->actor.colChkInfo.damageEffect == 0xF)) { + if ((this->actionFlags & ENGO_FLAG_HIT_BY_OTHER) && (this->actor.colChkInfo.damageEffect == ENGO_DMGEFF_BREAK)) { + // Stop the Gatekeeper when hit by an appropriate effect Actor_PlaySfx(&this->actor, NA_SE_EV_SNOWBALL_BROKEN); - this->actor.flags &= ~ACTOR_FLAG_10; this->actor.flags |= ACTOR_FLAG_2000000; - - func_80A118F8(this->unk_3F8, this->actor.world.pos); + EnGo_InitSnow(this->effectTable, this->actor.world.pos); this->actor.shape.rot.x = 0; this->actor.speed = 0.0f; - Actor_PlaySfx(&this->actor, NA_SE_EN_GOLON_COLD); if (gSaveContext.save.day == 3) { - func_80A141D4(this, play); - this->actionFunc = func_80A14E14; + EnGo_ChangeToFrozenAnimation(this, play); + this->actionFunc = EnGo_Frozen; } else { - func_80A143A8(this, play); - this->actionFunc = func_80A149B0; + EnGo_ChangeToShiveringAnimation(this, play); + this->actionFunc = EnGo_Idle; } - } else if (this->unk_284 != NULL) { - if (this->unk_390 & 0x800) { + } else if (this->gatekeeperPath != NULL) { + if (this->actionFlags & ENGO_FLAG_HIT_OTHER) { Player_PlaySfx(GET_PLAYER(play), NA_SE_PL_BODY_HIT); func_800B8D50(play, &this->actor, 2.0f, this->actor.yawTowardsPlayer, 0.0f, 0); } - sp5C = Lib_SegmentedToVirtual(this->unk_284->points); - if (SubS_HasReachedPoint(&this->actor, this->unk_284, this->unk_3E4)) { - if (this->unk_3E4 >= (this->unk_284->count - 1)) { - this->unk_3E4 = 0; + pathPoints = Lib_SegmentedToVirtual(this->gatekeeperPath->points); + if (SubS_HasReachedPoint(&this->actor, this->gatekeeperPath, this->indexPathPoint)) { + if (this->indexPathPoint >= (this->gatekeeperPath->count - 1)) { + this->indexPathPoint = 0; } else { - this->unk_3E4++; + this->indexPathPoint++; } } - Math_Vec3s_ToVec3f(&sp44, &sp5C[this->unk_3E4]); - Math_Vec3f_Copy(&sp50, &this->actor.world.pos); - Math_ApproachS(&this->actor.world.rot.y, Math_Vec3f_Yaw(&sp50, &sp44), 4, 0x38E); + Math_Vec3s_ToVec3f(¤tPathPoint, &pathPoints[this->indexPathPoint]); + Math_Vec3f_Copy(¤tPos, &this->actor.world.pos); + Math_ApproachS(&this->actor.world.rot.y, Math_Vec3f_Yaw(¤tPos, ¤tPathPoint), 4, 0x38E); this->actor.shape.rot.y = this->actor.world.rot.y; if (this->actor.bgCheckFlags & BGCHECKFLAG_GROUND) { Actor_PlaySfx(&this->actor, NA_SE_EV_BIGBALL_ROLL - SFX_FLAG); - func_800AE930(&play->colCtx, Effect_GetByIndex(this->unk_3E8), &this->actor.world.pos, 18.0f, + func_800AE930(&play->colCtx, Effect_GetByIndex(this->indexEffect), &this->actor.world.pos, 18.0f, this->actor.shape.rot.y, this->actor.floorPoly, this->actor.floorBgId); } else { - func_800AEF44(Effect_GetByIndex(this->unk_3E8)); + func_800AEF44(Effect_GetByIndex(this->indexEffect)); } this->actor.speed = 4.0f; @@ -1817,86 +2380,107 @@ void func_80A153FC(EnGo* this, PlayState* play) { } } -s32* func_80A15684(EnGo* this, PlayState* play) { - static s32* D_80A16704[] = { - D_80A16100, - D_80A16164, +/** + * Return the MsgEvent script appropriate for the actor. + */ +s32* EnGo_GetMsgEventScript(EnGo* this, PlayState* play) { + static s32 sMsgScriptGraveyard[] = { + sMsgScriptGoronGravemaker, + sMsgScriptGoronFrozen, }; - if (this->unk_3EC != 0) { - return D_80A1640C; + if (this->sleepState != ENGO_AWAKE) { + return sMsgScriptGoronSleeping; // Lullaby hint } - if (ENGO_GET_F(&this->actor) == ENGO_F_1) { - switch (ENGO_GET_70(&this->actor) % 6) { - case ENGO_70_0: - return D_80A163BC; - case ENGO_70_1: - return D_80A163CC; - case ENGO_70_2: - return D_80A163DC; - case ENGO_70_3: - return D_80A163EC; - case ENGO_70_4: - return D_80A163FC; - case ENGO_70_5: - return D_80A163FC; + if (ENGO_GET_TYPE(&this->actor) == ENGO_ATHLETIC) { + switch (ENGO_GET_SUBTYPE(&this->actor) % 6) { + case ENGO_ATHLETIC_A: + return sMsgScriptGoronAthleticA; + + case ENGO_ATHLETIC_B: // Unused! + return sMsgScriptGoronAthleticB; + + case ENGO_ATHLETIC_C: + return sMsgScriptGoronAthleticC; + + case ENGO_ATHLETIC_D: + return sMsgScriptGoronAthleticD; + + case ENGO_ATHLETIC_HAMSTRINGSIT: + return sMsgScriptGoronAthleticHamstring; + + case ENGO_ATHLETIC_HAMSTRINGSTAND: + return sMsgScriptGoronAthleticHamstring; + + default: + break; } } - switch (ENGO_GET_F(&this->actor)) { - case ENGO_F_3: - return D_80A16350; - case ENGO_F_4: - return D_80A16704[ENGO_GET_70(&this->actor)]; - case ENGO_F_5: - return D_80A16208; - case ENGO_F_6: - return D_80A16254; - case ENGO_F_7: - return D_80A16210; - case ENGO_F_8: - return D_80A16280; + switch (ENGO_GET_TYPE(&this->actor)) { + case ENGO_GATEKEEPER: + return sMsgScriptGoronGatekeeper; + + case ENGO_GRAVEYARD: + return sMsgScriptGraveyard[ENGO_GET_SUBTYPE(&this->actor)]; + + case ENGO_ASIDE_STORE: + return sMsgScriptGoronAsideStore; + + case ENGO_ASIDE_ELDERSROOM: + return sMsgScriptGoronAsideEldersRoom; + + case ENGO_ASIDE_ELDERSSON: + return sMsgScriptGoronAsideEldersSon; + + case ENGO_MEDIGORON: + return sMsgScriptGoronMedigoron; + default: - return D_80A16208; + return sMsgScriptGoronAsideStore; } } -void func_80A157C4(EnGo* this, PlayState* play) { +/** + * Action function for dialog, movement due to dialog, and ending dialog + */ +void EnGo_Talk(EnGo* this, PlayState* play) { s32 pad; - Vec3f sp40; - Vec3f sp34; + Vec3f targetPos; + Vec3f thisPos; - if (!func_8010BF58(&this->actor, play, func_80A15684(this, play), this->unk_3D8, &this->unk_28C)) { - if ((ENGO_GET_F(&this->actor) != ENGO_F_1) && !(this->unk_390 & 0x200)) { - Math_Vec3f_Copy(&sp40, &this->unk_38C->world.pos); - Math_Vec3f_Copy(&sp34, &this->actor.world.pos); - Math_ApproachS(&this->actor.shape.rot.y, Math_Vec3f_Yaw(&sp34, &sp40), 4, 0x2AA8); + if (!func_8010BF58(&this->actor, play, EnGo_GetMsgEventScript(this, play), this->msgEventFunc, + &this->msgScriptResumePos)) { + if ((ENGO_GET_TYPE(&this->actor) != ENGO_ATHLETIC) && !(this->actionFlags & ENGO_FLAG_ROLLED_UP)) { + Math_Vec3f_Copy(&targetPos, &this->attentionTarget->world.pos); + Math_Vec3f_Copy(&thisPos, &this->actor.world.pos); + Math_ApproachS(&this->actor.shape.rot.y, Math_Vec3f_Yaw(&thisPos, &targetPos), 4, 0x2AA8); } - SubS_FillLimbRotTables(play, this->unk_3CE, this->unk_3C8, ARRAY_COUNT(this->unk_3CE)); + SubS_FillLimbRotTables(play, this->limbRotTableY, this->limbRotTableZ, ARRAY_COUNT(this->limbRotTableY)); return; } - if ((ENGO_GET_F(&this->actor) == ENGO_F_5) || (ENGO_GET_F(&this->actor) == ENGO_F_6) || - (ENGO_GET_F(&this->actor) == ENGO_F_7)) { - this->unk_3BC = 0; - this->unk_390 &= ~0x20; - this->unk_3BE = 4; + if ((ENGO_GET_TYPE(&this->actor) == ENGO_ASIDE_STORE) || (ENGO_GET_TYPE(&this->actor) == ENGO_ASIDE_ELDERSROOM) || + (ENGO_GET_TYPE(&this->actor) == ENGO_ASIDE_ELDERSSON)) { + this->blinkTimer = 0; + this->actionFlags &= ~ENGO_FLAG_EYES_OPEN; + this->eyeTexIndex = ENGO_EYETEX_CLOSED2; } - this->unk_390 &= ~0x8; - SubS_UpdateFlags(&this->unk_390, 3, 7); - this->unk_28C = 0; - this->unk_390 |= 0x40; - this->actionFunc = this->unk_18C; + this->actionFlags &= ~ENGO_FLAG_ENGAGED; + SubS_UpdateFlags(&this->actionFlags, 3, 7); + this->msgScriptResumePos = 0; + this->actionFlags |= ENGO_FLAG_LOST_ATTENTION; + this->actionFunc = this->interruptedActionFunc; } void EnGo_Init(Actor* thisx, PlayState* play) { EnGo* this = THIS; - this->unk_288 = SubS_GetObjectIndex(OBJECT_TAISOU, play); - this->unk_289 = SubS_GetObjectIndex(OBJECT_HAKUGIN_DEMO, play); - this->actionFunc = func_80A14798; + this->taisouObjIndex = SubS_GetObjectIndex(OBJECT_TAISOU, play); + this->hakuginDemoObjIndex = SubS_GetObjectIndex(OBJECT_HAKUGIN_DEMO, play); + this->actionFunc = EnGo_SetupInitialAction; } void EnGo_Destroy(Actor* thisx, PlayState* play) { @@ -1904,50 +2488,55 @@ void EnGo_Destroy(Actor* thisx, PlayState* play) { Collider_DestroyCylinder(play, &this->colliderCylinder); Collider_DestroySphere(play, &this->colliderSphere); - Effect_Destroy(play, this->unk_3E8); + Effect_Destroy(play, this->indexEffect); } void EnGo_Update(Actor* thisx, PlayState* play) { EnGo* this = THIS; - f32 phi_f0; + f32 xzRange; - func_80A12868(this, play); - if (!func_80A12774(this, play)) { - func_80A12954(this, play); + EnGo_DetectCollisions(this, play); + + if (!EnGo_UpdateTalking(this, play)) { + EnGo_UpdateSpringArrivalCutscene(this, play); } this->actionFunc(this, play); - if (!(this->unk_390 & 0x400)) { - func_80A12D6C(this); - func_80A12A64(this, play); - func_80A131F8(this, play); - func_80A12B78(this, play); + if (!(this->actionFlags & ENGO_FLAG_FROZEN)) { + EnGo_UpdateEyes(this); + EnGo_UpdateAnimationToCurrent(this, play); + EnGo_UpdateAttentionTargetAndReactions(this, play); + EnGo_UpdateSfx(this, play); } - if (!(this->unk_390 & 0x100) && !(this->unk_390 & 0x200) && !(this->unk_390 & 0x400)) { - if (ENGO_GET_F(&this->actor) == ENGO_F_8) { - phi_f0 = this->colliderSphere.dim.worldSphere.radius + 60; + if (!(this->actionFlags & ENGO_FLAG_SNOWBALLED) && !(this->actionFlags & ENGO_FLAG_ROLLED_UP) && + !(this->actionFlags & ENGO_FLAG_FROZEN)) { + if (ENGO_GET_TYPE(&this->actor) == ENGO_MEDIGORON) { + xzRange = this->colliderSphere.dim.worldSphere.radius + 60; } else { - phi_f0 = this->colliderCylinder.dim.radius + 40; + xzRange = this->colliderCylinder.dim.radius + 40; } - func_8013C964(&this->actor, play, phi_f0, 20.0f, PLAYER_IA_NONE, this->unk_390 & 7); - } else if ((this->unk_390 & 0x200) && (this->unk_3EC != 0)) { - phi_f0 = this->colliderCylinder.dim.radius + 40; - func_8013C964(&this->actor, play, phi_f0, 20.0f, PLAYER_IA_NONE, this->unk_390 & 7); + func_8013C964(&this->actor, play, xzRange, 20.0f, PLAYER_IA_NONE, this->actionFlags & 7); + } else if ((this->actionFlags & ENGO_FLAG_ROLLED_UP) && (this->sleepState != ENGO_AWAKE)) { + xzRange = this->colliderCylinder.dim.radius + 40; + func_8013C964(&this->actor, play, xzRange, 20.0f, PLAYER_IA_NONE, this->actionFlags & 7); } - if ((ENGO_GET_F(&this->actor) != ENGO_F_8) && (ENGO_GET_F(&this->actor) != ENGO_F_2) && - (ENGO_GET_F(&this->actor) != ENGO_F_1)) { + if ((ENGO_GET_TYPE(&this->actor) != ENGO_MEDIGORON) && (ENGO_GET_TYPE(&this->actor) != ENGO_SPECTATOR) && + (ENGO_GET_TYPE(&this->actor) != ENGO_ATHLETIC)) { Actor_UpdateBgCheckInfo(play, &this->actor, 30.0f, 12.0f, 0.0f, UPDBGCHECKINFO_FLAG_4); } - func_80A122EC(this); - func_80A126BC(this, play); - func_80A1203C(this); + EnGo_UpdateFocus(this); + EnGo_UpdateCollider(this, play); + EnGo_UpdateEffects(this); } -void func_80A15B80(EnGo* this, PlayState* play) { +/** + * Draw function for a snowballed or rolled up Goron (no need to draw limbs). + */ +void EnGo_Draw_NoSkeleton(EnGo* this, PlayState* play) { Gfx* gfx; OPEN_DISPS(play->state.gfxCtx); @@ -1961,7 +2550,7 @@ void func_80A15B80(EnGo* this, PlayState* play) { Matrix_RotateZS(this->actor.shape.rot.z, MTXMODE_APPLY); Matrix_Translate(0.0f, this->actor.shape.yOffset, 0.0f, MTXMODE_APPLY); - if (this->unk_390 & 0x100) { + if (this->actionFlags & ENGO_FLAG_SNOWBALLED) { Matrix_Scale(this->actor.scale.x * 8.0f, this->actor.scale.y * 8.0f, this->actor.scale.z * 8.0f, MTXMODE_APPLY); } else { Matrix_Scale(this->actor.scale.x, this->actor.scale.y, this->actor.scale.z, MTXMODE_APPLY); @@ -1970,60 +2559,59 @@ void func_80A15B80(EnGo* this, PlayState* play) { Matrix_RotateXS(this->actor.shape.rot.x, MTXMODE_APPLY); gSPMatrix(POLY_OPA_DISP++, Matrix_NewMtx(play->state.gfxCtx), G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW); - gSPDisplayList(POLY_OPA_DISP++, (this->unk_390 & 0x100) ? gGoronSnowballDL : gGoronRolledUpDL); + gSPDisplayList(POLY_OPA_DISP++, (this->actionFlags & ENGO_FLAG_SNOWBALLED) ? gGoronSnowballDL : gGoronRolledUpDL); CLOSE_DISPS(play->state.gfxCtx); } s32 EnGo_OverrideLimbDraw(PlayState* play, s32 limbIndex, Gfx** dList, Vec3f* pos, Vec3s* rot, Actor* thisx) { EnGo* this = THIS; - Vec3f sp30; - s32 idx; + Vec3f worldPos; + s32 rotTableIndex; - if ((ENGO_GET_F(&this->actor) == ENGO_F_8) && (limbIndex == 10)) { - Matrix_MultZero(&sp30); - sp30.y = this->actor.world.pos.y; - Math_Vec3f_ToVec3s(&this->colliderSphere.dim.worldSphere.center, &sp30); + if ((ENGO_GET_TYPE(&this->actor) == ENGO_MEDIGORON) && (limbIndex == GORON_LIMB_BODY)) { + Matrix_MultZero(&worldPos); + worldPos.y = this->actor.world.pos.y; + Math_Vec3f_ToVec3s(&this->colliderSphere.dim.worldSphere.center, &worldPos); } switch (limbIndex) { - case 10: - idx = 0; + case GORON_LIMB_BODY: + rotTableIndex = 0; break; - case 11: - idx = 1; + case GORON_LIMB_LEFT_UPPER_ARM: + rotTableIndex = 1; break; - case 14: - idx = 2; + case GORON_LIMB_RIGHT_UPPER_ARM: + rotTableIndex = 2; break; default: - idx = 9; + rotTableIndex = 9; break; } - if ((this->unk_390 & 0x80) && (idx < 9)) { - rot->y += (s16)(Math_SinS(this->unk_3CE[idx]) * 200.0f); - rot->z += (s16)(Math_CosS(this->unk_3C8[idx]) * 200.0f); + if ((this->actionFlags & ENGO_FLAG_STANDING) && (rotTableIndex < 9)) { + rot->y += (s16)(Math_SinS(this->limbRotTableY[rotTableIndex]) * 200.0f); + rot->z += (s16)(Math_CosS(this->limbRotTableZ[rotTableIndex]) * 200.0f); } return false; } void EnGo_TransfromLimbDraw(PlayState* play, s32 limbIndex, Actor* thisx) { EnGo* this = THIS; - u16 temp_v0; s32 stepRot; s32 overrideRot; - if (this->unk_390 & 0x40) { + if (this->actionFlags & ENGO_FLAG_LOST_ATTENTION) { stepRot = false; } else { stepRot = true; } - if (this->unk_390 & 0x10) { + if (this->actionFlags & ENGO_FLAG_FACE_TARGET) { overrideRot = true; } else { overrideRot = false; @@ -2034,47 +2622,50 @@ void EnGo_TransfromLimbDraw(PlayState* play, s32 limbIndex, Actor* thisx) { } switch (limbIndex) { - case 17: - SubS_UpdateLimb(this->unk_3B0 + this->unk_3B4 + 0x4000, - this->unk_3B2 + this->unk_3B6 + this->actor.shape.rot.y + 0x4000, &this->unk_290, - &this->unk_2A8, stepRot, overrideRot); + case GORON_LIMB_HEAD: + SubS_UpdateLimb(this->headRotZ + this->bodyRotZ + 0x4000, + this->headRotY + this->bodyRotY + this->actor.shape.rot.y + 0x4000, &this->headPos, + &this->headRot, stepRot, overrideRot); Matrix_Pop(); - Matrix_Translate(this->unk_290.x, this->unk_290.y, this->unk_290.z, MTXMODE_NEW); + Matrix_Translate(this->headPos.x, this->headPos.y, this->headPos.z, MTXMODE_NEW); Matrix_Scale(this->actor.scale.x, this->actor.scale.y, this->actor.scale.z, MTXMODE_APPLY); - Matrix_RotateYS(this->unk_2A8.y, MTXMODE_APPLY); - Matrix_RotateXS(this->unk_2A8.x, MTXMODE_APPLY); - Matrix_RotateZS(this->unk_2A8.z, MTXMODE_APPLY); + Matrix_RotateYS(this->headRot.y, MTXMODE_APPLY); + Matrix_RotateXS(this->headRot.x, MTXMODE_APPLY); + Matrix_RotateZS(this->headRot.z, MTXMODE_APPLY); Matrix_Push(); break; - case 10: - SubS_UpdateLimb(this->unk_3B4 + 0x4000, this->unk_3B6 + this->actor.shape.rot.y + 0x4000, &this->unk_29C, - &this->unk_2AE, stepRot, overrideRot); + case GORON_LIMB_BODY: + SubS_UpdateLimb(this->bodyRotZ + 0x4000, this->bodyRotY + this->actor.shape.rot.y + 0x4000, &this->bodyPos, + &this->bodyRot, stepRot, overrideRot); Matrix_Pop(); - Matrix_Translate(this->unk_29C.x, this->unk_29C.y, this->unk_29C.z, MTXMODE_NEW); + Matrix_Translate(this->bodyPos.x, this->bodyPos.y, this->bodyPos.z, MTXMODE_NEW); Matrix_Scale(this->actor.scale.x, this->actor.scale.y, this->actor.scale.z, MTXMODE_APPLY); - Matrix_RotateYS(this->unk_2AE.y, MTXMODE_APPLY); - Matrix_RotateXS(this->unk_2AE.x, MTXMODE_APPLY); - Matrix_RotateZS(this->unk_2AE.z, MTXMODE_APPLY); + Matrix_RotateYS(this->bodyRot.y, MTXMODE_APPLY); + Matrix_RotateXS(this->bodyRot.x, MTXMODE_APPLY); + Matrix_RotateZS(this->bodyRot.z, MTXMODE_APPLY); Matrix_Push(); break; + + default: + break; } } -void func_80A15FEC(Actor* thisx, PlayState* play) { - static TexturePtr D_80A1670C[] = { +void EnGo_Draw(Actor* thisx, PlayState* play) { + static TexturePtr sEyeTextures[] = { gGoronEyeOpenTex, gGoronEyeHalfTex, gGoronEyeClosedTex, gGoronEyeHalfTex, gGoronEyeClosed2Tex, }; EnGo* this = THIS; - if (!(this->unk_390 & 0x300)) { + if (!(this->actionFlags & (ENGO_FLAG_SNOWBALLED | ENGO_FLAG_ROLLED_UP))) { OPEN_DISPS(play->state.gfxCtx); Gfx_SetupDL25_Opa(play->state.gfxCtx); - gSPSegment(POLY_OPA_DISP++, 0x08, Lib_SegmentedToVirtual(D_80A1670C[this->unk_3BE])); + gSPSegment(POLY_OPA_DISP++, 0x08, Lib_SegmentedToVirtual(sEyeTextures[this->eyeTexIndex])); - if (this->unk_3DC == 14) { + if (this->curAnimIndex == ENGO_ANIM_SITTING_STRETCH) { Matrix_Translate(0.0f, 0.0f, -4000.0f, MTXMODE_APPLY); } SkelAnime_DrawTransformFlexOpa(play, this->skelAnime.skeleton, this->skelAnime.jointTable, @@ -2083,8 +2674,8 @@ void func_80A15FEC(Actor* thisx, PlayState* play) { CLOSE_DISPS(play->state.gfxCtx); } else { - func_80A15B80(this, play); + EnGo_Draw_NoSkeleton(this, play); } - func_80A137C0(this, play, this->unk_39C, this->unk_3A0); - func_80A1213C(this, play); + EnGo_DrawIceBlockWhenFrozen(this, play, this->iceBlockScale, this->iceBlockAlpha); + EnGo_DrawEffects(this, play); } diff --git a/src/overlays/actors/ovl_En_Go/z_en_go.h b/src/overlays/actors/ovl_En_Go/z_en_go.h index 9d12dfdce8..a1c96214b5 100644 --- a/src/overlays/actors/ovl_En_Go/z_en_go.h +++ b/src/overlays/actors/ovl_En_Go/z_en_go.h @@ -2,103 +2,141 @@ #define Z_EN_GO_H #include "global.h" +#include "objects/object_oF1d_map/object_oF1d_map.h" struct EnGo; typedef void (*EnGoActionFunc)(struct EnGo*, PlayState*); +typedef s32 (*MsgEventFunc)(Actor*, PlayState*); -#define ENGO_GET_F(thisx) (((thisx)->params & 0xF) & 0xFF) -#define ENGO_GET_70(thisx) ((((thisx)->params & 0x70) >> 4) & 0xFF) -#define ENGO_GET_7F80(thisx) ((((thisx)->params & 0x7F80) >> 7) & 0xFF) +#define ENGO_GET_TYPE(thisx) (((thisx)->params & 0xF) & 0xFF) +#define ENGO_GET_SUBTYPE(thisx) ((((thisx)->params & 0x70) >> 4) & 0xFF) -enum { +#define ENGO_GET_PATH(thisx) ((((thisx)->params & 0x7F80) >> 7) & 0xFF) + +#define ENGO_SNOW_EFFECT_COUNT 16 +#define ENGO_OTHER_EFFECT_COUNT 16 +#define ENGO_EFFECT_COUNT (ENGO_SNOW_EFFECT_COUNT + ENGO_OTHER_EFFECT_COUNT) + +/** + * Struct to track the state of various visual effects. + * + * A Goron's 'effectTable' is comprised of a number of these effects, which depending on the context in which they are + * used, take on the form of snow, dust, or steam. The functions using these objects have an expectation that they are + * iterating through the full effectTable, or half of the effectTable. See individual functions containing 'EnGoEffect*' + * parameters for more details. + */ +typedef struct EnGoEffect { + /* 0x00 */ u8 type; + /* 0x01 */ u8 alphaDenom; + /* 0x02 */ u8 alphaNumer; + /* 0x04 */ Vec3s rotVelocity; + /* 0x0A */ Vec3s rotAngle; + /* 0x10 */ Vec3f pos; + /* 0x1C */ Vec3f accel; + /* 0x28 */ Vec3f velocity; + /* 0x34 */ f32 scaleXY; + /* 0x38 */ f32 scaleXYDelta; +} EnGoEffect; // size = 0x3C; + +/** + * Goron Type, identified by bits [3..0] of the actor's params + * + * - The ENGO_ATHLETIC and ENGO_SPECTATOR types share the same subtype domain (EnGoRacetrackSubtype: [0,7]) + * - ENGO_GRAVEYARD types have their own subtype domain (EnGoGraveyardSubtype: [0,1]) + * - Others have no subtypes. + */ +typedef enum EnGoType { /* 0 */ ENGO_F_0, - /* 1 */ ENGO_F_1, - /* 2 */ ENGO_F_2, - /* 3 */ ENGO_F_3, - /* 4 */ ENGO_F_4, - /* 5 */ ENGO_F_5, - /* 6 */ ENGO_F_6, - /* 7 */ ENGO_F_7, - /* 8 */ ENGO_F_8, -}; + /* 1 */ ENGO_ATHLETIC, // Racers stretching before the race + /* 2 */ ENGO_SPECTATOR, // Spectators to the race + /* 3 */ ENGO_GATEKEEPER, // Gatekeeper to the Goron Shrine + /* 4 */ ENGO_GRAVEYARD, // Gravemaker and other + /* 5 */ ENGO_ASIDE_STORE, // Shrine Goron outside store + /* 6 */ ENGO_ASIDE_ELDERSROOM, // Shrine Goron outside Elder's room + /* 7 */ ENGO_ASIDE_ELDERSSON, // Shrine Goron aside the Elder's Son + /* 8 */ ENGO_MEDIGORON, // Medigoron selling Powder Kegs +} EnGoType; -enum { - /* 0 */ ENGO_70_0, - /* 1 */ ENGO_70_1, - /* 2 */ ENGO_70_2, - /* 3 */ ENGO_70_3, - /* 4 */ ENGO_70_4, - /* 5 */ ENGO_70_5, -}; +/** + * Subtype for Gorons at the racetrack (ENGO_ATHLETIC and ENGO_SPECTATOR) + */ +typedef enum EnGoRacetrackSubtype { + /* 0 */ ENGO_ATHLETIC_A, + /* 1 */ ENGO_ATHLETIC_B, + /* 2 */ ENGO_ATHLETIC_C, + /* 3 */ ENGO_ATHLETIC_D, + /* 4 */ ENGO_ATHLETIC_HAMSTRINGSIT, + /* 5 */ ENGO_ATHLETIC_HAMSTRINGSTAND, + /* 6 */ ENGO_SPECTATOR_CHEER, + /* 7 */ ENGO_SPECTATOR_SHOUTING, +} EnGoRacetrackSubtype; -typedef struct { - /* 0x00 */ u8 unk_00; - /* 0x01 */ u8 unk_01; - /* 0x02 */ u8 unk_02; - /* 0x04 */ Vec3s unk_04; - /* 0x0A */ Vec3s unk_0A; - /* 0x10 */ Vec3f unk_10; - /* 0x1C */ Vec3f unk_1C; - /* 0x28 */ Vec3f unk_28; - /* 0x34 */ f32 unk_34; - /* 0x38 */ f32 unk_38; -} EnGoStruct; // size = 0x3C; +/** + * Subtype for Gorons outside the Goron Graveyard (ENGO_GRAVEYARD) + */ +typedef enum EnGoGraveyardSubtype { + /* 0 */ ENGO_GRAVEYARD_GRAVEMAKER, + /* 1 */ ENGO_GRAVEYARD_FROZEN, +} EnGoGraveyardSubtype; typedef struct EnGo { /* 0x000 */ Actor actor; /* 0x144 */ SkelAnime skelAnime; /* 0x188 */ EnGoActionFunc actionFunc; - /* 0x18C */ EnGoActionFunc unk_18C; - /* 0x190 */ EnGoActionFunc unk_190; + /* 0x18C */ EnGoActionFunc interruptedActionFunc; + /* 0x190 */ EnGoActionFunc graveyardDialogActionFunc; /* 0x194 */ ColliderCylinder colliderCylinder; - /* 0x1E0 */ UNK_TYPE1 unk1E0[0x4C]; + /* 0x1E0 */ ColliderCylinder unusedCylinder; /* 0x22C */ ColliderSphere colliderSphere; - /* 0x284 */ Path* unk_284; - /* 0x288 */ s8 unk_288; - /* 0x289 */ s8 unk_289; - /* 0x28C */ s32 unk_28C; - /* 0x290 */ Vec3f unk_290; - /* 0x29C */ Vec3f unk_29C; - /* 0x2A8 */ Vec3s unk_2A8; - /* 0x2AE */ Vec3s unk_2AE; - /* 0x2B4 */ Vec3s jointTable[18]; - /* 0x320 */ Vec3s morphTable[18]; - /* 0x38C */ Actor* unk_38C; - /* 0x390 */ u16 unk_390; - /* 0x392 */ u16 unk_392; - /* 0x394 */ u8 cueId; - /* 0x398 */ f32 unk_398; - /* 0x39C */ f32 unk_39C; - /* 0x3A0 */ f32 unk_3A0; - /* 0x3A4 */ f32 unk_3A4; - /* 0x3A8 */ f32 unk_3A8; + /* 0x284 */ Path* gatekeeperPath; + /* 0x288 */ s8 taisouObjIndex; + /* 0x289 */ s8 hakuginDemoObjIndex; + /* 0x28C */ s32 msgScriptResumePos; + /* 0x290 */ Vec3f headPos; + /* 0x29C */ Vec3f bodyPos; + /* 0x2A8 */ Vec3s headRot; + /* 0x2AE */ Vec3s bodyRot; + /* 0x2B4 */ Vec3s jointTable[GORON_LIMB_MAX]; + /* 0x320 */ Vec3s morphTable[GORON_LIMB_MAX]; + /* 0x38C */ Actor* attentionTarget; + /* 0x390 */ u16 actionFlags; + /* 0x392 */ u16 lastTextId; + /* 0x394 */ u8 springArrivalCueId; + /* 0x398 */ f32 curAnimPlaySpeed; + /* 0x39C */ f32 iceBlockScale; + /* 0x3A0 */ f32 iceBlockAlpha; + /* 0x3A4 */ f32 scaleFactor; + /* 0x3A8 */ f32 scaleFactorPoundDistortion; /* 0x3AC */ UNK_TYPE1 unk3AC[0x2]; - /* 0x3AE */ s16 unk_3AE; - /* 0x3B0 */ s16 unk_3B0; - /* 0x3B2 */ s16 unk_3B2; - /* 0x3B4 */ s16 unk_3B4; - /* 0x3B6 */ s16 unk_3B6; + /* 0x3AE */ union { + s16 snorePhase; // Used whilst a Goron is sleeping, +0x400 at a time + s16 elapsedHangtime; // Hangtime at the top of a pound. + }; + /* 0x3B0 */ s16 headRotZ; + /* 0x3B2 */ s16 headRotY; + /* 0x3B4 */ s16 bodyRotZ; + /* 0x3B6 */ s16 bodyRotY; /* 0x3B8 */ s16 csId; - /* 0x3BA */ s16 unk_3BA; - /* 0x3BC */ s16 unk_3BC; - /* 0x3BE */ s16 unk_3BE; - /* 0x3C0 */ s16 unk_3C0; - /* 0x3C2 */ s16 unk_3C2; - /* 0x3C4 */ s16 unk_3C4; - /* 0x3C6 */ s16 unk_3C6; - /* 0x3C8 */ s16 unk_3C8[3]; - /* 0x3CE */ s16 unk_3CE[3]; - /* 0x3D4 */ s16 unk_3D4; - /* 0x3D8 */ void* unk_3D8; - /* 0x3DC */ s32 unk_3DC; + /* 0x3BA */ s16 loseAttentionTimer; + /* 0x3BC */ s16 blinkTimer; + /* 0x3BE */ s16 eyeTexIndex; + /* 0x3C0 */ s16 cutsceneState; + /* 0x3C2 */ s16 cutsceneDelayTimer; + /* 0x3C4 */ s16 gatekeeperAnimState; + /* 0x3C6 */ s16 harmlessTimer; + /* 0x3C8 */ s16 limbRotTableZ[3]; + /* 0x3CE */ s16 limbRotTableY[3]; + /* 0x3D4 */ s16 surprisePhase; + /* 0x3D8 */ MsgEventFunc msgEventFunc; + /* 0x3DC */ s32 curAnimIndex; /* 0x3E0 */ UNK_TYPE1 unk3E0[0x4]; - /* 0x3E4 */ s32 unk_3E4; - /* 0x3E8 */ s32 unk_3E8; - /* 0x3EC */ s32 unk_3EC; - /* 0x3F0 */ s32 unk_3F0; - /* 0x3F4 */ s32 unk_3F4; - /* 0x3F8 */ EnGoStruct unk_3F8[32]; + /* 0x3E4 */ s32 indexPathPoint; + /* 0x3E8 */ s32 indexEffect; + /* 0x3EC */ s32 sleepState; + /* 0x3F0 */ s32 springArrivalCutsceneActive; + /* 0x3F4 */ s32 changedText; + /* 0x3F8 */ EnGoEffect effectTable[ENGO_EFFECT_COUNT]; } EnGo; // size = 0xB78 #endif // Z_EN_GO_H 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 27c3279e60..54fe2698dc 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 @@ -171,12 +171,12 @@ static AnimationInfoS sAnimationInfo[] = { { &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 }, + { &gGoronAthleticsDoubleArmSideBendAnim, 1.0f, 0, -1, ANIMMODE_LOOP, 0 }, + { &gGoronAthleticsShakeLimbsAnim, 1.0f, 0, -1, ANIMMODE_LOOP, 0 }, + { &gGoronAthleticsSingleArmSideBendAnim, 1.0f, 0, -1, ANIMMODE_LOOP, 0 }, + { &gGoronAthleticsHamstringStretchStandingAnim, 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 }, + { &gGoronAthleticsCheerAnim, 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 }, @@ -235,7 +235,7 @@ u16 EnSGoro_ShrineGoron_NextTextId(EnSGoro* this, PlayState* play) { switch (EN_S_GORO_GET_MAIN_TYPE(&this->actor)) { case EN_S_GORO_TYPE_SHRINE_WINTER_A: - if (!CHECK_WEEKEVENTREG(WEEKEVENTREG_22_04)) { + if (!CHECK_WEEKEVENTREG(WEEKEVENTREG_CALMED_GORON_ELDERS_SON)) { if (player->transformation == PLAYER_FORM_GORON) { if (!CHECK_WEEKEVENTREG(WEEKEVENTREG_36_02)) { switch (this->textId) { @@ -302,7 +302,7 @@ u16 EnSGoro_ShrineGoron_NextTextId(EnSGoro* this, PlayState* play) { break; case EN_S_GORO_TYPE_SHRINE_WINTER_B: - if (!CHECK_WEEKEVENTREG(WEEKEVENTREG_22_04)) { + if (!CHECK_WEEKEVENTREG(WEEKEVENTREG_CALMED_GORON_ELDERS_SON)) { if (player->transformation == PLAYER_FORM_GORON) { if (!CHECK_WEEKEVENTREG(WEEKEVENTREG_36_40)) { switch (this->textId) { @@ -367,7 +367,7 @@ u16 EnSGoro_ShrineGoron_NextTextId(EnSGoro* this, PlayState* play) { break; case EN_S_GORO_TYPE_SHRINE_WINTER_C: - if (!CHECK_WEEKEVENTREG(WEEKEVENTREG_22_04)) { + if (!CHECK_WEEKEVENTREG(WEEKEVENTREG_CALMED_GORON_ELDERS_SON)) { if (player->transformation == PLAYER_FORM_GORON) { if (!CHECK_WEEKEVENTREG(WEEKEVENTREG_37_02)) { switch (this->textId) { @@ -771,7 +771,7 @@ void EnSGoro_UpdateSleeping(EnSGoro* this, PlayState* play) { Actor_PlaySfx(&this->actor, NA_SE_EN_GOLON_SNORE1); } } - } else if (CHECK_WEEKEVENTREG(WEEKEVENTREG_22_04)) { + } else if (CHECK_WEEKEVENTREG(WEEKEVENTREG_CALMED_GORON_ELDERS_SON)) { this->actionFlags &= ~EN_S_GORO_ACTIONFLAG_SUPPRESS_SNORE; } @@ -842,7 +842,7 @@ s32 EnSGoro_CheckGKBehavior(EnSGoro* this, PlayState* play) { return false; } if ((!(this->actionFlags & EN_S_GORO_ACTIONFLAG_GKQUIET_ACKNOWLEDGED)) && - ((((EnGk*)this->otherGoron)->unk_1E4 & 0x80) || CHECK_WEEKEVENTREG(WEEKEVENTREG_22_04))) { + ((((EnGk*)this->otherGoron)->unk_1E4 & 0x80) || CHECK_WEEKEVENTREG(WEEKEVENTREG_CALMED_GORON_ELDERS_SON))) { this->actionFlags |= EN_S_GORO_ACTIONFLAG_GKQUIET_ACKNOWLEDGED; this->animInfoIndex = EN_S_GORO_ANIM_ROLLUP; @@ -1026,7 +1026,7 @@ void EnSGoro_SetupAction(EnSGoro* this, PlayState* play) { if (Object_IsLoaded(&play->objectCtx, this->loadedObjIndex)) { this->actionFlags = 0; if (EN_S_GORO_OFTYPE_WSHRINE) { - if (CHECK_WEEKEVENTREG(WEEKEVENTREG_22_04)) { + if (CHECK_WEEKEVENTREG(WEEKEVENTREG_CALMED_GORON_ELDERS_SON)) { this->actionFlags |= EN_S_GORO_ACTIONFLAG_GKQUIET_ACKNOWLEDGED; this->actionFlags |= EN_S_GORO_ACTIONFLAG_EYESOPEN; this->animInfoIndex = EN_S_GORO_ANIM_SHIVER_A; diff --git a/tools/disasm/functions.txt b/tools/disasm/functions.txt index 088d66ce96..4c65de06c4 100644 --- a/tools/disasm/functions.txt +++ b/tools/disasm/functions.txt @@ -9675,76 +9675,76 @@ 0x80A10368:("EnSob1_ZoraShopkeeper_Draw",), 0x80A104E4:("EnSob1_GoronShopkeeper_Draw",), 0x80A10608:("EnSob1_BombShopkeeper_Draw",), - 0x80A10FD0:("func_80A10FD0",), - 0x80A11144:("func_80A11144",), - 0x80A1143C:("func_80A1143C",), - 0x80A115B4:("func_80A115B4",), - 0x80A118F8:("func_80A118F8",), - 0x80A11BF8:("func_80A11BF8",), - 0x80A11EC0:("func_80A11EC0",), - 0x80A1203C:("func_80A1203C",), - 0x80A1213C:("func_80A1213C",), - 0x80A121F4:("func_80A121F4",), - 0x80A1222C:("func_80A1222C",), - 0x80A122EC:("func_80A122EC",), - 0x80A123A0:("func_80A123A0",), - 0x80A124A0:("func_80A124A0",), - 0x80A124FC:("func_80A124FC",), - 0x80A125BC:("func_80A125BC",), - 0x80A12660:("func_80A12660",), - 0x80A126BC:("func_80A126BC",), - 0x80A12774:("func_80A12774",), - 0x80A12868:("func_80A12868",), - 0x80A12954:("func_80A12954",), - 0x80A12A64:("func_80A12A64",), - 0x80A12B78:("func_80A12B78",), - 0x80A12C48:("func_80A12C48",), - 0x80A12D6C:("func_80A12D6C",), - 0x80A12DF4:("func_80A12DF4",), - 0x80A12E80:("func_80A12E80",), - 0x80A12FE8:("func_80A12FE8",), - 0x80A131F8:("func_80A131F8",), - 0x80A132C8:("func_80A132C8",), - 0x80A133A8:("func_80A133A8",), - 0x80A13400:("func_80A13400",), - 0x80A134B0:("func_80A134B0",), - 0x80A134F4:("func_80A134F4",), - 0x80A13564:("func_80A13564",), + 0x80A10FD0:("EnGo_InitSteam",), + 0x80A11144:("EnGo_DrawSteam",), + 0x80A1143C:("EnGo_InitDust",), + 0x80A115B4:("EnGo_DrawDust",), + 0x80A118F8:("EnGo_InitSnow",), + 0x80A11BF8:("EnGo_UpdateSnow",), + 0x80A11EC0:("EnGo_DrawSnow",), + 0x80A1203C:("EnGo_UpdateEffects",), + 0x80A1213C:("EnGo_DrawEffects",), + 0x80A121F4:("EnGo_CanSnowballHurtPlayer",), + 0x80A1222C:("EnGo_IsFallingAsleep",), + 0x80A122EC:("EnGo_UpdateFocus",), + 0x80A123A0:("EnGo_UpdateSnowballCollider",), + 0x80A124A0:("EnGo_UpdateMedigoronCollider",), + 0x80A124FC:("EnGo_UpdateRolledUpCollider",), + 0x80A125BC:("EnGo_UpdateFrozenCollider",), + 0x80A12660:("EnGo_UpdateStandingCollider",), + 0x80A126BC:("EnGo_UpdateCollider",), + 0x80A12774:("EnGo_UpdateTalking",), + 0x80A12868:("EnGo_DetectCollisions",), + 0x80A12954:("EnGo_UpdateSpringArrivalCutscene",), + 0x80A12A64:("EnGo_UpdateAnimationToCurrent",), + 0x80A12B78:("EnGo_UpdateSfx",), + 0x80A12C48:("EnGo_ChangeAnim",), + 0x80A12D6C:("EnGo_UpdateEyes",), + 0x80A12DF4:("EnGo_UpdateShiverSurprisedAnimation",), + 0x80A12E80:("EnGo_UpdateGraveyardAttentionTargetAndReactions",), + 0x80A12FE8:("EnGo_UpdateRotationToTarget",), + 0x80A131F8:("EnGo_UpdateAttentionTargetAndReactions",), + 0x80A132C8:("EnGo_GravemakerIdle",), + 0x80A133A8:("EnGo_FrozenIdle",), + 0x80A13400:("EnGo_FindGravemaker",), + 0x80A134B0:("EnGo_UpdateMedigoronColliderRadius",), + 0x80A134F4:("EnGo_ChangeCutscene",), + 0x80A13564:("EnGo_HandleGatekeeperPoundCutscene",), 0x80A136B8:("EnGo_RequestQuake",), - 0x80A13728:("func_80A13728",), - 0x80A137C0:("func_80A137C0",), - 0x80A139E4:("func_80A139E4",), - 0x80A13B1C:("func_80A13B1C",), - 0x80A13E80:("func_80A13E80",), - 0x80A14018:("func_80A14018",), - 0x80A14104:("func_80A14104",), - 0x80A141D4:("func_80A141D4",), - 0x80A1428C:("func_80A1428C",), - 0x80A14324:("func_80A14324",), - 0x80A143A8:("func_80A143A8",), - 0x80A14430:("func_80A14430",), - 0x80A1449C:("func_80A1449C",), - 0x80A144F4:("func_80A144F4",), - 0x80A145AC:("func_80A145AC",), - 0x80A14668:("func_80A14668",), - 0x80A146CC:("func_80A146CC",), - 0x80A14798:("func_80A14798",), - 0x80A149B0:("func_80A149B0",), - 0x80A14B30:("func_80A14B30",), - 0x80A14E14:("func_80A14E14",), - 0x80A14E74:("func_80A14E74",), - 0x80A14EB0:("func_80A14EB0",), - 0x80A14FC8:("func_80A14FC8",), - 0x80A153FC:("func_80A153FC",), - 0x80A15684:("func_80A15684",), - 0x80A157C4:("func_80A157C4",), + 0x80A13728:("EnGo_CreateGatekeeperPoundEffects",), + 0x80A137C0:("EnGo_DrawIceBlockWhenFrozen",), + 0x80A139E4:("EnGo_MakeSteam",), + 0x80A13B1C:("EnGo_HandleOpenShrineCutscene",), + 0x80A13E80:("EnGo_HandleGivePowderKegCutscene",), + 0x80A14018:("EnGo_ChangeToStretchingAnimation",), + 0x80A14104:("EnGo_ChangeToSpectatingAnimation",), + 0x80A141D4:("EnGo_ChangeToFrozenAnimation",), + 0x80A1428C:("EnGo_ChangeToSnowballAnimation",), + 0x80A14324:("EnGo_ChangeToCoveringEarsAnimation",), + 0x80A143A8:("EnGo_ChangeToShiveringAnimation",), + 0x80A14430:("EnGo_SetupAthletic",), + 0x80A1449C:("EnGo_SetupSpectator",), + 0x80A144F4:("EnGo_SetupGatekeeper",), + 0x80A145AC:("EnGo_SetupGraveyardGoron",), + 0x80A14668:("EnGo_SetupShrineGoron",), + 0x80A146CC:("EnGo_SetupMedigoron",), + 0x80A14798:("EnGo_SetupInitialAction",), + 0x80A149B0:("EnGo_Idle",), + 0x80A14B30:("EnGo_Sleep",), + 0x80A14E14:("EnGo_Frozen",), + 0x80A14E74:("EnGo_AwaitThaw",), + 0x80A14EB0:("EnGo_Thaw",), + 0x80A14FC8:("EnGo_HandleSpringArrivalCutscene",), + 0x80A153FC:("EnGo_Snowball",), + 0x80A15684:("EnGo_GetMsgEventScript",), + 0x80A157C4:("EnGo_Talk",), 0x80A1590C:("EnGo_Init",), 0x80A15960:("EnGo_Destroy",), 0x80A159B0:("EnGo_Update",), - 0x80A15B80:("func_80A15B80",), + 0x80A15B80:("EnGo_Draw_NoSkeleton",), 0x80A15D04:("EnGo_OverrideLimbDraw",), 0x80A15E38:("EnGo_TransfromLimbDraw",), - 0x80A15FEC:("func_80A15FEC",), + 0x80A15FEC:("EnGo_Draw",), 0x80A16D40:("EnRaf_ClearPixelTeeth",), 0x80A16D6C:("EnRaf_ClearPixelPetal",), 0x80A16D90:("EnRaf_Init",), diff --git a/tools/weekeventregconvert.py b/tools/weekeventregconvert.py index b96696b46d..28b64d2fa1 100755 --- a/tools/weekeventregconvert.py +++ b/tools/weekeventregconvert.py @@ -155,7 +155,7 @@ weekEventReg = { (18 << 8) | 0x10: "WEEKEVENTREG_18_10", (18 << 8) | 0x20: "WEEKEVENTREG_18_20", (18 << 8) | 0x40: "WEEKEVENTREG_18_40", - (18 << 8) | 0x80: "WEEKEVENTREG_18_80", + (18 << 8) | 0x80: "WEEKEVENTREG_HAS_POWDERKEG_PRIVILEGES", (19 << 8) | 0x01: "WEEKEVENTREG_19_01", (19 << 8) | 0x02: "WEEKEVENTREG_19_02", (19 << 8) | 0x04: "WEEKEVENTREG_19_04", @@ -174,15 +174,15 @@ weekEventReg = { (20 << 8) | 0x80: "WEEKEVENTREG_20_80", (21 << 8) | 0x01: "WEEKEVENTREG_21_01", (21 << 8) | 0x02: "WEEKEVENTREG_21_02", - (21 << 8) | 0x04: "WEEKEVENTREG_21_04", - (21 << 8) | 0x08: "WEEKEVENTREG_21_08", + (21 << 8) | 0x04: "WEEKEVENTREG_TALKED_GORON_GRAVEMAKER_AS_GORON", + (21 << 8) | 0x08: "WEEKEVENTREG_TALKED_THAWED_GRAVEYARD_GORON", (21 << 8) | 0x10: "WEEKEVENTREG_21_10", (21 << 8) | 0x20: "WEEKEVENTREG_21_20", (21 << 8) | 0x40: "WEEKEVENTREG_21_40", (21 << 8) | 0x80: "WEEKEVENTREG_21_80", (22 << 8) | 0x01: "WEEKEVENTREG_22_01", (22 << 8) | 0x02: "WEEKEVENTREG_22_02", - (22 << 8) | 0x04: "WEEKEVENTREG_22_04", + (22 << 8) | 0x04: "WEEKEVENTREG_CALMED_GORON_ELDERS_SON", (22 << 8) | 0x08: "WEEKEVENTREG_22_08", (22 << 8) | 0x10: "WEEKEVENTREG_22_10", (22 << 8) | 0x20: "WEEKEVENTREG_22_20", @@ -714,11 +714,11 @@ weekEventReg = { (88 << 8) | 0x08: "WEEKEVENTREG_88_08", (88 << 8) | 0x10: "WEEKEVENTREG_88_10", (88 << 8) | 0x20: "WEEKEVENTREG_88_20", - (88 << 8) | 0x40: "WEEKEVENTREG_88_40", - (88 << 8) | 0x80: "WEEKEVENTREG_88_80", - (89 << 8) | 0x01: "WEEKEVENTREG_89_01", - (89 << 8) | 0x02: "WEEKEVENTREG_89_02", - (89 << 8) | 0x04: "WEEKEVENTREG_89_04", + (88 << 8) | 0x40: "WEEKEVENTREG_GATEKEEPER_OPENED_GORON_SHRINE", + (88 << 8) | 0x80: "WEEKEVENTREG_GATEKEEPER_OPENED_GORON_SHRINE_FOR_HUMAN", + (89 << 8) | 0x01: "WEEKEVENTREG_GATEKEEPER_OPENED_GORON_SHRINE_FOR_DEKU", + (89 << 8) | 0x02: "WEEKEVENTREG_GATEKEEPER_OPENED_GORON_SHRINE_FOR_ZORA", + (89 << 8) | 0x04: "WEEKEVENTREG_GATEKEEPER_OPENED_GORON_SHRINE_FOR_GORON", (89 << 8) | 0x08: "WEEKEVENTREG_89_08", (89 << 8) | 0x10: "WEEKEVENTREG_89_10", (89 << 8) | 0x20: "WEEKEVENTREG_89_20",