Cleanup of Shooting Gallery actors (#1302)

* Change `EN_SYATEKI_*` enums/defines to `SG_*`

* Name shooting gallery weekeventregs

* Get rid of names on unions (this is what I wanted to begin with!)

* Use ARRAY_COUNT(sGuayFlagsPerWave) instead of 3

* Actually give a proper name for SG_DEKU_GET_PARAM_FF00

* Use anon's suggestion for path param name

* Remove comment that isn't true? What was I cooking back then

* Animation naming stuff + comments

* Tons of score and shooting game logic cleanup

* Fix build issues

* Some more Octorok docs

* Use ANIMMODE enum in EnShn

* Put a bug tag on the weird behavior in EnSyatekiWf
This commit is contained in:
Tom Overton 2023-06-21 06:29:16 -07:00 committed by GitHub
parent 763830b185
commit 96a1d37084
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
19 changed files with 311 additions and 255 deletions

View File

@ -79,11 +79,11 @@
<Texture Name="gSwampGuideMouthTex" OutName="swamp_guide_mouth" Format="ci8" Width="16" Height="32" Offset="0xCA98" />
<!-- Burly Guy Animations -->
<Animation Name="gSwampShootingGalleryManHeadScratchEndAnim" Offset="0xD2F8" /> <!-- Original name is "shn_w02TOw01" ("wait02 to wait01"?) -->
<Animation Name="gBurlyGuyHeadScratchEndAnim" Offset="0xD2F8" /> <!-- Original name is "shn_w02TOw01" ("wait02 to wait01"?) -->
<Animation Name="gBurlyGuyEmptyAnim" Offset="0xD3AC" /> <!-- Original name is "shn_wait". Unused and one frame long -->
<Animation Name="gBurlyGuyHandsOnTableAnim" Offset="0xD9D0" /> <!-- Original name is "shn_wait01" -->
<Animation Name="gSwampShootingGalleryManHeadScratchLoopAnim" Offset="0xDFEC" /> <!-- Original name is "shn_wait02" -->
<Animation Name="gSwampGuideChinScratchAnim" Offset="0xE6C4" /><!-- Original name is "shn_wait03" -->
<Animation Name="gBurlyGuyHeadScratchLoopAnim" Offset="0xDFEC" /> <!-- Original name is "shn_wait02" -->
<Animation Name="gBurlyGuyChinScratchAnim" Offset="0xE6C4" /><!-- Original name is "shn_wait03" -->
<!-- Burly Guy Limbs -->
<Limb Name="gBurlyGuyWaistLimb" Type="Standard" EnumName="BURLY_GUY_LIMB_WAIST" Offset="0xE6E0" />

View File

@ -510,7 +510,7 @@ void EffectSsEnIce_Spawn(PlayState* play, Vec3f* pos, f32 scale, Vec3f* velocity
void EffectSsFireTail_SpawnFlameOnPlayer(PlayState* play, f32 scale, s16 bodyPart, f32 colorIntensity);
void EffectSsEnFire_SpawnVec3f(PlayState* play, Actor* actor, Vec3f* pos, s16 scale, s16 params, s16 flags, s16 bodyPart);
// void EffectSsEnFire_SpawnVec3s(UNK_TYPE1 param_1, UNK_TYPE1 param_2, UNK_TYPE1 param_3, UNK_TYPE1 param_4, UNK_TYPE2 param_5, UNK_TYPE2 param_6, UNK_TYPE2 param_7);
void EffectSsExtra_Spawn(PlayState* play, Vec3f* pos, Vec3f* velocity, Vec3f* accel, s16 scale, s16 scoreIdx);
void EffectSsExtra_Spawn(PlayState* play, Vec3f* pos, Vec3f* velocity, Vec3f* accel, s16 scale, s16 scoreIndex);
void EffectSsDeadDb_Spawn(PlayState* play, Vec3f* pos, Vec3f* velocity, Vec3f* accel, Color_RGBA8* prim, Color_RGBA8* env, s16 scale, s16 scaleStep, s32 life);
void func_800B3030(PlayState* play, Vec3f* pos, Vec3f* velocity, Vec3f* accel, s16 scale, s16 scaleStep, s32 colorIndex);
void EffectSsDeadDd_Spawn(PlayState* play, Vec3f* pos, Vec3f* velocity, Vec3f* accel, Color_RGBA8* prim, Color_RGBA8* env, s16 scale, s16 scaleStep, s16 alphaStep, s32 life);

View File

@ -845,8 +845,8 @@ typedef enum {
#define WEEKEVENTREG_31_80 PACK_WEEKEVENTREG_FLAG(31, 0x80)
#define WEEKEVENTREG_32_01 PACK_WEEKEVENTREG_FLAG(32, 0x01)
#define WEEKEVENTREG_32_02 PACK_WEEKEVENTREG_FLAG(32, 0x02)
#define WEEKEVENTREG_32_04 PACK_WEEKEVENTREG_FLAG(32, 0x04)
#define WEEKEVENTREG_RECEIVED_SWAMP_SHOOTING_GALLERY_HEART_PIECE PACK_WEEKEVENTREG_FLAG(32, 0x02)
#define WEEKEVENTREG_RECEIVED_TOWN_SHOOTING_GALLERY_HEART_PIECE PACK_WEEKEVENTREG_FLAG(32, 0x04)
#define WEEKEVENTREG_32_08 PACK_WEEKEVENTREG_FLAG(32, 0x08)
#define WEEKEVENTREG_32_10 PACK_WEEKEVENTREG_FLAG(32, 0x10)
#define WEEKEVENTREG_32_20 PACK_WEEKEVENTREG_FLAG(32, 0x20)
@ -1042,8 +1042,8 @@ typedef enum {
#define WEEKEVENTREG_59_04 PACK_WEEKEVENTREG_FLAG(59, 0x04)
#define WEEKEVENTREG_59_08 PACK_WEEKEVENTREG_FLAG(59, 0x08)
#define WEEKEVENTREG_59_10 PACK_WEEKEVENTREG_FLAG(59, 0x10)
#define WEEKEVENTREG_59_20 PACK_WEEKEVENTREG_FLAG(59, 0x20)
#define WEEKEVENTREG_RECEIVED_SWAMP_SHOOTING_GALLERY_QUIVER_UPGRADE PACK_WEEKEVENTREG_FLAG(59, 0x10)
#define WEEKEVENTREG_RECEIVED_TOWN_SHOOTING_GALLERY_QUIVER_UPGRADE PACK_WEEKEVENTREG_FLAG(59, 0x20)
#define WEEKEVENTREG_59_40 PACK_WEEKEVENTREG_FLAG(59, 0x40)
#define WEEKEVENTREG_59_80 PACK_WEEKEVENTREG_FLAG(59, 0x80)
#define WEEKEVENTREG_60_01 PACK_WEEKEVENTREG_FLAG(60, 0x01)

View File

@ -925,14 +925,14 @@ void EffectSsEnFire_SpawnVec3s(PlayState* play, Actor* actor, Vec3s* pos, s16 sc
// EffectSsExtra Spawn Functions
void EffectSsExtra_Spawn(PlayState* play, Vec3f* pos, Vec3f* velocity, Vec3f* accel, s16 scale, s16 scoreIdx) {
void EffectSsExtra_Spawn(PlayState* play, Vec3f* pos, Vec3f* velocity, Vec3f* accel, s16 scale, s16 scoreIndex) {
EffectSsExtraInitParams initParams;
Math_Vec3f_Copy(&initParams.pos, pos);
Math_Vec3f_Copy(&initParams.velocity, velocity);
Math_Vec3f_Copy(&initParams.accel, accel);
initParams.scale = scale;
initParams.scoreIdx = scoreIdx;
initParams.scoreIndex = scoreIndex;
EffectSs_Spawn(play, EFFECT_SS_EXTRA, 100, &initParams);
}

View File

@ -112,8 +112,9 @@ u16 sPersistentCycleWeekEventRegs[ARRAY_COUNT(gSaveContext.save.saveInfo.weekEve
PERSISTENT_WEEKEVENTREG(WEEKEVENTREG_31_01) | PERSISTENT_WEEKEVENTREG(WEEKEVENTREG_31_02) |
PERSISTENT_WEEKEVENTREG(WEEKEVENTREG_31_04) | PERSISTENT_WEEKEVENTREG(WEEKEVENTREG_31_20),
/* 32 */
PERSISTENT_WEEKEVENTREG(WEEKEVENTREG_32_01) | PERSISTENT_WEEKEVENTREG(WEEKEVENTREG_32_02) |
PERSISTENT_WEEKEVENTREG(WEEKEVENTREG_32_04),
PERSISTENT_WEEKEVENTREG(WEEKEVENTREG_32_01) |
PERSISTENT_WEEKEVENTREG(WEEKEVENTREG_RECEIVED_SWAMP_SHOOTING_GALLERY_HEART_PIECE) |
PERSISTENT_WEEKEVENTREG(WEEKEVENTREG_RECEIVED_TOWN_SHOOTING_GALLERY_HEART_PIECE),
/* 33 */ 0,
/* 34 */ 0,
/* 35 */
@ -146,7 +147,8 @@ u16 sPersistentCycleWeekEventRegs[ARRAY_COUNT(gSaveContext.save.saveInfo.weekEve
/* 58 */ 0,
/* 59 */
PERSISTENT_WEEKEVENTREG(WEEKEVENTREG_59_04) | PERSISTENT_WEEKEVENTREG(WEEKEVENTREG_59_08) |
PERSISTENT_WEEKEVENTREG(WEEKEVENTREG_59_10) | PERSISTENT_WEEKEVENTREG(WEEKEVENTREG_59_20),
PERSISTENT_WEEKEVENTREG(WEEKEVENTREG_RECEIVED_SWAMP_SHOOTING_GALLERY_QUIVER_UPGRADE) |
PERSISTENT_WEEKEVENTREG(WEEKEVENTREG_RECEIVED_TOWN_SHOOTING_GALLERY_QUIVER_UPGRADE),
/* 60 */ PERSISTENT_WEEKEVENTREG(WEEKEVENTREG_60_10),
/* 61 */ 0,
/* 62 */ 0,

View File

@ -70,10 +70,10 @@ void func_80AE6130(EnShn* this) {
s32 func_80AE615C(EnShn* this, s32 animIndex) {
static AnimationInfoS sAnimationInfo[] = {
{ &gBurlyGuyHandsOnTableAnim, 1.0f, 0, -1, 0, 0 },
{ &gBurlyGuyHandsOnTableAnim, 1.0f, 0, -1, 0, -4 },
{ &gSwampGuideChinScratchAnim, 1.0f, 0, -1, 0, 0 },
{ &gSwampGuideChinScratchAnim, 1.0f, 0, -1, 0, -4 },
{ &gBurlyGuyHandsOnTableAnim, 1.0f, 0, -1, ANIMMODE_LOOP, 0 },
{ &gBurlyGuyHandsOnTableAnim, 1.0f, 0, -1, ANIMMODE_LOOP, -4 },
{ &gBurlyGuyChinScratchAnim, 1.0f, 0, -1, ANIMMODE_LOOP, 0 },
{ &gBurlyGuyChinScratchAnim, 1.0f, 0, -1, ANIMMODE_LOOP, -4 },
};
s32 phi_v0 = 0;
s32 phi_v1 = 0;

View File

@ -79,11 +79,11 @@ void EnSyatekiCrow_Init(Actor* thisx, PlayState* play2) {
s32 i;
path = syatekiMan->path;
while (path->customValue != SG_PATH_TYPE_CROW) {
while (path->customValue != SG_PATH_TYPE_GUAY) {
path = &play->setupPathList[path->additionalPathIndex];
}
for (i = 0; i < EN_SYATEKI_CROW_GET_INDEX(&this->actor); i++) {
for (i = 0; i < SG_GUAY_GET_INDEX(&this->actor); i++) {
path = &play->setupPathList[path->additionalPathIndex];
}
@ -95,7 +95,7 @@ void EnSyatekiCrow_Init(Actor* thisx, PlayState* play2) {
this->collider.elements[0].dim.worldSphere.radius = sJntSphInit.elements[0].dim.modelSphere.radius;
ActorShape_Init(&this->actor.shape, 2000.0f, ActorShadow_DrawCircle, 20.0f);
if ((path == NULL) || (EN_SYATEKI_CROW_GET_INDEX(&this->actor) >= 0x80)) {
if ((path == NULL) || (SG_GUAY_GET_INDEX(&this->actor) >= 0x80)) {
Actor_Kill(&this->actor);
return;
}
@ -133,7 +133,7 @@ void EnSyatekiCrow_WaitForSignal(EnSyatekiCrow* this, PlayState* play) {
EnSyatekiMan* syatekiMan = (EnSyatekiMan*)this->actor.parent;
if ((syatekiMan->shootingGameState == SG_GAME_STATE_RUNNING) && (this->isActive == true) &&
(syatekiMan->guayFlags & (1 << EN_SYATEKI_CROW_GET_INDEX(&this->actor)))) {
(syatekiMan->guayFlags & (1 << SG_GUAY_GET_INDEX(&this->actor)))) {
EnSyatekiCrow_SetupWaitToMove(this);
} else if (syatekiMan->shootingGameState != SG_GAME_STATE_RUNNING) {
this->isActive = true;
@ -168,10 +168,10 @@ void EnSyatekiCrow_SetupWaitToMove(EnSyatekiCrow* this) {
* How long the Guay should wait is controlled by its params.
*/
void EnSyatekiCrow_WaitToMove(EnSyatekiCrow* this, PlayState* play) {
if (((EN_SYATEKI_CROW_GET_WAIT_MOD(&this->actor) * 20) + 20) < this->waitTimer) {
if (((SG_GUAY_GET_WAIT_MOD(&this->actor) * 20) + 20) < this->waitTimer) {
Actor_PlaySfx(this->actor.parent, NA_SE_EN_KAICHO_CRY);
this->waitTimer = 0;
this->actor.speed = EN_SYATEKI_CROW_GET_SPEED_MOD(&this->actor) + 6.0f;
this->actor.speed = SG_GUAY_GET_SPEED_MOD(&this->actor) + 6.0f;
this->actor.gravity = -0.5f;
this->actionFunc = EnSyatekiCrow_Fly;
} else {
@ -206,13 +206,13 @@ void EnSyatekiCrow_Fly(EnSyatekiCrow* this, PlayState* play) {
this->currentPointIndex++;
} else {
this->isActive = false;
syatekiMan->guayFlags &= ~(1 << EN_SYATEKI_CROW_GET_INDEX(&this->actor));
syatekiMan->guayFlags &= ~(1 << SG_GUAY_GET_INDEX(&this->actor));
EnSyatekiCrow_SetupWaitForSignal(this);
}
SkelAnime_Update(&this->skelAnime);
this->actor.shape.yOffset = (fabsf(this->skelAnime.curFrame - 3.0f) * 150.0f) + 1700.0f;
if ((syatekiMan->perGameVar1.guaySpawnTimer % 90) == 0) {
if ((syatekiMan->guayAppearTimer % 90) == 0) {
Actor_PlaySfx(&this->actor, NA_SE_EN_KAICHO_CRY);
}
}
@ -220,7 +220,7 @@ void EnSyatekiCrow_Fly(EnSyatekiCrow* this, PlayState* play) {
void EnSyatekiCrow_SetupDead(EnSyatekiCrow* this) {
EnSyatekiMan* syatekiMan = (EnSyatekiMan*)this->actor.parent;
syatekiMan->score += 60;
syatekiMan->score += SG_POINTS_GUAY;
this->isActive = false;
this->actor.speed *= Math_CosS(this->actor.world.rot.x);
this->actor.velocity.y = 0.0f;
@ -245,7 +245,7 @@ void EnSyatekiCrow_Dead(EnSyatekiCrow* this, PlayState* play) {
if (this->deathTimer > 20) {
func_800B3030(play, &this->actor.world.pos, &sZeroVec, &sZeroVec, this->actor.scale.x * 10000.0f, 0, 0);
syatekiMan->guayHitCounter++;
syatekiMan->guayFlags &= ~(1 << EN_SYATEKI_CROW_GET_INDEX(&this->actor));
syatekiMan->guayFlags &= ~(1 << SG_GUAY_GET_INDEX(&this->actor));
EnSyatekiCrow_SetupWaitForSignal(this);
}
@ -262,7 +262,7 @@ void EnSyatekiCrow_UpdateDamage(EnSyatekiCrow* this, PlayState* play) {
Audio_PlaySfx(NA_SE_SY_TRE_BOX_APPEAR);
this->deathTimer = 0;
this->collider.base.acFlags &= ~AC_HIT;
EffectSsExtra_Spawn(play, &this->actor.world.pos, &sVelocity, &sAccel, 5, 1);
EffectSsExtra_Spawn(play, &this->actor.world.pos, &sVelocity, &sAccel, 5, EXTRA_SCORE_INDEX_60);
EnSyatekiCrow_SetupDead(this);
} else {
this->collider.elements[0].dim.worldSphere.center.x = this->actor.world.pos.x;

View File

@ -4,10 +4,10 @@
#include "global.h"
#include "objects/object_crow/object_crow.h"
#define EN_SYATEKI_CROW_GET_WAIT_MOD(thisx) ((thisx)->params & 0xF)
#define EN_SYATEKI_CROW_GET_SPEED_MOD(thisx) (((thisx)->params & 0xF0) >> 4)
#define EN_SYATEKI_CROW_GET_INDEX(thisx) (((thisx)->params & 0xFF00) >> 8)
#define EN_SYATEKI_CROW_PARAMS(index, speedMod, waitMod) (((index << 8) & 0xFF00) | ((speedMod << 4) & 0xF0) | (waitMod & 0xF))
#define SG_GUAY_GET_WAIT_MOD(thisx) ((thisx)->params & 0xF)
#define SG_GUAY_GET_SPEED_MOD(thisx) (((thisx)->params & 0xF0) >> 4)
#define SG_GUAY_GET_INDEX(thisx) (((thisx)->params & 0xFF00) >> 8)
#define SG_GUAY_PARAMS(index, speedMod, waitMod) (((index << 8) & 0xFF00) | ((speedMod << 4) & 0xF0) | (waitMod & 0xF))
struct EnSyatekiCrow;

View File

@ -35,9 +35,9 @@ void EnSyatekiDekunuts_GameEnd(EnSyatekiDekunuts* this, PlayState* play);
void EnSyatekiDekunuts_Dead(EnSyatekiDekunuts* this, PlayState* play);
typedef enum {
/* 0 */ EN_SYATEKI_DEKUNUTS_HEADDRESS_TYPE_NORMAL,
/* 1 */ EN_SYATEKI_DEKUNUTS_HEADDRESS_TYPE_FLIPPED_UP
} EnSyatekiDekunutsHeaddressType;
/* 0 */ SG_DEKU_HEADDRESS_TYPE_NORMAL,
/* 1 */ SG_DEKU_HEADDRESS_TYPE_FLIPPED_UP
} ShootingGalleryDekuScrubHeaddressType;
ActorInit En_Syateki_Dekunuts_InitVars = {
ACTOR_EN_SYATEKI_DEKUNUTS,
@ -74,23 +74,23 @@ static ColliderCylinderInit sCylinderInit = {
static Cylinder16 sBonusDekuScrubColliderDimensions[] = { { 24, 40, 0, { 0, 0, 0 } } };
typedef enum {
/* 0 */ EN_SYATEKI_DEKUNUTS_ANIM_UP,
/* 1 */ EN_SYATEKI_DEKUNUTS_ANIM_BURROW,
/* 2 */ EN_SYATEKI_DEKUNUTS_ANIM_IDLE, // unused
/* 3 */ EN_SYATEKI_DEKUNUTS_ANIM_LOOK_AROUND,
/* 4 */ EN_SYATEKI_DEKUNUTS_ANIM_DAMAGE,
/* 5 */ EN_SYATEKI_DEKUNUTS_ANIM_DIE,
/* 6 */ EN_SYATEKI_DEKUNUTS_ANIM_UNBURROW // unused
} EnSyatekiDekunutsAnimation;
/* 0 */ SG_DEKU_ANIM_UP,
/* 1 */ SG_DEKU_ANIM_BURROW,
/* 2 */ SG_DEKU_ANIM_IDLE, // unused
/* 3 */ SG_DEKU_ANIM_LOOK_AROUND,
/* 4 */ SG_DEKU_ANIM_DAMAGE,
/* 5 */ SG_DEKU_ANIM_DIE,
/* 6 */ SG_DEKU_ANIM_UNBURROW // unused
} ShootingGalleryDekuScrubAnimation;
static AnimationInfo sAnimationInfo[] = {
{ &gDekuScrubUpAnim, 1.0f, 0.0f, 0.0f, ANIMMODE_ONCE, -1.0f },
{ &gDekuScrubBurrowAnim, 1.0f, 0.0f, 0.0f, ANIMMODE_ONCE, -1.0f },
{ &gDekuScrubIdleAnim, 1.0f, 0.0f, 0.0f, ANIMMODE_LOOP, -1.0f },
{ &gDekuScrubLookAroundAnim, 1.0f, 0.0f, 0.0f, ANIMMODE_LOOP, -1.0f },
{ &gDekuScrubDamageAnim, 1.0f, 0.0f, 0.0f, ANIMMODE_ONCE, -1.0f },
{ &gDekuScrubDieAnim, 1.0f, 0.0f, 0.0f, ANIMMODE_ONCE, -1.0f },
{ &gDekuScrubUnburrowAnim, 1.0f, 0.0f, 0.0f, ANIMMODE_ONCE, -1.0f },
{ &gDekuScrubUpAnim, 1.0f, 0.0f, 0.0f, ANIMMODE_ONCE, -1.0f }, // SG_DEKU_ANIM_UP
{ &gDekuScrubBurrowAnim, 1.0f, 0.0f, 0.0f, ANIMMODE_ONCE, -1.0f }, // SG_DEKU_ANIM_BURROW
{ &gDekuScrubIdleAnim, 1.0f, 0.0f, 0.0f, ANIMMODE_LOOP, -1.0f }, // SG_DEKU_ANIM_IDLE
{ &gDekuScrubLookAroundAnim, 1.0f, 0.0f, 0.0f, ANIMMODE_LOOP, -1.0f }, // SG_DEKU_ANIM_LOOK_AROUND
{ &gDekuScrubDamageAnim, 1.0f, 0.0f, 0.0f, ANIMMODE_ONCE, -1.0f }, // SG_DEKU_ANIM_DAMAGE
{ &gDekuScrubDieAnim, 1.0f, 0.0f, 0.0f, ANIMMODE_ONCE, -1.0f }, // SG_DEKU_ANIM_DIE
{ &gDekuScrubUnburrowAnim, 1.0f, 0.0f, 0.0f, ANIMMODE_ONCE, -1.0f }, // SG_DEKU_ANIM_UNBURROW
};
static InitChainEntry sInitChain[] = {
@ -112,20 +112,20 @@ void EnSyatekiDekunuts_Init(Actor* thisx, PlayState* play2) {
Collider_InitCylinder(play, &this->collider);
Collider_SetCylinder(play, &this->collider, &this->actor, &sCylinderInit);
if (EN_SYATEKI_DEKUNUTS_GET_TYPE(&this->actor) == EN_SYATEKI_DEKUNUTS_TYPE_BONUS) {
if (SG_DEKU_GET_TYPE(&this->actor) == SG_DEKU_TYPE_BONUS) {
Actor_SetScale(&this->actor, 0.01f);
this->collider.dim = sBonusDekuScrubColliderDimensions[0];
pathType = SG_PATH_TYPE_SCRUB_BONUS;
pathType = SG_PATH_TYPE_DEKU_BONUS;
} else {
Actor_SetScale(&this->actor, 0.02f);
pathType = SG_PATH_TYPE_SCRUB_NORMAL;
pathType = SG_PATH_TYPE_DEKU_NORMAL;
}
while (path->customValue != pathType) {
path = &play->setupPathList[path->additionalPathIndex];
}
for (i = 0; i < EN_SYATEKI_DEKUNUTS_GET_PARAM_FF00(&this->actor); i++) {
for (i = 0; i < SG_DEKU_GET_ADDITIONAL_PATH_INDEX_LIMIT(&this->actor); i++) {
path = &play->setupPathList[path->additionalPathIndex];
}
@ -147,7 +147,7 @@ void EnSyatekiDekunuts_Init(Actor* thisx, PlayState* play2) {
}
this->flowerPos = Lib_SegmentedToVirtual(path->points);
this->index = EN_SYATEKI_DEKUNUTS_GET_INDEX(&this->actor);
this->index = SG_DEKU_GET_INDEX(&this->actor);
this->flowerCount = path->count;
this->timer = 0;
this->unk_1DC = 0;
@ -172,7 +172,7 @@ void EnSyatekiDekunuts_SetupWaitForSignal(EnSyatekiDekunuts* this) {
this->timer = 0;
this->unk_1DC = 0;
if (EN_SYATEKI_DEKUNUTS_GET_TYPE(&this->actor) != EN_SYATEKI_DEKUNUTS_TYPE_BONUS) {
if (SG_DEKU_GET_TYPE(&this->actor) != SG_DEKU_TYPE_BONUS) {
this->isAlive = true;
}
@ -193,7 +193,7 @@ void EnSyatekiDekunuts_WaitForSignal(EnSyatekiDekunuts* this, PlayState* play) {
}
if (!syatekiMan->dekuScrubFlags && !syatekiMan->guayFlags &&
(EN_SYATEKI_DEKUNUTS_GET_TYPE(&this->actor) != EN_SYATEKI_DEKUNUTS_TYPE_BONUS)) {
(SG_DEKU_GET_TYPE(&this->actor) != SG_DEKU_TYPE_BONUS)) {
this->isAlive = true;
}
}
@ -215,10 +215,10 @@ void EnSyatekiDekunuts_SetupWaitToStart(EnSyatekiDekunuts* this) {
this->timeToBurrow = 140 - (syatekiMan->currentWave * 20);
if ((syatekiMan->currentWave % 2) != 0) {
this->headdressType = EN_SYATEKI_DEKUNUTS_HEADDRESS_TYPE_FLIPPED_UP;
this->headdressType = SG_DEKU_HEADDRESS_TYPE_FLIPPED_UP;
this->headdressRotZ = 0;
} else {
this->headdressType = EN_SYATEKI_DEKUNUTS_HEADDRESS_TYPE_NORMAL;
this->headdressType = SG_DEKU_HEADDRESS_TYPE_NORMAL;
}
this->actionFunc = EnSyatekiDekunuts_WaitToStart;
@ -259,7 +259,7 @@ void EnSyatekiDekunuts_WaitToEmerge(EnSyatekiDekunuts* this, PlayState* play) {
void EnSyatekiDekunuts_SetupEmerge(EnSyatekiDekunuts* this) {
Actor_PlaySfx(&this->actor, NA_SE_EN_NUTS_UP);
Actor_ChangeAnimationByInfo(&this->skelAnime, sAnimationInfo, EN_SYATEKI_DEKUNUTS_ANIM_UP);
Actor_ChangeAnimationByInfo(&this->skelAnime, sAnimationInfo, SG_DEKU_ANIM_UP);
this->actor.shape.rot.y = this->actor.yawTowardsPlayer;
this->actor.world.rot.y = this->actor.yawTowardsPlayer;
this->actionFunc = EnSyatekiDekunuts_Emerge;
@ -275,7 +275,7 @@ void EnSyatekiDekunuts_Emerge(EnSyatekiDekunuts* this, PlayState* play) {
EnSyatekiDekunuts_SetupLookAround(this);
}
if (this->headdressType == EN_SYATEKI_DEKUNUTS_HEADDRESS_TYPE_FLIPPED_UP) {
if (this->headdressType == SG_DEKU_HEADDRESS_TYPE_FLIPPED_UP) {
Math_SmoothStepToS(&this->headdressRotZ, -0x8000, 5, 0x1000, 0x100);
}
@ -283,8 +283,8 @@ void EnSyatekiDekunuts_Emerge(EnSyatekiDekunuts* this, PlayState* play) {
}
void EnSyatekiDekunuts_SetupLookAround(EnSyatekiDekunuts* this) {
Actor_ChangeAnimationByInfo(&this->skelAnime, sAnimationInfo, EN_SYATEKI_DEKUNUTS_ANIM_LOOK_AROUND);
if (EN_SYATEKI_DEKUNUTS_GET_TYPE(&this->actor) != EN_SYATEKI_DEKUNUTS_TYPE_BONUS) {
Actor_ChangeAnimationByInfo(&this->skelAnime, sAnimationInfo, SG_DEKU_ANIM_LOOK_AROUND);
if (SG_DEKU_GET_TYPE(&this->actor) != SG_DEKU_TYPE_BONUS) {
this->actionFunc = EnSyatekiDekunuts_LookAround;
} else {
this->actionFunc = EnSyatekiDekunuts_BonusLookAround;
@ -325,7 +325,7 @@ void EnSyatekiDekunuts_BonusLookAround(EnSyatekiDekunuts* this, PlayState* play)
}
void EnSyatekiDekunuts_SetupBurrow(EnSyatekiDekunuts* this) {
Actor_ChangeAnimationByInfo(&this->skelAnime, sAnimationInfo, EN_SYATEKI_DEKUNUTS_ANIM_BURROW);
Actor_ChangeAnimationByInfo(&this->skelAnime, sAnimationInfo, SG_DEKU_ANIM_BURROW);
this->actionFunc = EnSyatekiDekunuts_Burrow;
}
@ -369,19 +369,19 @@ void EnSyatekiDekunuts_SetupDead(EnSyatekiDekunuts* this, PlayState* play) {
static Vec3f sAccel = { 0.0f, 0.0f, 0.0f };
EnSyatekiMan* syatekiMan = (EnSyatekiMan*)this->actor.parent;
if (EN_SYATEKI_DEKUNUTS_GET_TYPE(&this->actor) == EN_SYATEKI_DEKUNUTS_TYPE_BONUS) {
EffectSsExtra_Spawn(play, &this->actor.world.pos, &sVelocity, &sAccel, 5, 2);
syatekiMan->score += 100;
syatekiMan->perGameVar2.bonusDekuScrubHitCounter++;
if (SG_DEKU_GET_TYPE(&this->actor) == SG_DEKU_TYPE_BONUS) {
EffectSsExtra_Spawn(play, &this->actor.world.pos, &sVelocity, &sAccel, 5, EXTRA_SCORE_INDEX_100);
syatekiMan->score += SG_POINTS_DEKU_BONUS;
syatekiMan->bonusDekuScrubHitCounter++;
} else {
EffectSsExtra_Spawn(play, &this->actor.world.pos, &sVelocity, &sAccel, 5, 0);
syatekiMan->score += 30;
EffectSsExtra_Spawn(play, &this->actor.world.pos, &sVelocity, &sAccel, 5, EXTRA_SCORE_INDEX_30);
syatekiMan->score += SG_POINTS_DEKU_NORMAL;
syatekiMan->dekuScrubHitCounter++;
}
Actor_PlaySfx(&this->actor, NA_SE_EN_NUTS_DAMAGE);
this->isAlive = false;
Actor_ChangeAnimationByInfo(&this->skelAnime, sAnimationInfo, EN_SYATEKI_DEKUNUTS_ANIM_DAMAGE);
Actor_ChangeAnimationByInfo(&this->skelAnime, sAnimationInfo, SG_DEKU_ANIM_DAMAGE);
this->timer = 160;
this->actionFunc = EnSyatekiDekunuts_Dead;
}
@ -393,7 +393,7 @@ void EnSyatekiDekunuts_Dead(EnSyatekiDekunuts* this, PlayState* play) {
if (Animation_OnFrame(&this->skelAnime, this->skelAnime.endFrame)) {
if (this->timer == 160) {
Actor_ChangeAnimationByInfo(&this->skelAnime, sAnimationInfo, EN_SYATEKI_DEKUNUTS_ANIM_DIE);
Actor_ChangeAnimationByInfo(&this->skelAnime, sAnimationInfo, SG_DEKU_ANIM_DIE);
Actor_PlaySfx(&this->actor, NA_SE_EN_NUTS_DEAD);
this->timer--;
} else if (this->timer < 160) {
@ -407,7 +407,7 @@ void EnSyatekiDekunuts_Dead(EnSyatekiDekunuts* this, PlayState* play) {
pos.y = this->actor.world.pos.y + 10.0f;
EffectSsHahen_SpawnBurst(play, &pos, 3.0f, 0, 12, 3, 15, HAHEN_OBJECT_DEFAULT, 10, NULL);
if (EN_SYATEKI_DEKUNUTS_GET_TYPE(&this->actor) != EN_SYATEKI_DEKUNUTS_TYPE_BONUS) {
if (SG_DEKU_GET_TYPE(&this->actor) != SG_DEKU_TYPE_BONUS) {
syatekiMan->dekuScrubFlags &= ~(1 << this->index);
}
@ -427,7 +427,7 @@ void EnSyatekiDekunuts_Update(Actor* thisx, PlayState* play) {
if ((this->actionFunc != EnSyatekiDekunuts_WaitForSignal) && (this->timer < this->timeToBurrow) &&
(this->timer > 10)) {
if ((this->collider.base.acFlags & AC_HIT) && (this->isAlive == true)) {
if (EN_SYATEKI_DEKUNUTS_GET_TYPE(&this->actor) == EN_SYATEKI_DEKUNUTS_TYPE_BONUS) {
if (SG_DEKU_GET_TYPE(&this->actor) == SG_DEKU_TYPE_BONUS) {
Audio_PlayFanfare(NA_BGM_GET_ITEM | 0x900);
} else {
Audio_PlaySfx(NA_SE_SY_TRE_BOX_APPEAR);
@ -450,8 +450,7 @@ s32 EnSyatekiDekunuts_OverrideLimbDraw(PlayState* play, s32 limbIndex, Gfx** dLi
Actor* thisx) {
EnSyatekiDekunuts* this = THIS;
if ((limbIndex == DEKU_SCRUB_LIMB_HEADDRESS) &&
(this->headdressType == EN_SYATEKI_DEKUNUTS_HEADDRESS_TYPE_FLIPPED_UP)) {
if ((limbIndex == DEKU_SCRUB_LIMB_HEADDRESS) && (this->headdressType == SG_DEKU_HEADDRESS_TYPE_FLIPPED_UP)) {
rot->z += this->headdressRotZ;
}

View File

@ -4,15 +4,15 @@
#include "global.h"
#include "objects/object_dekunuts/object_dekunuts.h"
#define EN_SYATEKI_DEKUNUTS_GET_TYPE(thisx) ((thisx)->params & 0xF)
#define EN_SYATEKI_DEKUNUTS_GET_INDEX(thisx) (((thisx)->params & 0xF0) >> 4)
#define EN_SYATEKI_DEKUNUTS_GET_PARAM_FF00(thisx) (((thisx)->params & 0xFF00) >> 8)
#define EN_SYATEKI_DEKUNUTS_PARAMS(unkFF00, index, type) (((unkFF00 << 8) & 0xFF00) | ((index << 4) & 0xF0) | (type & 0xF))
#define SG_DEKU_GET_TYPE(thisx) ((thisx)->params & 0xF)
#define SG_DEKU_GET_INDEX(thisx) (((thisx)->params & 0xF0) >> 4)
#define SG_DEKU_GET_ADDITIONAL_PATH_INDEX_LIMIT(thisx) (((thisx)->params & 0xFF00) >> 8)
#define SG_DEKU_PARAMS(additionalPathIndexLimit, index, type) (((additionalPathIndexLimit << 8) & 0xFF00) | ((index << 4) & 0xF0) | (type & 0xF))
typedef enum {
/* 0 */ EN_SYATEKI_DEKUNUTS_TYPE_NORMAL, // Worth 30 points
/* 1 */ EN_SYATEKI_DEKUNUTS_TYPE_BONUS // Worth 100 points
} EnSyatekiDekunutsType;
/* 0 */ SG_DEKU_TYPE_NORMAL, // Worth 30 points
/* 1 */ SG_DEKU_TYPE_BONUS // Worth 100 points
} ShootingGalleryDekuScrubType;
struct EnSyatekiDekunuts;

View File

@ -50,11 +50,42 @@ 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)
// This defines the configuration of a single wave of Octoroks in the Town Shooting Gallery. These are
// arranged in the same columns and rows that appear in-game; the player stands in the center column, and
// the Octorok with an index of 7 appears directly in front of them like so:
// 0 1 2
// 3 4 5
// 6 7 8
// Player
#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))
// These defines assume that sNormalSwampTargetActorList is used to spawn actors and that the logic of
// EnSyatekiMan_Swamp_RunGame is not modified; in other words, it assumes that each wave consists of five
// Deku Scrubs that the player must shoot and three Guays that the player can either shoot or let escape.
// Once all Deku Scrubs and Guays have been shot or escape, the next wave starts.
#define SG_SWAMP_WAVE_COUNT 4
#define SG_SWAMP_DEKUS_PER_WAVE 5
#define SG_SWAMP_GUAYS_PER_WAVE 3
#define SG_SWAMP_BONUS_DEKU_COUNT 2
// This is the score the player will receive if they hit every single Deku Scrub (both normal and bonus), Guay, and
// Wolfos. There are two conditions for a Wolfos to appear, hence why their point value appears twice; one Wolfos
// will appear after shooting two waves of Deku Scrubs, and one Wolfos will appear after shooting one wave of Guays.
// Assuming the point values, actor list, and shooting game logic are unmodified, this should total to 2120 points.
#define SG_SWAMP_PERFECT_SCORE_WITHOUT_BONUS \
(SG_POINTS_DEKU_NORMAL * (SG_SWAMP_DEKUS_PER_WAVE * SG_SWAMP_WAVE_COUNT) + \
SG_POINTS_GUAY * (SG_SWAMP_GUAYS_PER_WAVE * SG_SWAMP_WAVE_COUNT) + \
SG_POINTS_DEKU_BONUS * SG_SWAMP_BONUS_DEKU_COUNT + SG_POINTS_WOLFOS * SG_SWAMP_WAVE_COUNT + \
SG_POINTS_WOLFOS * (SG_SWAMP_WAVE_COUNT / 2))
// To obtain the Heart Piece from the Swamp Shooting Gallery, the player not only needs to achieve a perfect score,
// but they must also have at least six seconds remaining on the minigame timer. If the player has already obtained
// the Heart Piece, then this score will be used instead to determine if the player should get a Purple Rupee.
#define SG_SWAMP_HEART_PIECE_SCORE (SG_SWAMP_PERFECT_SCORE_WITHOUT_BONUS + (6 * SG_BONUS_POINTS_PER_SECOND))
ActorInit En_Syateki_Man_InitVars = {
ACTOR_EN_SYATEKI_MAN,
ACTORCAT_NPC,
@ -68,22 +99,23 @@ ActorInit En_Syateki_Man_InitVars = {
};
typedef enum {
/* 0 */ EN_SYATEKI_MAN_ANIM_HANDS_ON_TABLE,
/* 1 */ EN_SYATEKI_MAN_ANIM_SWAMP_HEAD_SCRATCH_LOOP,
/* 2 */ EN_SYATEKI_MAN_ANIM_SWAMP_HEAD_SCRATCH_END
} EnSyatekiManAnimation;
/* 0 */ SG_MAN_ANIM_HANDS_ON_TABLE,
/* 1 */ SG_MAN_ANIM_HEAD_SCRATCH_LOOP,
/* 2 */ SG_MAN_ANIM_HEAD_SCRATCH_END
} ShootingGalleryManAnimation;
static AnimationInfo sAnimationInfo[] = {
{ &gBurlyGuyHandsOnTableAnim, 1.0f, 0.0f, 0.0f, ANIMMODE_LOOP, -8.0f },
{ &gSwampShootingGalleryManHeadScratchLoopAnim, 1.0f, 0.0f, 0.0f, ANIMMODE_LOOP, -8.0f },
{ &gSwampShootingGalleryManHeadScratchEndAnim, 1.0f, 0.0f, 0.0f, ANIMMODE_ONCE, -8.0f },
{ &gBurlyGuyHandsOnTableAnim, 1.0f, 0.0f, 0.0f, ANIMMODE_LOOP, -8.0f }, // SG_MAN_ANIM_HANDS_ON_TABLE
{ &gBurlyGuyHeadScratchLoopAnim, 1.0f, 0.0f, 0.0f, ANIMMODE_LOOP, -8.0f }, // SG_MAN_ANIM_HEAD_SCRATCH_LOOP
{ &gBurlyGuyHeadScratchEndAnim, 1.0f, 0.0f, 0.0f, ANIMMODE_ONCE, -8.0f }, // SG_MAN_ANIM_HEAD_SCRATCH_END
};
/**
* In the Swamp Shooting Gallery, there are four waves of Guays.
* For each wave, these flags are used to control which Guays appear.
* The number of flags per wave should be exactly SG_SWAMP_GUAYS_PER_WAVE for all waves.
*/
static s16 sGuayFlagsPerWave[] = {
static s16 sGuayFlagsPerWave[SG_SWAMP_WAVE_COUNT] = {
(1 << 7) | (1 << 6) | (1 << 0),
(1 << 9) | (1 << 8) | (1 << 1),
(1 << 4) | (1 << 3) | (1 << 0),
@ -97,32 +129,25 @@ typedef struct {
} SwampTargetActorEntry; // size = 0x14
static SwampTargetActorEntry sNormalSwampTargetActorList[] = {
{ ACTOR_EN_SYATEKI_WF, -1000.0f, 200.0f, -700.0f, EN_SYATEKI_WF_PARAMS(1, 3, 0) },
{ ACTOR_EN_SYATEKI_WF, -1000.0f, 200.0f, -700.0f, EN_SYATEKI_WF_PARAMS(0, 2, 0) },
{ ACTOR_EN_SYATEKI_DEKUNUTS, -1000.0f, 200.0f, -700.0f,
EN_SYATEKI_DEKUNUTS_PARAMS(0, 0, EN_SYATEKI_DEKUNUTS_TYPE_NORMAL) },
{ ACTOR_EN_SYATEKI_DEKUNUTS, -1000.0f, 200.0f, -700.0f,
EN_SYATEKI_DEKUNUTS_PARAMS(0, 1, EN_SYATEKI_DEKUNUTS_TYPE_NORMAL) },
{ ACTOR_EN_SYATEKI_DEKUNUTS, -1000.0f, 200.0f, -700.0f,
EN_SYATEKI_DEKUNUTS_PARAMS(0, 2, EN_SYATEKI_DEKUNUTS_TYPE_NORMAL) },
{ ACTOR_EN_SYATEKI_DEKUNUTS, -1000.0f, 200.0f, -700.0f,
EN_SYATEKI_DEKUNUTS_PARAMS(0, 3, EN_SYATEKI_DEKUNUTS_TYPE_NORMAL) },
{ ACTOR_EN_SYATEKI_DEKUNUTS, -1000.0f, 200.0f, -700.0f,
EN_SYATEKI_DEKUNUTS_PARAMS(0, 4, EN_SYATEKI_DEKUNUTS_TYPE_NORMAL) },
{ ACTOR_EN_SYATEKI_DEKUNUTS, -1000.0f, 200.0f, -700.0f,
EN_SYATEKI_DEKUNUTS_PARAMS(0, 0, EN_SYATEKI_DEKUNUTS_TYPE_BONUS) },
{ ACTOR_EN_SYATEKI_DEKUNUTS, -1000.0f, 200.0f, -700.0f,
EN_SYATEKI_DEKUNUTS_PARAMS(0, 1, EN_SYATEKI_DEKUNUTS_TYPE_BONUS) },
{ ACTOR_EN_SYATEKI_CROW, -1000.0f, 200.0f, -700.0f, EN_SYATEKI_CROW_PARAMS(0, 0, 0) },
{ ACTOR_EN_SYATEKI_CROW, -1000.0f, 200.0f, -700.0f, EN_SYATEKI_CROW_PARAMS(1, 0, 0) },
{ ACTOR_EN_SYATEKI_CROW, -1000.0f, 200.0f, -700.0f, EN_SYATEKI_CROW_PARAMS(2, 0, 0) },
{ ACTOR_EN_SYATEKI_CROW, -1000.0f, 200.0f, -700.0f, EN_SYATEKI_CROW_PARAMS(3, 0, 0) },
{ ACTOR_EN_SYATEKI_CROW, -1000.0f, 200.0f, -700.0f, EN_SYATEKI_CROW_PARAMS(4, 2, 0) },
{ ACTOR_EN_SYATEKI_CROW, -1000.0f, 200.0f, -700.0f, EN_SYATEKI_CROW_PARAMS(5, 2, 0) },
{ ACTOR_EN_SYATEKI_CROW, -1000.0f, 200.0f, -700.0f, EN_SYATEKI_CROW_PARAMS(6, 0, 1) },
{ ACTOR_EN_SYATEKI_CROW, -1000.0f, 200.0f, -700.0f, EN_SYATEKI_CROW_PARAMS(7, 0, 2) },
{ ACTOR_EN_SYATEKI_CROW, -1000.0f, 200.0f, -700.0f, EN_SYATEKI_CROW_PARAMS(8, 0, 1) },
{ ACTOR_EN_SYATEKI_CROW, -1000.0f, 200.0f, -700.0f, EN_SYATEKI_CROW_PARAMS(9, 0, 2) },
{ ACTOR_EN_SYATEKI_WF, -1000.0f, 200.0f, -700.0f, SG_WOLFOS_PARAMS(1, 3, 0) },
{ ACTOR_EN_SYATEKI_WF, -1000.0f, 200.0f, -700.0f, SG_WOLFOS_PARAMS(0, 2, 0) },
{ ACTOR_EN_SYATEKI_DEKUNUTS, -1000.0f, 200.0f, -700.0f, SG_DEKU_PARAMS(0, 0, SG_DEKU_TYPE_NORMAL) },
{ ACTOR_EN_SYATEKI_DEKUNUTS, -1000.0f, 200.0f, -700.0f, SG_DEKU_PARAMS(0, 1, SG_DEKU_TYPE_NORMAL) },
{ ACTOR_EN_SYATEKI_DEKUNUTS, -1000.0f, 200.0f, -700.0f, SG_DEKU_PARAMS(0, 2, SG_DEKU_TYPE_NORMAL) },
{ ACTOR_EN_SYATEKI_DEKUNUTS, -1000.0f, 200.0f, -700.0f, SG_DEKU_PARAMS(0, 3, SG_DEKU_TYPE_NORMAL) },
{ ACTOR_EN_SYATEKI_DEKUNUTS, -1000.0f, 200.0f, -700.0f, SG_DEKU_PARAMS(0, 4, SG_DEKU_TYPE_NORMAL) },
{ ACTOR_EN_SYATEKI_DEKUNUTS, -1000.0f, 200.0f, -700.0f, SG_DEKU_PARAMS(0, 0, SG_DEKU_TYPE_BONUS) },
{ ACTOR_EN_SYATEKI_DEKUNUTS, -1000.0f, 200.0f, -700.0f, SG_DEKU_PARAMS(0, 1, SG_DEKU_TYPE_BONUS) },
{ ACTOR_EN_SYATEKI_CROW, -1000.0f, 200.0f, -700.0f, SG_GUAY_PARAMS(0, 0, 0) },
{ ACTOR_EN_SYATEKI_CROW, -1000.0f, 200.0f, -700.0f, SG_GUAY_PARAMS(1, 0, 0) },
{ ACTOR_EN_SYATEKI_CROW, -1000.0f, 200.0f, -700.0f, SG_GUAY_PARAMS(2, 0, 0) },
{ ACTOR_EN_SYATEKI_CROW, -1000.0f, 200.0f, -700.0f, SG_GUAY_PARAMS(3, 0, 0) },
{ ACTOR_EN_SYATEKI_CROW, -1000.0f, 200.0f, -700.0f, SG_GUAY_PARAMS(4, 2, 0) },
{ ACTOR_EN_SYATEKI_CROW, -1000.0f, 200.0f, -700.0f, SG_GUAY_PARAMS(5, 2, 0) },
{ ACTOR_EN_SYATEKI_CROW, -1000.0f, 200.0f, -700.0f, SG_GUAY_PARAMS(6, 0, 1) },
{ ACTOR_EN_SYATEKI_CROW, -1000.0f, 200.0f, -700.0f, SG_GUAY_PARAMS(7, 0, 2) },
{ ACTOR_EN_SYATEKI_CROW, -1000.0f, 200.0f, -700.0f, SG_GUAY_PARAMS(8, 0, 1) },
{ ACTOR_EN_SYATEKI_CROW, -1000.0f, 200.0f, -700.0f, SG_GUAY_PARAMS(9, 0, 2) },
};
/**
@ -130,22 +155,20 @@ static SwampTargetActorEntry sNormalSwampTargetActorList[] = {
* Without any "normal" Deku Scrubs, the game will not progress beyond the first wave.
*/
static SwampTargetActorEntry sUnusedSwampTargetActorList[] = {
{ ACTOR_EN_SYATEKI_CROW, -1000.0f, 200.0f, -700.0f, EN_SYATEKI_CROW_PARAMS(0, 0, 0) },
{ ACTOR_EN_SYATEKI_CROW, -1000.0f, 200.0f, -700.0f, EN_SYATEKI_CROW_PARAMS(1, 0, 0) },
{ ACTOR_EN_SYATEKI_DEKUNUTS, -1000.0f, 200.0f, -700.0f,
EN_SYATEKI_DEKUNUTS_PARAMS(0, 0, EN_SYATEKI_DEKUNUTS_TYPE_BONUS) },
{ ACTOR_EN_SYATEKI_DEKUNUTS, -1000.0f, 200.0f, -700.0f,
EN_SYATEKI_DEKUNUTS_PARAMS(0, 1, EN_SYATEKI_DEKUNUTS_TYPE_BONUS) },
{ ACTOR_EN_SYATEKI_CROW, -1000.0f, 200.0f, -700.0f, EN_SYATEKI_CROW_PARAMS(2, 0, 2) },
{ ACTOR_EN_SYATEKI_CROW, -1000.0f, 200.0f, -700.0f, EN_SYATEKI_CROW_PARAMS(3, 0, 2) },
{ ACTOR_EN_SYATEKI_CROW, -1000.0f, 200.0f, -700.0f, EN_SYATEKI_CROW_PARAMS(0, 0, 3) },
{ ACTOR_EN_SYATEKI_CROW, -1000.0f, 200.0f, -700.0f, EN_SYATEKI_CROW_PARAMS(1, 0, 3) },
{ ACTOR_EN_SYATEKI_CROW, -1000.0f, 200.0f, -700.0f, EN_SYATEKI_CROW_PARAMS(4, 2, 3) },
{ ACTOR_EN_SYATEKI_CROW, -1000.0f, 200.0f, -700.0f, EN_SYATEKI_CROW_PARAMS(2, 0, 4) },
{ ACTOR_EN_SYATEKI_CROW, -1000.0f, 200.0f, -700.0f, EN_SYATEKI_CROW_PARAMS(3, 0, 4) },
{ ACTOR_EN_SYATEKI_CROW, -1000.0f, 200.0f, -700.0f, EN_SYATEKI_CROW_PARAMS(4, 2, 4) },
{ ACTOR_EN_SYATEKI_WF, -1000.0f, 200.0f, -700.0f, EN_SYATEKI_WF_PARAMS(0, 2, 5) },
{ ACTOR_EN_SYATEKI_WF, -1000.0f, 200.0f, -700.0f, EN_SYATEKI_WF_PARAMS(1, 3, 6) },
{ ACTOR_EN_SYATEKI_CROW, -1000.0f, 200.0f, -700.0f, SG_GUAY_PARAMS(0, 0, 0) },
{ ACTOR_EN_SYATEKI_CROW, -1000.0f, 200.0f, -700.0f, SG_GUAY_PARAMS(1, 0, 0) },
{ ACTOR_EN_SYATEKI_DEKUNUTS, -1000.0f, 200.0f, -700.0f, SG_DEKU_PARAMS(0, 0, SG_DEKU_TYPE_BONUS) },
{ ACTOR_EN_SYATEKI_DEKUNUTS, -1000.0f, 200.0f, -700.0f, SG_DEKU_PARAMS(0, 1, SG_DEKU_TYPE_BONUS) },
{ ACTOR_EN_SYATEKI_CROW, -1000.0f, 200.0f, -700.0f, SG_GUAY_PARAMS(2, 0, 2) },
{ ACTOR_EN_SYATEKI_CROW, -1000.0f, 200.0f, -700.0f, SG_GUAY_PARAMS(3, 0, 2) },
{ ACTOR_EN_SYATEKI_CROW, -1000.0f, 200.0f, -700.0f, SG_GUAY_PARAMS(0, 0, 3) },
{ ACTOR_EN_SYATEKI_CROW, -1000.0f, 200.0f, -700.0f, SG_GUAY_PARAMS(1, 0, 3) },
{ ACTOR_EN_SYATEKI_CROW, -1000.0f, 200.0f, -700.0f, SG_GUAY_PARAMS(4, 2, 3) },
{ ACTOR_EN_SYATEKI_CROW, -1000.0f, 200.0f, -700.0f, SG_GUAY_PARAMS(2, 0, 4) },
{ ACTOR_EN_SYATEKI_CROW, -1000.0f, 200.0f, -700.0f, SG_GUAY_PARAMS(3, 0, 4) },
{ ACTOR_EN_SYATEKI_CROW, -1000.0f, 200.0f, -700.0f, SG_GUAY_PARAMS(4, 2, 4) },
{ ACTOR_EN_SYATEKI_WF, -1000.0f, 200.0f, -700.0f, SG_WOLFOS_PARAMS(0, 2, 5) },
{ ACTOR_EN_SYATEKI_WF, -1000.0f, 200.0f, -700.0f, SG_WOLFOS_PARAMS(1, 3, 6) },
};
static SwampTargetActorEntry* sSwampTargetActorLists[] = {
@ -179,14 +202,14 @@ void EnSyatekiMan_Swamp_SpawnTargetActors(EnSyatekiMan* this, PlayState* play2,
void EnSyatekiMan_Init(Actor* thisx, PlayState* play) {
EnSyatekiMan* this = THIS;
s32 pad;
Path* path = &play->setupPathList[EN_SYATEKI_MAN_GET_PATH_INDEX(&this->actor)];
Path* path = &play->setupPathList[SG_MAN_GET_PATH_INDEX(&this->actor)];
s32 actorListLength = sSwampTargetActorListLengths[this->swampTargetActorListIndex];
this->actor.targetMode = 1;
Actor_SetScale(&this->actor, 0.01f);
if (play->sceneId == SCENE_SYATEKI_MORI) {
SkelAnime_InitFlex(play, &this->skelAnime, &gBurlyGuySkel, &gSwampShootingGalleryManHeadScratchLoopAnim,
this->jointTable, this->morphTable, BURLY_GUY_LIMB_MAX);
SkelAnime_InitFlex(play, &this->skelAnime, &gBurlyGuySkel, &gBurlyGuyHeadScratchLoopAnim, this->jointTable,
this->morphTable, BURLY_GUY_LIMB_MAX);
} else {
SkelAnime_InitFlex(play, &this->skelAnime, &gBurlyGuySkel, &gBurlyGuyHandsOnTableAnim, this->jointTable,
this->morphTable, BURLY_GUY_LIMB_MAX);
@ -197,7 +220,7 @@ void EnSyatekiMan_Init(Actor* thisx, PlayState* play) {
this->shootingGameState = SG_GAME_STATE_NONE;
this->talkWaitTimer = 15;
this->flagsIndex = 0;
this->perGameVar2.lastHitOctorokType = SG_OCTO_TYPE_NONE;
this->lastHitOctorokType = SG_OCTO_TYPE_NONE;
this->octorokFlags = 0;
this->dekuScrubFlags = 0;
this->guayFlags = 0;
@ -265,7 +288,7 @@ void EnSyatekiMan_Swamp_Idle(EnSyatekiMan* this, PlayState* play) {
if (Actor_ProcessTalkRequest(&this->actor, &play->state)) {
u16 faceReactionTextId;
Actor_ChangeAnimationByInfo(&this->skelAnime, sAnimationInfo, EN_SYATEKI_MAN_ANIM_SWAMP_HEAD_SCRATCH_END);
Actor_ChangeAnimationByInfo(&this->skelAnime, sAnimationInfo, SG_MAN_ANIM_HEAD_SCRATCH_END);
faceReactionTextId = Text_GetFaceReaction(play, FACE_REACTION_SET_SWAMP_SHOOTING_GALLERY_MAN);
if (faceReactionTextId != 0) {
Message_StartTextbox(play, faceReactionTextId, &this->actor);
@ -482,9 +505,9 @@ void EnSyatekiMan_Swamp_Talk(EnSyatekiMan* this, PlayState* play) {
break;
}
if (this->skelAnime.animation == &gSwampShootingGalleryManHeadScratchEndAnim) {
if (this->skelAnime.animation == &gBurlyGuyHeadScratchEndAnim) {
if (Animation_OnFrame(&this->skelAnime, this->skelAnime.endFrame)) {
Actor_ChangeAnimationByInfo(&this->skelAnime, sAnimationInfo, EN_SYATEKI_MAN_ANIM_HANDS_ON_TABLE);
Actor_ChangeAnimationByInfo(&this->skelAnime, sAnimationInfo, SG_MAN_ANIM_HANDS_ON_TABLE);
}
}
}
@ -858,20 +881,22 @@ void EnSyatekiMan_Swamp_SetupGiveReward(EnSyatekiMan* this, PlayState* play) {
Player* player = GET_PLAYER(play);
if (Actor_HasParent(&this->actor, play)) {
if (!CHECK_WEEKEVENTREG(WEEKEVENTREG_59_10)) {
SET_WEEKEVENTREG(WEEKEVENTREG_59_10);
} else if (!CHECK_WEEKEVENTREG(WEEKEVENTREG_32_02) && (this->score >= 2180)) {
SET_WEEKEVENTREG(WEEKEVENTREG_32_02);
if (!CHECK_WEEKEVENTREG(WEEKEVENTREG_RECEIVED_SWAMP_SHOOTING_GALLERY_QUIVER_UPGRADE)) {
SET_WEEKEVENTREG(WEEKEVENTREG_RECEIVED_SWAMP_SHOOTING_GALLERY_QUIVER_UPGRADE);
} else if (!CHECK_WEEKEVENTREG(WEEKEVENTREG_RECEIVED_SWAMP_SHOOTING_GALLERY_HEART_PIECE) &&
(this->score >= SG_SWAMP_HEART_PIECE_SCORE)) {
SET_WEEKEVENTREG(WEEKEVENTREG_RECEIVED_SWAMP_SHOOTING_GALLERY_HEART_PIECE);
}
this->actor.parent = NULL;
this->actionFunc = EnSyatekiMan_Swamp_GiveReward;
} else {
if ((CUR_UPG_VALUE(UPG_QUIVER) < 3) && !CHECK_WEEKEVENTREG(WEEKEVENTREG_59_10)) {
if ((CUR_UPG_VALUE(UPG_QUIVER) < 3) &&
!CHECK_WEEKEVENTREG(WEEKEVENTREG_RECEIVED_SWAMP_SHOOTING_GALLERY_QUIVER_UPGRADE)) {
Actor_OfferGetItem(&this->actor, play, GI_QUIVER_30 + CUR_UPG_VALUE(UPG_QUIVER), 500.0f, 100.0f);
} else if (this->score < 2180) {
} else if (this->score < SG_SWAMP_HEART_PIECE_SCORE) {
Actor_OfferGetItem(&this->actor, play, GI_RUPEE_RED, 500.0f, 100.0f);
} else if (!CHECK_WEEKEVENTREG(WEEKEVENTREG_32_02)) {
} else if (!CHECK_WEEKEVENTREG(WEEKEVENTREG_RECEIVED_SWAMP_SHOOTING_GALLERY_HEART_PIECE)) {
Actor_OfferGetItem(&this->actor, play, GI_HEART_PIECE, 500.0f, 100.0f);
} else {
Actor_OfferGetItem(&this->actor, play, GI_RUPEE_PURPLE, 500.0f, 100.0f);
@ -913,14 +938,14 @@ void EnSyatekiMan_Town_SetupGiveReward(EnSyatekiMan* this, PlayState* play) {
if (Actor_HasParent(&this->actor, play)) {
if (this->prevTextId == 0x407) {
if (!CHECK_WEEKEVENTREG(WEEKEVENTREG_59_20)) {
SET_WEEKEVENTREG(WEEKEVENTREG_59_20);
if (!CHECK_WEEKEVENTREG(WEEKEVENTREG_RECEIVED_TOWN_SHOOTING_GALLERY_QUIVER_UPGRADE)) {
SET_WEEKEVENTREG(WEEKEVENTREG_RECEIVED_TOWN_SHOOTING_GALLERY_QUIVER_UPGRADE);
}
}
if ((this->prevTextId == 0x405) || (this->prevTextId == 0x406)) {
if (!CHECK_WEEKEVENTREG(WEEKEVENTREG_32_04)) {
SET_WEEKEVENTREG(WEEKEVENTREG_32_04);
if (!CHECK_WEEKEVENTREG(WEEKEVENTREG_RECEIVED_TOWN_SHOOTING_GALLERY_HEART_PIECE)) {
SET_WEEKEVENTREG(WEEKEVENTREG_RECEIVED_TOWN_SHOOTING_GALLERY_HEART_PIECE);
}
}
@ -928,12 +953,13 @@ void EnSyatekiMan_Town_SetupGiveReward(EnSyatekiMan* this, PlayState* play) {
this->actionFunc = EnSyatekiMan_Town_GiveReward;
} else {
if (this->prevTextId == 0x407) {
if ((CUR_UPG_VALUE(UPG_QUIVER) < 3) && !CHECK_WEEKEVENTREG(WEEKEVENTREG_59_20)) {
if ((CUR_UPG_VALUE(UPG_QUIVER) < 3) &&
!CHECK_WEEKEVENTREG(WEEKEVENTREG_RECEIVED_TOWN_SHOOTING_GALLERY_QUIVER_UPGRADE)) {
Actor_OfferGetItem(&this->actor, play, GI_QUIVER_30 + CUR_UPG_VALUE(UPG_QUIVER), 500.0f, 100.0f);
} else {
Actor_OfferGetItem(&this->actor, play, GI_RUPEE_PURPLE, 500.0f, 100.0f);
}
} else if (!CHECK_WEEKEVENTREG(WEEKEVENTREG_32_04)) {
} else if (!CHECK_WEEKEVENTREG(WEEKEVENTREG_RECEIVED_TOWN_SHOOTING_GALLERY_HEART_PIECE)) {
Actor_OfferGetItem(&this->actor, play, GI_HEART_PIECE, 500.0f, 100.0f);
} else {
Actor_OfferGetItem(&this->actor, play, GI_RUPEE_HUGE, 500.0f, 100.0f);
@ -1012,11 +1038,11 @@ void EnSyatekiMan_Swamp_StartGame(EnSyatekiMan* this, PlayState* play) {
this->dekuScrubFlags = (1 << 4) | (1 << 3) | (1 << 2) | (1 << 1) | (1 << 0);
this->guayFlags = 0;
this->wolfosFlags = 0;
this->perGameVar1.guaySpawnTimer = 0;
this->guayAppearTimer = 0;
this->dekuScrubHitCounter = 0;
this->guayHitCounter = 0;
this->currentWave = 0;
this->perGameVar2.bonusDekuScrubHitCounter = 0;
this->bonusDekuScrubHitCounter = 0;
Interface_StartTimer(TIMER_ID_MINIGAME_1, 100);
this->actor.draw = NULL;
this->actionFunc = EnSyatekiMan_Swamp_RunGame;
@ -1024,72 +1050,80 @@ void EnSyatekiMan_Swamp_StartGame(EnSyatekiMan* this, PlayState* play) {
}
void EnSyatekiMan_Swamp_RunGame(EnSyatekiMan* this, PlayState* play) {
static s16 sHasSpawnedGuaysForThisWave = false;
static s16 sHasSignaledGuaysForThisWave = false;
Player* player = GET_PLAYER(play);
if (((this->dekuScrubFlags == 0) || (this->perGameVar1.guaySpawnTimer > 140)) && !sHasSpawnedGuaysForThisWave &&
(this->currentWave < 4)) {
// Spawn three guays after the player has killed all Deku Scrubs, or after 140 frames.
sHasSpawnedGuaysForThisWave = true;
this->perGameVar1.guaySpawnTimer = 0;
if (((this->dekuScrubFlags == 0) || (this->guayAppearTimer > 140)) && !sHasSignaledGuaysForThisWave &&
(this->currentWave < SG_SWAMP_WAVE_COUNT)) {
// Make three Guays appear after the player has killed all Deku Scrubs, or after 140 frames.
sHasSignaledGuaysForThisWave = true;
this->guayAppearTimer = 0;
Actor_PlaySfx(&this->actor, NA_SE_SY_FOUND);
this->guayFlags = sGuayFlagsPerWave[this->flagsIndex];
if (this->flagsIndex == 3) {
if (this->flagsIndex == ARRAY_COUNT(sGuayFlagsPerWave) - 1) {
this->flagsIndex = 0;
} else {
this->flagsIndex++;
}
} else if ((this->guayFlags == 0) && (this->dekuScrubFlags == 0) && (sHasSpawnedGuaysForThisWave == true) &&
(this->currentWave < 4)) {
} else if ((this->guayFlags == 0) && (this->dekuScrubFlags == 0) && (sHasSignaledGuaysForThisWave == true) &&
(this->currentWave < SG_SWAMP_WAVE_COUNT)) {
// Once all Deku Scrubs and Guays in this wave have either disappeared or died, move on to the next wave.
if (this->guayHitCounter < 3) {
if (this->guayHitCounter < SG_SWAMP_GUAYS_PER_WAVE) {
this->guayHitCounter = 0;
}
this->perGameVar1.guaySpawnTimer = 0;
sHasSpawnedGuaysForThisWave = false;
this->guayAppearTimer = 0;
sHasSignaledGuaysForThisWave = false;
this->currentWave++;
if (this->currentWave < 4) {
if (this->currentWave < SG_SWAMP_WAVE_COUNT) {
this->dekuScrubFlags = (1 << 4) | (1 << 3) | (1 << 2) | (1 << 1) | (1 << 0);
}
}
if (this->guayHitCounter == 3) {
// Makes a Wolfos appear after the player has shot all the Guays in the current wave.
if (this->guayHitCounter == SG_SWAMP_GUAYS_PER_WAVE) {
this->guayHitCounter = 0;
this->wolfosFlags |= 1;
}
if (this->dekuScrubHitCounter == 10) {
// Makes a Wolfos appear after the player has shot two waves of Deku Scrubs.
if (this->dekuScrubHitCounter == SG_SWAMP_DEKUS_PER_WAVE * 2) {
this->dekuScrubHitCounter = 0;
this->wolfosFlags |= 2;
}
this->perGameVar1.guaySpawnTimer++;
this->guayAppearTimer++;
if (gSaveContext.timerCurTimes[TIMER_ID_MINIGAME_1] == SECONDS_TO_TIMER(0)) {
// End the game because the timer ran out.
gSaveContext.timerCurTimes[TIMER_ID_MINIGAME_1] = SECONDS_TO_TIMER(0);
gSaveContext.timerStates[TIMER_ID_MINIGAME_1] = TIMER_STATE_STOP;
this->actor.draw = EnSyatekiMan_Draw;
this->flagsIndex = 0;
this->currentWave = 0;
player->stateFlags1 |= PLAYER_STATE1_20;
sHasSpawnedGuaysForThisWave = false;
sHasSignaledGuaysForThisWave = false;
Audio_StopSubBgm();
this->actionFunc = EnSyatekiMan_Swamp_EndGame;
} else if ((this->currentWave == 4) && (this->wolfosFlags == 0) &&
(this->perGameVar2.bonusDekuScrubHitCounter == 2)) {
} else if ((this->currentWave == SG_SWAMP_WAVE_COUNT) && (this->wolfosFlags == 0) &&
(this->bonusDekuScrubHitCounter == SG_SWAMP_BONUS_DEKU_COUNT)) {
// End the game because the player has nothing left to shoot. This doesn't mean the
// player actually hit everything, since Guays and Wolfos can escape.
this->actor.draw = EnSyatekiMan_Draw;
this->flagsIndex = 0;
this->currentWave = 0;
player->stateFlags1 |= PLAYER_STATE1_20;
sHasSpawnedGuaysForThisWave = false;
sHasSignaledGuaysForThisWave = false;
Audio_StopSubBgm();
this->shootingGameState = SG_GAME_STATE_GIVING_BONUS;
if (this->score == 2120) {
if (this->score == SG_SWAMP_PERFECT_SCORE_WITHOUT_BONUS) {
Interface_SetPerfectLetters(play, PERFECT_LETTERS_TYPE_2);
gSaveContext.timerStates[TIMER_ID_MINIGAME_1] = TIMER_STATE_6;
this->actionFunc = EnSyatekiMan_Swamp_AddBonusPoints;
} else {
// If the player ran out of things to shoot but did *not* get a perfect score, then
// they must have missed a Guay or Wolfos at some point; don't award any bonus points.
gSaveContext.timerStates[TIMER_ID_MINIGAME_1] = TIMER_STATE_STOP;
this->actionFunc = EnSyatekiMan_Swamp_EndGame;
}
@ -1108,7 +1142,7 @@ void EnSyatekiMan_Swamp_EndGame(EnSyatekiMan* this, PlayState* play) {
}
this->talkWaitTimer = 15;
if (this->score >= 2120) {
if (this->score >= SG_SWAMP_PERFECT_SCORE_WITHOUT_BONUS) {
// Perfect! Take this!
Message_StartTextbox(play, 0xA34, &this->actor);
this->prevTextId = 0xA34;
@ -1162,8 +1196,8 @@ void EnSyatekiMan_Swamp_AddBonusPoints(EnSyatekiMan* this, PlayState* play) {
sBonusTimer = 0;
} else if (sBonusTimer > 10) {
gSaveContext.timerStopTimes[TIMER_ID_MINIGAME_1] += SECONDS_TO_TIMER(1);
play->interfaceCtx.minigamePoints += 10;
this->score += 10;
play->interfaceCtx.minigamePoints += SG_BONUS_POINTS_PER_SECOND;
this->score += SG_BONUS_POINTS_PER_SECOND;
Actor_PlaySfx(&this->actor, NA_SE_SY_TRE_BOX_APPEAR);
sBonusTimer = 0;
} else {
@ -1222,8 +1256,8 @@ void EnSyatekiMan_Town_StartGame(EnSyatekiMan* this, PlayState* play) {
player->stateFlags1 &= ~PLAYER_STATE1_20;
this->score = 0;
this->flagsIndex = 0;
this->perGameVar1.octorokState = SG_OCTO_STATE_INITIAL;
this->perGameVar2.lastHitOctorokType = SG_OCTO_TYPE_NONE;
this->octorokState = SG_OCTO_STATE_INITIAL;
this->lastHitOctorokType = SG_OCTO_TYPE_NONE;
sGameStartTimer = 30;
Interface_StartTimer(TIMER_ID_MINIGAME_1, 75);
this->actor.draw = NULL;
@ -1321,36 +1355,36 @@ void EnSyatekiMan_Town_RunGame(EnSyatekiMan* this, PlayState* play) {
// Octoroks begin hiding four seconds after a wave begins.
if (waveTimer < 100) {
this->perGameVar1.octorokState = SG_OCTO_STATE_HIDING;
this->octorokState = SG_OCTO_STATE_HIDING;
}
if (this->perGameVar2.lastHitOctorokType != SG_OCTO_TYPE_NONE) {
if (this->perGameVar2.lastHitOctorokType == SG_OCTO_TYPE_BLUE) {
if (this->lastHitOctorokType != SG_OCTO_TYPE_NONE) {
if (this->lastHitOctorokType == SG_OCTO_TYPE_BLUE) {
gSaveContext.timerTimeLimits[TIMER_ID_MINIGAME_1] -= SECONDS_TO_TIMER_PRECISE(2, 50);
sModFromLosingTime = (sModFromLosingTime + 25) % 50;
}
this->perGameVar2.lastHitOctorokType = SG_OCTO_TYPE_NONE;
this->lastHitOctorokType = SG_OCTO_TYPE_NONE;
}
if (this->perGameVar1.octorokState == SG_OCTO_STATE_APPEARING) {
this->perGameVar1.octorokState++;
if (this->octorokState == SG_OCTO_STATE_APPEARING) {
this->octorokState++;
}
// A new wave of Octoroks should appear every five seconds. However, we need to take into account
// 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 ((sModFromLosingTime == (timer % 50)) && (this->octorokState >= SG_OCTO_STATE_INITIAL)) {
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_APPEARING;
this->octorokState = SG_OCTO_STATE_APPEARING;
}
}
if (gSaveContext.timerCurTimes[TIMER_ID_MINIGAME_1] == SECONDS_TO_TIMER(0)) {
this->flagsIndex = 0;
this->perGameVar1.octorokState = SG_OCTO_STATE_HIDING;
this->octorokState = SG_OCTO_STATE_HIDING;
gSaveContext.timerCurTimes[TIMER_ID_MINIGAME_1] = SECONDS_TO_TIMER(0);
gSaveContext.timerStates[TIMER_ID_MINIGAME_1] = TIMER_STATE_STOP;
player->stateFlags1 |= PLAYER_STATE1_20;
@ -1374,7 +1408,7 @@ void EnSyatekiMan_Town_EndGame(EnSyatekiMan* this, PlayState* play) {
this->talkWaitTimer = 15;
if ((GET_TOWN_SHOOTING_GALLERY_HIGH_SCORE() < this->score) || (this->score == 50)) {
if (GET_TOWN_SHOOTING_GALLERY_HIGH_SCORE() < this->score) {
if (!CHECK_WEEKEVENTREG(WEEKEVENTREG_59_20)) {
if (!CHECK_WEEKEVENTREG(WEEKEVENTREG_RECEIVED_TOWN_SHOOTING_GALLERY_QUIVER_UPGRADE)) {
// You got a new record!
Message_StartTextbox(play, 0x407, &this->actor);
this->prevTextId = 0x407;

View File

@ -3,12 +3,29 @@
#include "global.h"
#include "objects/object_shn/object_shn.h"
#include "overlays/effects/ovl_Effect_Ss_Extra/z_eff_ss_extra.h"
struct EnSyatekiMan;
typedef void (*EnSyatekiManActionFunc)(struct EnSyatekiMan*, PlayState*);
#define EN_SYATEKI_MAN_GET_PATH_INDEX(thisx) (((thisx)->params & 0xFF00) >> 8)
#define SG_MAN_GET_PATH_INDEX(thisx) (((thisx)->params & 0xFF00) >> 8)
// These values are used to modify the shooting gallery man's internal score. They are
// defined in terms of the scores used by EffectSsExtra because EffectSsExtra_Update
// updates the score displayed to the player, and defining them like this will prevent
// these two different scores from becoming desynchronized. If you intend to modify these
// values, then you'll also need to make sure that EffectSsExtra_Spawn in the appropriate
// actor is called with the correct parameter for the index; failing to do this will
// cause the two different score variables to fall out of sync.
#define SG_POINTS_DEKU_NORMAL EXTRA_SCORE_30
#define SG_POINTS_DEKU_BONUS EXTRA_SCORE_100
#define SG_POINTS_GUAY EXTRA_SCORE_60
#define SG_POINTS_WOLFOS EXTRA_SCORE_100
// After getting a perfect score in the Swamp Shooting Gallery, the player is rewarded
// additional points for every second remaining on the minigame timer.
#define SG_BONUS_POINTS_PER_SECOND 10
typedef enum {
/* 0 */ SG_GAME_STATE_NONE, // None of the states below apply.
@ -22,17 +39,17 @@ typedef enum {
} ShootingGalleryGameState;
typedef enum {
/* 0 */ SG_OCTO_STATE_APPEARING,
/* 1 */ SG_OCTO_STATE_APPEARED,
/* 70 */ SG_OCTO_STATE_INITIAL = 70,
/* 80 */ SG_OCTO_STATE_HIDING = 80
/* 0 */ SG_OCTO_STATE_APPEARING, // The Octoroks will begin to appear on the next frame.
/* 1 */ SG_OCTO_STATE_APPEARED, // The Octoroks are appearing from underwater or have already appeared and are floating.
/* 70 */ SG_OCTO_STATE_INITIAL = 70, // The initial state of the game. The Octoroks have not appeared yet.
/* 80 */ SG_OCTO_STATE_HIDING = 80 // The Octoroks are in the process of hiding underwater.
} ShootingGalleryOctorokState;
typedef enum {
/* 0 */ SG_PATH_TYPE_CROW,
/* 1 */ SG_PATH_TYPE_SCRUB_NORMAL,
/* 0 */ SG_PATH_TYPE_GUAY,
/* 1 */ SG_PATH_TYPE_DEKU_NORMAL,
/* 2 */ SG_PATH_TYPE_WOLFOS,
/* 3 */ SG_PATH_TYPE_SCRUB_BONUS
/* 3 */ SG_PATH_TYPE_DEKU_BONUS
} ShootingGalleryPathType;
typedef struct EnSyatekiMan {
@ -41,7 +58,7 @@ typedef struct EnSyatekiMan {
/* 0x188 */ EnSyatekiManActionFunc actionFunc;
/* 0x18C */ Path* path;
/* 0x190 */ s32 octorokFlags;
/* 0x194 */ s32 swampTargetActorListIndex; // used but never initialized, so the value is implicitly always 0
/* 0x194 */ s32 swampTargetActorListIndex;
/* 0x198 */ Vec3s jointTable[BURLY_GUY_LIMB_MAX];
/* 0x1F8 */ Vec3s morphTable[BURLY_GUY_LIMB_MAX];
/* 0x258 */ Vec3s headRot;
@ -51,13 +68,13 @@ typedef struct EnSyatekiMan {
/* 0x268 */ UNK_TYPE1 unk268[0x2];
/* 0x26A */ s16 shootingGameState;
/* 0x26C */ union {
s16 guaySpawnTimer;
s16 guayAppearTimer;
s16 octorokState;
} perGameVar1;
};
/* 0x26E */ union {
s16 bonusDekuScrubHitCounter;
s16 lastHitOctorokType;
} perGameVar2;
};
/* 0x270 */ s16 talkWaitTimer;
/* 0x272 */ s16 dekuScrubFlags;
/* 0x274 */ s16 guayFlags;

View File

@ -249,7 +249,7 @@ void EnSyatekiOkuta_Float(EnSyatekiOkuta* this, PlayState* play) {
// 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) {
if (syatekiMan->octorokState >= SG_OCTO_STATE_INITIAL) {
EnSyatekiOkuta_SetupHide(this);
}
}
@ -405,7 +405,7 @@ void EnSyatekiOkuta_CheckForSignal(EnSyatekiOkuta* this, PlayState* play) {
if ((this->actionFunc != EnSyatekiOkuta_Float) && (this->actionFunc != EnSyatekiOkuta_Appear) &&
(syatekiMan->shootingGameState == SG_GAME_STATE_RUNNING) &&
(syatekiMan->perGameVar1.octorokState == SG_OCTO_STATE_APPEARING)) {
(syatekiMan->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);
@ -434,10 +434,10 @@ void EnSyatekiOkuta_Update(Actor* thisx, PlayState* play) {
Actor_PlaySfx(&this->actor, NA_SE_SY_TRE_BOX_APPEAR);
play->interfaceCtx.minigamePoints++;
syatekiMan->score++;
syatekiMan->perGameVar2.lastHitOctorokType = SG_OCTO_TYPE_RED;
syatekiMan->lastHitOctorokType = SG_OCTO_TYPE_RED;
} else {
Actor_PlaySfx(&this->actor, NA_SE_SY_ERROR);
syatekiMan->perGameVar2.lastHitOctorokType = SG_OCTO_TYPE_BLUE;
syatekiMan->lastHitOctorokType = SG_OCTO_TYPE_BLUE;
}
EnSyatekiOkuta_SetupDie(this);

View File

@ -114,23 +114,23 @@ ActorInit En_Syateki_Wf_InitVars = {
};
typedef enum {
/* 0 */ EN_SYATEKI_WF_ANIM_WAIT, // unused
/* 1 */ EN_SYATEKI_WF_ANIM_RUN,
/* 2 */ EN_SYATEKI_WF_ANIM_JUMP,
/* 3 */ EN_SYATEKI_WF_ANIM_LAND,
/* 4 */ EN_SYATEKI_WF_ANIM_BACKFLIP, // unused
/* 5 */ EN_SYATEKI_WF_ANIM_DAMAGED,
/* 6 */ EN_SYATEKI_WF_ANIM_REAR_UP_FALL_OVER
} EnSyatekiWfAnimation;
/* 0 */ SG_WOLFOS_ANIM_WAIT, // unused
/* 1 */ SG_WOLFOS_ANIM_RUN,
/* 2 */ SG_WOLFOS_ANIM_JUMP,
/* 3 */ SG_WOLFOS_ANIM_LAND,
/* 4 */ SG_WOLFOS_ANIM_BACKFLIP, // unused
/* 5 */ SG_WOLFOS_ANIM_DAMAGED,
/* 6 */ SG_WOLFOS_ANIM_REAR_UP_FALL_OVER
} ShootingGalleryWolfosAnimation;
static AnimationInfo sAnimationInfo[] = {
{ &gWolfosWaitAnim, 2.0f, 0.0f, 0.0f, ANIMMODE_LOOP, -1.0f },
{ &gWolfosRunAnim, 1.0f, 0.0f, 0.0f, ANIMMODE_LOOP, -8.0f },
{ &gWolfosRunAnim, 1.0f, 0.0f, 4.0f, ANIMMODE_ONCE, 1.0f },
{ &gWolfosRunAnim, 1.0f, 4.0f, 8.0f, ANIMMODE_ONCE, 1.0f },
{ &gWolfosBackflipAnim, 1.0f, 0.0f, 0.0f, ANIMMODE_ONCE, -1.0f },
{ &gWolfosDamagedAnim, 1.0f, 0.0f, 0.0f, ANIMMODE_ONCE, 8.0f },
{ &gWolfosRearUpFallOverAnim, 1.0f, 0.0f, 0.0f, ANIMMODE_ONCE, -1.0f },
{ &gWolfosWaitAnim, 2.0f, 0.0f, 0.0f, ANIMMODE_LOOP, -1.0f }, // SG_WOLFOS_ANIM_WAIT
{ &gWolfosRunAnim, 1.0f, 0.0f, 0.0f, ANIMMODE_LOOP, -8.0f }, // SG_WOLFOS_ANIM_RUN
{ &gWolfosRunAnim, 1.0f, 0.0f, 4.0f, ANIMMODE_ONCE, 1.0f }, // SG_WOLFOS_ANIM_JUMP
{ &gWolfosRunAnim, 1.0f, 4.0f, 8.0f, ANIMMODE_ONCE, 1.0f }, // SG_WOLFOS_ANIM_LAND
{ &gWolfosBackflipAnim, 1.0f, 0.0f, 0.0f, ANIMMODE_ONCE, -1.0f }, // SG_WOLFOS_ANIM_BACKFLIP
{ &gWolfosDamagedAnim, 1.0f, 0.0f, 0.0f, ANIMMODE_ONCE, 8.0f }, // SG_WOLFOS_ANIM_DAMAGED
{ &gWolfosRearUpFallOverAnim, 1.0f, 0.0f, 0.0f, ANIMMODE_ONCE, -1.0f }, // SG_WOLFOS_ANIM_REAR_UP_FALL_OVER
};
static InitChainEntry sInitChain[] = {
@ -150,7 +150,7 @@ void EnSyatekiWf_Init(Actor* thisx, PlayState* play) {
path = &play->setupPathList[path->additionalPathIndex];
}
for (i = 0; i < EN_SYATEKI_WF_GET_INDEX(&this->actor); i++) {
for (i = 0; i < SG_WOLFOS_GET_INDEX(&this->actor); i++) {
path = &play->setupPathList[path->additionalPathIndex];
}
@ -224,7 +224,7 @@ void EnSyatekiWf_SetupWaitForSignal(EnSyatekiWf* this) {
this->actor.draw = NULL;
this->currentPointIndex = 1;
this->isActive = false;
syatekiMan->wolfosFlags &= ~(1 << EN_SYATEKI_WF_GET_INDEX(&this->actor));
syatekiMan->wolfosFlags &= ~(1 << SG_WOLFOS_GET_INDEX(&this->actor));
this->actionFunc = EnSyatekiWf_WaitForSignal;
}
@ -239,7 +239,7 @@ void EnSyatekiWf_WaitForSignal(EnSyatekiWf* this, PlayState* play) {
if ((syatekiMan->shootingGameState == SG_GAME_STATE_RUNNING) && (this->isActive == true)) {
EnSyatekiWf_InitPathStart(this);
EnSyatekiWf_SetupWaitToMove(this);
} else if (syatekiMan->wolfosFlags & (1 << EN_SYATEKI_WF_GET_INDEX(&this->actor))) {
} else if (syatekiMan->wolfosFlags & (1 << SG_WOLFOS_GET_INDEX(&this->actor))) {
this->isActive = true;
}
}
@ -263,7 +263,7 @@ void EnSyatekiWf_WaitToMove(EnSyatekiWf* this, PlayState* play) {
}
void EnSyatekiWf_SetupRun(EnSyatekiWf* this) {
Actor_ChangeAnimationByInfo(&this->skelAnime, sAnimationInfo, EN_SYATEKI_WF_ANIM_RUN);
Actor_ChangeAnimationByInfo(&this->skelAnime, sAnimationInfo, SG_WOLFOS_ANIM_RUN);
this->actor.speed = 10.0f;
this->actor.world.rot.y = this->actor.shape.rot.y;
this->actor.draw = EnSyatekiWf_Draw;
@ -318,7 +318,7 @@ void EnSyatekiWf_Run(EnSyatekiWf* this, PlayState* play) {
}
} else {
if (this->currentPointIndex < (this->maxPointIndex - 1)) {
if (this->currentPointIndex == EN_SYATEKI_WF_GET_POINT_TO_HOWL(&this->actor)) {
if (this->currentPointIndex == SG_WOLFOS_GET_POINT_TO_HOWL(&this->actor)) {
EnSyatekiWf_SetupHowl(this);
}
@ -340,7 +340,7 @@ void EnSyatekiWf_SetupJump(EnSyatekiWf* this) {
Actor_PlaySfx(&this->actor, NA_SE_EN_TEKU_JUMP);
this->actor.velocity.y = 20.0f;
this->actor.speed = 5.0f;
Actor_ChangeAnimationByInfo(&this->skelAnime, sAnimationInfo, EN_SYATEKI_WF_ANIM_JUMP);
Actor_ChangeAnimationByInfo(&this->skelAnime, sAnimationInfo, SG_WOLFOS_ANIM_JUMP);
this->actionFunc = EnSyatekiWf_Jump;
}
@ -352,7 +352,7 @@ void EnSyatekiWf_Jump(EnSyatekiWf* this, PlayState* play) {
void EnSyatekiWf_SetupLand(EnSyatekiWf* this) {
this->actor.speed = 0.0f;
Actor_ChangeAnimationByInfo(&this->skelAnime, sAnimationInfo, EN_SYATEKI_WF_ANIM_LAND);
Actor_ChangeAnimationByInfo(&this->skelAnime, sAnimationInfo, SG_WOLFOS_ANIM_LAND);
this->actionFunc = EnSyatekiWf_Land;
}
@ -369,7 +369,7 @@ void EnSyatekiWf_SetupHowl(EnSyatekiWf* this) {
this->timer = 40;
this->actor.speed = 0.0f;
Actor_PlaySfx(&this->actor, NA_SE_EN_WOLFOS_APPEAR);
Actor_ChangeAnimationByInfo(&this->skelAnime, sAnimationInfo, EN_SYATEKI_WF_ANIM_DAMAGED);
Actor_ChangeAnimationByInfo(&this->skelAnime, sAnimationInfo, SG_WOLFOS_ANIM_DAMAGED);
this->actionFunc = EnSyatekiWf_Howl;
}
@ -390,10 +390,10 @@ void EnSyatekiWf_SetupDead(EnSyatekiWf* this, PlayState* play) {
this->isActive = false;
this->actor.speed = 0.0f;
EffectSsExtra_Spawn(play, &this->actor.world.pos, &sVelocity, &sAccel, 5, 2);
EffectSsExtra_Spawn(play, &this->actor.world.pos, &sVelocity, &sAccel, 5, EXTRA_SCORE_INDEX_100);
Actor_PlaySfx(&this->actor, NA_SE_EN_WOLFOS_DEAD);
Actor_ChangeAnimationByInfo(&this->skelAnime, sAnimationInfo, EN_SYATEKI_WF_ANIM_REAR_UP_FALL_OVER);
syatekiMan->score += 100;
Actor_ChangeAnimationByInfo(&this->skelAnime, sAnimationInfo, SG_WOLFOS_ANIM_REAR_UP_FALL_OVER);
syatekiMan->score += SG_POINTS_WOLFOS;
this->actionFunc = EnSyatekiWf_Dead;
}
@ -441,19 +441,19 @@ void EnSyatekiWf_Update(Actor* thisx, PlayState* play2) {
this->tailCollider.base.acFlags &= ~AC_HIT;
this->headCollider.base.acFlags &= ~AC_HIT;
// The Wolfos always starts with 2 health, so the subtraction below is guaranteed to kill it;
// the else-block is never reached in practice. If you *could* damage the Wolfos without killing
// it, then the number "30" would appear every time you hit it, and the player's displayed score
// would increase by 30. However, the else-block doesn't increase the shooting gallery man's
// "score" variable, so it would become desynchronized from the displayed score. This could cause
// weird behavior, like not getting a free replay after finishing a game with 2000 or more points.
//! @bug: The Wolfos always starts with 2 health, so the subtraction below is guaranteed to kill it;
//! the else-block is never reached in practice. If you *could* damage the Wolfos without killing
//! it, then the number "30" would appear every time you hit it, and the player's displayed score
//! would increase by 30. However, the else-block doesn't increase the shooting gallery man's
//! "score" variable, so it would become desynchronized from the displayed score. This could cause
//! weird behavior, like not getting a free replay after finishing a game with 2000 or more points.
this->actor.colChkInfo.health -= 2;
if (this->actor.colChkInfo.health == 0) {
Audio_PlayFanfare(NA_BGM_GET_ITEM | 0x900);
EnSyatekiWf_SetupDead(this, play);
} else {
Audio_PlaySfx(NA_SE_SY_TRE_BOX_APPEAR);
EffectSsExtra_Spawn(play, &this->actor.world.pos, &sVelocity, &sAccel, 3, 0);
EffectSsExtra_Spawn(play, &this->actor.world.pos, &sVelocity, &sAccel, 3, EXTRA_SCORE_INDEX_30);
}
}

View File

@ -4,9 +4,9 @@
#include "global.h"
#include "objects/object_wf/object_wf.h"
#define EN_SYATEKI_WF_GET_POINT_TO_HOWL(thisx) (((thisx)->params & 0xF0) >> 4)
#define EN_SYATEKI_WF_GET_INDEX(thisx) (((thisx)->params & 0xFF00) >> 8)
#define EN_SYATEKI_WF_PARAMS(index, pointToHowl, unused) (((index << 8) & 0xFF00) | ((pointToHowl << 4) & 0xF0) | (unused & 0xF))
#define SG_WOLFOS_GET_POINT_TO_HOWL(thisx) (((thisx)->params & 0xF0) >> 4)
#define SG_WOLFOS_GET_INDEX(thisx) (((thisx)->params & 0xFF00) >> 8)
#define SG_WOLFOS_PARAMS(index, pointToHowl, unused) (((index << 8) & 0xFF00) | ((pointToHowl << 4) & 0xF0) | (unused & 0xF))
struct EnSyatekiWf;

View File

@ -14,7 +14,7 @@ u32 EffectSsExtra_Init(PlayState* play, u32 index, EffectSs* this, void* initPar
void EffectSsExtra_Update(PlayState* play, u32 index, EffectSs* this);
void EffectSsExtra_Draw(PlayState* play, u32 index, EffectSs* this);
static s16 sScores[] = { 30, 60, 100 };
static s16 sScores[] = { EXTRA_SCORE_30, EXTRA_SCORE_60, EXTRA_SCORE_100 };
EffectSsInit Effect_Ss_Extra_InitVars = {
EFFECT_SS_EXTRA,
@ -45,7 +45,7 @@ u32 EffectSsExtra_Init(PlayState* play, u32 index, EffectSs* this, void* initPar
this->draw = EffectSsExtra_Draw;
this->update = EffectSsExtra_Update;
this->life = 50;
this->rScoreIndex = params->scoreIdx;
this->rScoreIndex = params->scoreIndex;
this->rScale = params->scale;
this->rTimer = 5;
this->rObjId = objIndex;

View File

@ -3,18 +3,22 @@
#include "global.h"
#define EXTRA_SCORE_30 30
#define EXTRA_SCORE_60 60
#define EXTRA_SCORE_100 100
typedef enum {
/* 0 */ EXTRA_SCORE_30,
/* 1 */ EXTRA_SCORE_60,
/* 2 */ EXTRA_SCORE_100
} ExtraScoreIdx;
/* 0 */ EXTRA_SCORE_INDEX_30,
/* 1 */ EXTRA_SCORE_INDEX_60,
/* 2 */ EXTRA_SCORE_INDEX_100
} ExtraScoreIndex;
typedef struct {
/* 0x00 */ Vec3f pos;
/* 0x0C */ Vec3f velocity;
/* 0x18 */ Vec3f accel;
/* 0x24 */ s16 scale;
/* 0x26 */ s16 scoreIdx;
/* 0x26 */ s16 scoreIndex;
} EffectSsExtraInitParams; // size = 0x28
#endif

View File

@ -9817,7 +9817,7 @@
0x809C9480:("sTownFierceDeityPlayerPos","UNK_TYPE4","",0x4),
0x809C948C:("sTownPlayerPos","UNK_TYPE4","",0x4),
0x809C9498:("sGameStartTimer","s16","",0x2),
0x809C949C:("sHasSpawnedGuaysForThisWave","UNK_TYPE2","",0x2),
0x809C949C:("sHasSignaledGuaysForThisWave","UNK_TYPE2","",0x2),
0x809C94A0:("sBonusTimer","s32","",0x4),
0x809C94A4:("sGameStartTimer","s16","",0x2),
0x809C94A8:("sModFromLosingTime","s32","",0x4),

View File

@ -261,8 +261,8 @@ weekEventReg = {
(31 << 8) | 0x40: "WEEKEVENTREG_31_40",
(31 << 8) | 0x80: "WEEKEVENTREG_31_80",
(32 << 8) | 0x01: "WEEKEVENTREG_32_01",
(32 << 8) | 0x02: "WEEKEVENTREG_32_02",
(32 << 8) | 0x04: "WEEKEVENTREG_32_04",
(32 << 8) | 0x02: "WEEKEVENTREG_RECEIVED_SWAMP_SHOOTING_GALLERY_HEART_PIECE",
(32 << 8) | 0x04: "WEEKEVENTREG_RECEIVED_TOWN_SHOOTING_GALLERY_HEART_PIECE",
(32 << 8) | 0x08: "WEEKEVENTREG_32_08",
(32 << 8) | 0x10: "WEEKEVENTREG_32_10",
(32 << 8) | 0x20: "WEEKEVENTREG_32_20",
@ -480,8 +480,8 @@ weekEventReg = {
(59 << 8) | 0x02: "WEEKEVENTREG_59_02",
(59 << 8) | 0x08: "WEEKEVENTREG_59_08",
(59 << 8) | 0x04: "WEEKEVENTREG_59_04",
(59 << 8) | 0x10: "WEEKEVENTREG_59_10",
(59 << 8) | 0x20: "WEEKEVENTREG_59_20",
(59 << 8) | 0x10: "WEEKEVENTREG_RECEIVED_SWAMP_SHOOTING_GALLERY_QUIVER_UPGRADE",
(59 << 8) | 0x20: "WEEKEVENTREG_RECEIVED_TOWN_SHOOTING_GALLERY_QUIVER_UPGRADE",
(59 << 8) | 0x40: "WEEKEVENTREG_59_40",
(59 << 8) | 0x80: "WEEKEVENTREG_59_80",
(60 << 8) | 0x01: "WEEKEVENTREG_60_01",