Document EnSyatekiOkuta (Shooting Gallery Octorok) (#1287)

* Initial docs

* Tons of stuff done

* Fix spacing thing now that the function is actually named

* Temporarily add un-macro'd flags as comment

* Name and document EnSyatekiOkuta_IsHiddenByAnotherOctorok

* Finish naming all functions

* Better macros + explanations

* Comments on a lot of functions

* Some stuff I was supposed to revert

* Fix merge issue

* Another merge fix

* Make data static + move it in-function

* Respond to engineer's review

* circleOrCrossAlpha -> hitResultAlpha

* Respond to more of engineer's feedback

* octorokHitType -> lastHitOctorokType

* Animation enum stuff
This commit is contained in:
Tom Overton 2023-06-17 15:15:55 -07:00 committed by GitHub
parent 5800c4669f
commit 9c40dea770
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 383 additions and 284 deletions

View File

@ -7,7 +7,7 @@
<!-- Textures and DisplayLists for the cross and circle indicators that appear when you shoot an Octorok -->
<Texture Name="gShootingGalleryOctorokCrossTex" OutName="shooting_gallery_octorok_cross" Format="ia16" Width="16" Height="16" Offset="0x1658"/>
<Texture Name="gShootingGalleryOctorokCircleTex" OutName="shooting_gallery_octorok_circle" Format="ia16" Width="16" Height="16" Offset="0x1858"/>
<DList Name="gShootingGalleryOctorokCrossDL" Offset="0x1A98"/>
<DList Name="gShootingGalleryOctorokCircleDL" Offset="0x1B18"/>
<DList Name="gShootingGalleryOctorokCrossDL" Offset="0x1A98"/> <!-- Original name is "okuta_peke_model" ("peke" = "x (mark); cross") -->
<DList Name="gShootingGalleryOctorokCircleDL" Offset="0x1B18"/> <!-- Original name is "okuta_maru_model" ("maru" = "circle") -->
</File>
</Root>

View File

@ -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;
}
}

View File

@ -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;

View File

@ -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);

View File

@ -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

View File

@ -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",),

View File

@ -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),