En_Baguo (Nejiron) OK and mostly documented (#351)

* Migrate data to C

* EnBaguo_Init OK

* EnBaguo_Destroy OK

* func_80A3B220 OK

* func_80A3B2CC OK

* func_80A3B2CC OK

* func_80A3B794 OK

* func_80A3B5E0 OK

* func_80A3B7B8 OK

* EnBaguo_Update OK

* func_80A3B8F8

* func_80A3BE24 OK, some other not-OK junk

* func_80A3BE60 OK (wow this is bad!)

* Document the blink system

* func_80A3C17C OK

* Document timer and fix warnings

* func_80A3C008 OK

* Rename x/y/z so it's clear they are positions

* func_80A3BE60 OK in a not-crazy way

* func_80A3B958 OK

* func_80A3BF0C OK

* Make the rotation a Vec3s

* Update the spec to use the built reloc

* Use ARRAY_COUNT instead of hardcoded length

* Document the state stuff

* Document NejironParticle

* Document the rolling rotation stuff

* unk_1BC -> maxDistanceFromHome

* unk_1B8 -> zRollDirection

* Name the two draw functions

* Name the static variables properly

* Name all other functions

* Clean up forward declares

* Last bit of documentation and cleanup

* Add an enum for the rolling direction

* Add explanatory comment

* state -> action and move action descriptions inline

* Use enum for Stone Mask

* Use "Setup" for the setup function

* Document the damage effect

* Add some space around the for-loop

* ./format.sh

* Use % 8 everywhere

* Use -= instead of += a negative number

* Switch order of max check

* Use CLEAR_TAG_POP enum value

* eyeIndexTemp -> eyeIndex

* visible -> isVisible

* Move enums above structs

* Merge animation system changes

* yDist fix

* Respond to review feedback
This commit is contained in:
Tom Overton 2021-11-05 06:14:22 -07:00 committed by GitHub
parent 693c701025
commit c706b2be70
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 499 additions and 83 deletions

3
spec
View File

@ -2863,8 +2863,7 @@ beginseg
name "ovl_En_Baguo" name "ovl_En_Baguo"
compress compress
include "build/src/overlays/actors/ovl_En_Baguo/z_en_baguo.o" include "build/src/overlays/actors/ovl_En_Baguo/z_en_baguo.o"
include "build/data/ovl_En_Baguo/ovl_En_Baguo.data.o" include "build/src/overlays/actors/ovl_En_Baguo/ovl_En_Baguo_reloc.o"
include "build/data/ovl_En_Baguo/ovl_En_Baguo.reloc.o"
endseg endseg
beginseg beginseg

View File

@ -1,5 +1,5 @@
/* /*
* File z_en_baguo.c * File: z_en_baguo.c
* Overlay: ovl_En_Baguo * Overlay: ovl_En_Baguo
* Description: Nejiron * Description: Nejiron
*/ */
@ -14,7 +14,18 @@ void EnBaguo_Init(Actor* thisx, GlobalContext* globalCtx);
void EnBaguo_Destroy(Actor* thisx, GlobalContext* globalCtx); void EnBaguo_Destroy(Actor* thisx, GlobalContext* globalCtx);
void EnBaguo_Update(Actor* thisx, GlobalContext* globalCtx); void EnBaguo_Update(Actor* thisx, GlobalContext* globalCtx);
#if 0 void EnBaguo_UndergroundIdle(EnBaguo* this, GlobalContext* globalCtx);
void EnBaguo_EmergeFromUnderground(EnBaguo* this, GlobalContext* globalCtx);
void EnBaguo_Idle(EnBaguo* this, GlobalContext* globalCtx);
void EnBaguo_Roll(EnBaguo* this, GlobalContext* globalCtx);
void EnBaguo_SetupRetreatUnderground(EnBaguo* this);
void EnBaguo_RetreatUnderground(EnBaguo* this, GlobalContext* globalCtx);
void EnBaguo_DrawBody(Actor* thisx, GlobalContext* globalCtx);
void EnBaguo_InitializeParticle(EnBaguo* this, Vec3f* position, Vec3f* velocity, Vec3f* acceleration, f32 scale,
s16 timer);
void EnBaguo_UpdateParticles(EnBaguo* this, GlobalContext* globalCtx);
void EnBaguo_DrawRockParticles(EnBaguo* this, GlobalContext* globalCtx);
const ActorInit En_Baguo_InitVars = { const ActorInit En_Baguo_InitVars = {
ACTOR_EN_BAGUO, ACTOR_EN_BAGUO,
ACTORCAT_ENEMY, ACTORCAT_ENEMY,
@ -27,92 +38,453 @@ const ActorInit En_Baguo_InitVars = {
(ActorFunc)NULL, (ActorFunc)NULL,
}; };
// static ColliderJntSphElementInit sJntSphElementsInit[1] = { static ColliderJntSphElementInit sJntSphElementsInit[1] = {
static ColliderJntSphElementInit D_80A3C2F0[1] = {
{ {
{ ELEMTYPE_UNK0, { 0xF7CFFFFF, 0x04, 0x04 }, { 0xF7CFFFFF, 0x00, 0x00 }, TOUCH_ON | TOUCH_SFX_NORMAL, BUMP_ON, OCELEM_ON, }, {
ELEMTYPE_UNK0,
{ 0xF7CFFFFF, 0x04, 0x04 },
{ 0xF7CFFFFF, 0x00, 0x00 },
TOUCH_ON | TOUCH_SFX_NORMAL,
BUMP_ON,
OCELEM_ON,
},
{ 1, { { 0, 0, 0 }, 0 }, 1 }, { 1, { { 0, 0, 0 }, 0 }, 1 },
}, },
}; };
// static ColliderJntSphInit sJntSphInit = { static ColliderJntSphInit sJntSphInit = {
static ColliderJntSphInit D_80A3C314 = { {
{ COLTYPE_HARD, AT_ON | AT_TYPE_ENEMY, AC_ON | AC_TYPE_PLAYER, OC1_ON | OC1_TYPE_ALL, OC2_TYPE_1, COLSHAPE_JNTSPH, }, COLTYPE_HARD,
1, D_80A3C2F0, // sJntSphElementsInit, AT_ON | AT_TYPE_ENEMY,
AC_ON | AC_TYPE_PLAYER,
OC1_ON | OC1_TYPE_ALL,
OC2_TYPE_1,
COLSHAPE_JNTSPH,
},
1,
sJntSphElementsInit,
}; };
// static DamageTable sDamageTable = { typedef enum {
static DamageTable D_80A3C324 = { /* 0x0 */ NEJIRON_DMGEFF_NONE, // Does not interact with the Nejiron at all
/* Deku Nut */ DMG_ENTRY(0, 0xF), /* 0xE */ NEJIRON_DMGEFF_KILL = 14, // Kills and detonates the Nejiron
/* Deku Stick */ DMG_ENTRY(0, 0xF), /* 0xF */ NEJIRON_DMGEFF_RECOIL // Deals no damage, but displays the appropriate hit mark and recoil animation
/* Horse trample */ DMG_ENTRY(0, 0x0), } NejironDamageEffect;
/* Explosives */ DMG_ENTRY(1, 0xE),
/* Zora boomerang */ DMG_ENTRY(3, 0xE), static DamageTable sDamageTable = {
/* Normal arrow */ DMG_ENTRY(0, 0xF), /* Deku Nut */ DMG_ENTRY(0, NEJIRON_DMGEFF_RECOIL),
/* UNK_DMG_0x06 */ DMG_ENTRY(0, 0x0), /* Deku Stick */ DMG_ENTRY(0, NEJIRON_DMGEFF_RECOIL),
/* Hookshot */ DMG_ENTRY(3, 0xE), /* Horse trample */ DMG_ENTRY(0, NEJIRON_DMGEFF_NONE),
/* Goron punch */ DMG_ENTRY(2, 0xE), /* Explosives */ DMG_ENTRY(1, NEJIRON_DMGEFF_KILL),
/* Sword */ DMG_ENTRY(1, 0xE), /* Zora boomerang */ DMG_ENTRY(3, NEJIRON_DMGEFF_KILL),
/* Goron pound */ DMG_ENTRY(1, 0xE), /* Normal arrow */ DMG_ENTRY(0, NEJIRON_DMGEFF_RECOIL),
/* Fire arrow */ DMG_ENTRY(0, 0xF), /* UNK_DMG_0x06 */ DMG_ENTRY(0, NEJIRON_DMGEFF_NONE),
/* Ice arrow */ DMG_ENTRY(0, 0xF), /* Hookshot */ DMG_ENTRY(3, NEJIRON_DMGEFF_KILL),
/* Light arrow */ DMG_ENTRY(1, 0xE), /* Goron punch */ DMG_ENTRY(2, NEJIRON_DMGEFF_KILL),
/* Goron spikes */ DMG_ENTRY(2, 0xE), /* Sword */ DMG_ENTRY(1, NEJIRON_DMGEFF_KILL),
/* Deku spin */ DMG_ENTRY(0, 0xF), /* Goron pound */ DMG_ENTRY(1, NEJIRON_DMGEFF_KILL),
/* Deku bubble */ DMG_ENTRY(0, 0xF), /* Fire arrow */ DMG_ENTRY(0, NEJIRON_DMGEFF_RECOIL),
/* Deku launch */ DMG_ENTRY(1, 0xE), /* Ice arrow */ DMG_ENTRY(0, NEJIRON_DMGEFF_RECOIL),
/* UNK_DMG_0x12 */ DMG_ENTRY(0, 0xF), /* Light arrow */ DMG_ENTRY(1, NEJIRON_DMGEFF_KILL),
/* Zora barrier */ DMG_ENTRY(0, 0x0), /* Goron spikes */ DMG_ENTRY(2, NEJIRON_DMGEFF_KILL),
/* Normal shield */ DMG_ENTRY(0, 0x0), /* Deku spin */ DMG_ENTRY(0, NEJIRON_DMGEFF_RECOIL),
/* Light ray */ DMG_ENTRY(0, 0x0), /* Deku bubble */ DMG_ENTRY(0, NEJIRON_DMGEFF_RECOIL),
/* Thrown object */ DMG_ENTRY(0, 0x0), /* Deku launch */ DMG_ENTRY(1, NEJIRON_DMGEFF_KILL),
/* Zora punch */ DMG_ENTRY(1, 0xE), /* UNK_DMG_0x12 */ DMG_ENTRY(0, NEJIRON_DMGEFF_RECOIL),
/* Spin attack */ DMG_ENTRY(1, 0xE), /* Zora barrier */ DMG_ENTRY(0, NEJIRON_DMGEFF_NONE),
/* Sword beam */ DMG_ENTRY(0, 0x0), /* Normal shield */ DMG_ENTRY(0, NEJIRON_DMGEFF_NONE),
/* Normal Roll */ DMG_ENTRY(0, 0x0), /* Light ray */ DMG_ENTRY(0, NEJIRON_DMGEFF_NONE),
/* UNK_DMG_0x1B */ DMG_ENTRY(0, 0x0), /* Thrown object */ DMG_ENTRY(0, NEJIRON_DMGEFF_NONE),
/* UNK_DMG_0x1C */ DMG_ENTRY(0, 0x0), /* Zora punch */ DMG_ENTRY(1, NEJIRON_DMGEFF_KILL),
/* Unblockable */ DMG_ENTRY(0, 0x0), /* Spin attack */ DMG_ENTRY(1, NEJIRON_DMGEFF_KILL),
/* UNK_DMG_0x1E */ DMG_ENTRY(0, 0x0), /* Sword beam */ DMG_ENTRY(0, NEJIRON_DMGEFF_NONE),
/* Powder Keg */ DMG_ENTRY(1, 0xE), /* Normal Roll */ DMG_ENTRY(0, NEJIRON_DMGEFF_NONE),
/* UNK_DMG_0x1B */ DMG_ENTRY(0, NEJIRON_DMGEFF_NONE),
/* UNK_DMG_0x1C */ DMG_ENTRY(0, NEJIRON_DMGEFF_NONE),
/* Unblockable */ DMG_ENTRY(0, NEJIRON_DMGEFF_NONE),
/* UNK_DMG_0x1E */ DMG_ENTRY(0, NEJIRON_DMGEFF_NONE),
/* Powder Keg */ DMG_ENTRY(1, NEJIRON_DMGEFF_KILL),
}; };
#endif extern Gfx D_060014C8;
extern Gfx D_060018C8;
extern Gfx D_06001CC8;
extern SkeletonHeader D_060020E8;
extern ColliderJntSphElementInit D_80A3C2F0[1]; void EnBaguo_Init(Actor* thisx, GlobalContext* globalCtx) {
extern ColliderJntSphInit D_80A3C314; EnBaguo* this = THIS;
extern DamageTable D_80A3C324;
extern UNK_TYPE D_060020E8; ActorShape_Init(&this->actor.shape, 0.0f, func_800B3FC0, 0.0f);
SkelAnime_Init(globalCtx, &this->skelAnime, &D_060020E8, NULL, this->jointTable, this->morphTable, 3);
this->actor.hintId = 0xB;
this->maxDistanceFromHome = 240.0f;
this->maxDistanceFromHome += this->actor.world.rot.z * 40.0f;
this->actor.world.rot.z = 0;
Actor_SetScale(&this->actor, 0.01f);
this->actor.colChkInfo.mass = MASS_IMMOVABLE;
this->actor.targetMode = 2;
Collider_InitAndSetJntSph(globalCtx, &this->collider, &this->actor, &sJntSphInit, this->colliderElements);
this->collider.elements[0].dim.modelSphere.radius = 30;
this->collider.elements[0].dim.scale = 1.0f;
this->collider.elements[0].dim.modelSphere.center.x = 80;
this->collider.elements[0].dim.modelSphere.center.y = 80;
this->collider.elements[0].dim.modelSphere.center.z = 0;
this->actor.shape.yOffset = -3000.0f;
this->actor.gravity = -3.0f;
this->actor.colChkInfo.damageTable = &sDamageTable;
this->actor.flags |= 0x8000000;
this->actor.flags &= ~1;
this->collider.base.acFlags |= AC_HARD;
this->actionFunc = EnBaguo_UndergroundIdle;
}
#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Baguo/EnBaguo_Init.s") void EnBaguo_Destroy(Actor* thisx, GlobalContext* globalCtx) {
EnBaguo* this = THIS;
#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Baguo/EnBaguo_Destroy.s") Collider_DestroyJntSph(globalCtx, &this->collider);
}
#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Baguo/func_80A3B220.s") void EnBaguo_UndergroundIdle(EnBaguo* this, GlobalContext* globalCtx) {
this->action = NEJIRON_ACTION_INACTIVE;
if (this->actor.xzDistToPlayer < 200.0f && Player_GetMask(globalCtx) != PLAYER_MASK_STONE_MASK) {
this->actor.draw = EnBaguo_DrawBody;
Audio_PlayActorSound2(&this->actor, NA_SE_EN_BAKUO_APPEAR);
this->actor.world.rot.z = 0;
this->actor.world.rot.x = this->actor.world.rot.z;
this->actor.flags &= ~0x8000000;
this->actor.flags |= 1;
this->actionFunc = EnBaguo_EmergeFromUnderground;
}
this->actor.shape.rot.y = this->actor.world.rot.y;
}
#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Baguo/func_80A3B2CC.s") void EnBaguo_EmergeFromUnderground(EnBaguo* this, GlobalContext* globalCtx) {
this->actor.world.rot.y += 0x1518;
this->actor.shape.rot.y = this->actor.world.rot.y;
if ((globalCtx->gameplayFrames % 8) == 0) {
func_800BBDAC(globalCtx, &this->actor, &this->actor.world.pos, this->actor.shape.shadowScale - 20.0f, 10, 8.0f,
500, 10, 1);
}
Math_ApproachF(&this->actor.shape.shadowScale, 50.0f, 0.3f, 5.0f);
Math_ApproachF(&this->actor.shape.yOffset, 2700.0f, 100.0f, 500.0f);
if (this->actor.shape.yOffset > 2650.0f) {
this->action = NEJIRON_ACTION_ACTIVE;
this->actor.shape.yOffset = 2700.0f;
this->timer = 60;
this->actionFunc = EnBaguo_Idle;
}
}
#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Baguo/func_80A3B3E0.s") void EnBaguo_Idle(EnBaguo* this, GlobalContext* globalCtx) {
s16 absoluteYaw;
s16 yaw;
#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Baguo/func_80A3B5E0.s") if (this->timer != 0) {
// Depending on how the last roll ended, this actor may be "sitting" on
// something other than its legs. This slowly corrects that.
Math_SmoothStepToS(&this->actor.world.rot.x, 0, 10, 100, 1000);
Math_SmoothStepToS(&this->actor.world.rot.z, 0, 10, 100, 1000);
#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Baguo/func_80A3B794.s") // If this actor isn't mostly facing the player, do a discrete turn towards
// them. It takes 8 frames to turn, and we must wait 8 frames to do another.
if ((this->timer & 8) != 0) {
if (fabsf(this->actor.world.rot.y - this->actor.yawTowardsPlayer) > 200.0f) {
Math_SmoothStepToS(&this->actor.world.rot.y, this->actor.yawTowardsPlayer, 30, 300, 1000);
if ((globalCtx->gameplayFrames % 8) == 0) {
func_800BBDAC(globalCtx, &this->actor, &this->actor.world.pos,
this->actor.shape.shadowScale - 20.0f, 10, 8.0f, 500, 10, 1);
Audio_PlayActorSound2(&this->actor, NA_SE_EN_BAKUO_VOICE);
}
}
}
this->actor.shape.rot.y = this->actor.world.rot.y;
return;
}
#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Baguo/func_80A3B7B8.s") yaw = this->actor.yawTowardsPlayer - this->actor.world.rot.y;
absoluteYaw = ABS_ALT(yaw);
Math_Vec3f_Copy(&this->targetRotation, &D_801D15B0);
Math_Vec3f_Copy(&this->currentRotation, &D_801D15B0);
if (absoluteYaw < 0x2000) {
this->targetRotation.x = 2000.0f;
} else {
this->zRollDirection = NEJIRON_DIRECTION_RIGHT;
this->targetRotation.z = 2000.0f;
if ((s16)(this->actor.yawTowardsPlayer - this->actor.world.rot.y) > 0) {
this->zRollDirection = NEJIRON_DIRECTION_LEFT;
}
}
this->timer = 38;
this->actor.world.rot.y = this->actor.yawTowardsPlayer;
this->hardHitFlag = 0;
this->actionFunc = EnBaguo_Roll;
}
#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Baguo/func_80A3B8F8.s") void EnBaguo_Roll(EnBaguo* this, GlobalContext* globalCtx) {
f32 xDistanceFromHome = this->actor.home.pos.x - this->actor.world.pos.x;
f32 zDistanceFromHome = this->actor.home.pos.z - this->actor.world.pos.z;
#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Baguo/func_80A3B958.s") if ((sqrtf(SQ(xDistanceFromHome) + SQ(zDistanceFromHome)) > this->maxDistanceFromHome) ||
(Player_GetMask(globalCtx) == PLAYER_MASK_STONE_MASK)) {
EnBaguo_SetupRetreatUnderground(this);
return;
}
#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Baguo/EnBaguo_Update.s") if (this->timer == 0) {
this->timer = 100;
this->actor.world.rot.y = this->actor.shape.rot.y;
this->actionFunc = EnBaguo_Idle;
this->actor.speedXZ = 0.0f;
return;
}
#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Baguo/func_80A3BE24.s") if (!this->hardHitFlag && this->collider.base.atFlags & AC_HARD) {
this->zRollDirection ^= 1;
this->hardHitFlag = 1;
this->actor.speedXZ = -7.0f;
}
#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Baguo/func_80A3BE60.s") Math_ApproachF(&this->currentRotation.x, this->targetRotation.x, 0.2f, 1000.0f);
Math_ApproachF(&this->currentRotation.z, this->targetRotation.z, 0.2f, 1000.0f);
Math_ApproachF(&this->actor.speedXZ, 5.0f, 0.3f, 0.5f);
this->actor.world.rot.x += (s16)this->currentRotation.x;
if (this->currentRotation.z != 0.0f) {
if (this->zRollDirection == NEJIRON_DIRECTION_RIGHT) {
this->actor.world.rot.z += (s16)this->currentRotation.z;
} else {
this->actor.world.rot.z -= (s16)this->currentRotation.z;
}
}
Audio_PlayActorSound2(&this->actor, NA_SE_EN_BAKUO_ROLL - SFX_FLAG);
}
#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Baguo/func_80A3BF0C.s") void EnBaguo_SetupRetreatUnderground(EnBaguo* this) {
this->action = NEJIRON_ACTION_RETREATING;
this->actionFunc = EnBaguo_RetreatUnderground;
this->actor.speedXZ = 0.0f;
}
#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Baguo/func_80A3C008.s") void EnBaguo_RetreatUnderground(EnBaguo* this, GlobalContext* globalCtx) {
this->actor.world.rot.y -= 0x1518;
this->actor.shape.rot.y = this->actor.world.rot.y;
if ((globalCtx->gameplayFrames % 8) == 0) {
func_800BBDAC(globalCtx, &this->actor, &this->actor.world.pos, this->actor.shape.shadowScale - 20.0f, 10, 8.0f,
500, 10, 1);
}
Math_ApproachF(&this->actor.shape.yOffset, -3000.0f, 100.0f, 500.0f);
Math_ApproachZeroF(&this->actor.shape.shadowScale, 0.3f, 5.0f);
if (this->actor.shape.yOffset < -2970.0f) {
this->actor.shape.yOffset = -3000.0f;
this->actor.draw = EnBaguo_DrawBody;
Math_Vec3f_Copy(&this->actor.world.pos, &this->actor.home.pos);
Audio_PlayActorSound2(&this->actor, NA_SE_EN_BAKUO_APPEAR);
this->actor.flags |= 0x8000000;
this->actor.flags &= ~1;
this->actionFunc = EnBaguo_UndergroundIdle;
}
}
#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Baguo/func_80A3C17C.s") void EnBaguo_PostDetonation(EnBaguo* this, GlobalContext* globalCtx) {
if (this->timer == 0) {
Actor_MarkForDeath(&this->actor);
}
if (this->timer >= 26) {
CollisionCheck_SetAT(globalCtx, &globalCtx->colChkCtx, &this->collider.base);
}
}
void EnBaguo_CheckForDetonation(EnBaguo* this, GlobalContext* globalCtx) {
Vec3f velocity = { 0.0f, 0.0f, 0.0f };
Vec3f acceleration = { 0.0f, 0.0f, 0.0f };
s32 i;
// In order to match, this variable must act as both a boolean to check if
// the Nejiron should forcibly explode and as a loop index.
i = false;
if (this->action != NEJIRON_ACTION_EXPLODING && this->action != NEJIRON_ACTION_RETREATING) {
if (!(this->actor.bgCheckFlags & 1) && this->actor.world.pos.y < (this->actor.home.pos.y - 100.0f)) {
// Force a detonation if we're off the ground and have fallen
// below our home position (e.g., we rolled off a ledge).
i = true;
}
if (this->actor.bgCheckFlags & 0x60 && this->actor.depthInWater >= 40.0f) {
// Force a detonation if we're too far below the water's surface.
i = true;
}
if ((this->collider.base.acFlags & AC_HIT || i)) {
this->collider.base.acFlags &= ~AC_HIT;
if (i || this->actor.colChkInfo.damageEffect == NEJIRON_DMGEFF_KILL) {
func_800BCB70(&this->actor, 0x4000, 0xFF, 0, 8);
this->action = NEJIRON_ACTION_EXPLODING;
this->actor.speedXZ = 0.0f;
this->actor.shape.shadowScale = 0.0f;
for (i = 0; i < ARRAY_COUNT(this->particles); i++) {
acceleration.x = (Rand_ZeroOne() - 0.5f) * 8.0f;
acceleration.y = -1.0f;
acceleration.z = (Rand_ZeroOne() - 0.5f) * 8.0f;
velocity.x = (Rand_ZeroOne() - 0.5f) * 14.0f;
velocity.y = Rand_ZeroOne() * 30.0f;
velocity.z = (Rand_ZeroOne() - 0.5f) * 14.0f;
EnBaguo_InitializeParticle(this, &this->actor.focus.pos, &velocity, &acceleration,
(Rand_ZeroFloat(1.0f) * 0.01f) + 0.003f, 90);
}
Actor_Spawn(&globalCtx->actorCtx, globalCtx, ACTOR_EN_CLEAR_TAG, this->actor.world.pos.x,
this->actor.world.pos.y, this->actor.world.pos.z, 0, 0, 0, CLEAR_TAG_POP);
Audio_PlayActorSound2(&this->actor, NA_SE_IT_BOMB_EXPLOSION);
Audio_PlayActorSound2(&this->actor, NA_SE_EN_BAKUO_DEAD);
this->timer = 30;
this->actor.flags |= 0x8000000;
this->actor.flags &= ~1;
Actor_SetScale(&this->actor, 0.0f);
this->collider.elements->dim.scale = 3.0f;
this->collider.elements->info.toucher.damage = 8;
Item_DropCollectibleRandom(globalCtx, NULL, &this->actor.world.pos, 0xB0);
this->actionFunc = EnBaguo_PostDetonation;
}
}
}
}
void EnBaguo_Update(Actor* thisx, GlobalContext* globalCtx) {
EnBaguo* this = THIS;
Actor_SetHeight(&this->actor, 30.0f);
EnBaguo_UpdateParticles(this, globalCtx);
EnBaguo_CheckForDetonation(this, globalCtx);
this->actionFunc(this, globalCtx);
DECR(this->blinkTimer);
DECR(this->timer);
if (this->action != NEJIRON_ACTION_EXPLODING && this->action != NEJIRON_ACTION_INACTIVE) {
CollisionCheck_SetAT(globalCtx, &globalCtx->colChkCtx, &this->collider.base);
}
if (this->action != NEJIRON_ACTION_EXPLODING) {
this->actor.shape.rot.x = this->actor.world.rot.x;
this->actor.shape.rot.z = this->actor.world.rot.z;
if (this->blinkTimer == 0) {
this->eyeIndex++;
if (this->eyeIndex >= 3) {
this->eyeIndex = 0;
this->blinkTimer = Rand_ZeroFloat(60.0f) + 20.0f;
}
}
Actor_SetVelocityAndMoveYRotationAndGravity(&this->actor);
Actor_UpdateBgCheckInfo(globalCtx, &this->actor, 20.0f, 20.0f, 60.0f, 0x1D);
if (this->action != NEJIRON_ACTION_INACTIVE) {
CollisionCheck_SetAC(globalCtx, &globalCtx->colChkCtx, &this->collider.base);
}
if (this->action != NEJIRON_ACTION_EXPLODING) {
CollisionCheck_SetOC(globalCtx, &globalCtx->colChkCtx, &this->collider.base);
}
}
}
void EnBaguo_PostLimbDraw(GlobalContext* globalCtx, s32 limbIndex, Gfx** dList, Vec3s* rot, Actor* thisx) {
EnBaguo* this = THIS;
Collider_UpdateSpheres(limbIndex, &this->collider);
}
void EnBaguo_DrawBody(Actor* thisx, GlobalContext* globalCtx) {
static TexturePtr sEyeTextures[] = { &D_060014C8, &D_060018C8, &D_06001CC8 };
EnBaguo* this = THIS;
Gfx* gfx;
s32 eyeIndex;
void* virtualAddress;
OPEN_DISPS(globalCtx->state.gfxCtx);
func_8012C28C(globalCtx->state.gfxCtx);
gfx = POLY_OPA_DISP;
eyeIndex = this->eyeIndex;
virtualAddress = Lib_SegmentedToVirtual(sEyeTextures[eyeIndex]);
gSPSegment(&gfx[0], 0x08, virtualAddress);
POLY_OPA_DISP = &gfx[1];
SkelAnime_DrawOpa(globalCtx, this->skelAnime.skeleton, this->skelAnime.jointTable, NULL, EnBaguo_PostLimbDraw,
&this->actor);
CLOSE_DISPS(globalCtx->state.gfxCtx);
EnBaguo_DrawRockParticles(this, globalCtx);
}
void EnBaguo_InitializeParticle(EnBaguo* this, Vec3f* position, Vec3f* velocity, Vec3f* acceleration, f32 scale,
s16 timer) {
s16 i;
NejironParticle* particle = this->particles;
for (i = 0; i < ARRAY_COUNT(this->particles); i++, particle++) {
if (!particle->isVisible) {
particle->isVisible = true;
particle->position = *position;
particle->velocity = *velocity;
particle->acceleration = *acceleration;
particle->scale = scale;
particle->timer = timer;
particle->rotation.x = (s16)randPlusMinusPoint5Scaled(30000.0f);
particle->rotation.y = (s16)randPlusMinusPoint5Scaled(30000.0f);
particle->rotation.z = (s16)randPlusMinusPoint5Scaled(30000.0f);
return;
}
}
}
void EnBaguo_UpdateParticles(EnBaguo* this, GlobalContext* globalCtx) {
s32 i;
NejironParticle* particle = this->particles;
for (i = 0; i < ARRAY_COUNT(this->particles); i++, particle++) {
if (particle->isVisible) {
particle->position.x += particle->velocity.x;
particle->position.y += particle->velocity.y;
particle->position.z += particle->velocity.z;
particle->rotation.x += 0xBB8;
particle->rotation.y += 0xBB8;
particle->rotation.z += 0xBB8;
particle->velocity.x += particle->acceleration.x;
particle->velocity.y += particle->acceleration.y;
particle->velocity.z += particle->acceleration.z;
if (particle->position.y < (this->actor.world.pos.y - 10.0f)) {
Math_ApproachZeroF(&particle->scale, 0.2f, 0.001f);
if (particle->scale <= 0.0001f) {
particle->timer = 0;
}
}
if (particle->timer != 0) {
particle->timer--;
} else {
particle->isVisible = false;
}
}
}
}
void EnBaguo_DrawRockParticles(EnBaguo* this, GlobalContext* globalCtx) {
s16 i;
NejironParticle* particle = this->particles;
GraphicsContext* gfxCtx = globalCtx->state.gfxCtx;
OPEN_DISPS(gfxCtx);
func_8012C28C(globalCtx->state.gfxCtx);
for (i = 0; i < ARRAY_COUNT(this->particles); i++, particle++) {
if (particle->isVisible) {
Matrix_InsertTranslation(particle->position.x, particle->position.y, particle->position.z, MTXMODE_NEW);
Matrix_InsertXRotation_s(particle->rotation.x, MTXMODE_APPLY);
Matrix_RotateY(particle->rotation.y, MTXMODE_APPLY);
Matrix_InsertZRotation_s(particle->rotation.z, MTXMODE_APPLY);
Matrix_Scale(particle->scale, particle->scale, particle->scale, MTXMODE_APPLY);
gSPMatrix(POLY_OPA_DISP++, Matrix_NewMtx(gfxCtx), G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW);
gDPSetPrimColor(POLY_OPA_DISP++, 0, 1, 255, 255, 255, 255);
gSPDisplayList(POLY_OPA_DISP++, &D_0401FA40);
}
}
CLOSE_DISPS(gfxCtx);
}

View File

@ -7,11 +7,53 @@ struct EnBaguo;
typedef void (*EnBaguoActionFunc)(struct EnBaguo*, GlobalContext*); typedef void (*EnBaguoActionFunc)(struct EnBaguo*, GlobalContext*);
typedef enum {
/* 0x0 */ NEJIRON_ACTION_INACTIVE, // The Nejiron is either underground or emerging from underground
/* 0x1 */ NEJIRON_ACTION_ACTIVE, // The Nejiron is above ground and actively chasing the player
/* 0x2 */ NEJIRON_ACTION_RETREATING, // The Nejiron is burrowing back underground
/* 0x3 */ NEJIRON_ACTION_EXPLODING // The Nejiron has detonated
} NejironAction;
/**
* These directions are relative to the Nejiron.
*/
typedef enum {
/* 0x0 */ NEJIRON_DIRECTION_RIGHT,
/* 0x1 */ NEJIRON_DIRECTION_LEFT
} NejironRollDirection;
/**
* When a Nejiron explodes, rock particles fly out from where it exploded.
* This struct governs how these rock particles behave.
*/
typedef struct NejironParticle {
/* 0x00 */ u8 isVisible;
/* 0x04 */ Vec3f position;
/* 0x10 */ Vec3f velocity;
/* 0x1C */ Vec3f acceleration;
/* 0x28 */ Vec3s rotation;
/* 0x30 */ f32 scale;
/* 0x34 */ s16 timer;
} NejironParticle; // size = 0x38
typedef struct EnBaguo { typedef struct EnBaguo {
/* 0x0000 */ Actor actor; /* 0x000 */ Actor actor;
/* 0x0144 */ char unk_144[0x68]; /* 0x144 */ SkelAnime skelAnime;
/* 0x01AC */ EnBaguoActionFunc actionFunc; /* 0x188 */ Vec3s jointTable[3];
/* 0x01B0 */ char unk_1B0[0x71C]; /* 0x19A */ Vec3s morphTable[3];
/* 0x1AC */ EnBaguoActionFunc actionFunc;
/* 0x1B0 */ s16 eyeIndex;
/* 0x1B2 */ s16 blinkTimer;
/* 0x1B4 */ s16 timer;
/* 0x1B6 */ s16 action;
/* 0x1B8 */ s16 zRollDirection;
/* 0x1BC */ f32 maxDistanceFromHome;
/* 0x1C0 */ u8 hardHitFlag;
/* 0x1C4 */ Vec3f currentRotation;
/* 0x1D0 */ Vec3f targetRotation;
/* 0x1DC */ ColliderJntSph collider;
/* 0x1FC */ ColliderJntSphElement colliderElements[1];
/* 0x23C */ NejironParticle particles[30];
} EnBaguo; // size = 0x8CC } EnBaguo; // size = 0x8CC
extern const ActorInit En_Baguo_InitVars; extern const ActorInit En_Baguo_InitVars;

View File

@ -10297,20 +10297,20 @@
0x80A3AEC8:("DmTsg_Draw",), 0x80A3AEC8:("DmTsg_Draw",),
0x80A3B080:("EnBaguo_Init",), 0x80A3B080:("EnBaguo_Init",),
0x80A3B1F4:("EnBaguo_Destroy",), 0x80A3B1F4:("EnBaguo_Destroy",),
0x80A3B220:("func_80A3B220",), 0x80A3B220:("EnBaguo_UndergroundIdle",),
0x80A3B2CC:("func_80A3B2CC",), 0x80A3B2CC:("EnBaguo_EmergeFromUnderground",),
0x80A3B3E0:("func_80A3B3E0",), 0x80A3B3E0:("EnBaguo_Idle",),
0x80A3B5E0:("func_80A3B5E0",), 0x80A3B5E0:("EnBaguo_Roll",),
0x80A3B794:("func_80A3B794",), 0x80A3B794:("EnBaguo_SetupRetreatUnderground",),
0x80A3B7B8:("func_80A3B7B8",), 0x80A3B7B8:("EnBaguo_RetreatUnderground",),
0x80A3B8F8:("func_80A3B8F8",), 0x80A3B8F8:("EnBaguo_PostDetonation",),
0x80A3B958:("func_80A3B958",), 0x80A3B958:("EnBaguo_CheckForDetonation",),
0x80A3BC88:("EnBaguo_Update",), 0x80A3BC88:("EnBaguo_Update",),
0x80A3BE24:("func_80A3BE24",), 0x80A3BE24:("EnBaguo_PostLimbDraw",),
0x80A3BE60:("func_80A3BE60",), 0x80A3BE60:("EnBaguo_DrawBody",),
0x80A3BF0C:("func_80A3BF0C",), 0x80A3BF0C:("EnBaguo_InitializeParticle",),
0x80A3C008:("func_80A3C008",), 0x80A3C008:("EnBaguo_UpdateParticles",),
0x80A3C17C:("func_80A3C17C",), 0x80A3C17C:("EnBaguo_DrawRockParticles",),
0x80A3C4E0:("func_80A3C4E0",), 0x80A3C4E0:("func_80A3C4E0",),
0x80A3C560:("func_80A3C560",), 0x80A3C560:("func_80A3C560",),
0x80A3C658:("func_80A3C658",), 0x80A3C658:("func_80A3C658",),

View File

@ -1514,6 +1514,9 @@ D_060092A0 = 0x060092A0;
// ovl_En_Baguo // ovl_En_Baguo
D_060014C8 = 0x060014C8;
D_060018C8 = 0x060018C8;
D_06001CC8 = 0x06001CC8;
D_060020E8 = 0x060020E8; D_060020E8 = 0x060020E8;
// ovl_En_Baisen // ovl_En_Baisen