EnJso2 (Garo Master) OK and documented (#1485)

* EnJso2 (Garo Master) OK and documented

* Name all the override input things

* Respond to reviews
This commit is contained in:
Tom Overton 2023-11-13 04:41:51 -08:00 committed by GitHub
parent 71d83a5e15
commit 60ddc5891e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 2066 additions and 248 deletions

3
spec
View File

@ -2862,8 +2862,7 @@ beginseg
name "ovl_En_Jso2"
compress
include "build/src/overlays/actors/ovl_En_Jso2/z_en_jso2.o"
include "build/data/ovl_En_Jso2/ovl_En_Jso2.data.o"
include "build/data/ovl_En_Jso2/ovl_En_Jso2.reloc.o"
include "build/src/overlays/actors/ovl_En_Jso2/ovl_En_Jso2_reloc.o"
endseg
beginseg

View File

@ -18,8 +18,8 @@ void EnJso_Destroy(Actor* thisx, PlayState* play);
void EnJso_Update(Actor* thisx, PlayState* play);
void EnJso_Draw(Actor* thisx, PlayState* play);
void EnJso_SetupHandleIntroCutscene(EnJso* this);
void EnJso_HandleIntroCutscene(EnJso* this, PlayState* play);
void EnJso_SetupIntroCutscene(EnJso* this);
void EnJso_IntroCutscene(EnJso* this, PlayState* play);
void EnJso_Reappear(EnJso* this, PlayState* play);
void EnJso_SetupCirclePlayer(EnJso* this, PlayState* play);
void EnJso_CirclePlayer(EnJso* this, PlayState* play);
@ -46,8 +46,8 @@ void EnJso_FallDownAndTalk(EnJso* this, PlayState* play);
void EnJso_TellHint(EnJso* this, PlayState* play);
void EnJso_BurstIntoFlames(EnJso* this, PlayState* play);
typedef enum {
/* 0 */ EN_JSO_ACTION_HANDLE_INTRO_CUTSCENE,
typedef enum EnJsoAction {
/* 0 */ EN_JSO_ACTION_INTRO_CUTSCENE,
/* 1 */ EN_JSO_ACTION_REAPPEAR,
/* 2 */ EN_JSO_ACTION_CIRCLE_PLAYER,
/* 3 */ EN_JSO_ACTION_GUARD,
@ -65,30 +65,35 @@ typedef enum {
/* 15 */ EN_JSO_ACTION_UNK_15 // Checked in EnJso_Update, but never actually used
} EnJsoAction;
typedef enum {
typedef enum EnJsoIntroType {
/* 0 */ EN_JSO_INTRO_SPIN_UP_FROM_GROUND,
/* 1 */ EN_JSO_INTRO_JUMP_OUT_FROM_GROUND,
/* 2 */ EN_JSO_INTRO_LAND_FROM_ABOVE,
/* 3 */ EN_JSO_INTRO_SCALE_UP
} EnJsoIntroType;
typedef enum {
typedef enum EnJsoIntroCsState {
// Either the cutscene started (in which case, we'll transition to the next state on the next frame) or it's done.
/* 0 */ EN_JSO_INTRO_CS_STATE_DONE_OR_STARTED,
// Waits for the Garo to finish their intro animation and open the first textbox.
/* 1 */ EN_JSO_INTRO_CS_STATE_WAITING_FOR_TEXTBOX_TO_APPEAR,
// Waits for the player to press a button to continue on from the Garo's first textbox.
/* 2 */ EN_JSO_INTRO_CS_STATE_WAITING_FOR_TEXTBOX_TO_CONTINUE,
// Lifts the Garo's right arm such that, when they draw their sword, it's pointed at the player. Waits until the
// player has finished reading all of the Garo's dialogue before continuing.
/* 3 */ EN_JSO_INTRO_CS_STATE_RAISE_ARM_AND_DRAW_RIGHT_SWORD,
// Waits 10 frames, then the Garo draws its left sword and continues to the next state.
/* 4 */ EN_JSO_INTRO_CS_STATE_DRAW_LEFT_SWORD,
// Waits 10 frames, then the Garo jumps back and the cutscene ends.
/* 5 */ EN_JSO_INTRO_CS_STATE_ENDING
} EnJsoIntroCsState;
typedef enum {
typedef enum EnJsoSwordState {
/* 0 */ EN_JSO_SWORD_STATE_BOTH_DRAWN,
/* 1 */ EN_JSO_SWORD_STATE_KNOCKED_OUT_OF_HANDS,
/* 2 */ EN_JSO_SWORD_STATE_RIGHT_DRAWN,
@ -102,7 +107,7 @@ static s32 sIsAttacking = false;
// Seemingly a duplicate of the isPlayerLockedOn instance variable. Its purpose is unknown.
static s32 sIsPlayerLockedOn = false;
typedef enum {
typedef enum EnJsoDamageEffect {
/* 0x0 */ EN_JSO_DMGEFF_IMMUNE, // Deals no damage and has no special effect
/* 0x1 */ EN_JSO_DMGEFF_STUN, // Deals no damage but stuns the Garo
/* 0x2 */ EN_JSO_DMGEFF_FIRE, // Damages and sets the Garo on fire
@ -208,7 +213,7 @@ static u16 sTextIds[] = {
0x1399,
};
typedef enum {
typedef enum EnJsoAnimation {
/* 0 */ EN_JSO_ANIM_APPEAR,
/* 1 */ EN_JSO_ANIM_IDLE,
/* 2 */ EN_JSO_ANIM_BOUNCE,
@ -301,7 +306,7 @@ void EnJso_Init(Actor* thisx, PlayState* play) {
this->actor.flags |= ACTOR_FLAG_CANT_LOCK_ON;
this->hintType = EN_JSO_GET_HINT_TYPE(&this->actor);
this->introCsType = this->hintType & EN_JSO_INTRO_SCALE_UP;
EnJso_SetupHandleIntroCutscene(this);
EnJso_SetupIntroCutscene(this);
}
void EnJso_Destroy(Actor* thisx, PlayState* play) {
@ -338,14 +343,14 @@ void EnJso_ChangeAnim(EnJso* this, s32 animIndex) {
sAnimationModes[animIndex], morphFrames);
}
void EnJso_SetupHandleIntroCutscene(EnJso* this) {
void EnJso_SetupIntroCutscene(EnJso* this) {
EnEncount3* parent = (EnEncount3*)this->actor.parent;
this->csId = parent->csId;
this->swordState = EN_JSO_SWORD_STATE_NONE_DRAWN;
this->action = EN_JSO_ACTION_HANDLE_INTRO_CUTSCENE;
this->action = EN_JSO_ACTION_INTRO_CUTSCENE;
this->actor.flags |= ACTOR_FLAG_100000;
this->actionFunc = EnJso_HandleIntroCutscene;
this->actionFunc = EnJso_IntroCutscene;
}
/**
@ -353,13 +358,13 @@ void EnJso_SetupHandleIntroCutscene(EnJso* this) {
* appear in one of four different ways, activating the ring of fire, etc. When the cutscene is over, the Garo will
* jump back to start the fight.
*/
void EnJso_HandleIntroCutscene(EnJso* this, PlayState* play) {
void EnJso_IntroCutscene(EnJso* this, PlayState* play) {
Player* player = GET_PLAYER(play);
f32 curFrame = this->skelAnime.curFrame;
s16 showTextbox;
s16 diffToTargetRobeRightRot;
switch (this->introCsState) {
switch (this->cutsceneState) {
case EN_JSO_INTRO_CS_STATE_DONE_OR_STARTED:
if (!CutsceneManager_IsNext(this->csId)) {
CutsceneManager_Queue(this->csId);
@ -412,8 +417,8 @@ void EnJso_HandleIntroCutscene(EnJso* this, PlayState* play) {
break;
}
this->introCsTimer = 0;
this->introCsState++;
this->cutsceneTimer = 0;
this->cutsceneState++;
break;
case EN_JSO_INTRO_CS_STATE_WAITING_FOR_TEXTBOX_TO_APPEAR:
@ -476,8 +481,8 @@ void EnJso_HandleIntroCutscene(EnJso* this, PlayState* play) {
Message_StartTextbox(play, sTextIds[this->textIndex], &this->actor);
this->textIndex++;
this->actor.shape.yOffset = 970.0f;
this->introCsTimer = 0;
this->introCsState++;
this->cutsceneTimer = 0;
this->cutsceneState++;
}
break;
@ -493,9 +498,9 @@ void EnJso_HandleIntroCutscene(EnJso* this, PlayState* play) {
if ((Message_GetState(&play->msgCtx) == TEXT_STATE_5) && Message_ShouldAdvance(play)) {
Message_CloseTextbox(play);
Message_ContinueTextbox(play, sTextIds[this->textIndex]);
this->introCsTimer = 0;
this->cutsceneTimer = 0;
this->textIndex++;
this->introCsState++;
this->cutsceneState++;
}
break;
@ -531,8 +536,8 @@ void EnJso_HandleIntroCutscene(EnJso* this, PlayState* play) {
Message_CloseTextbox(play);
this->targetRightArmRot.x = this->targetRightArmRot.y = this->targetRightArmRot.z =
this->targetRobeRightRot.x = this->targetRobeRightRot.y = this->targetRobeRightRot.z = 0;
this->introCsTimer = 0;
this->introCsState++;
this->cutsceneTimer = 0;
this->cutsceneState++;
}
break;
@ -543,9 +548,9 @@ void EnJso_HandleIntroCutscene(EnJso* this, PlayState* play) {
this->subCamAtNext.x = player->actor.world.pos.x - 30.0f;
this->subCamAtNext.y = player->actor.world.pos.y + 40.0f;
this->subCamAtNext.z = player->actor.world.pos.z - 130.0f;
this->introCsTimer++;
this->cutsceneTimer++;
if (this->introCsTimer >= 10) {
if (this->cutsceneTimer >= 10) {
this->swordState = EN_JSO_SWORD_STATE_BOTH_DRAWN;
Actor_PlaySfx(&this->actor, NA_SE_EN_ANSATSUSYA_SWORD);
if ((this->actor.parent != NULL) && (this->actor.parent->update != NULL)) {
@ -558,8 +563,8 @@ void EnJso_HandleIntroCutscene(EnJso* this, PlayState* play) {
}
EnJso_ChangeAnim(this, EN_JSO_ANIM_IDLE);
this->introCsTimer = 0;
this->introCsState++;
this->cutsceneTimer = 0;
this->cutsceneState++;
}
break;
@ -570,14 +575,14 @@ void EnJso_HandleIntroCutscene(EnJso* this, PlayState* play) {
this->subCamAtNext.x = player->actor.world.pos.x - 30.0f;
this->subCamAtNext.y = player->actor.world.pos.y + 40.0f;
this->subCamAtNext.z = player->actor.world.pos.z - 130.0f;
this->introCsTimer++;
this->cutsceneTimer++;
if (this->introCsTimer >= 10) {
if (this->cutsceneTimer >= 10) {
Player_SetCsActionWithHaltedActors(play, &this->actor, PLAYER_CSACTION_END);
CutsceneManager_Stop(this->csId);
this->rightArmRot.x = this->rightArmRot.y = this->rightArmRot.z = this->robeRightRot.x =
this->robeRightRot.y = this->robeRightRot.z = 0;
this->introCsState = EN_JSO_INTRO_CS_STATE_DONE_OR_STARTED;
this->cutsceneState = EN_JSO_INTRO_CS_STATE_DONE_OR_STARTED;
this->subCamId = SUB_CAM_ID_DONE;
this->actor.flags &= ~ACTOR_FLAG_100000;
this->actor.flags &= ~ACTOR_FLAG_CANT_LOCK_ON;
@ -683,7 +688,7 @@ void EnJso_SetupCirclePlayer(EnJso* this, PlayState* play) {
/**
* Makes the Garo bounce in a circle around the player, sometimes randomly switching the direction it's traveling, until
* the attack wait timer reaches 0. Once it does, then the Garo will prepare to attack.
* the attack timer reaches 0. Once it does, then the Garo will prepare to attack.
*/
void EnJso_CirclePlayer(EnJso* this, PlayState* play) {
f32 curFrame = this->skelAnime.curFrame;
@ -692,7 +697,8 @@ void EnJso_CirclePlayer(EnJso* this, PlayState* play) {
s32 pad;
Actor_PlaySfx(&this->actor, NA_SE_EN_ANSATSUSYA_MOVING - SFX_FLAG);
if ((this->action != EN_JSO_ACTION_REAPPEAR) && (this->action != EN_JSO_ACTION_HANDLE_INTRO_CUTSCENE) &&
if ((this->action != EN_JSO_ACTION_REAPPEAR) && (this->action != EN_JSO_ACTION_INTRO_CUTSCENE) &&
(fabsf(player->actor.world.pos.y - this->actor.world.pos.y) > 60.0f)) {
EnJso_SetupReappear(this, play);
return;
@ -722,7 +728,7 @@ void EnJso_CirclePlayer(EnJso* this, PlayState* play) {
//! @note: Since sIsPlayerLockedOn always mirrors the value of this->isPlayerLockedOn, the last part of this
//! if-statement is always true and has no impact on the logic. In other words, the Garo doesn't care whether or not
//! the player is locked on; it will attack regardless as long as the other conditions are met.
if ((this->attackWaitTimer == 0) && !sIsAttacking && (!sIsPlayerLockedOn || this->isPlayerLockedOn)) {
if ((this->attackTimer == 0) && !sIsAttacking && (!sIsPlayerLockedOn || this->isPlayerLockedOn)) {
sIsAttacking = true;
this->isAttacking = true;
this->action = EN_JSO_ACTION_SPIN_BEFORE_ATTACK;
@ -797,7 +803,7 @@ void EnJso_SpinBeforeAttack(EnJso* this, PlayState* play) {
void EnJso_SetupDashAttack(EnJso* this) {
this->action = EN_JSO_ACTION_DASH_ATTACK;
this->dashAttackTimer = 40;
this->attackMovementTimer = 40;
this->bodyCollider.base.colType = COLTYPE_HIT2;
this->bodyCollider.base.acFlags &= ~AC_HARD;
this->actor.speed = 15.0f;
@ -829,7 +835,7 @@ void EnJso_DashAttack(EnJso* this, PlayState* play) {
knockbackVelocity.z = -10.0f;
Matrix_MultVec3f(&knockbackVelocity, &this->knockbackVelocity);
this->swordState = EN_JSO_SWORD_STATE_KNOCKED_OUT_OF_HANDS;
this->dashAttackTimer = 0;
this->attackMovementTimer = 0;
this->disableBlure = true;
AudioSfx_SetChannelIO(&this->actor.projectedPos, NA_SE_EN_ANSATSUSYA_DASH_2, 0);
EnJso_SetupKnockedBack(this);
@ -848,7 +854,7 @@ void EnJso_DashAttack(EnJso* this, PlayState* play) {
yawDiff = this->actor.yawTowardsPlayer - this->actor.shape.rot.y;
absYawDiff = ABS_ALT(yawDiff);
if ((this->dashAttackTimer == 0) || (this->actor.xzDistToPlayer < 100.0f) || (absYawDiff > 0x4300)) {
if ((this->attackMovementTimer == 0) || (this->actor.xzDistToPlayer < 100.0f) || (absYawDiff > 0x4300)) {
AudioSfx_SetChannelIO(&this->actor.projectedPos, NA_SE_EN_ANSATSUSYA_DASH_2, 0);
Math_ApproachZeroF(&this->actor.speed, 0.3f, 3.0f);
EnJso_SetupSlash(this, play);
@ -861,7 +867,7 @@ void EnJso_SetupSlash(EnJso* this, PlayState* play) {
Actor_SpawnFloorDustRing(play, &this->actor, &this->actor.world.pos, this->actor.shape.shadowScale, 1, 8.0f, 500,
10, true);
Math_ApproachZeroF(&this->actor.speed, 0.3f, 3.0f);
this->swordHitSomething = false;
this->slashHitSomething = false;
Actor_PlaySfx(&this->actor, NA_SE_IT_SWORD_SWING_HARD);
this->actionFunc = EnJso_Slash;
}
@ -881,7 +887,7 @@ void EnJso_Slash(EnJso* this, PlayState* play) {
}
if ((this->rightSwordCollider.base.atFlags & AT_HIT) || (this->leftSwordCollider.base.atFlags & AT_HIT)) {
this->swordHitSomething = true;
this->slashHitSomething = true;
this->rightSwordCollider.base.atFlags &= ~AT_HIT;
this->leftSwordCollider.base.atFlags &= ~AT_HIT;
}
@ -913,7 +919,7 @@ void EnJso_Slash(EnJso* this, PlayState* play) {
}
void EnJso_SetupWaitAfterSlash(EnJso* this) {
if (this->swordHitSomething) {
if (this->slashHitSomething) {
EnJso_ChangeAnim(this, EN_JSO_ANIM_SLASH_LOOP);
this->timer = 20;
} else {
@ -931,10 +937,10 @@ void EnJso_SetupWaitAfterSlash(EnJso* this) {
*/
void EnJso_WaitAfterSlash(EnJso* this, PlayState* play) {
if (this->timer == 0) {
this->attackWaitTimer = Rand_S16Offset(30, 30);
this->attackTimer = Rand_S16Offset(30, 30);
this->bodyCollider.base.colType = COLTYPE_NONE;
this->bodyCollider.base.acFlags |= AC_HARD;
this->swordHitSomething = false;
this->slashHitSomething = false;
sIsAttacking = false;
this->isAttacking = false;
EnJso_SetupCirclePlayer(this, play);
@ -986,9 +992,12 @@ void EnJso_SetupStunned(EnJso* this) {
AudioSfx_SetChannelIO(&this->actor.projectedPos, NA_SE_EN_ANSATSUSYA_DASH_2, 0);
EnJso_ChangeAnim(this, EN_JSO_ANIM_DAMAGED);
// This assignment is immediately overriden below.
//! @note: This assignment is immediately overriden below. This is probably a leftover from EnJso2's version of this
//! function, where the Garo Master is stunned for longer if it's frozen. Garos just use the longer stun
//! unconditionally, resulting in this useless assignment here.
this->timer = 30;
this->actor.speed = 0.0f;
if (((this->drawDmgEffType == ACTOR_DRAW_DMGEFF_FROZEN_SFX) ||
(this->drawDmgEffType == ACTOR_DRAW_DMGEFF_FROZEN_NO_SFX)) &&
(this->drawDmgEffAlpha == 0)) {
@ -1032,7 +1041,7 @@ void EnJso_SetupDamaged(EnJso* this, PlayState* play) {
AudioSfx_SetChannelIO(&this->actor.projectedPos, NA_SE_EN_ANSATSUSYA_DASH_2, 0);
EnJso_ChangeAnim(this, EN_JSO_ANIM_DAMAGED);
this->swordHitSomething = false;
this->slashHitSomething = false;
this->actor.velocity.y = 10.0f;
this->actor.speed = 0.0f;
Matrix_RotateYS(this->actor.yawTowardsPlayer, MTXMODE_NEW);
@ -1104,7 +1113,7 @@ void EnJso_JumpBack(EnJso* this, PlayState* play) {
sIsAttacking = false;
this->isAttacking = false;
this->actor.world.rot.y = this->actor.shape.rot.y;
this->attackWaitTimer = Rand_S16Offset(10, 10);
this->attackTimer = Rand_S16Offset(10, 10);
EnJso_SetupCirclePlayer(this, play);
}
}
@ -1449,8 +1458,8 @@ void EnJso_Update(Actor* thisx, PlayState* play) {
}
this->actionFunc(this, play);
DECR(this->dashAttackTimer);
DECR(this->attackWaitTimer);
DECR(this->attackMovementTimer);
DECR(this->attackTimer);
DECR(this->timer);
DECR(this->drawDmgEffAlpha);
@ -1501,7 +1510,7 @@ void EnJso_Update(Actor* thisx, PlayState* play) {
this->afterimageCount = 0;
}
if ((this->action != EN_JSO_ACTION_HANDLE_INTRO_CUTSCENE) && (this->action != EN_JSO_ACTION_CIRCLE_PLAYER) &&
if ((this->action != EN_JSO_ACTION_INTRO_CUTSCENE) && (this->action != EN_JSO_ACTION_CIRCLE_PLAYER) &&
(this->action != EN_JSO_ACTION_SPIN_BEFORE_ATTACK) && (this->action != EN_JSO_ACTION_DAMAGED) &&
(this->action != EN_JSO_ACTION_JUMP_BACK)) {
this->actor.shape.rot.y = this->actor.world.rot.y;
@ -1510,14 +1519,14 @@ void EnJso_Update(Actor* thisx, PlayState* play) {
this->actor.shape.rot.x = this->actor.world.rot.x;
Collider_UpdateCylinder(&this->actor, &this->bodyCollider);
if ((this->action != EN_JSO_ACTION_HANDLE_INTRO_CUTSCENE) && (this->action != EN_JSO_ACTION_REAPPEAR) &&
if ((this->action != EN_JSO_ACTION_INTRO_CUTSCENE) && (this->action != EN_JSO_ACTION_REAPPEAR) &&
(this->action != EN_JSO_ACTION_DAMAGED) && (this->action != EN_JSO_ACTION_SPIN_BEFORE_ATTACK) &&
(this->action != EN_JSO_ACTION_DEAD) && (this->action != EN_JSO_ACTION_FALL_DOWN_AND_TALK) &&
(this->action != EN_JSO_ACTION_UNK_15)) {
CollisionCheck_SetOC(play, &play->colChkCtx, &this->bodyCollider.base);
CollisionCheck_SetAC(play, &play->colChkCtx, &this->bodyCollider.base);
if ((this->action == EN_JSO_ACTION_SLASH) && !this->swordHitSomething &&
if ((this->action == EN_JSO_ACTION_SLASH) && !this->slashHitSomething &&
(this->swordState == EN_JSO_SWORD_STATE_BOTH_DRAWN)) {
CollisionCheck_SetAT(play, &play->colChkCtx, &this->rightSwordCollider.base);
CollisionCheck_SetAT(play, &play->colChkCtx, &this->leftSwordCollider.base);

View File

@ -15,7 +15,7 @@ typedef void (*EnJsoActionFunc)(struct EnJso*, PlayState*);
// For the four `VARIABLE` hint types, the former hint is used if the player hasn't restored the river in
// Ikana Canyon yet, and the latter hint is used if the player has. If the player has the Elegy of Emptiness,
// then all hints will be replaced with a hint telling the player to use the song to climb Stone Tower.
typedef enum {
typedef enum EnJsoHintType {
/* 0 */ EN_JSO_HINT_FREEZE_OCTOROKS,
/* 1 */ EN_JSO_HINT_FLATS_LOCATION,
/* 2 */ EN_JSO_HINT_VARIABLE_1, // Hints that Pamela's family is in the house or that the Song of Healing can heal Pamela's father
@ -28,7 +28,7 @@ typedef enum {
/* 9 */ EN_JSO_HINT_KING_WEAK_TO_MIRROR_SHIELD
} EnJsoHintType;
typedef enum {
typedef enum EnJsoBodyPart {
/* 0 */ EN_JSO_BODYPART_LEFT_SWORD,
/* 1 */ EN_JSO_BODYPART_RIGHT_SWORD,
/* 2 */ EN_JSO_BODYPART_ROBE_TOP,
@ -44,7 +44,6 @@ typedef enum {
/* 12 */ EN_JSO_BODYPART_MAX
} EnJsoBodyPart;
typedef struct EnJso {
/* 0x000 */ Actor actor;
/* 0x144 */ SkelAnime skelAnime;
@ -54,9 +53,9 @@ typedef struct EnJso {
/* 0x27C */ s16 action;
/* 0x27E */ s16 circlingAngle;
/* 0x280 */ s16 circlingAngularVelocity;
/* 0x282 */ s16 dashAttackTimer;
/* 0x282 */ s16 attackMovementTimer;
/* 0x284 */ UNK_TYPE1 unk_284[0x2];
/* 0x286 */ s16 attackWaitTimer; // while bouncing, the Garo cannot start an attack until this reaches 0
/* 0x286 */ s16 attackTimer; // while bouncing, the Garo cannot start an attack until this reaches 0
/* 0x288 */ s16 timer;
/* 0x28A */ s16 isGuarding; // Set to false when the guard animation ends, never checked or set otherwise. Name is inferred based on how it's being set.
/* 0x28C */ s16 isPlayerLockedOn;
@ -76,7 +75,7 @@ typedef struct EnJso {
/* 0x34A */ s16 hintType;
/* 0x34C */ u8 disableBlure;
/* 0x34D */ u8 swordState;
/* 0x34E */ u8 swordHitSomething;
/* 0x34E */ u8 slashHitSomething;
/* 0x350 */ f32 animEndFrame;
/* 0x354 */ f32 scale;
/* 0x358 */ UNK_TYPE1 unk_358[0x4];
@ -88,8 +87,8 @@ typedef struct EnJso {
/* 0x4B0 */ s16 afterimageIndex;
/* 0x4B4 */ s32 afterimageCount;
/* 0x4B8 */ s16 csId;
/* 0x4BC */ u32 introCsTimer;
/* 0x4C0 */ s16 introCsState;
/* 0x4BC */ u32 cutsceneTimer;
/* 0x4C0 */ s16 cutsceneState;
/* 0x4C2 */ s16 subCamId;
/* 0x4C4 */ UNK_TYPE1 unk_4C4[0x4];
/* 0x4C8 */ Vec3f subCamEye;

File diff suppressed because it is too large Load Diff

View File

@ -2,16 +2,109 @@
#define Z_EN_JSO2_H
#include "global.h"
#include "assets/objects/object_jso/object_jso.h"
struct EnJso2;
#define EN_JSO2_GET_TYPE(thisx) ((thisx)->params)
#define EN_JSO2_AFTERIMAGE_COUNT 20
#define EN_JSO2_FLAME_COUNT 6
typedef void (*EnJso2ActionFunc)(struct EnJso2*, PlayState*);
typedef enum EnJso2Type {
// This type is exclusively used by the Garo Master in Stone Tower Temple who guards the Light Arrow.
// It has an intro and death cutscene, and the intro cutscene uses many hardcoded coordinates which
// assume the Garo Master is in the Light Arrow room.
/* 0 */ EN_JSO2_TYPE_LIGHT_ARROW_ROOM,
// This type is used everywhere outside of Stone Tower Temple, and it lacks an intro or death cutscene.
/* 1 */ EN_JSO2_TYPE_NORMAL
} EnJso2Type;
typedef enum EnJso2BodyPart {
/* 0 */ EN_JSO2_BODYPART_LEFT_SWORD,
/* 1 */ EN_JSO2_BODYPART_RIGHT_SWORD,
/* 2 */ EN_JSO2_BODYPART_ROBE_TOP,
/* 3 */ EN_JSO2_BODYPART_ROBE_BACK,
/* 4 */ EN_JSO2_BODYPART_ROBE_LEFT,
/* 5 */ EN_JSO2_BODYPART_ROBE_RIGHT,
/* 6 */ EN_JSO2_BODYPART_ROBE_FRONT,
/* 7 */ EN_JSO2_BODYPART_HEAD,
/* 8 */ EN_JSO2_BODYPART_RIGHT_THIGH,
/* 9 */ EN_JSO2_BODYPART_RIGHT_FOOT,
/* 10 */ EN_JSO2_BODYPART_LEFT_THIGH,
/* 11 */ EN_JSO2_BODYPART_LEFT_FOOT,
/* 12 */ EN_JSO2_BODYPART_MAX
} EnJso2BodyPart;
typedef struct EnJso2 {
/* 0x0000 */ Actor actor;
/* 0x0144 */ char unk_144[0x134];
/* 0x0144 */ SkelAnime skelAnime;
/* 0x0188 */ Vec3s jointTable[GARO_MASTER_LIMB_MAX];
/* 0x0200 */ Vec3s morphTable[GARO_MASTER_LIMB_MAX];
/* 0x0278 */ EnJso2ActionFunc actionFunc;
/* 0x027C */ char unk_27C[0xE14];
/* 0x027C */ struct_80122744_arg1 overrideInputEntry;
/* 0x0284 */ s16 action;
/* 0x0286 */ s16 circlingAngle;
/* 0x0288 */ s16 circlingAngularVelocity;
/* 0x028A */ s16 attackMovementTimer;
/* 0x028C */ UNK_TYPE1 unk_28C[2];
/* 0x028E */ s16 attackTimer;
/* 0x0290 */ s16 timer;
/* 0x0294 */ f32 subCamMaxVelocityFrac;
/* 0x0298 */ f32 subCamVelocity;
/* 0x029C */ s32 type;
/* 0x02A0 */ s16 drawDmgEffAlpha;
/* 0x02A2 */ s16 drawDmgEffType;
/* 0x02A4 */ f32 drawDmgEffScale;
/* 0x02A8 */ f32 drawDmgEffFrozenSteamScale;
/* 0x02AC */ UNK_TYPE1 unk_2AC[4];
/* 0x02B0 */ s16 bodyPartsCount;
/* 0x02B4 */ s32 isFadingAway;
/* 0x02B8 */ Vec3f baseSubCamEye;
/* 0x02C4 */ Vec3f bombPos;
/* 0x02D0 */ Actor* bomb;
/* 0x02D4 */ Vec3f bodyPartsPos[EN_JSO2_BODYPART_MAX];
/* 0x0364 */ s16 bodyPartIndex;
/* 0x0366 */ s16 alpha;
/* 0x0368 */ u8 disableBlure;
/* 0x036C */ s32 swordState;
/* 0x0370 */ u8 isTeleporting; // set, but never checked
/* 0x0371 */ u8 slashHitSomething;
/* 0x0374 */ f32 animEndFrame;
/* 0x0378 */ f32 scale;
/* 0x037C */ UNK_TYPE1 unk_37C[4];
/* 0x0380 */ s32 rightSwordBlureIndex;
/* 0x0384 */ s32 leftSwordBlureIndex;
/* 0x0388 */ s32 afterimageCount;
/* 0x038C */ s16 afterimageIndex;
/* 0x038E */ s16 flameScroll;
/* 0x0390 */ Vec3f afterimagePos[EN_JSO2_AFTERIMAGE_COUNT];
/* 0x0480 */ Vec3s afterimageRot[EN_JSO2_AFTERIMAGE_COUNT];
/* 0x04F8 */ Vec3s afterimageJointTable[EN_JSO2_AFTERIMAGE_COUNT][GARO_MASTER_LIMB_MAX];
/* 0x0E58 */ Vec3f knockbackVelocity; // Adds a little push backwards when the Garo Master is bounced off the player's shield, damaged, or stunned
/* 0x0E64 */ Vec3f flamePos[EN_JSO2_FLAME_COUNT];
/* 0x0EAC */ Vec3f flameScale[EN_JSO2_FLAME_COUNT];
/* 0x0EF4 */ ColliderCylinder bodyCollider;
/* 0x0F40 */ ColliderQuad rightSwordCollider;
/* 0x0FC0 */ ColliderQuad leftSwordCollider;
/* 0x1040 */ s32 animIndex;
/* 0x1044 */ s16 cutsceneTimer;
/* 0x1046 */ union {
s16 cutsceneState; // exclusively used by the EN_JSO2_TYPE_LIGHT_ARROW_ROOM type
s16 appearState; // exclusively used by the EN_JSO2_TYPE_NORMAL type
};
/* 0x1048 */ s16 subCamId;
/* 0x104A */ s16 blowUpFrameCounter;
/* 0x104C */ f32 subCamFov;
/* 0x1050 */ f32 subCamFovNext;
/* 0x1054 */ Vec3f subCamEye;
/* 0x1060 */ Vec3f subCamAt;
/* 0x106C */ Vec3f unk_106C; // unused, type inferred from surrounding members
/* 0x1078 */ Vec3f subCamEyeNext;
/* 0x1084 */ Vec3f subCamAtNext;
} EnJso2; // size = 0x1090
#endif // Z_EN_JSO2_H

View File

@ -8847,8 +8847,8 @@
0x809AD8E0:("EnJso_Init",),
0x809ADB24:("EnJso_Destroy",),
0x809ADBC8:("EnJso_ChangeAnim",),
0x809ADC7C:("EnJso_SetupHandleIntroCutscene",),
0x809ADCB8:("EnJso_HandleIntroCutscene",),
0x809ADC7C:("EnJso_SetupIntroCutscene",),
0x809ADCB8:("EnJso_IntroCutscene",),
0x809AE754:("EnJso_SetupReappear",),
0x809AE87C:("EnJso_Reappear",),
0x809AE9B0:("EnJso_SetupCirclePlayer",),
@ -11054,48 +11054,48 @@
0x80A77040:("EnPrz_Draw",),
0x80A773C0:("EnJso2_Init",),
0x80A77664:("EnJso2_Destroy",),
0x80A776E0:("func_80A776E0",),
0x80A776E0:("EnJso2_ChangeAnim",),
0x80A77790:("func_80A77790",),
0x80A77880:("func_80A77880",),
0x80A778D8:("func_80A778D8",),
0x80A778F8:("func_80A778F8",),
0x80A78588:("func_80A78588",),
0x80A785E4:("func_80A785E4",),
0x80A787FC:("func_80A787FC",),
0x80A78868:("func_80A78868",),
0x80A78A70:("func_80A78A70",),
0x80A78ACC:("func_80A78ACC",),
0x80A78B04:("func_80A78B04",),
0x80A78B70:("func_80A78B70",),
0x80A78C08:("func_80A78C08",),
0x80A78C7C:("func_80A78C7C",),
0x80A78E8C:("func_80A78E8C",),
0x80A78F04:("func_80A78F04",),
0x80A78F80:("func_80A78F80",),
0x80A79038:("func_80A79038",),
0x80A790E4:("func_80A790E4",),
0x80A7919C:("func_80A7919C",),
0x80A79300:("func_80A79300",),
0x80A79364:("func_80A79364",),
0x80A79450:("func_80A79450",),
0x80A794C8:("func_80A794C8",),
0x80A79524:("func_80A79524",),
0x80A79600:("func_80A79600",),
0x80A796BC:("func_80A796BC",),
0x80A7980C:("func_80A7980C",),
0x80A79864:("func_80A79864",),
0x80A798C8:("func_80A798C8",),
0x80A7998C:("func_80A7998C",),
0x80A79A84:("func_80A79A84",),
0x80A79B60:("func_80A79B60",),
0x80A79BA0:("func_80A79BA0",),
0x80A7A0D0:("func_80A7A0D0",),
0x80A7A124:("func_80A7A124",),
0x80A7A2EC:("func_80A7A2EC",),
0x80A7A360:("func_80A7A360",),
0x80A77880:("EnJso2_ShouldAdvanceMessage",),
0x80A778D8:("EnJso2_SetupIntroCutscene",),
0x80A778F8:("EnJso2_IntroCutscene",),
0x80A78588:("EnJso2_SetupAppear",),
0x80A785E4:("EnJso2_Appear",),
0x80A787FC:("EnJso2_SetupCirclePlayer",),
0x80A78868:("EnJso2_CirclePlayer",),
0x80A78A70:("EnJso2_SetupGuard",),
0x80A78ACC:("EnJso2_Guard",),
0x80A78B04:("EnJso2_SetupSpinBeforeAttack",),
0x80A78B70:("EnJso2_SpinBeforeAttack",),
0x80A78C08:("EnJso2_SetupDashAttack",),
0x80A78C7C:("EnJso2_DashAttack",),
0x80A78E8C:("EnJso2_SetupTeleport",),
0x80A78F04:("EnJso2_Teleport",),
0x80A78F80:("EnJso2_SetupFallFromTeleport",),
0x80A79038:("EnJso2_FallFromTeleport",),
0x80A790E4:("EnJso2_SetupSlash",),
0x80A7919C:("EnJso2_Slash",),
0x80A79300:("EnJso2_SetupSpinAttack",),
0x80A79364:("EnJso2_SpinAttack",),
0x80A79450:("EnJso2_SetupWaitAfterSlash",),
0x80A794C8:("EnJso2_WaitAfterSlash",),
0x80A79524:("EnJso2_SetupStunned",),
0x80A79600:("EnJso2_Stunned",),
0x80A796BC:("EnJso2_SetupDamaged",),
0x80A7980C:("EnJso2_Damaged",),
0x80A79864:("EnJso2_SetupJumpBack",),
0x80A798C8:("EnJso2_JumpBack",),
0x80A7998C:("EnJso2_SetupDead",),
0x80A79A84:("EnJso2_Dead",),
0x80A79B60:("EnJso2_SetupDeathCutscene",),
0x80A79BA0:("EnJso2_DeathCutscene",),
0x80A7A0D0:("EnJso2_SetupBlowUp",),
0x80A7A124:("EnJso2_BlowUp",),
0x80A7A2EC:("EnJso2_FadeAway",),
0x80A7A360:("EnJso2_UpdateDamage",),
0x80A7A61C:("EnJso2_Update",),
0x80A7AA48:("func_80A7AA48",),
0x80A7AA9C:("func_80A7AA9C",),
0x80A7AA48:("EnJso2_OverrideLimbDraw",),
0x80A7AA9C:("EnJso2_PostLimbDraw",),
0x80A7AFA8:("EnJso2_Draw",),
0x80A7BC70:("ObjEtcetera_Init",),
0x80A7BD80:("ObjEtcetera_Destroy",),

View File

@ -11974,32 +11974,22 @@
0x80A7727C:("D_80A7727C","f32","",0x4),
0x80A77280:("D_80A77280","f32","",0x4),
0x80A77284:("D_80A77284","f32","",0x4),
0x80A7B4F0:("D_80A7B4F0","UNK_TYPE1","",0x1),
0x80A7B510:("D_80A7B510","UNK_TYPE4","",0x4),
0x80A7B558:("D_80A7B558","UNK_TYPE1","",0x1),
0x80A7B564:("D_80A7B564","UNK_TYPE1","",0x1),
0x80A7B570:("D_80A7B570","UNK_TYPE1","",0x1),
0x80A7B57C:("D_80A7B57C","UNK_TYPE1","",0x1),
0x80A7B588:("D_80A7B588","UNK_TYPE1","",0x1),
0x80A7B594:("D_80A7B594","UNK_TYPE1","",0x1),
0x80A7B5A0:("D_80A7B5A0","UNK_TYPE1","",0x1),
0x80A7B5AC:("D_80A7B5AC","UNK_TYPE1","",0x1),
0x80A7B5B8:("D_80A7B5B8","UNK_TYPE1","",0x1),
0x80A7B5C4:("D_80A7B5C4","UNK_TYPE1","",0x1),
0x80A7B5D0:("D_80A7B5D0","UNK_TYPE1","",0x1),
0x80A7B5DC:("D_80A7B5DC","UNK_TYPE1","",0x1),
0x80A7B5E8:("En_Jso2_InitVars","UNK_TYPE1","",0x1),
0x80A7B608:("D_80A7B608","UNK_TYPE1","",0x1),
0x80A7B634:("D_80A7B634","UNK_TYPE1","",0x1),
0x80A7B684:("D_80A7B684","UNK_TYPE1","",0x1),
0x80A7B6DC:("D_80A7B6DC","UNK_TYPE1","",0x1),
0x80A7B6F4:("D_80A7B6F4","UNK_TYPE2","",0x2),
0x80A7B6FC:("D_80A7B6FC","UNK_TYPE4","",0x4),
0x80A7B708:("D_80A7B708","UNK_TYPE1","",0x1),
0x80A7B714:("D_80A7B714","UNK_TYPE1","",0x1),
0x80A7B720:("D_80A7B720","UNK_TYPE1","",0x1),
0x80A7B72C:("D_80A7B72C","UNK_TYPE1","",0x1),
0x80A7B738:("D_80A7B738","UNK_TYPE2","",0x2),
0x80A7B4F0:("sDamageTable","DamageTable","",0x20),
0x80A7B510:("sTargetFlameScales","Vec3f","[6]",0x48),
0x80A7B558:("sFlameOffsets","Vec3f","[6]",0x48),
0x80A7B5A0:("sSlashFlameOffsets","Vec3f","[6]",0x48),
0x80A7B5E8:("En_Jso2_InitVars","ActorInit","",0x20),
0x80A7B608:("sCylinderInit","ColliderCylinderInit","",0x2C),
0x80A7B634:("sQuadInit","ColliderQuadInit","",0x50),
0x80A7B684:("sAnimations","AnimationHeader*","[22]",0x58),
0x80A7B6DC:("sAnimationModes","u8","[22]",0x16),
0x80A7B6F4:("sPlayerOverrideInputPosList","Vec3s","[1]",0x6),
0x80A7B6FC:("bombOffset","Vec3f","",0xC),
0x80A7B708:("sSwordTipOffset","Vec3f","",0xC),
0x80A7B714:("sSwordBaseOffset","Vec3f","",0xC),
0x80A7B720:("sSwordTipQuadOffset","Vec3f","",0xC),
0x80A7B72C:("sSwordBaseQuadOffset","Vec3f","",0xC),
0x80A7B738:("sAfterimageAlpha","s16","[20]",0x28),
0x80A7B760:("D_80A7B760","f32","",0x4),
0x80A7B764:("jtbl_80A7B764","UNK_PTR","",0x4),
0x80A7B794:("D_80A7B794","f32","",0x4),

View File

@ -402,12 +402,6 @@ D_06015C28 = 0x06015C28;
D_060156D8 = 0x060156D8;
D_06016720 = 0x06016720;
// ovl_En_Jso2
D_06002ED8 = 0x06002ED8;
D_06003168 = 0x06003168;
D_060081F4 = 0x060081F4;
// ovl_En_Kitan
D_06000CE8 = 0x06000CE8;