diff --git a/assets/xml/overlays/ovl_En_Syateki_Okuta.xml b/assets/xml/overlays/ovl_En_Syateki_Okuta.xml index 0e5054c19f..aa38c85339 100644 --- a/assets/xml/overlays/ovl_En_Syateki_Okuta.xml +++ b/assets/xml/overlays/ovl_En_Syateki_Okuta.xml @@ -7,7 +7,7 @@ - - + + diff --git a/src/overlays/actors/ovl_En_Syateki_Man/z_en_syateki_man.c b/src/overlays/actors/ovl_En_Syateki_Man/z_en_syateki_man.c index f5910a06dd..a5c4ad4e25 100644 --- a/src/overlays/actors/ovl_En_Syateki_Man/z_en_syateki_man.c +++ b/src/overlays/actors/ovl_En_Syateki_Man/z_en_syateki_man.c @@ -10,6 +10,7 @@ #include "z_en_syateki_man.h" #include "overlays/actors/ovl_En_Syateki_Crow/z_en_syateki_crow.h" #include "overlays/actors/ovl_En_Syateki_Dekunuts/z_en_syateki_dekunuts.h" +#include "overlays/actors/ovl_En_Syateki_Okuta/z_en_syateki_okuta.h" #include "overlays/actors/ovl_En_Syateki_Wf/z_en_syateki_wf.h" #define FLAGS (ACTOR_FLAG_1 | ACTOR_FLAG_8 | ACTOR_FLAG_10 | ACTOR_FLAG_CANT_LOCK_ON) @@ -49,15 +50,10 @@ void EnSyatekiMan_Town_EndGame(EnSyatekiMan* this, PlayState* play); #define TALK_FLAG_SWAMP_HAS_SPOKEN_WITH_HUMAN (1 << 0) #define TALK_FLAG_SWAMP_HAS_EXPLAINED_THE_RULES (1 << 1) -#define OCTOROK_FLAG(color, row, column) (1 << ((row * 6) + (column * 2) + color)) -#define COLOR_RED 0 -#define COLOR_BLUE 1 -#define ROW_BACK 0 -#define ROW_CENTER 1 -#define ROW_FRONT 2 -#define COLUMN_LEFT 0 -#define COLUMN_CENTER 1 -#define COLUMN_RIGHT 2 +#define OCTO_FLAGS(type0, type1, type2, type3, type4, type5, type6, type7, type8) \ + (SG_OCTO_SET_FLAG(type0, 0) | SG_OCTO_SET_FLAG(type1, 1) | SG_OCTO_SET_FLAG(type2, 2) | \ + SG_OCTO_SET_FLAG(type3, 3) | SG_OCTO_SET_FLAG(type4, 4) | SG_OCTO_SET_FLAG(type5, 5) | \ + SG_OCTO_SET_FLAG(type6, 6) | SG_OCTO_SET_FLAG(type7, 7) | SG_OCTO_SET_FLAG(type8, 8)) ActorInit En_Syateki_Man_InitVars = { ACTOR_EN_SYATEKI_MAN, @@ -201,7 +197,7 @@ void EnSyatekiMan_Init(Actor* thisx, PlayState* play) { this->shootingGameState = SG_GAME_STATE_NONE; this->talkWaitTimer = 15; this->flagsIndex = 0; - this->perGameVar2.octorokHitType = SG_OCTO_HIT_TYPE_NONE; + this->perGameVar2.lastHitOctorokType = SG_OCTO_TYPE_NONE; this->octorokFlags = 0; this->dekuScrubFlags = 0; this->guayFlags = 0; @@ -1227,7 +1223,7 @@ void EnSyatekiMan_Town_StartGame(EnSyatekiMan* this, PlayState* play) { this->score = 0; this->flagsIndex = 0; this->perGameVar1.octorokState = SG_OCTO_STATE_INITIAL; - this->perGameVar2.octorokHitType = SG_OCTO_HIT_TYPE_NONE; + this->perGameVar2.lastHitOctorokType = SG_OCTO_TYPE_NONE; sGameStartTimer = 30; Interface_StartTimer(TIMER_ID_MINIGAME_1, 75); this->actor.draw = NULL; @@ -1240,62 +1236,67 @@ void EnSyatekiMan_Town_StartGame(EnSyatekiMan* this, PlayState* play) { * For each wave, these flags are used to control which Octoroks appear. */ static const s32 sOctorokFlagsPerWave[] = { - OCTOROK_FLAG(COLOR_RED, ROW_CENTER, COLUMN_CENTER) | OCTOROK_FLAG(COLOR_RED, ROW_BACK, COLUMN_RIGHT) | - OCTOROK_FLAG(COLOR_RED, ROW_BACK, COLUMN_LEFT), + // clang-format off + OCTO_FLAGS(SG_OCTO_TYPE_RED, SG_OCTO_TYPE_NONE, SG_OCTO_TYPE_RED, + SG_OCTO_TYPE_NONE, SG_OCTO_TYPE_RED, SG_OCTO_TYPE_NONE, + SG_OCTO_TYPE_NONE, SG_OCTO_TYPE_NONE, SG_OCTO_TYPE_NONE), - OCTOROK_FLAG(COLOR_RED, ROW_CENTER, COLUMN_RIGHT) | OCTOROK_FLAG(COLOR_BLUE, ROW_CENTER, COLUMN_CENTER) | - OCTOROK_FLAG(COLOR_RED, ROW_CENTER, COLUMN_LEFT) | OCTOROK_FLAG(COLOR_RED, ROW_BACK, COLUMN_RIGHT), + OCTO_FLAGS(SG_OCTO_TYPE_NONE, SG_OCTO_TYPE_NONE, SG_OCTO_TYPE_RED, + SG_OCTO_TYPE_RED, SG_OCTO_TYPE_BLUE, SG_OCTO_TYPE_RED, + SG_OCTO_TYPE_NONE, SG_OCTO_TYPE_NONE, SG_OCTO_TYPE_NONE), - OCTOROK_FLAG(COLOR_RED, ROW_FRONT, COLUMN_RIGHT) | OCTOROK_FLAG(COLOR_BLUE, ROW_BACK, COLUMN_RIGHT) | - OCTOROK_FLAG(COLOR_RED, ROW_BACK, COLUMN_CENTER) | OCTOROK_FLAG(COLOR_RED, ROW_BACK, COLUMN_LEFT), + OCTO_FLAGS(SG_OCTO_TYPE_RED, SG_OCTO_TYPE_RED, SG_OCTO_TYPE_BLUE, + SG_OCTO_TYPE_NONE, SG_OCTO_TYPE_NONE, SG_OCTO_TYPE_NONE, + SG_OCTO_TYPE_NONE, SG_OCTO_TYPE_NONE, SG_OCTO_TYPE_RED), - OCTOROK_FLAG(COLOR_RED, ROW_FRONT, COLUMN_RIGHT) | OCTOROK_FLAG(COLOR_RED, ROW_FRONT, COLUMN_LEFT) | - OCTOROK_FLAG(COLOR_RED, ROW_BACK, COLUMN_RIGHT) | OCTOROK_FLAG(COLOR_RED, ROW_BACK, COLUMN_LEFT), + OCTO_FLAGS(SG_OCTO_TYPE_RED, SG_OCTO_TYPE_NONE, SG_OCTO_TYPE_RED, + SG_OCTO_TYPE_NONE, SG_OCTO_TYPE_NONE, SG_OCTO_TYPE_NONE, + SG_OCTO_TYPE_RED, SG_OCTO_TYPE_NONE, SG_OCTO_TYPE_RED), - OCTOROK_FLAG(COLOR_BLUE, ROW_CENTER, COLUMN_RIGHT) | OCTOROK_FLAG(COLOR_RED, ROW_CENTER, COLUMN_CENTER) | - OCTOROK_FLAG(COLOR_BLUE, ROW_CENTER, COLUMN_LEFT) | OCTOROK_FLAG(COLOR_RED, ROW_BACK, COLUMN_CENTER), + OCTO_FLAGS(SG_OCTO_TYPE_NONE, SG_OCTO_TYPE_RED, SG_OCTO_TYPE_NONE, + SG_OCTO_TYPE_BLUE, SG_OCTO_TYPE_RED, SG_OCTO_TYPE_BLUE, + SG_OCTO_TYPE_NONE, SG_OCTO_TYPE_NONE, SG_OCTO_TYPE_NONE), - OCTOROK_FLAG(COLOR_RED, ROW_FRONT, COLUMN_CENTER) | OCTOROK_FLAG(COLOR_RED, ROW_CENTER, COLUMN_LEFT) | - OCTOROK_FLAG(COLOR_RED, ROW_BACK, COLUMN_RIGHT), + OCTO_FLAGS(SG_OCTO_TYPE_NONE, SG_OCTO_TYPE_NONE, SG_OCTO_TYPE_RED, + SG_OCTO_TYPE_RED, SG_OCTO_TYPE_NONE, SG_OCTO_TYPE_NONE, + SG_OCTO_TYPE_NONE, SG_OCTO_TYPE_RED, SG_OCTO_TYPE_NONE), - OCTOROK_FLAG(COLOR_RED, ROW_FRONT, COLUMN_RIGHT) | OCTOROK_FLAG(COLOR_BLUE, ROW_CENTER, COLUMN_CENTER) | - OCTOROK_FLAG(COLOR_RED, ROW_BACK, COLUMN_RIGHT) | OCTOROK_FLAG(COLOR_RED, ROW_BACK, COLUMN_LEFT), + OCTO_FLAGS(SG_OCTO_TYPE_RED, SG_OCTO_TYPE_NONE, SG_OCTO_TYPE_RED, + SG_OCTO_TYPE_NONE, SG_OCTO_TYPE_BLUE, SG_OCTO_TYPE_NONE, + SG_OCTO_TYPE_NONE, SG_OCTO_TYPE_NONE, SG_OCTO_TYPE_RED), - OCTOROK_FLAG(COLOR_BLUE, ROW_FRONT, COLUMN_RIGHT) | OCTOROK_FLAG(COLOR_BLUE, ROW_FRONT, COLUMN_LEFT) | - OCTOROK_FLAG(COLOR_RED, ROW_BACK, COLUMN_RIGHT) | OCTOROK_FLAG(COLOR_RED, ROW_BACK, COLUMN_CENTER) | - OCTOROK_FLAG(COLOR_RED, ROW_BACK, COLUMN_LEFT), + OCTO_FLAGS(SG_OCTO_TYPE_RED, SG_OCTO_TYPE_RED, SG_OCTO_TYPE_RED, + SG_OCTO_TYPE_NONE, SG_OCTO_TYPE_NONE, SG_OCTO_TYPE_NONE, + SG_OCTO_TYPE_BLUE, SG_OCTO_TYPE_NONE, SG_OCTO_TYPE_BLUE), - OCTOROK_FLAG(COLOR_BLUE, ROW_FRONT, COLUMN_RIGHT) | OCTOROK_FLAG(COLOR_RED, ROW_FRONT, COLUMN_CENTER) | - OCTOROK_FLAG(COLOR_BLUE, ROW_FRONT, COLUMN_LEFT) | OCTOROK_FLAG(COLOR_BLUE, ROW_CENTER, COLUMN_RIGHT) | - OCTOROK_FLAG(COLOR_RED, ROW_CENTER, COLUMN_CENTER) | OCTOROK_FLAG(COLOR_BLUE, ROW_CENTER, COLUMN_LEFT) | - OCTOROK_FLAG(COLOR_RED, ROW_BACK, COLUMN_CENTER), + OCTO_FLAGS(SG_OCTO_TYPE_NONE, SG_OCTO_TYPE_RED, SG_OCTO_TYPE_NONE, + SG_OCTO_TYPE_BLUE, SG_OCTO_TYPE_RED, SG_OCTO_TYPE_BLUE, + SG_OCTO_TYPE_BLUE, SG_OCTO_TYPE_RED, SG_OCTO_TYPE_BLUE), - OCTOROK_FLAG(COLOR_RED, ROW_FRONT, COLUMN_RIGHT) | OCTOROK_FLAG(COLOR_BLUE, ROW_FRONT, COLUMN_LEFT) | - OCTOROK_FLAG(COLOR_BLUE, ROW_CENTER, COLUMN_RIGHT) | OCTOROK_FLAG(COLOR_RED, ROW_CENTER, COLUMN_LEFT) | - OCTOROK_FLAG(COLOR_RED, ROW_BACK, COLUMN_RIGHT) | OCTOROK_FLAG(COLOR_BLUE, ROW_BACK, COLUMN_LEFT), + OCTO_FLAGS(SG_OCTO_TYPE_BLUE, SG_OCTO_TYPE_NONE, SG_OCTO_TYPE_RED, + SG_OCTO_TYPE_RED, SG_OCTO_TYPE_NONE, SG_OCTO_TYPE_BLUE, + SG_OCTO_TYPE_BLUE, SG_OCTO_TYPE_NONE, SG_OCTO_TYPE_RED), - OCTOROK_FLAG(COLOR_RED, ROW_FRONT, COLUMN_RIGHT) | OCTOROK_FLAG(COLOR_RED, ROW_FRONT, COLUMN_LEFT) | - OCTOROK_FLAG(COLOR_BLUE, ROW_CENTER, COLUMN_RIGHT) | OCTOROK_FLAG(COLOR_RED, ROW_CENTER, COLUMN_CENTER) | - OCTOROK_FLAG(COLOR_BLUE, ROW_CENTER, COLUMN_LEFT) | OCTOROK_FLAG(COLOR_RED, ROW_BACK, COLUMN_RIGHT) | - OCTOROK_FLAG(COLOR_BLUE, ROW_BACK, COLUMN_CENTER) | OCTOROK_FLAG(COLOR_RED, ROW_BACK, COLUMN_LEFT), + OCTO_FLAGS(SG_OCTO_TYPE_RED, SG_OCTO_TYPE_BLUE, SG_OCTO_TYPE_RED, + SG_OCTO_TYPE_BLUE, SG_OCTO_TYPE_RED, SG_OCTO_TYPE_BLUE, + SG_OCTO_TYPE_RED, SG_OCTO_TYPE_NONE, SG_OCTO_TYPE_RED), - OCTOROK_FLAG(COLOR_BLUE, ROW_FRONT, COLUMN_RIGHT) | OCTOROK_FLAG(COLOR_BLUE, ROW_FRONT, COLUMN_LEFT) | - OCTOROK_FLAG(COLOR_BLUE, ROW_CENTER, COLUMN_RIGHT) | OCTOROK_FLAG(COLOR_BLUE, ROW_CENTER, COLUMN_LEFT) | - OCTOROK_FLAG(COLOR_RED, ROW_BACK, COLUMN_RIGHT) | OCTOROK_FLAG(COLOR_RED, ROW_BACK, COLUMN_CENTER) | - OCTOROK_FLAG(COLOR_RED, ROW_BACK, COLUMN_LEFT), + OCTO_FLAGS(SG_OCTO_TYPE_RED, SG_OCTO_TYPE_RED, SG_OCTO_TYPE_RED, + SG_OCTO_TYPE_BLUE, SG_OCTO_TYPE_NONE, SG_OCTO_TYPE_BLUE, + SG_OCTO_TYPE_BLUE, SG_OCTO_TYPE_NONE, SG_OCTO_TYPE_BLUE), - OCTOROK_FLAG(COLOR_RED, ROW_CENTER, COLUMN_RIGHT) | OCTOROK_FLAG(COLOR_RED, ROW_CENTER, COLUMN_CENTER) | - OCTOROK_FLAG(COLOR_RED, ROW_CENTER, COLUMN_LEFT) | OCTOROK_FLAG(COLOR_BLUE, ROW_BACK, COLUMN_RIGHT) | - OCTOROK_FLAG(COLOR_BLUE, ROW_BACK, COLUMN_CENTER) | OCTOROK_FLAG(COLOR_BLUE, ROW_BACK, COLUMN_LEFT), + OCTO_FLAGS(SG_OCTO_TYPE_BLUE, SG_OCTO_TYPE_BLUE, SG_OCTO_TYPE_BLUE, + SG_OCTO_TYPE_RED, SG_OCTO_TYPE_RED, SG_OCTO_TYPE_RED, + SG_OCTO_TYPE_NONE, SG_OCTO_TYPE_NONE, SG_OCTO_TYPE_NONE), - OCTOROK_FLAG(COLOR_BLUE, ROW_FRONT, COLUMN_RIGHT) | OCTOROK_FLAG(COLOR_BLUE, ROW_FRONT, COLUMN_CENTER) | - OCTOROK_FLAG(COLOR_BLUE, ROW_FRONT, COLUMN_LEFT) | OCTOROK_FLAG(COLOR_RED, ROW_CENTER, COLUMN_RIGHT) | - OCTOROK_FLAG(COLOR_RED, ROW_CENTER, COLUMN_LEFT) | OCTOROK_FLAG(COLOR_RED, ROW_BACK, COLUMN_RIGHT) | - OCTOROK_FLAG(COLOR_RED, ROW_BACK, COLUMN_LEFT), + OCTO_FLAGS(SG_OCTO_TYPE_RED, SG_OCTO_TYPE_NONE, SG_OCTO_TYPE_RED, + SG_OCTO_TYPE_RED, SG_OCTO_TYPE_NONE, SG_OCTO_TYPE_RED, + SG_OCTO_TYPE_BLUE, SG_OCTO_TYPE_BLUE, SG_OCTO_TYPE_BLUE), - OCTOROK_FLAG(COLOR_RED, ROW_FRONT, COLUMN_CENTER) | OCTOROK_FLAG(COLOR_RED, ROW_CENTER, COLUMN_CENTER) | - OCTOROK_FLAG(COLOR_RED, ROW_BACK, COLUMN_RIGHT) | OCTOROK_FLAG(COLOR_RED, ROW_BACK, COLUMN_CENTER) | - OCTOROK_FLAG(COLOR_RED, ROW_BACK, COLUMN_LEFT), + OCTO_FLAGS(SG_OCTO_TYPE_RED, SG_OCTO_TYPE_RED, SG_OCTO_TYPE_RED, + SG_OCTO_TYPE_NONE, SG_OCTO_TYPE_RED, SG_OCTO_TYPE_NONE, + SG_OCTO_TYPE_NONE, SG_OCTO_TYPE_RED, SG_OCTO_TYPE_NONE), + // clang-format on }; void EnSyatekiMan_Town_RunGame(EnSyatekiMan* this, PlayState* play) { @@ -1323,16 +1324,16 @@ void EnSyatekiMan_Town_RunGame(EnSyatekiMan* this, PlayState* play) { this->perGameVar1.octorokState = SG_OCTO_STATE_HIDING; } - if (this->perGameVar2.octorokHitType != SG_OCTO_HIT_TYPE_NONE) { - if (this->perGameVar2.octorokHitType == SG_OCTO_HIT_TYPE_BLUE) { + if (this->perGameVar2.lastHitOctorokType != SG_OCTO_TYPE_NONE) { + if (this->perGameVar2.lastHitOctorokType == SG_OCTO_TYPE_BLUE) { gSaveContext.timerTimeLimits[TIMER_ID_MINIGAME_1] -= SECONDS_TO_TIMER_PRECISE(2, 50); sModFromLosingTime = (sModFromLosingTime + 25) % 50; } - this->perGameVar2.octorokHitType = SG_OCTO_HIT_TYPE_NONE; + this->perGameVar2.lastHitOctorokType = SG_OCTO_TYPE_NONE; } - if (this->perGameVar1.octorokState == SG_OCTO_STATE_SPAWNING) { + if (this->perGameVar1.octorokState == SG_OCTO_STATE_APPEARING) { this->perGameVar1.octorokState++; } @@ -1340,10 +1341,10 @@ void EnSyatekiMan_Town_RunGame(EnSyatekiMan* this, PlayState* play) { // that the player might have lost time from hitting Blue Octoroks, so we do something similar to // what was done with waveTimer above. if ((sModFromLosingTime == (timer % 50)) && (this->perGameVar1.octorokState >= SG_OCTO_STATE_INITIAL)) { - if (this->flagsIndex < 15) { + if (this->flagsIndex < ARRAY_COUNT(sOctorokFlagsPerWave)) { this->octorokFlags = sOctorokFlagsPerWave[this->flagsIndex++]; Actor_PlaySfx(&this->actor, NA_SE_SY_FOUND); - this->perGameVar1.octorokState = SG_OCTO_STATE_SPAWNING; + this->perGameVar1.octorokState = SG_OCTO_STATE_APPEARING; } } diff --git a/src/overlays/actors/ovl_En_Syateki_Man/z_en_syateki_man.h b/src/overlays/actors/ovl_En_Syateki_Man/z_en_syateki_man.h index 468cb981c6..28d19871ba 100644 --- a/src/overlays/actors/ovl_En_Syateki_Man/z_en_syateki_man.h +++ b/src/overlays/actors/ovl_En_Syateki_Man/z_en_syateki_man.h @@ -22,18 +22,12 @@ typedef enum { } ShootingGalleryGameState; typedef enum { - /* 0 */ SG_OCTO_STATE_SPAWNING, - /* 1 */ SG_OCTO_STATE_SPAWNED, + /* 0 */ SG_OCTO_STATE_APPEARING, + /* 1 */ SG_OCTO_STATE_APPEARED, /* 70 */ SG_OCTO_STATE_INITIAL = 70, /* 80 */ SG_OCTO_STATE_HIDING = 80 } ShootingGalleryOctorokState; -typedef enum { - /* 0 */ SG_OCTO_HIT_TYPE_NONE, - /* 1 */ SG_OCTO_HIT_TYPE_RED, - /* 2 */ SG_OCTO_HIT_TYPE_BLUE -} ShootingGalleryoctorokHitType; - typedef enum { /* 0 */ SG_PATH_TYPE_CROW, /* 1 */ SG_PATH_TYPE_SCRUB_NORMAL, @@ -62,7 +56,7 @@ typedef struct EnSyatekiMan { } perGameVar1; /* 0x26E */ union { s16 bonusDekuScrubHitCounter; - s16 octorokHitType; + s16 lastHitOctorokType; } perGameVar2; /* 0x270 */ s16 talkWaitTimer; /* 0x272 */ s16 dekuScrubFlags; diff --git a/src/overlays/actors/ovl_En_Syateki_Okuta/z_en_syateki_okuta.c b/src/overlays/actors/ovl_En_Syateki_Okuta/z_en_syateki_okuta.c index 5711b86fe0..5673439cf3 100644 --- a/src/overlays/actors/ovl_En_Syateki_Okuta/z_en_syateki_okuta.c +++ b/src/overlays/actors/ovl_En_Syateki_Okuta/z_en_syateki_okuta.c @@ -16,17 +16,17 @@ void EnSyatekiOkuta_Destroy(Actor* thisx, PlayState* play); void EnSyatekiOkuta_Update(Actor* thisx, PlayState* play); void EnSyatekiOkuta_Draw(Actor* thisx, PlayState* play); -void func_80A36260(EnSyatekiOkuta* this); -void func_80A362A8(EnSyatekiOkuta* this, PlayState* play); -void func_80A362F8(EnSyatekiOkuta* this); -void func_80A36350(EnSyatekiOkuta* this, PlayState* play); -void func_80A363B4(EnSyatekiOkuta* this, PlayState* play); -void func_80A36444(EnSyatekiOkuta* this); -void func_80A36488(EnSyatekiOkuta* this, PlayState* play); -void func_80A364C0(EnSyatekiOkuta* this); -void func_80A36504(EnSyatekiOkuta* this, PlayState* play); -void func_80A365EC(EnSyatekiOkuta* this, PlayState* play); -void func_80A36CB0(EnSyatekiOkuta* this); +void EnSyatekiOkuta_SetupAttachToShootingGalleryMan(EnSyatekiOkuta* this); +void EnSyatekiOkuta_AttachToShootingGalleryMan(EnSyatekiOkuta* this, PlayState* play); +void EnSyatekiOkuta_SetupDoNothing(EnSyatekiOkuta* this); +void EnSyatekiOkuta_DoNothing(EnSyatekiOkuta* this, PlayState* play); +void EnSyatekiOkuta_Appear(EnSyatekiOkuta* this, PlayState* play); +void EnSyatekiOkuta_SetupFloat(EnSyatekiOkuta* this); +void EnSyatekiOkuta_Float(EnSyatekiOkuta* this, PlayState* play); +void EnSyatekiOkuta_SetupHide(EnSyatekiOkuta* this); +void EnSyatekiOkuta_Hide(EnSyatekiOkuta* this, PlayState* play); +void EnSyatekiOkuta_Die(EnSyatekiOkuta* this, PlayState* play); +void EnSyatekiOkuta_UpdateHeadScale(EnSyatekiOkuta* this); ActorInit En_Syateki_Okuta_InitVars = { ACTOR_EN_SYATEKI_OKUTA, @@ -60,13 +60,23 @@ static ColliderCylinderInit sCylinderInit = { { 20, 40, -30, { 0, 0, 0 } }, }; +typedef enum { + /* 0 */ SG_OCTO_ANIM_SHOOT, // unused + /* 1 */ SG_OCTO_ANIM_DIE, + /* 2 */ SG_OCTO_ANIM_HIDE, + /* 3 */ SG_OCTO_ANIM_FLOAT, + /* 4 */ SG_OCTO_ANIM_APPEAR, + /* 5 */ SG_OCTO_ANIM_HIT, // unused + /* 6 */ SG_OCTO_ANIM_MAX +} ShootingGalleryOctorokAnimation; + static AnimationInfo sAnimationInfo[] = { - { &gOctorokShootAnim, 1.0f, 0.0f, 0.0f, ANIMMODE_ONCE, -1.0f }, - { &gOctorokDieAnim, 1.0f, 0.0f, 0.0f, ANIMMODE_ONCE, -1.0f }, - { &gOctorokHideAnim, 1.0f, 0.0f, 0.0f, ANIMMODE_ONCE, -1.0f }, - { &gOctorokFloatAnim, 1.0f, 0.0f, 0.0f, ANIMMODE_LOOP, -1.0f }, - { &gOctorokAppearAnim, 1.0f, 0.0f, 0.0f, ANIMMODE_ONCE, -1.0f }, - { &gOctorokHitAnim, 1.0f, 0.0f, 0.0f, ANIMMODE_ONCE, -1.0f }, + { &gOctorokShootAnim, 1.0f, 0.0f, 0.0f, ANIMMODE_ONCE, -1.0f }, // SG_OCTO_ANIM_SHOOT + { &gOctorokDieAnim, 1.0f, 0.0f, 0.0f, ANIMMODE_ONCE, -1.0f }, // SG_OCTO_ANIM_DIE + { &gOctorokHideAnim, 1.0f, 0.0f, 0.0f, ANIMMODE_ONCE, -1.0f }, // SG_OCTO_ANIM_HIDE + { &gOctorokFloatAnim, 1.0f, 0.0f, 0.0f, ANIMMODE_LOOP, -1.0f }, // SG_OCTO_ANIM_FLOAT + { &gOctorokAppearAnim, 1.0f, 0.0f, 0.0f, ANIMMODE_ONCE, -1.0f }, // SG_OCTO_ANIM_APPEAR + { &gOctorokHitAnim, 1.0f, 0.0f, 0.0f, ANIMMODE_ONCE, -1.0f }, // SG_OCTO_ANIM_HIT }; #include "assets/overlays/ovl_En_Syateki_Okuta/ovl_En_Syateki_Okuta.c" @@ -76,16 +86,6 @@ static InitChainEntry sInitChain[] = { ICHAIN_F32(targetArrowOffset, 6500, ICHAIN_STOP), }; -Color_RGBA8 D_80A37B90 = { 255, 255, 255, 255 }; - -Color_RGBA8 D_80A37B94 = { 150, 150, 150, 255 }; - -Vec3f D_80A37B98 = { 0.0f, -0.5, 0.0f }; - -Color_RGBA8 D_80A37BA4 = { 255, 255, 255, 255 }; - -Color_RGBA8 D_80A37BA8 = { 150, 150, 150, 0 }; - void EnSyatekiOkuta_Init(Actor* thisx, PlayState* play) { s32 pad; EnSyatekiOkuta* this = THIS; @@ -110,9 +110,9 @@ void EnSyatekiOkuta_Init(Actor* thisx, PlayState* play) { this->actor.world.pos.y = this->actor.home.pos.y = ySurface; } - this->unk_2A4 = 0; - this->unk_2AA = 0; - func_80A36260(this); + this->deathTimer = 0; + this->hitResultAlpha = 0; + EnSyatekiOkuta_SetupAttachToShootingGalleryMan(this); } void EnSyatekiOkuta_Destroy(Actor* thisx, PlayState* play) { @@ -121,30 +121,45 @@ void EnSyatekiOkuta_Destroy(Actor* thisx, PlayState* play) { Collider_DestroyCylinder(play, &this->collider); } -void func_80A36148(Vec3f* pos, Vec3f* velocity, s16 scaleStep, PlayState* play) { - func_800B0DE0(play, pos, velocity, &gZeroVec3f, &D_80A37B90, &D_80A37B94, 400, scaleStep); +/** + * Spawns the puff of smoke that appears when the Octorok disappears when it dies. + */ +void EnSyatekiOkuta_SpawnDust(Vec3f* pos, Vec3f* velocity, s16 scaleStep, PlayState* play) { + static Color_RGBA8 sDustPrimColor = { 255, 255, 255, 255 }; + static Color_RGBA8 sDustEnvColor = { 150, 150, 150, 255 }; + + func_800B0DE0(play, pos, velocity, &gZeroVec3f, &sDustPrimColor, &sDustEnvColor, 400, scaleStep); } -void func_80A361B0(EnSyatekiOkuta* this, PlayState* play) { +/** + * Spawns the splash that appears when the Octorok appears from underwater, hides underwater, or dies. + */ +void EnSyatekiOkuta_SpawnSplash(EnSyatekiOkuta* this, PlayState* play) { EffectSsGSplash_Spawn(play, &this->actor.home.pos, NULL, NULL, 0, 800); } -s32 func_80A361F4(EnSyatekiOkuta* this) { - s32 temp_a0; - s32 temp_a1; - s32 temp_v1; +/* + * Returns true if this Octorok is hidden (in other words, if it's in the center + * column and has another Octorok in front of it), false otherwise. + */ +s32 EnSyatekiOkuta_IsHiddenByAnotherOctorok(EnSyatekiOkuta* this) { EnSyatekiMan* syatekiMan = (EnSyatekiMan*)this->actor.parent; + s32 index = SG_OCTO_GET_INDEX(&this->actor); - temp_v1 = EN_SYATEKI_OKUTA_GET_F(&this->actor); - if ((temp_v1 == 1) || (temp_v1 == 4)) { - temp_a0 = syatekiMan->octorokFlags; - temp_a1 = (temp_v1 * 2) + 6; - - if ((temp_a0 >> temp_a1) & 3) { + // Only the Octoroks in the center column can be obscured by another Octorok. The Octoroks in the + // left and right columns are always visible, since the player looks at them from an angle. + // Additionally, the Octorok in the front row is always visible, even if it's in the center column. + if ((index == SG_OCTO_INDEX_FOR_POS(SG_OCTO_ROW_BACK, SG_OCTO_COL_CENTER)) || + (index == SG_OCTO_INDEX_FOR_POS(SG_OCTO_ROW_CENTER, SG_OCTO_COL_CENTER))) { + // Checks to see if this Octorok is hidden by an Octorok immediately in front of it. + if (SG_OCTO_GET_TYPE(syatekiMan->octorokFlags, SG_OCTO_INDEX_DIRECTLY_IN_FRONT(index)) != SG_OCTO_TYPE_NONE) { return true; } - if ((temp_a1 == 8) && ((temp_a0 >> 0xE) & 3)) { + // If this Octorok is in the back row, it can also be hidden by an Octorok in the front row. + if ((index == SG_OCTO_INDEX_FOR_POS(SG_OCTO_ROW_BACK, SG_OCTO_COL_CENTER)) && + (SG_OCTO_GET_TYPE(syatekiMan->octorokFlags, SG_OCTO_INDEX_FOR_POS(SG_OCTO_ROW_FRONT, SG_OCTO_COL_CENTER)) != + SG_OCTO_TYPE_NONE)) { return true; } } @@ -152,142 +167,177 @@ s32 func_80A361F4(EnSyatekiOkuta* this) { return false; } -void func_80A36260(EnSyatekiOkuta* this) { +void EnSyatekiOkuta_SetupAttachToShootingGalleryMan(EnSyatekiOkuta* this) { Animation_PlayOnceSetSpeed(&this->skelAnime, &gOctorokAppearAnim, 0.0f); this->actor.draw = NULL; - this->actionFunc = func_80A362A8; + this->actionFunc = EnSyatekiOkuta_AttachToShootingGalleryMan; } -void func_80A362A8(EnSyatekiOkuta* this, PlayState* play) { +/** + * Checks every NPC actor in the scene to find the Shooting Gallery Man. Once it finds him, this will + * make him the parent to the Octorok. This is required because the Octoroks are normally spawned as + * part of the Town Shooting Gallery scene, so they don't have anything that links them to the Shooting + * Gallery Man, and the Octoroks need a pointer to him in order to access his Octorok flags. If this + * actor is spawned in a scene *without* the Shooting Gallery Man, its action function will never change + * from this function, and the Octorok will effectively do nothing. + */ +void EnSyatekiOkuta_AttachToShootingGalleryMan(EnSyatekiOkuta* this, PlayState* play) { Actor* actorIt = play->actorCtx.actorLists[ACTORCAT_NPC].first; while (actorIt != NULL) { if (actorIt->id == ACTOR_EN_SYATEKI_MAN) { this->actor.parent = actorIt; - func_80A362F8(this); + EnSyatekiOkuta_SetupDoNothing(this); break; - } else { - actorIt = actorIt->next; } + + actorIt = actorIt->next; } } -void func_80A362F8(EnSyatekiOkuta* this) { +/** + * Stops the Octorok's animation, prevents it from drawing, and sets its action function to do nothing. + * The intention here is to stay in this action function doing nothing until the Shooting Gallery Man + * tells it to appear in EnSyatekiOkuta_CheckForSignal, at which point the action function will be changed. + */ +void EnSyatekiOkuta_SetupDoNothing(EnSyatekiOkuta* this) { Animation_PlayOnceSetSpeed(&this->skelAnime, &gOctorokAppearAnim, 0.0f); this->actor.draw = NULL; Actor_SetScale(&this->actor, 0.01f); - this->actionFunc = func_80A36350; + this->actionFunc = EnSyatekiOkuta_DoNothing; } -void func_80A36350(EnSyatekiOkuta* this, PlayState* play) { +void EnSyatekiOkuta_DoNothing(EnSyatekiOkuta* this, PlayState* play) { } -void func_80A36360(EnSyatekiOkuta* this) { +void EnSyatekiOkuta_SetupAppear(EnSyatekiOkuta* this) { this->actor.draw = EnSyatekiOkuta_Draw; - this->unk_2AA = 0; - Actor_ChangeAnimationByInfo(&this->skelAnime, sAnimationInfo, 4); - this->actionFunc = func_80A363B4; + this->hitResultAlpha = 0; + Actor_ChangeAnimationByInfo(&this->skelAnime, sAnimationInfo, SG_OCTO_ANIM_APPEAR); + this->actionFunc = EnSyatekiOkuta_Appear; } -void func_80A363B4(EnSyatekiOkuta* this, PlayState* play) { +/** + * Jumps out of the water and starts floating. + */ +void EnSyatekiOkuta_Appear(EnSyatekiOkuta* this, PlayState* play) { if (Animation_OnFrame(&this->skelAnime, 2.0f) || Animation_OnFrame(&this->skelAnime, 15.0f)) { - if (func_80A361F4(this)) { + if (EnSyatekiOkuta_IsHiddenByAnotherOctorok(this)) { return; } - func_80A361B0(this, play); + + EnSyatekiOkuta_SpawnSplash(this, play); Actor_PlaySfx(&this->actor, NA_SE_EN_OCTAROCK_JUMP); } if (Animation_OnFrame(&this->skelAnime, this->skelAnime.endFrame)) { - func_80A36444(this); + EnSyatekiOkuta_SetupFloat(this); } } -void func_80A36444(EnSyatekiOkuta* this) { - Actor_ChangeAnimationByInfo(&this->skelAnime, sAnimationInfo, 3); - this->actionFunc = func_80A36488; +void EnSyatekiOkuta_SetupFloat(EnSyatekiOkuta* this) { + Actor_ChangeAnimationByInfo(&this->skelAnime, sAnimationInfo, SG_OCTO_ANIM_FLOAT); + this->actionFunc = EnSyatekiOkuta_Float; } -void func_80A36488(EnSyatekiOkuta* this, PlayState* play) { +/** + * Floats in place until the Shooting Gallery Man tells it to hide. + */ +void EnSyatekiOkuta_Float(EnSyatekiOkuta* this, PlayState* play) { EnSyatekiMan* syatekiMan = (EnSyatekiMan*)this->actor.parent; + // In practice, if the Octorok is floating, then the octorokState is either SG_OCTO_STATE_APPEARED or + // SG_OCTO_STATE_HIDING. Only the latter state is greater than SG_OCTO_STATE_INITIAL, so that's what + // this check is looking for. if (syatekiMan->perGameVar1.octorokState >= SG_OCTO_STATE_INITIAL) { - func_80A364C0(this); + EnSyatekiOkuta_SetupHide(this); } } -void func_80A364C0(EnSyatekiOkuta* this) { - Actor_ChangeAnimationByInfo(&this->skelAnime, sAnimationInfo, 2); - this->actionFunc = func_80A36504; +void EnSyatekiOkuta_SetupHide(EnSyatekiOkuta* this) { + Actor_ChangeAnimationByInfo(&this->skelAnime, sAnimationInfo, SG_OCTO_ANIM_HIDE); + this->actionFunc = EnSyatekiOkuta_Hide; } -void func_80A36504(EnSyatekiOkuta* this, PlayState* play) { +/** + * Retreats underwater, then makes the Octorok do nothing until the Shooting Gallery Man tells it to appear again. + */ +void EnSyatekiOkuta_Hide(EnSyatekiOkuta* this, PlayState* play) { if (Animation_OnFrame(&this->skelAnime, 4.0f)) { - func_80A361B0(this, play); + EnSyatekiOkuta_SpawnSplash(this, play); Actor_PlaySfx(&this->actor, NA_SE_EN_DAIOCTA_LAND); } else if (Animation_OnFrame(&this->skelAnime, this->skelAnime.endFrame)) { - func_80A362F8(this); + EnSyatekiOkuta_SetupDoNothing(this); } } -void func_80A3657C(EnSyatekiOkuta* this) { - this->unk_2A4 = 0; - this->unk_2AA = 300; - if (this->unk_2A6 == 1) { +void EnSyatekiOkuta_SetupDie(EnSyatekiOkuta* this) { + this->deathTimer = 0; + this->hitResultAlpha = 300; + if (this->type == SG_OCTO_TYPE_RED) { Actor_PlaySfx(&this->actor, NA_SE_EN_OCTAROCK_DEAD1); } - Actor_ChangeAnimationByInfo(&this->skelAnime, sAnimationInfo, 1); - this->actionFunc = func_80A365EC; + Actor_ChangeAnimationByInfo(&this->skelAnime, sAnimationInfo, SG_OCTO_ANIM_DIE); + this->actionFunc = EnSyatekiOkuta_Die; } -void func_80A365EC(EnSyatekiOkuta* this, PlayState* play) { - Vec3f sp84; - Vec3f sp78; +/** + * Plays the death animation and slowly shrinks the Octorok. Also spawns various bubble and dust + * effects as it dies. Once the Octorok is finished with its death animation, this function will + * make it do nothing until the Shooting Gallery Man tells it to appear again. + */ +void EnSyatekiOkuta_Die(EnSyatekiOkuta* this, PlayState* play) { + static Vec3f sBubbleAccel = { 0.0f, -0.5, 0.0f }; + static Color_RGBA8 sBubblePrimColor = { 255, 255, 255, 255 }; + static Color_RGBA8 sBubbleEnvColor = { 150, 150, 150, 0 }; + Vec3f velocity; + Vec3f pos; s32 pad; s32 i; - if (this->unk_2AA > 0) { - this->unk_2AA -= 15; + if (this->hitResultAlpha > 0) { + this->hitResultAlpha -= 15; } if (Animation_OnFrame(&this->skelAnime, this->skelAnime.endFrame)) { - if (this->unk_2A4 == 0) { - sp78.x = this->actor.world.pos.x; - sp78.y = this->actor.world.pos.y + 40.0f; - sp78.z = this->actor.world.pos.z; - sp84.x = 0.0f; - sp84.y = -0.5f; - sp84.z = 0.0f; - func_80A36148(&sp78, &sp84, -20, play); + if (this->deathTimer == 0) { + pos.x = this->actor.world.pos.x; + pos.y = this->actor.world.pos.y + 40.0f; + pos.z = this->actor.world.pos.z; + velocity.x = 0.0f; + velocity.y = -0.5f; + velocity.z = 0.0f; + EnSyatekiOkuta_SpawnDust(&pos, &velocity, -20, play); Actor_PlaySfx(&this->actor, NA_SE_EN_OCTAROCK_DEAD2); } - this->unk_2A4++; + this->deathTimer++; } if (Animation_OnFrame(&this->skelAnime, 15.0f)) { - func_80A361B0(this, play); + EnSyatekiOkuta_SpawnSplash(this, play); } - if (this->unk_2A4 < 3) { - Actor_SetScale(&this->actor, ((this->unk_2A4 * 0.25f) + 1.0f) * 0.01f); - } else if (this->unk_2A4 < 6) { - Actor_SetScale(&this->actor, (1.5f - ((this->unk_2A4 - 2) * 0.2333f)) * 0.01f); - } else if (this->unk_2A4 < 11) { - Actor_SetScale(&this->actor, (((this->unk_2A4 - 5) * 0.04f) + 0.8f) * 0.01f); + if (this->deathTimer < 3) { + Actor_SetScale(&this->actor, ((this->deathTimer * 0.25f) + 1.0f) * 0.01f); + } else if (this->deathTimer < 6) { + Actor_SetScale(&this->actor, (1.5f - ((this->deathTimer - 2) * 0.2333f)) * 0.01f); + } else if (this->deathTimer < 11) { + Actor_SetScale(&this->actor, (((this->deathTimer - 5) * 0.04f) + 0.8f) * 0.01f); } else { if (Math_StepToF(&this->actor.scale.x, 0.0f, 0.002f)) { SoundSource_PlaySfxAtFixedWorldPos(play, &this->actor.world.pos, 30, NA_SE_EN_COMMON_WATER_MID); for (i = 0; i < 10; i++) { - sp84.x = (Rand_ZeroOne() - 0.5f) * 7.0f; - sp84.y = Rand_ZeroOne() * 7.0f; - sp84.z = (Rand_ZeroOne() - 0.5f) * 7.0f; - EffectSsDtBubble_SpawnCustomColor(play, &this->actor.world.pos, &sp84, &D_80A37B98, &D_80A37BA4, - &D_80A37BA8, Rand_S16Offset(100, 50), 25, false); + velocity.x = (Rand_ZeroOne() - 0.5f) * 7.0f; + velocity.y = Rand_ZeroOne() * 7.0f; + velocity.z = (Rand_ZeroOne() - 0.5f) * 7.0f; + EffectSsDtBubble_SpawnCustomColor(play, &this->actor.world.pos, &velocity, &sBubbleAccel, + &sBubblePrimColor, &sBubbleEnvColor, Rand_S16Offset(100, 50), 25, + false); } - func_80A362F8(this); + EnSyatekiOkuta_SetupDoNothing(this); } this->actor.scale.y = this->actor.scale.x; @@ -295,13 +345,17 @@ void func_80A365EC(EnSyatekiOkuta* this, PlayState* play) { } } -void func_80A368E0(EnSyatekiOkuta* this, PlayState* play) { +/** + * Adjusts the collider's dimensions and position based on a few different factors, like the Octorok's + * type, current scale and head scale, and current action. + */ +void EnSyatekiOkuta_UpdateCollision(EnSyatekiOkuta* this, PlayState* play) { this->collider.dim.height = - (sCylinderInit.dim.height - this->collider.dim.yShift) * this->unk_1D8.y * this->actor.scale.y * 100.0f; + (sCylinderInit.dim.height - this->collider.dim.yShift) * this->headScale.y * this->actor.scale.y * 100.0f; this->collider.dim.radius = sCylinderInit.dim.radius * this->actor.scale.x * 100.0f; - if (this->actionFunc == func_80A363B4) { - if ((this->unk_2A6 == 2) && func_80A361F4(this)) { + if (this->actionFunc == EnSyatekiOkuta_Appear) { + if ((this->type == SG_OCTO_TYPE_BLUE) && EnSyatekiOkuta_IsHiddenByAnotherOctorok(this)) { return; } @@ -310,7 +364,7 @@ void func_80A368E0(EnSyatekiOkuta* this, PlayState* play) { } } - if (this->unk_2A6 == 1) { + if (this->type == SG_OCTO_TYPE_RED) { this->collider.dim.radius += 10; this->collider.dim.height += 15; } @@ -322,8 +376,11 @@ void func_80A368E0(EnSyatekiOkuta* this, PlayState* play) { CollisionCheck_SetAC(play, &play->colChkCtx, &this->collider.base); } -s32 func_80A36A90(EnSyatekiOkuta* this, PlayState* play) { - if ((this->actionFunc == func_80A365EC) || (this->actionFunc == func_80A36350)) { +/** + * Returns true if the Octorok has been hit, false otherwise. + */ +s32 EnSyatekiOkuta_CheckCollision(EnSyatekiOkuta* this, PlayState* play) { + if ((this->actionFunc == EnSyatekiOkuta_Die) || (this->actionFunc == EnSyatekiOkuta_DoNothing)) { return false; } @@ -332,22 +389,28 @@ s32 func_80A36A90(EnSyatekiOkuta* this, PlayState* play) { return true; } - func_80A368E0(this, play); + EnSyatekiOkuta_UpdateCollision(this, play); return false; } -void func_80A36AF8(EnSyatekiOkuta* this, PlayState* play) { +/** + * Checks to see if both the archery game and this Octorok are in the appropriate state to consider + * appearing. If the conditions are right, then the Shooting Gallery Man's Octorok flags determine + * what type this Octorok should be for the current wave; if the type is *not* SG_OCTO_TYPE_NONE, + * then this Octorok will set itself to the appropriate type and get ready to jump out of the water. + */ +void EnSyatekiOkuta_CheckForSignal(EnSyatekiOkuta* this, PlayState* play) { EnSyatekiMan* syatekiMan = (EnSyatekiMan*)this->actor.parent; - s16 temp_v1_2; + s16 type; - if ((this->actionFunc != func_80A36488) && (this->actionFunc != func_80A363B4) && + if ((this->actionFunc != EnSyatekiOkuta_Float) && (this->actionFunc != EnSyatekiOkuta_Appear) && (syatekiMan->shootingGameState == SG_GAME_STATE_RUNNING) && - (syatekiMan->perGameVar1.octorokState == SG_OCTO_STATE_SPAWNING)) { - temp_v1_2 = (syatekiMan->octorokFlags >> (EN_SYATEKI_OKUTA_GET_F(&this->actor) * 2)) & 3; - if (temp_v1_2 > 0) { + (syatekiMan->perGameVar1.octorokState == SG_OCTO_STATE_APPEARING)) { + type = SG_OCTO_GET_TYPE(syatekiMan->octorokFlags, SG_OCTO_GET_INDEX(&this->actor)); + if (type > SG_OCTO_TYPE_NONE) { Actor_SetScale(&this->actor, 0.01f); - this->unk_2A6 = temp_v1_2; - func_80A36360(this); + this->type = type; + EnSyatekiOkuta_SetupAppear(this); } } } @@ -359,101 +422,108 @@ void EnSyatekiOkuta_Update(Actor* thisx, PlayState* play) { this->actionFunc(this, play); - if (this->actionFunc != func_80A36350) { + if (this->actionFunc != EnSyatekiOkuta_DoNothing) { SkelAnime_Update(&this->skelAnime); } - func_80A36AF8(this, play); + EnSyatekiOkuta_CheckForSignal(this, play); - if (func_80A36A90(this, play)) { + if (EnSyatekiOkuta_CheckCollision(this, play)) { syatekiMan = (EnSyatekiMan*)this->actor.parent; - if (this->unk_2A6 == 1) { + if (this->type == SG_OCTO_TYPE_RED) { Actor_PlaySfx(&this->actor, NA_SE_SY_TRE_BOX_APPEAR); play->interfaceCtx.minigamePoints++; syatekiMan->score++; - syatekiMan->perGameVar2.octorokHitType = SG_OCTO_HIT_TYPE_RED; + syatekiMan->perGameVar2.lastHitOctorokType = SG_OCTO_TYPE_RED; } else { Actor_PlaySfx(&this->actor, NA_SE_SY_ERROR); - syatekiMan->perGameVar2.octorokHitType = SG_OCTO_HIT_TYPE_BLUE; + syatekiMan->perGameVar2.lastHitOctorokType = SG_OCTO_TYPE_BLUE; } - func_80A3657C(this); + EnSyatekiOkuta_SetupDie(this); } else { this->collider.base.acFlags &= ~AC_HIT; } - func_80A36CB0(this); + EnSyatekiOkuta_UpdateHeadScale(this); } -void func_80A36CB0(EnSyatekiOkuta* this) { +/** + * Adjusts the scale of the Octorok's head based on their current action and their current animation frame. + */ +void EnSyatekiOkuta_UpdateHeadScale(EnSyatekiOkuta* this) { f32 curFrame = this->skelAnime.curFrame; - if (this->actionFunc == func_80A363B4) { + if (this->actionFunc == EnSyatekiOkuta_Appear) { if (curFrame < 8.0f) { - this->unk_1D8.x = this->unk_1D8.y = this->unk_1D8.z = 1.0f; + this->headScale.x = this->headScale.y = this->headScale.z = 1.0f; } else if (curFrame < 10.0f) { - this->unk_1D8.x = this->unk_1D8.z = 1.0f; - this->unk_1D8.y = ((curFrame - 7.0f) * 0.4f) + 1.0f; + this->headScale.x = this->headScale.z = 1.0f; + this->headScale.y = ((curFrame - 7.0f) * 0.4f) + 1.0f; } else if (curFrame < 14.0f) { - this->unk_1D8.x = this->unk_1D8.z = ((curFrame - 9.0f) * 0.075f) + 1.0f; - this->unk_1D8.y = 1.8f - ((curFrame - 9.0f) * 0.25f); + this->headScale.x = this->headScale.z = ((curFrame - 9.0f) * 0.075f) + 1.0f; + this->headScale.y = 1.8f - ((curFrame - 9.0f) * 0.25f); } else { - this->unk_1D8.x = this->unk_1D8.z = 1.3f - ((curFrame - 13.0f) * 0.05f); - this->unk_1D8.y = ((curFrame - 13.0f) * 0.0333f) + 0.8f; + this->headScale.x = this->headScale.z = 1.3f - ((curFrame - 13.0f) * 0.05f); + this->headScale.y = ((curFrame - 13.0f) * 0.0333f) + 0.8f; } - } else if (this->actionFunc == func_80A36488) { - this->unk_1D8.x = this->unk_1D8.z = 1.0f; - this->unk_1D8.y = (Math_SinF((M_PI / 16) * curFrame) * 0.2f) + 1.0f; - } else if (this->actionFunc == func_80A36504) { + } else if (this->actionFunc == EnSyatekiOkuta_Float) { + this->headScale.x = this->headScale.z = 1.0f; + this->headScale.y = (Math_SinF((M_PI / 16) * curFrame) * 0.2f) + 1.0f; + } else if (this->actionFunc == EnSyatekiOkuta_Hide) { if (curFrame < 3.0f) { - this->unk_1D8.y = 1.0f; + this->headScale.y = 1.0f; } else if (curFrame < 4.0f) { - this->unk_1D8.y = (curFrame - 2.0f) + 1.0f; + this->headScale.y = (curFrame - 2.0f) + 1.0f; } else { - this->unk_1D8.y = 2.0f - ((curFrame - 3.0f) * 0.333f); + this->headScale.y = 2.0f - ((curFrame - 3.0f) * 0.333f); } - this->unk_1D8.x = this->unk_1D8.z = 1.0f; - } else if (this->actionFunc == func_80A365EC) { - curFrame += this->unk_2A4; + this->headScale.x = this->headScale.z = 1.0f; + } else if (this->actionFunc == EnSyatekiOkuta_Die) { + curFrame += this->deathTimer; if (curFrame >= 35.0f) { - this->unk_1D8.x = this->unk_1D8.y = this->unk_1D8.z = 1.0f; + this->headScale.x = this->headScale.y = this->headScale.z = 1.0f; } else if (curFrame < 4.0f) { - this->unk_1D8.x = this->unk_1D8.z = 1.0f - (curFrame * 0.0666f); - this->unk_1D8.y = (curFrame * 0.1666f) + 1.0f; + this->headScale.x = this->headScale.z = 1.0f - (curFrame * 0.0666f); + this->headScale.y = (curFrame * 0.1666f) + 1.0f; } else if (curFrame < 25.0f) { - this->unk_1D8.x = this->unk_1D8.z = ((curFrame - 4.0f) * 0.01f) + 0.8f; - this->unk_1D8.y = 1.5f - ((curFrame - 4.0f) * 0.025f); + this->headScale.x = this->headScale.z = ((curFrame - 4.0f) * 0.01f) + 0.8f; + this->headScale.y = 1.5f - ((curFrame - 4.0f) * 0.025f); } else if (curFrame < 27.0f) { - this->unk_1D8.x = this->unk_1D8.y = this->unk_1D8.z = ((curFrame - 24.0f) * 0.25f) + 1.0f; + this->headScale.x = this->headScale.y = this->headScale.z = ((curFrame - 24.0f) * 0.25f) + 1.0f; } else if (curFrame < 30.0f) { - this->unk_1D8.x = this->unk_1D8.y = this->unk_1D8.z = 1.5f - ((curFrame - 26.0f) * 0.233f); + this->headScale.x = this->headScale.y = this->headScale.z = 1.5f - ((curFrame - 26.0f) * 0.233f); } else { - this->unk_1D8.x = this->unk_1D8.y = this->unk_1D8.z = ((curFrame - 29.0f) * 0.04f) + 0.8f; + this->headScale.x = this->headScale.y = this->headScale.z = ((curFrame - 29.0f) * 0.04f) + 0.8f; } } else { - this->unk_1D8.x = this->unk_1D8.y = this->unk_1D8.z = 1.0f; + this->headScale.x = this->headScale.y = this->headScale.z = 1.0f; } } -s32 func_80A370EC(EnSyatekiOkuta* this, f32 arg1, Vec3f* arg2) { - if (this->actionFunc == func_80A363B4) { - arg2->y = 1.0f; - arg2->z = 1.0f; - arg2->x = (Math_SinF((M_PI / 16) * arg1) * 0.4f) + 1.0f; - } else if (this->actionFunc == func_80A365EC) { - if ((arg1 >= 35.0f) || (arg1 < 25.0f)) { +/** + * Returns true if the snout scale should be updated, false otherwise. The snout scale is returned via the scale + * parameter. + */ +s32 EnSyatekiOkuta_GetSnoutScale(EnSyatekiOkuta* this, f32 curFrame, Vec3f* scale) { + if (this->actionFunc == EnSyatekiOkuta_Appear) { + scale->y = 1.0f; + scale->z = 1.0f; + scale->x = (Math_SinF((M_PI / 16) * curFrame) * 0.4f) + 1.0f; + } else if (this->actionFunc == EnSyatekiOkuta_Die) { + if ((curFrame >= 35.0f) || (curFrame < 25.0f)) { return false; } - if (arg1 < 27.0f) { - arg2->z = 1.0f; - arg2->x = arg2->y = ((arg1 - 24.0f) * 0.5f) + 1.0f; - } else if (arg1 < 30.0f) { - arg2->z = (arg1 - 26.0f) * 0.333f + 1.0f; - arg2->x = arg2->y = 2.0f - (arg1 - 26.0f) * 0.333f; + if (curFrame < 27.0f) { + scale->z = 1.0f; + scale->x = scale->y = ((curFrame - 24.0f) * 0.5f) + 1.0f; + } else if (curFrame < 30.0f) { + scale->z = (curFrame - 26.0f) * 0.333f + 1.0f; + scale->x = scale->y = 2.0f - (curFrame - 26.0f) * 0.333f; } else { - arg2->z = 2.0f - ((arg1 - 29.0f) * 0.2f); - arg2->x = arg2->y = 1.0f; + scale->z = 2.0f - ((curFrame - 29.0f) * 0.2f); + scale->x = scale->y = 1.0f; } } else { return false; @@ -464,20 +534,20 @@ s32 func_80A370EC(EnSyatekiOkuta* this, f32 arg1, Vec3f* arg2) { s32 EnSyatekiOkuta_OverrideLimbDraw(PlayState* play, s32 limbIndex, Gfx** dList, Vec3f* pos, Vec3s* rot, Actor* thisx) { s32 pad; - Vec3f sp20; + Vec3f scale; f32 curFrame; EnSyatekiOkuta* this = THIS; curFrame = this->skelAnime.curFrame; - if (this->actionFunc == func_80A365EC) { - curFrame += this->unk_2A4; + if (this->actionFunc == EnSyatekiOkuta_Die) { + curFrame += this->deathTimer; } if (limbIndex == OCTOROK_LIMB_HEAD) { - sp20 = this->unk_1D8; - Matrix_Scale(sp20.x, sp20.y, sp20.z, MTXMODE_APPLY); - } else if ((limbIndex == OCTOROK_LIMB_SNOUT) && (func_80A370EC(this, curFrame, &sp20))) { - Matrix_Scale(sp20.x, sp20.y, sp20.z, MTXMODE_APPLY); + scale = this->headScale; + Matrix_Scale(scale.x, scale.y, scale.z, MTXMODE_APPLY); + } else if ((limbIndex == OCTOROK_LIMB_SNOUT) && (EnSyatekiOkuta_GetSnoutScale(this, curFrame, &scale))) { + Matrix_Scale(scale.x, scale.y, scale.z, MTXMODE_APPLY); } return false; @@ -489,7 +559,7 @@ void EnSyatekiOkuta_Draw(Actor* thisx, PlayState* play) { OPEN_DISPS(play->state.gfxCtx); Gfx_SetupDL25_Opa(play->state.gfxCtx); - if (this->unk_2A6 == 1) { + if (this->type == SG_OCTO_TYPE_RED) { gSPSegment(POLY_OPA_DISP++, 0x08, D_801AEFA0); } else { gSPSegment(POLY_OPA_DISP++, 0x08, gShootingGalleryOctorokBlueMaterialDL); @@ -497,20 +567,22 @@ void EnSyatekiOkuta_Draw(Actor* thisx, PlayState* play) { SkelAnime_DrawOpa(play, this->skelAnime.skeleton, this->skelAnime.jointTable, EnSyatekiOkuta_OverrideLimbDraw, NULL, &this->actor); + + // Draw the circle or cross that appears when the player hits an Octorok Gfx_SetupDL25_Xlu(play->state.gfxCtx); - if (this->actionFunc == func_80A365EC) { + if (this->actionFunc == EnSyatekiOkuta_Die) { Matrix_Translate(this->actor.world.pos.x, this->actor.world.pos.y + 30.0f, this->actor.world.pos.z + 20.0f, MTXMODE_NEW); - if (this->unk_2AA >= 256) { + if (this->hitResultAlpha > 255) { gDPSetPrimColor(POLY_XLU_DISP++, 0, 0, 210, 64, 32, 255); } else { - gDPSetPrimColor(POLY_XLU_DISP++, 0, 0, 210, 64, 32, this->unk_2AA); + gDPSetPrimColor(POLY_XLU_DISP++, 0, 0, 210, 64, 32, this->hitResultAlpha); } gSPMatrix(POLY_XLU_DISP++, Matrix_NewMtx(play->state.gfxCtx), G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW); - if (this->unk_2A6 == 2) { + if (this->type == SG_OCTO_TYPE_BLUE) { gSPDisplayList(POLY_XLU_DISP++, gShootingGalleryOctorokCrossDL); } else { gSPDisplayList(POLY_XLU_DISP++, gShootingGalleryOctorokCircleDL); diff --git a/src/overlays/actors/ovl_En_Syateki_Okuta/z_en_syateki_okuta.h b/src/overlays/actors/ovl_En_Syateki_Okuta/z_en_syateki_okuta.h index 0527354d06..72be15406d 100644 --- a/src/overlays/actors/ovl_En_Syateki_Okuta/z_en_syateki_okuta.h +++ b/src/overlays/actors/ovl_En_Syateki_Okuta/z_en_syateki_okuta.h @@ -4,7 +4,39 @@ #include "global.h" #include "objects/object_okuta/object_okuta.h" -#define EN_SYATEKI_OKUTA_GET_F(thisx) ((thisx)->params & 0xF) +typedef enum { + /* 0 */ SG_OCTO_TYPE_NONE, + /* 1 */ SG_OCTO_TYPE_RED, + /* 2 */ SG_OCTO_TYPE_BLUE, + /* 3 */ SG_OCTO_TYPE_MAX +} ShootingGalleryOctorokType; + +typedef enum { + /* 0 */ SG_OCTO_ROW_BACK, + /* 1 */ SG_OCTO_ROW_CENTER, + /* 2 */ SG_OCTO_ROW_FRONT, + /* 3 */ SG_OCTO_ROW_MAX +} ShootingGalleryOctorokRow; + +typedef enum { + /* 0 */ SG_OCTO_COL_LEFT, + /* 1 */ SG_OCTO_COL_CENTER, + /* 2 */ SG_OCTO_COL_RIGHT, + /* 3 */ SG_OCTO_COL_MAX +} ShootingGalleryOctorokColumn; + +#define SG_OCTO_GET_INDEX(thisx) ((thisx)->params & 0xF) +#define SG_OCTO_INDEX_FOR_POS(row, column) (((row) * SG_OCTO_COL_MAX) + (column)) + +// This returns the index of the Octorok directly in front of the Octorok at the given index. In other words, it +// returns the index of the Octorok in the same column as the one with the given index, but one row ahead. It's +// assumed that this will only be used for Octoroks in the back or center row; it returns an invalid index for +// Octoroks in the front row. +#define SG_OCTO_INDEX_DIRECTLY_IN_FRONT(index) ((index) + SG_OCTO_COL_MAX) + +// Both of these macros assume that the Octorok types can fit in two bits, hence why the index is multiplied by 2. +#define SG_OCTO_GET_TYPE(octorokFlags, index) (((octorokFlags) >> ((index) * 2)) & SG_OCTO_TYPE_MAX) +#define SG_OCTO_SET_FLAG(type, index) ((type & SG_OCTO_TYPE_MAX) << ((index) * 2)) struct EnSyatekiOkuta; @@ -15,13 +47,13 @@ typedef struct EnSyatekiOkuta { /* 0x144 */ SkelAnime skelAnime; /* 0x188 */ EnSyatekiOkutaActionFunc actionFunc; /* 0x18C */ ColliderCylinder collider; - /* 0x1DC */ Vec3f unk_1D8; + /* 0x1DC */ Vec3f headScale; /* 0x1E4 */ Vec3s jointTable[OCTOROK_LIMB_MAX]; /* 0x244 */ Vec3s morphTable[OCTOROK_LIMB_MAX]; - /* 0x2A4 */ s16 unk_2A4; - /* 0x2A6 */ s16 unk_2A6; + /* 0x2A4 */ s16 deathTimer; + /* 0x2A6 */ s16 type; /* 0x2A8 */ UNK_TYPE1 unk_2A8[0x2]; - /* 0x2AA */ s16 unk_2AA; + /* 0x2AA */ s16 hitResultAlpha; } EnSyatekiOkuta; // size = 0x2AC #endif // Z_EN_SYATEKI_OKUTA_H diff --git a/tools/disasm/functions.txt b/tools/disasm/functions.txt index 4fc8f07c15..fd08f2af82 100644 --- a/tools/disasm/functions.txt +++ b/tools/disasm/functions.txt @@ -10217,27 +10217,27 @@ 0x80A35DDC:("ObjBell_Draw",), 0x80A35FF0:("EnSyatekiOkuta_Init",), 0x80A3611C:("EnSyatekiOkuta_Destroy",), - 0x80A36148:("func_80A36148",), - 0x80A361B0:("func_80A361B0",), - 0x80A361F4:("func_80A361F4",), - 0x80A36260:("func_80A36260",), - 0x80A362A8:("func_80A362A8",), - 0x80A362F8:("func_80A362F8",), - 0x80A36350:("func_80A36350",), - 0x80A36360:("func_80A36360",), - 0x80A363B4:("func_80A363B4",), - 0x80A36444:("func_80A36444",), - 0x80A36488:("func_80A36488",), - 0x80A364C0:("func_80A364C0",), - 0x80A36504:("func_80A36504",), - 0x80A3657C:("func_80A3657C",), - 0x80A365EC:("func_80A365EC",), - 0x80A368E0:("func_80A368E0",), - 0x80A36A90:("func_80A36A90",), - 0x80A36AF8:("func_80A36AF8",), + 0x80A36148:("EnSyatekiOkuta_SpawnDust",), + 0x80A361B0:("EnSyatekiOkuta_SpawnSplash",), + 0x80A361F4:("EnSyatekiOkuta_IsHiddenByAnotherOctorok",), + 0x80A36260:("EnSyatekiOkuta_SetupAttachToShootingGalleryMan",), + 0x80A362A8:("EnSyatekiOkuta_AttachToShootingGalleryMan",), + 0x80A362F8:("EnSyatekiOkuta_SetupDoNothing",), + 0x80A36350:("EnSyatekiOkuta_DoNothing",), + 0x80A36360:("EnSyatekiOkuta_SetupAppear",), + 0x80A363B4:("EnSyatekiOkuta_Appear",), + 0x80A36444:("EnSyatekiOkuta_SetupFloat",), + 0x80A36488:("EnSyatekiOkuta_Float",), + 0x80A364C0:("EnSyatekiOkuta_SetupHide",), + 0x80A36504:("EnSyatekiOkuta_Hide",), + 0x80A3657C:("EnSyatekiOkuta_SetupDie",), + 0x80A365EC:("EnSyatekiOkuta_Die",), + 0x80A368E0:("EnSyatekiOkuta_UpdateCollision",), + 0x80A36A90:("EnSyatekiOkuta_CheckCollision",), + 0x80A36AF8:("EnSyatekiOkuta_CheckForSignal",), 0x80A36B9C:("EnSyatekiOkuta_Update",), - 0x80A36CB0:("func_80A36CB0",), - 0x80A370EC:("func_80A370EC",), + 0x80A36CB0:("EnSyatekiOkuta_UpdateHeadScale",), + 0x80A370EC:("EnSyatekiOkuta_GetSnoutScale",), 0x80A37294:("EnSyatekiOkuta_OverrideLimbDraw",), 0x80A3735C:("EnSyatekiOkuta_Draw",), 0x80A37ED0:("ObjShutter_Init",), diff --git a/tools/disasm/variables.txt b/tools/disasm/variables.txt index b2c82bf7f2..bce95ca116 100644 --- a/tools/disasm/variables.txt +++ b/tools/disasm/variables.txt @@ -11207,11 +11207,11 @@ 0x80A37A88:("D_80A37A88","UNK_TYPE1","",0x1), 0x80A37B08:("D_80A37B08","UNK_TYPE1","",0x1), 0x80A37B88:("D_80A37B88","UNK_TYPE1","",0x1), - 0x80A37B90:("D_80A37B90","UNK_TYPE1","",0x1), - 0x80A37B94:("D_80A37B94","UNK_TYPE1","",0x1), - 0x80A37B98:("D_80A37B98","UNK_TYPE1","",0x1), - 0x80A37BA4:("D_80A37BA4","UNK_TYPE1","",0x1), - 0x80A37BA8:("D_80A37BA8","UNK_TYPE1","",0x1), + 0x80A37B90:("sDustPrimColor","UNK_TYPE1","",0x1), + 0x80A37B94:("sDustEnvColor","UNK_TYPE1","",0x1), + 0x80A37B98:("sBubbleAccel","UNK_TYPE1","",0x1), + 0x80A37BA4:("sBubblePrimColor","UNK_TYPE1","",0x1), + 0x80A37BA8:("sBubbleEnvColor","UNK_TYPE1","",0x1), 0x80A37BB0:("D_80A37BB0","f32","",0x4), 0x80A37BB4:("D_80A37BB4","f32","",0x4), 0x80A37BB8:("D_80A37BB8","f32","",0x4),