diff --git a/assets/xml/objects/object_haka_objects.xml b/assets/xml/objects/object_haka_objects.xml
index 2325e663a8..615f67b3b5 100644
--- a/assets/xml/objects/object_haka_objects.xml
+++ b/assets/xml/objects/object_haka_objects.xml
@@ -60,16 +60,16 @@
-
+
-
-
-
+
+
+
-
-
+
+
diff --git a/assets/xml/objects/object_hakach_objects.xml b/assets/xml/objects/object_hakach_objects.xml
index 92679bc8de..7a68751068 100644
--- a/assets/xml/objects/object_hakach_objects.xml
+++ b/assets/xml/objects/object_hakach_objects.xml
@@ -12,10 +12,10 @@
-
+
-
+
@@ -38,7 +38,7 @@
-
+
diff --git a/src/overlays/actors/ovl_Bg_Haka_Zou/z_bg_haka_zou.c b/src/overlays/actors/ovl_Bg_Haka_Zou/z_bg_haka_zou.c
index 40c5797627..f2218398ae 100644
--- a/src/overlays/actors/ovl_Bg_Haka_Zou/z_bg_haka_zou.c
+++ b/src/overlays/actors/ovl_Bg_Haka_Zou/z_bg_haka_zou.c
@@ -1,7 +1,7 @@
/*
* File: z_bg_haka_zou.c
* Overlay: ovl_Bg_Haka_Zou
- * Description: Statue and Wall (Shadow Temple)
+ * Description: Bombable Shadow Temple themed objects
*/
#include "z_bg_haka_zou.h"
@@ -20,26 +20,19 @@
#define FLAGS ACTOR_FLAG_UPDATE_CULLING_DISABLED
-typedef enum ShadowTempleAssetsType {
- /* 0x0 */ STA_GIANT_BIRD_STATUE,
- /* 0x1 */ STA_BOMBABLE_SKULL_WALL,
- /* 0x2 */ STA_BOMBABLE_RUBBLE,
- /* 0x3 */ STA_UNKNOWN
-} ShadowTempleAssetsType;
-
void BgHakaZou_Init(Actor* thisx, PlayState* play);
void BgHakaZou_Destroy(Actor* thisx, PlayState* play);
void BgHakaZou_Update(Actor* thisx, PlayState* play);
void BgHakaZou_Draw(Actor* thisx, PlayState* play);
-void BgHakaZou_Wait(BgHakaZou* this, PlayState* play);
-void func_80882BDC(BgHakaZou* this, PlayState* play);
-void func_80883000(BgHakaZou* this, PlayState* play);
-void func_80883104(BgHakaZou* this, PlayState* play);
-void func_80883144(BgHakaZou* this, PlayState* play);
-void func_80883254(BgHakaZou* this, PlayState* play);
-void func_80883328(BgHakaZou* this, PlayState* play);
-void func_808834D8(BgHakaZou* this, PlayState* play);
+void BgHakaZou_WaitForObject(BgHakaZou* this, PlayState* play);
+void BgHakaZou_CrumbleSkullWall(BgHakaZou* this, PlayState* play);
+void BgHakaZou_WaitForHit(BgHakaZou* this, PlayState* play);
+void BgHakaZou_IdleKill(BgHakaZou* this, PlayState* play);
+void BgHakaZou_BirdStatueAnim_Explode(BgHakaZou* this, PlayState* play);
+void BgHakaZou_BirdStatueAnim_Shear(BgHakaZou* this, PlayState* play);
+void BgHakaZou_BirdStatueAnim_Topple(BgHakaZou* this, PlayState* play);
+void BgHakaZou_BirdStatueAnim_Settle(BgHakaZou* this, PlayState* play);
void BgHakaZou_DoNothing(BgHakaZou* this, PlayState* play);
static ColliderCylinderInit sCylinderInit = {
@@ -90,7 +83,7 @@ void BgHakaZou_Init(Actor* thisx, PlayState* play) {
this->switchFlag = PARAMS_GET_U(thisx->params, 8, 8);
thisx->params &= 0xFF;
- if (thisx->params == STA_UNKNOWN) {
+ if (thisx->params == BGHAKAZOU_TYPE_SKULL_WALL_RUBBLE) {
Actor_SetScale(thisx, (Rand_ZeroOne() * 0.005f) + 0.025f);
thisx->speed = Rand_ZeroOne();
@@ -105,36 +98,38 @@ void BgHakaZou_Init(Actor* thisx, PlayState* play) {
DynaPolyActor_Init(&this->dyna, 0);
- if (thisx->params == STA_GIANT_BIRD_STATUE) {
+ if (thisx->params == BGHAKAZOU_TYPE_GIANT_BIRD_STATUE) {
thisx->cullingVolumeDistance = 2000.0f;
thisx->cullingVolumeScale = 3000.0f;
thisx->cullingVolumeDownward = 3000.0f;
}
}
- this->requiredObjectSlot = (thisx->params == STA_BOMBABLE_RUBBLE)
+ this->requiredObjectSlot = (thisx->params == BGHAKAZOU_TYPE_BOMBABLE_RUBBLE)
? Object_GetSlot(&play->objectCtx, OBJECT_HAKACH_OBJECTS)
: Object_GetSlot(&play->objectCtx, OBJECT_HAKA_OBJECTS);
if (this->requiredObjectSlot < 0) {
Actor_Kill(thisx);
- } else if ((thisx->params != STA_UNKNOWN) && Flags_GetSwitch(play, this->switchFlag)) {
- if (thisx->params != STA_GIANT_BIRD_STATUE) {
+ } else if (thisx->params != BGHAKAZOU_TYPE_SKULL_WALL_RUBBLE && Flags_GetSwitch(play, this->switchFlag)) {
+ if (thisx->params != BGHAKAZOU_TYPE_GIANT_BIRD_STATUE) {
+ // Object has already been destroyed
Actor_Kill(thisx);
} else {
+ // Initialize the statue toppled over
thisx->shape.rot.x = -0x4000;
thisx->world.pos.z -= 80.0f;
- thisx->world.pos.y -= 54.0f;
+ thisx->world.pos.y -= 40 + 14;
}
}
- this->actionFunc = BgHakaZou_Wait;
+ this->actionFunc = BgHakaZou_WaitForObject;
}
void BgHakaZou_Destroy(Actor* thisx, PlayState* play) {
BgHakaZou* this = (BgHakaZou*)thisx;
- if (this->dyna.actor.params != STA_UNKNOWN) {
+ if (this->dyna.actor.params != BGHAKAZOU_TYPE_SKULL_WALL_RUBBLE) {
DynaPoly_DeleteBgActor(play, &play->colCtx.dyna, this->dyna.bgId);
Collider_DestroyCylinder(play, &this->collider);
}
@@ -165,48 +160,49 @@ void func_808828F4(BgHakaZou* this, PlayState* play) {
}
}
-void BgHakaZou_Wait(BgHakaZou* this, PlayState* play) {
- CollisionHeader* colHeader;
+void BgHakaZou_WaitForObject(BgHakaZou* this, PlayState* play) {
if (Object_IsLoaded(&play->objectCtx, this->requiredObjectSlot)) {
this->dyna.actor.objectSlot = this->requiredObjectSlot;
this->dyna.actor.draw = BgHakaZou_Draw;
- if (this->dyna.actor.params == STA_UNKNOWN) {
- this->actionFunc = func_80882BDC;
+ if (this->dyna.actor.params == BGHAKAZOU_TYPE_SKULL_WALL_RUBBLE) {
+ this->actionFunc = BgHakaZou_CrumbleSkullWall;
} else {
- Actor_SetObjectDependency(play, &this->dyna.actor);
+ CollisionHeader* colHeader;
+ Actor_SetObjectDependency(play, &this->dyna.actor);
colHeader = NULL;
- if (this->dyna.actor.params == STA_GIANT_BIRD_STATUE) {
- CollisionHeader_GetVirtual(&object_haka_objects_Col_006F70, &colHeader);
+ if (this->dyna.actor.params == BGHAKAZOU_TYPE_GIANT_BIRD_STATUE) {
+ CollisionHeader_GetVirtual(&gShadowTempleBirdStatueCol, &colHeader);
this->collider.dim.radius = 80;
this->collider.dim.height = 100;
this->collider.dim.yShift = -30;
this->collider.dim.pos.x -= 56;
this->collider.dim.pos.z += 56;
this->dyna.actor.cullingVolumeScale = 1500.0f;
- } else if (this->dyna.actor.params == STA_BOMBABLE_SKULL_WALL) {
- CollisionHeader_GetVirtual(&object_haka_objects_Col_005E30, &colHeader);
+ } else if (this->dyna.actor.params == BGHAKAZOU_TYPE_BOMBABLE_SKULL_WALL) {
+ CollisionHeader_GetVirtual(&gShadowTempleSkullWallCol, &colHeader);
this->collider.dim.yShift = -50;
- } else {
- CollisionHeader_GetVirtual(&gBotwBombSpotCol, &colHeader);
+ } else /* BGHAKAZOU_TYPE_BOMBABLE_RUBBLE */ {
+ CollisionHeader_GetVirtual(&gBotwBombableRubbleCol, &colHeader);
this->collider.dim.radius = 55;
this->collider.dim.height = 20;
}
this->dyna.bgId = DynaPoly_SetBgActor(play, &play->colCtx.dyna, &this->dyna.actor, colHeader);
- if ((this->dyna.actor.params == STA_GIANT_BIRD_STATUE) && Flags_GetSwitch(play, this->switchFlag)) {
+ if ((this->dyna.actor.params == BGHAKAZOU_TYPE_GIANT_BIRD_STATUE) &&
+ Flags_GetSwitch(play, this->switchFlag)) {
this->actionFunc = BgHakaZou_DoNothing;
} else {
- this->actionFunc = func_80883000;
+ this->actionFunc = BgHakaZou_WaitForHit;
}
}
}
}
-void func_80882BDC(BgHakaZou* this, PlayState* play) {
+void BgHakaZou_CrumbleSkullWall(BgHakaZou* this, PlayState* play) {
if (this->timer != 0) {
this->timer--;
}
@@ -230,7 +226,7 @@ void func_80882BDC(BgHakaZou* this, PlayState* play) {
}
}
-void func_80882CC4(BgHakaZou* this, PlayState* play) {
+void BgHakaZou_SpawnSkullWallRubble(BgHakaZou* this, PlayState* play) {
s32 i;
s32 j;
Vec3f actorSpawnPos;
@@ -248,13 +244,14 @@ void func_80882CC4(BgHakaZou* this, PlayState* play) {
actorSpawnPos.y = this->dyna.actor.world.pos.y + (i - 1) * 55;
Actor_Spawn(&play->actorCtx, play, ACTOR_BG_HAKA_ZOU, actorSpawnPos.x, actorSpawnPos.y, actorSpawnPos.z, 0,
- this->dyna.actor.shape.rot.y, 0, this->dyna.actor.params + 2);
+ this->dyna.actor.shape.rot.y, 0,
+ this->dyna.actor.params + 2); // this passes BGHAKAZOU_TYPE_SKULL_WALL_RUBBLE into params
func_800286CC(play, &actorSpawnPos, &sZeroVec, &sZeroVec, 1000, 50);
}
}
}
-void func_80882E54(BgHakaZou* this, PlayState* play) {
+void BgHakaZou_SpawnRubbleParticles(BgHakaZou* this, PlayState* play) {
Vec3f fragmentPos;
s32 i;
s32 j;
@@ -264,44 +261,44 @@ void func_80882E54(BgHakaZou* this, PlayState* play) {
fragmentPos.y = this->collider.dim.pos.y;
fragmentPos.z = this->collider.dim.pos.z;
- EffectSsHahen_SpawnBurst(play, &fragmentPos, 10.0f, 0, 10, 10, 4, 141, 40, gBotwBombSpotDL);
+ EffectSsHahen_SpawnBurst(play, &fragmentPos, 10.0f, 0, 10, 10, 4, 141, 40, gBotwBombableRubbleDL);
for (i = 0; i < 2; i++) {
for (j = 0; j < 2; j++) {
fragmentPos.x = this->collider.dim.pos.x + (((j * 2) - 1) * num);
fragmentPos.z = this->collider.dim.pos.z + (((i * 2) - 1) * num);
- EffectSsHahen_SpawnBurst(play, &fragmentPos, 10.0f, 0, 10, 10, 4, 141, 40, gBotwBombSpotDL);
+ EffectSsHahen_SpawnBurst(play, &fragmentPos, 10.0f, 0, 10, 10, 4, 141, 40, gBotwBombableRubbleDL);
func_800286CC(play, &fragmentPos, &sZeroVec, &sZeroVec, 1000, 50);
}
}
}
-void func_80883000(BgHakaZou* this, PlayState* play) {
+void BgHakaZou_WaitForHit(BgHakaZou* this, PlayState* play) {
if (this->collider.base.acFlags & AC_HIT) {
Flags_SetSwitch(play, this->switchFlag);
- if (this->dyna.actor.params == STA_GIANT_BIRD_STATUE) {
+ if (this->dyna.actor.params == BGHAKAZOU_TYPE_GIANT_BIRD_STATUE) {
this->timer = 20;
- this->actionFunc = func_80883144;
+ this->actionFunc = BgHakaZou_BirdStatueAnim_Explode;
OnePointCutscene_Init(play, 3400, 999, &this->dyna.actor, CAM_ID_MAIN);
- } else if (this->dyna.actor.params == 2) {
- func_80882E54(this, play);
+ } else if (this->dyna.actor.params == BGHAKAZOU_TYPE_BOMBABLE_RUBBLE) {
+ BgHakaZou_SpawnRubbleParticles(this, play);
this->dyna.actor.draw = NULL;
this->timer = 1;
Actor_PlaySfx(&this->dyna.actor, NA_SE_EV_EXPLOSION);
- this->actionFunc = func_80883104;
- } else {
- func_80882CC4(this, play);
+ this->actionFunc = BgHakaZou_IdleKill;
+ } else /* BGHAKAZOU_TYPE_BOMBABLE_SKULL_WALL */ {
+ BgHakaZou_SpawnSkullWallRubble(this, play);
this->timer = 1;
Actor_PlaySfx(&this->dyna.actor, NA_SE_EV_WALL_BROKEN);
- this->actionFunc = func_80883104;
+ this->actionFunc = BgHakaZou_IdleKill;
}
} else {
CollisionCheck_SetAC(play, &play->colChkCtx, &this->collider.base);
}
}
-void func_80883104(BgHakaZou* this, PlayState* play) {
+void BgHakaZou_IdleKill(BgHakaZou* this, PlayState* play) {
if (this->timer != 0) {
this->timer--;
}
@@ -311,7 +308,7 @@ void func_80883104(BgHakaZou* this, PlayState* play) {
}
}
-void func_80883144(BgHakaZou* this, PlayState* play) {
+void BgHakaZou_BirdStatueAnim_Explode(BgHakaZou* this, PlayState* play) {
Vec3f explosionPos;
if (this->timer != 0) {
@@ -329,11 +326,11 @@ void func_80883144(BgHakaZou* this, PlayState* play) {
if (this->timer == 0) {
this->timer = 20;
- this->actionFunc = func_80883254;
+ this->actionFunc = BgHakaZou_BirdStatueAnim_Shear;
}
}
-void func_80883254(BgHakaZou* this, PlayState* play) {
+void BgHakaZou_BirdStatueAnim_Shear(BgHakaZou* this, PlayState* play) {
f32 moveDist = (Rand_ZeroOne() * 0.5f) + 0.5f;
Math_StepToF(&this->dyna.actor.world.pos.z, this->dyna.actor.home.pos.z - 80.0f, 2.0f * moveDist);
@@ -346,14 +343,14 @@ void func_80883254(BgHakaZou* this, PlayState* play) {
if (this->timer == 0) {
this->timer = 60;
this->dyna.actor.world.rot.x = 8;
- this->actionFunc = func_80883328;
+ this->actionFunc = BgHakaZou_BirdStatueAnim_Topple;
}
} else {
func_808828F4(this, play);
}
}
-void func_80883328(BgHakaZou* this, PlayState* play) {
+void BgHakaZou_BirdStatueAnim_Topple(BgHakaZou* this, PlayState* play) {
Vec3f effectPos;
s32 i;
s32 j;
@@ -377,19 +374,30 @@ void func_80883328(BgHakaZou* this, PlayState* play) {
Actor_PlaySfx(&this->dyna.actor, NA_SE_EV_STONE_BOUND);
this->timer = 25;
- this->actionFunc = func_808834D8;
+ this->actionFunc = BgHakaZou_BirdStatueAnim_Settle;
}
}
-void func_808834D8(BgHakaZou* this, PlayState* play) {
+void BgHakaZou_BirdStatueAnim_Settle(BgHakaZou* this, PlayState* play) {
f32 moveDist;
if (this->timer != 0) {
this->timer--;
}
+ // The idea is to shake the pillar up and down on alternate frames, with the magnitude of the shaking decreasing
+ // linearly as the timer approaches zero. With an even numbered starting timer, the pillar will go up one frame,
+ // down the next with the same magnitude, cancelling out any movement (except perhaps for some miniscule rounding
+ // error). However, the starting timer is set to 25, (an odd number). This skips the increment step and shifts the
+ // pillar down an extra -14.4 units.
+ //
+ // The programmer was likely aware of a discrepancy as BgHakaZou_Init subtracts 14 units to account for this
+ // (resulting in a 0.4 unit discrepancy between post animation and the next time the actor is reloaded). Lowering
+ // the statue 14 units causes the model to clip into the ground, but it is also enough to make the pillar low enough
+ // for Link to climb on top of it if the player is missing keys.
+
moveDist = (this->timer % 2) ? 15.0f : -15.0f;
- this->dyna.actor.world.pos.y += ((this->timer & 0xFE) * 0.04f * moveDist);
+ this->dyna.actor.world.pos.y += ((this->timer & 0xFE) * (1.0f / 25) * moveDist);
if (this->timer == 0) {
this->actionFunc = BgHakaZou_DoNothing;
@@ -404,17 +412,17 @@ void BgHakaZou_Update(Actor* thisx, PlayState* play) {
this->actionFunc(this, play);
- if (this->dyna.actor.params == 3) {
+ if (this->dyna.actor.params == BGHAKAZOU_TYPE_SKULL_WALL_RUBBLE) {
Actor_MoveXZGravity(&this->dyna.actor);
}
}
void BgHakaZou_Draw(Actor* thisx, PlayState* play) {
static Gfx* dLists[] = {
- object_haka_objects_DL_0064E0,
- object_haka_objects_DL_005CE0,
- gBotwBombSpotDL,
- object_haka_objects_DL_005CE0,
+ gShadowTempleBirdStatueDL,
+ gShadowTempleSkullWallDL,
+ gBotwBombableRubbleDL,
+ gShadowTempleSkullWallDL,
};
Gfx_DrawDListOpa(play, dLists[thisx->params]);
diff --git a/src/overlays/actors/ovl_Bg_Haka_Zou/z_bg_haka_zou.h b/src/overlays/actors/ovl_Bg_Haka_Zou/z_bg_haka_zou.h
index 1d4c4798d6..1f31cece45 100644
--- a/src/overlays/actors/ovl_Bg_Haka_Zou/z_bg_haka_zou.h
+++ b/src/overlays/actors/ovl_Bg_Haka_Zou/z_bg_haka_zou.h
@@ -4,6 +4,13 @@
#include "ultra64.h"
#include "actor.h"
+typedef enum BgHakaZouType {
+ /* 0x0 */ BGHAKAZOU_TYPE_GIANT_BIRD_STATUE,
+ /* 0x1 */ BGHAKAZOU_TYPE_BOMBABLE_SKULL_WALL,
+ /* 0x2 */ BGHAKAZOU_TYPE_BOMBABLE_RUBBLE,
+ /* 0x3 */ BGHAKAZOU_TYPE_SKULL_WALL_RUBBLE
+} BgHakaZouType;
+
struct BgHakaZou;
typedef void (*BgHakaZouActionFunc)(struct BgHakaZou*, struct PlayState*);