Boss01 (Odolwa) OK and documented (#1452)

* Boss01 (Odolwa) OK and documented

* Unify existing InitRand implementations

* Remove newlines after `// fallthrough`

* Respond to the rest of engineer's review

* Respond to most of anon's review

* Try to comment the shadow thing correctly

* Fix boss_01 after merge

* SEGMENTED_TO_VIRTUAL -> SEGMENTED_TO_K0

* Review

* Use DMG_SWORD_BEAM and update the comment in z64collision_check.h

* Respond to engineer's review
This commit is contained in:
Tom Overton
2023-10-28 14:29:43 -07:00
committed by GitHub
parent e634be7cd4
commit 2859cbbf5e
12 changed files with 3827 additions and 582 deletions
File diff suppressed because it is too large Load Diff
+139 -2
View File
@@ -2,16 +2,153 @@
#define Z_BOSS_01_H
#include "global.h"
#include "assets/objects/object_boss01/object_boss01.h"
struct Boss01;
#define ODOLWA_GET_TYPE(thisx) ((thisx)->params)
#define ODOLWA_GET_AFTERIMAGE_DESPAWN_TIMER(thisx) ((thisx)->world.rot.z)
#define ODOLWA_SHADOW_TEX_WIDTH 64
#define ODOLWA_SHADOW_TEX_HEIGHT 64
#define ODOLWA_SHADOW_TEX_SIZE ((s32)sizeof(u8[ODOLWA_SHADOW_TEX_HEIGHT][ODOLWA_SHADOW_TEX_WIDTH]))
typedef void (*Boss01ActionFunc)(struct Boss01*, PlayState*);
typedef enum OdolwaType {
/* 0 */ ODOLWA_TYPE_ODOLWA,
/* 10 */ ODOLWA_TYPE_BUG = 10,
/* 35 */ ODOLWA_TYPE_AFTERIMAGE = 35
} OdolwaType;
typedef enum OdolwaBodyPart {
/* 0 */ ODOLWA_BODYPART_HEAD,
/* 1 */ ODOLWA_BODYPART_TORSO,
/* 2 */ ODOLWA_BODYPART_PELVIS,
/* 3 */ ODOLWA_BODYPART_LEFT_UPPER_ARM,
/* 4 */ ODOLWA_BODYPART_LEFT_FOREARM,
/* 5 */ ODOLWA_BODYPART_SHIELD,
/* 6 */ ODOLWA_BODYPART_RIGHT_UPPER_ARM,
/* 7 */ ODOLWA_BODYPART_RIGHT_FOREARM,
/* 8 */ ODOLWA_BODYPART_SWORD,
/* 9 */ ODOLWA_BODYPART_RIGHT_THIGH,
/* 10 */ ODOLWA_BODYPART_RIGHT_SHIN,
/* 11 */ ODOLWA_BODYPART_RIGHT_FOOT,
/* 12 */ ODOLWA_BODYPART_LEFT_THIGH,
/* 13 */ ODOLWA_BODYPART_LEFT_SHIN,
/* 14 */ ODOLWA_BODYPART_LEFT_FOOT,
/* 15 */ ODOLWA_BODYPART_MAX
} OdolwaBodyPart;
typedef enum OdolwaColliderBodyPart {
/* 0 */ ODOLWA_COLLIDER_BODYPART_HEAD,
/* 1 */ ODOLWA_COLLIDER_BODYPART_TORSO,
/* 2 */ ODOLWA_COLLIDER_BODYPART_PELVIS,
/* 3 */ ODOLWA_COLLIDER_BODYPART_LEFT_UPPER_ARM,
/* 4 */ ODOLWA_COLLIDER_BODYPART_LEFT_FOREARM,
/* 5 */ ODOLWA_COLLIDER_BODYPART_RIGHT_UPPER_ARM,
/* 6 */ ODOLWA_COLLIDER_BODYPART_RIGHT_FOREARM,
/* 7 */ ODOLWA_COLLIDER_BODYPART_LEFT_THIGH,
/* 8 */ ODOLWA_COLLIDER_BODYPART_LEFT_SHIN,
/* 9 */ ODOLWA_COLLIDER_BODYPART_RIGHT_THIGH,
/* 10 */ ODOLWA_COLLIDER_BODYPART_RIGHT_SHIN,
/* 11 */ ODOLWA_COLLIDER_BODYPART_MAX
} OdolwaColliderBodyPart;
typedef enum OdolwaSwordCollider {
/* 0 */ ODOLWA_SWORD_COLLIDER_SWORD_BASE,
/* 1 */ ODOLWA_SWORD_COLLIDER_SWORD_TIP,
/* 2 */ ODOLWA_SWORD_COLLIDER_PELVIS,
/* 3 */ ODOLWA_SWORD_COLLIDER_MAX
} OdolwaSwordCollider;
typedef enum OdolwaShieldCollider {
/* 0 */ ODOLWA_SHIELD_COLLIDER_SHIELD,
/* 1 */ ODOLWA_SHIELD_COLLIDER_MAX
} OdolwaShieldCollider;
typedef enum OdolwaKickAndShieldBashCollider {
/* 0 */ ODOLWA_KICK_AND_SHIELD_BASH_COLLIDER_SHIELD,
/* 1 */ ODOLWA_KICK_AND_SHIELD_BASH_COLLIDER_LEFT_FOOT,
/* 2 */ ODOLWA_KICK_AND_SHIELD_BASH_COLLIDER_MAX
} OdolwaKickAndShieldBashCollider;
typedef struct Boss01 {
/* 0x000 */ Actor actor;
/* 0x144 */ char unk_144[0x320];
/* 0x144 */ s16 frameCounter;
/* 0x148 */ s32 phaseFrameCounter;
/* 0x14C */ union {
u8 jumpIfPlayerIsClose;
u8 shouldPerformFallingSlash;
u8 bugDrawDmgEffType;
};
/* 0x14E */ s16 timers[3];
/* 0x154 */ f32 animMorphFrames1;
/* 0x158 */ f32 animMorphFrames2;
/* 0x15C */ s16 damageTimer;
/* 0x15E */ s16 damageFlashTimer;
/* 0x160 */ u8 isPerformingVerticalSlash; // set, but never checked
/* 0x160 */ u8 landedFromJump;
/* 0x162 */ u8 waitType;
/* 0x163 */ u8 lookAtPlayer;
/* 0x164 */ SkelAnime skelAnime;
/* 0x1A8 */ f32 animEndFrame;
/* 0x1AC */ f32 prevJumpVelocityY;
/* 0x1B0 */ f32 runTargetPosAngularVelocityY;
/* 0x1B4 */ f32 runTargetPosRotY;
/* 0x1B8 */ u8 swordState;
/* 0x1B9 */ u8 kickAndShieldBashCollisionEnabled;
/* 0x1BA */ u8 swordAndShieldCollisionEnabled;
/* 0x1BB */ u8 canGuardOrEvade;
/* 0x1BC */ u8 bodyInvincibilityTimer;
/* 0x1BE */ s16 disableCollisionTimer;
/* 0x1C0 */ u8 afterimageSpawnFrameMask; // used as a bitmask with frameCounter to control how often to spawn afterimages
/* 0x1C1 */ u8 hasPlayedSummonBugCs;
/* 0x1C4 */ f32 additionalVelocityX;
/* 0x1C8 */ f32 additionalVelocityZ;
/* 0x1CC */ s16 headRotY;
/* 0x1CE */ s16 headRotX;
/* 0x1D0 */ Vec3s jointTable[ODOLWA_LIMB_MAX];
/* 0x308 */ Vec3s morphTable[ODOLWA_LIMB_MAX];
/* 0x440 */ Vec3f feetPos[2];
/* 0x458 */ Vec3f pelvisPos;
/* 0x464 */ Boss01ActionFunc actionFunc;
/* 0x468 */ char unk_468[0x674];
/* 0x468 */ ColliderJntSph swordCollider;
/* 0x488 */ ColliderJntSphElement swordColliderElements[ODOLWA_SWORD_COLLIDER_MAX];
/* 0x548 */ ColliderJntSph shieldCollider;
/* 0x568 */ ColliderJntSphElement shieldColliderElements[ODOLWA_SHIELD_COLLIDER_MAX];
/* 0x5A8 */ ColliderJntSph bodyCollider;
/* 0x5C8 */ ColliderJntSphElement bodyColliderElements[ODOLWA_COLLIDER_BODYPART_MAX];
/* 0x888 */ ColliderJntSph kickAndShieldBashCollider;
/* 0x8A8 */ ColliderJntSphElement kickAndShieldBashColliderElements[ODOLWA_KICK_AND_SHIELD_BASH_COLLIDER_MAX];
/* 0x928 */ Vec3f bodyPartsPos[ODOLWA_BODYPART_MAX];
/* 0x9DC */ union {
u32 cutsceneTimer;
u32 waitTimer;
u32 summonMothsTimer;
};
/* 0x9E0 */ s16 cutsceneState;
/* 0x9E2 */ s16 subCamId;
/* 0x9E4 */ Vec3f subCamEye;
/* 0x9F0 */ Vec3f subCamAt;
/* 0x9FC */ Vec3f subCamUp;
/* 0xA08 */ Vec3f subCamEyeNext;
/* 0xA14 */ f32 deathCsInitialSubCamRot;
/* 0xA18 */ f32 deathCsSubCamRot;
/* 0xA1C */ f32 subCamVelocity;
/* 0xA20 */ f32 deathShrinkSpeed;
/* 0xA24 */ f32 screenShakeOffsetY;
/* 0xA28 */ f32 screenShakeMagnitude;
/* 0xA2C */ ColliderCylinder bugACCollider;
/* 0xA78 */ ColliderCylinder bugATCollider;
/* 0xAC4 */ f32 bugDrawDmgEffScale;
/* 0xAC8 */ f32 bugDrawDmgEffAlpha;
/* 0xACC */ f32 drawDmgEffScale;
/* 0xAD0 */ f32 drawDmgEffFrozenSteamScale;
/* 0xAD4 */ f32 drawDmgEffAlpha;
/* 0xAD8 */ u8 drawDmgEffType;
/* 0xAD9 */ u8 drawDmgEffState;
/* 0xADA */ s16 drawDmgEffTimer;
} Boss01; // size = 0xADC
#endif // Z_BOSS_01_H
+10 -10
View File
@@ -69,9 +69,9 @@ u8 sIsInGiantMode;
Boss02* sRedTwinmold;
Boss02* sBlueTwinmold;
Boss02* sTwinmoldStatic;
u8 sMusicStartTimer;
u8 sTwinmoldMusicStartTimer;
DoorWarp1* sBlueWarp;
TwinmoldEffect sEffects[TWINMOLD_EFFECT_COUNT];
TwinmoldEffect sTwinmoldEffects[TWINMOLD_EFFECT_COUNT];
static DamageTable sBlueTwinmoldDamageTable = {
/* Deku Nut */ DMG_ENTRY(0, 0x0),
@@ -588,7 +588,7 @@ void Boss02_Init(Actor* thisx, PlayState* play) {
if (CHECK_WEEKEVENTREG(WEEKEVENTREG_CLEARED_STONE_TOWER_TEMPLE) &&
(TWINMOLD_GET_TYPE(&this->actor) == TWINMOLD_TYPE_RED)) {
sBlueWarp = (DoorWarp1*)Actor_SpawnAsChild(&play->actorCtx, &this->actor, play, ACTOR_DOOR_WARP1, 0.0f, 60.0f,
0.0f, 0, 0, 0, 1);
0.0f, 0, 0, 0, ENDOORWARP1_FF_1);
Actor_Spawn(&play->actorCtx, play, ACTOR_ITEM_B_HEART, 0.0f, 30.0f, -150.0f, 0, 1, 0, BHEART_PARAM_NORMAL);
}
@@ -597,14 +597,14 @@ void Boss02_Init(Actor* thisx, PlayState* play) {
this->subCamUp.y = 1.0f;
if (TWINMOLD_GET_TYPE(&this->actor) == TWINMOLD_TYPE_STATIC) {
sTwinmoldStatic = this;
play->specialEffects = (void*)sEffects;
play->specialEffects = (void*)sTwinmoldEffects;
this->actor.update = Boss02_Static_Update;
this->actor.draw = Boss02_Static_Draw;
this->actor.flags &= ~ACTOR_FLAG_TARGETABLE;
this->playerScale = 0.01f;
if ((KREG(64) != 0) || CHECK_EVENTINF(EVENTINF_55) || (sBlueWarp != NULL)) {
this->unk_1D20 = 0;
sMusicStartTimer = KREG(15) + 20;
sTwinmoldMusicStartTimer = KREG(15) + 20;
} else {
this->unk_1D20 = 1;
}
@@ -1346,9 +1346,9 @@ void Boss02_Static_Update(Actor* thisx, PlayState* play) {
}
if (sBlueWarp == NULL) {
if (sMusicStartTimer != 0) {
sMusicStartTimer--;
if (sMusicStartTimer == 0) {
if (sTwinmoldMusicStartTimer != 0) {
sTwinmoldMusicStartTimer--;
if (sTwinmoldMusicStartTimer == 0) {
SEQCMD_PLAY_SEQUENCE(SEQ_PLAYER_BGM_MAIN, 0, NA_BGM_BOSS | SEQ_FLAG_ASYNC);
}
}
@@ -2173,7 +2173,7 @@ void func_809DEAC4(Boss02* this, PlayState* play) {
if (this->unk_1D1C == 45) {
func_800B7298(play, &this->actor, PLAYER_CSACTION_21);
sMusicStartTimer = KREG(91) + 43;
sTwinmoldMusicStartTimer = KREG(91) + 43;
}
if (this->unk_1D1C == 85) {
@@ -2304,7 +2304,7 @@ void func_809DEAC4(Boss02* this, PlayState* play) {
phi_f0 = 3155.0f;
}
sBlueWarp = (DoorWarp1*)Actor_SpawnAsChild(&play->actorCtx, &this->actor, play, ACTOR_DOOR_WARP1,
0.0f, phi_f0, 0.0f, 0, 0, 0, 1);
0.0f, phi_f0, 0.0f, 0, 0, 0, ENDOORWARP1_FF_1);
if (!sIsInGiantMode) {
sBlueWarp->unk_203 = 0;
+17 -17
View File
@@ -231,30 +231,30 @@ void Boss03_UpdateSphereElement(s32 index, ColliderJntSph* collider, Vec3f* sphe
/* Start of RNG section */
static s32 sRandSeed0;
static s32 sRandSeed1;
static s32 sRandSeed2;
s32 sGyorgRandSeed1;
s32 sGyorgRandSeed2;
s32 sGyorgRandSeed3;
void Boss03_SeedRand(s32 seed0, s32 seed1, s32 seed2) {
sRandSeed0 = seed0;
sRandSeed1 = seed1;
sRandSeed2 = seed2;
void Boss03_InitRand(s32 seedInit1, s32 seedInit2, s32 seedInit3) {
sGyorgRandSeed1 = seedInit1;
sGyorgRandSeed2 = seedInit2;
sGyorgRandSeed3 = seedInit3;
}
f32 Boss03_RandZeroOne(void) {
f32 rand;
// Wichmann-Hill algorithm
sRandSeed0 = (sRandSeed0 * 171) % 30269;
sRandSeed1 = (sRandSeed1 * 172) % 30307;
sRandSeed2 = (sRandSeed2 * 170) % 30323;
f32 randFloat;
rand = (sRandSeed0 / 30269.0f) + (sRandSeed1 / 30307.0f) + (sRandSeed2 / 30323.0f);
while (rand >= 1.0f) {
rand -= 1.0f;
sGyorgRandSeed1 = (sGyorgRandSeed1 * 171) % 30269;
sGyorgRandSeed2 = (sGyorgRandSeed2 * 172) % 30307;
sGyorgRandSeed3 = (sGyorgRandSeed3 * 170) % 30323;
randFloat = (sGyorgRandSeed1 / 30269.0f) + (sGyorgRandSeed2 / 30307.0f) + (sGyorgRandSeed3 / 30323.0f);
while (randFloat >= 1.0f) {
randFloat -= 1.0f;
}
return fabsf(rand);
return fabsf(randFloat);
}
/* End of RNG section */
@@ -483,7 +483,7 @@ void Boss03_Init(Actor* thisx, PlayState* play2) {
this->actor.world.pos = sGyorgInitialPos;
// Since Boss03_RandZeroOne is only used on this Init function, the resulting values end up being deterministic
Boss03_SeedRand(1, 29093, 9786);
Boss03_InitRand(1, 29093, 9786);
for (i = 0; i < 5; i++) {
f32 rand;
@@ -147,9 +147,9 @@ f32 sSubCamVelFactor;
f32 D_80911F50;
Vec3f sSinkingLureBasePos;
f32 D_80911F64;
s32 sRandSeed0;
s32 sRandSeed1;
s32 sRandSeed2;
s32 sFishingRandSeed1;
s32 sFishingRandSeed2;
s32 sFishingRandSeed3;
FishingProp sPondProps[POND_PROP_COUNT];
FishingGroupFish sGroupFishes[GROUP_FISH_COUNT];
f32 sFishGroupAngle1;
@@ -404,26 +404,26 @@ void EnFishing_SetColliderElement(s32 index, ColliderJntSph* collider, Vec3f* po
collider->elements[index].dim.modelSphere.radius * collider->elements[index].dim.scale * scale * 1.6f;
}
void EnFishing_SeedRand(s32 seed0, s32 seed1, s32 seed2) {
sRandSeed0 = seed0;
sRandSeed1 = seed1;
sRandSeed2 = seed2;
void EnFishing_InitRand(s32 seedInit1, s32 seedInit2, s32 seedInit3) {
sFishingRandSeed1 = seedInit1;
sFishingRandSeed2 = seedInit2;
sFishingRandSeed3 = seedInit3;
}
f32 EnFishing_RandZeroOne(void) {
f32 rand;
// Wichmann-Hill algorithm
sRandSeed0 = (sRandSeed0 * 171) % 30269;
sRandSeed1 = (sRandSeed1 * 172) % 30307;
sRandSeed2 = (sRandSeed2 * 170) % 30323;
f32 randFloat;
rand = (sRandSeed0 / 30269.0f) + (sRandSeed1 / 30307.0f) + (sRandSeed2 / 30323.0f);
while (rand >= 1.0f) {
rand -= 1.0f;
sFishingRandSeed1 = (sFishingRandSeed1 * 171) % 30269;
sFishingRandSeed2 = (sFishingRandSeed2 * 172) % 30307;
sFishingRandSeed3 = (sFishingRandSeed3 * 170) % 30323;
randFloat = (sFishingRandSeed1 / 30269.0f) + (sFishingRandSeed2 / 30307.0f) + (sFishingRandSeed3 / 30323.0f);
while (randFloat >= 1.0f) {
randFloat -= 1.0f;
}
return fabsf(rand);
return fabsf(randFloat);
}
s16 EnFishing_SmoothStepToS(s16* pValue, s16 target, s16 scale, s16 step) {
@@ -730,7 +730,7 @@ void EnFishing_InitPondProps(EnFishing* this, PlayState* play) {
Vec3f colliderPos;
s16 i;
EnFishing_SeedRand(1, 29100, 9786);
EnFishing_InitRand(1, 29100, 9786);
for (i = 0; i < POND_PROP_COUNT; i++) {
if (sPondPropInits[i].type == FS_PROP_INIT_STOP) {