Boss07 (Majora) OK and documented [mm-n64-us.z64 OK] (#1753)

* more matches

* more functions

* merge, I hope

* wrath done-ish

* 5 nonmatchings

* more matchings

* more improvements

* more stuff

* stuff

* docs part 1 / infinity

* more docs

* .

* more adjustments

* linked assets

* Document object_boss07 and match Boss07_Incarnation_Intro (thanks Synray!)

* more stuff

* play part 2

* lol merge

* update

* unk types

* SWEET GOOGLY MOOGLY IT MATCHES

* cam fixes

* adjust damage stuff

* if?

* stuff

* signs

* macro stuff. clean up later

* names

* Some small cleanup

* cleanup and docs

* more cleanup

* Wrath shadow docs

* Use `EVENTINF_INTRO_CS_WATCHED_MAJORA` after merging

* Update functions.txt

* Types cleanup

* Some low hanging fruit

* Undefined_syms.txt

* More static -> battle handler

* Lots of naming cleanup

* Remove z_boss_07_dmgtbl.inc
The reasoning behind removing this file is simple; it wasn't all that long, so extracting it out to an included file didn't really add much, and it made refactoring and/or things much harder, since you needed to check in multiple places to change things.

* Get most of the limb stuff named (and actually update the spec)

* Some minor cleanup

* Updating the repo with what we talked about in discord

* Some syncing with Odolwa and other misc name stuff

* Some Odolwa/Bio Baba sync

* Another bit of Odolwa/Bio Baba sync

* Name a lot of incarnation limb variables

* Finalize the incarnation intro variable stuff

* Fix a goof

* `incarnationWrathTransition` variables

* `generalCollider` and always use "tentacle"

* Completely remove "shot," always use "projectile"

* Clean up `Boss07_Mask_Draw`

* Name `maskShakeTimer`

* Give better names to a few more things

* Some beam-related struct vars

* undefined_syms

* More beam names

* More beam stuff

* Beam, pt 100000

* Some intro struct members

* Some timers

* More non-beam stuff, back to beam

* Done with beam finally

* All but one of the subcam variables, some other stuff

* Some variable names and cleanup

* More cleanup

* jumpSfxTimer -> landSfxTimer

* actionState -> subAction and a little bit of syncing with Odolwa

* A couple more variables sync

* Buncha variables

* Lots of non-whip variables

* Commit what I have before starting on some of the grab stuff

* All but one struct var done

* Lots of header cleanup

* Finish the header file

* Fix build after merging main

* Damage effect enums

* Update damage effect enums for Incarnation and Wrath

* Update damage effect enums for Mask and Remains

* First pass at top damage effects

* Do a few sub action enums so I have something to show

* Fix the damage effect enums, clean up a lot of subaction enums

* All remaining sub action enums, cleanup damage effect enums, other misc cleanup

* Finish enums

* Finish data

* Push up what I have

* Consistency

* scroll -> texScroll

* low hanging fruit

* PR + small fix

* Happy with >20% of functions

* Happy with >40% of functions

* Happy with >60% of functions

* Happy with >75% of functions

* Happy with >90% of functions

* Happy with >95% of functions

* Happy with `Boss07_Wrath_DeathCutscene`

* Happy with `Boss07_Mask_FireBeam`

* Happy with `Boss07_Wrath_CheckWhipCollisions`

* Happy with everything but `Boss07_Mask_Draw`

* Happy with all functions I think?

* Clean up forward declarations

* Write a half-decent file header

* Fix after merging

* Fix some minor stuff here and there

* Minor fix in the file header because I forgot I renamed this

* Respond to engineer's review

* Respond to Anghelo's review

* Replace as many actor lookups with for-loops as I can in Odolwa/Majora

* Change the comment about the hookshot from a `@note` to a `@bug`

* `drag` -> `deceleration`

* Extra scopes for the matrix stuff in `Boss07_Mask_DrawBeam`

* Use decimal numbers in the various `FillShadowTex` functions

---------

Co-authored-by: petrie911 <pmontag@DESKTOP-LG8A167.localdomain>
Co-authored-by: petrie911 <pmontag@Monday.localdomain>
Co-authored-by: petrie911 <69443847+petrie911@users.noreply.github.com>
Co-authored-by: petrie911 <pmontag@PHYS-S129.iowa.uiowa.edu>
Co-authored-by: petrie911 <petrie911@users.noreply.github.com>
Co-authored-by: Derek Hensley <hensley.derek58@gmail.com>
Co-authored-by: engineer124 <engineer124engineer124@gmail.com>
This commit is contained in:
Tom Overton
2024-12-10 18:06:55 -08:00
committed by GitHub
parent 3c16f534de
commit fa240048cf
15 changed files with 8288 additions and 992 deletions
+2 -2
View File
@@ -1553,7 +1553,7 @@ s32 SubS_OfferTalkExchangeCustom(Actor* actor, PlayState* play, f32 xzRange, f32
return canAccept;
}
s32 SubS_ActorAndPlayerFaceEachOther(PlayState* play, Actor* actor, void* data) {
s32 SubS_ArePlayerAndActorFacing(PlayState* play, Actor* actor, void* data) {
Player* player = GET_PLAYER(play);
Vec3s* yawRanges = (Vec3s*)data;
s16 playerYaw = ABS(BINANG_SUB(Actor_WorldYawTowardActor(&player->actor, actor), player->actor.shape.rot.y));
@@ -1579,7 +1579,7 @@ s32 SubS_OfferTalkExchangeFacing(Actor* actor, PlayState* play, f32 xzRange, f32
yawRanges.x = playerYawRange;
yawRanges.y = actorYawRange;
return SubS_OfferTalkExchangeCustom(actor, play, xzRange, yRange, exchangeItemAction, &yawRanges,
SubS_ActorAndPlayerFaceEachOther);
SubS_ArePlayerAndActorFacing);
}
/**
+31 -32
View File
@@ -236,8 +236,8 @@ typedef enum {
// Deals damage and has no special effect.
/* 0xD */ ODOLWA_DMGEFF_DAMAGE,
// Deals damage and checks the timer that tracks how long Odolwa should be in his damaged state. If the timer is 7
// or more, it will reset the timer to 20 frames keep Odolwa in the damaged state for longer. If the timer is 6 or
// Deals damage and checks the timer that tracks how long Odolwa should be in his damaged state. If the timer is 5
// or more, it will reset the timer to 20 frames keep Odolwa in the damaged state for longer. If the timer is 4 or
// less, it will disable Odolwa's collision for 20 frames to ensure he can jump away without taking further damage.
/* 0xE */ ODOLWA_DMGEFF_DAMAGE_TIMER_CHECK,
@@ -958,16 +958,15 @@ void Boss01_Destroy(Actor* thisx, PlayState* play) {
* Checks every explosive actor to see if Odolwa is close enough to any of them. If he is, then he'll jump.
*/
void Boss01_JumpAwayFromExplosive(Boss01* this, PlayState* play) {
Actor* explosive = play->actorCtx.actorLists[ACTORCAT_EXPLOSIVES].first;
Actor* explosive;
while (explosive != NULL) {
for (explosive = play->actorCtx.actorLists[ACTORCAT_EXPLOSIVES].first; explosive != NULL;
explosive = explosive->next) {
if (sqrtf(SQ(explosive->world.pos.x - this->actor.world.pos.x) +
SQ(explosive->world.pos.y - this->actor.world.pos.y) +
SQ(explosive->world.pos.z - this->actor.world.pos.z)) < 150.0f) {
Boss01_SetupJump(this, play, false);
}
explosive = explosive->next;
}
}
@@ -1224,7 +1223,7 @@ void Boss01_SummonBugsCutscene(Boss01* this, PlayState* play) {
pos.z = Rand_CenteredFloat(200.0f) + (this->actor.world.pos.z + offset.z);
Audio_PlaySfx(NA_SE_PL_DEKUNUTS_DROP_BOMB);
Actor_Spawn(&play->actorCtx, play, ACTOR_BOSS_01, pos.x, 1200.0f, pos.z, 0, Rand_ZeroFloat(0x10000),
0, ODOLWA_TYPE_BUG);
0, ODOLWA_PARAMS(ODOLWA_TYPE_BUG));
}
}
@@ -1424,7 +1423,7 @@ void Boss01_Wait(Boss01* this, PlayState* play) {
case ODOLWA_WAIT_ARM_SWING_DANCE:
case ODOLWA_WAIT_THRUST_ATTACK:
Actor_Spawn(&play->actorCtx, play, ACTOR_BOSS_01, pos.x, pos.y, pos.z, 0, Rand_ZeroFloat(0x10000), 0,
ODOLWA_TYPE_BUG);
ODOLWA_PARAMS(ODOLWA_TYPE_BUG));
break;
case ODOLWA_WAIT_SIDE_TO_SIDE_DANCE:
@@ -1906,9 +1905,9 @@ void Boss01_ShieldBash(Boss01* this, PlayState* play) {
* function will transition him to that state and start a 20 frame timer; when this timer reaches 0, he will recover and
* jump away. However, if he is already in the "damaged" state, and if the player attacked him with an attack that has
* the ODOLWA_DMGEFF_DAMAGE_TIMER_CHECK damage effect, then one of two things will happen:
* - If the attack hit while his current action timer is 7 or more, the timer will be set to 20 again; this will keep
* - If the attack hit while his current action timer is 5 or more, the timer will be set to 20 again; this will keep
* Odolwa in the "damaged" state for longer and allow the player to attack him more.
* - If the attack hit while his current action timer is 6 or less, Odolwa will disable all of his collision for 20
* - If the attack hit while his current action timer is 4 or less, Odolwa will disable all of his collision for 20
* frames to ensure that the player cannot hit him with subsequent attacks.
*/
void Boss01_SetupDamaged(Boss01* this, PlayState* play, u8 damageEffect) {
@@ -2150,8 +2149,8 @@ void Boss01_DeathCutscene(Boss01* this, PlayState* play) {
this->subCamAt.z = mainCam->at.z;
diffX = this->subCamEye.x - this->actor.world.pos.x;
diffZ = this->subCamEye.z - this->actor.world.pos.z;
this->deathCsInitialSubCamRot = Math_Atan2F_XY(diffZ, diffX);
this->deathCsSubCamRot = -0.5f;
this->deathCsInitialSubCamRotY = Math_Atan2F_XY(diffZ, diffX);
this->deathCsSubCamRotY = -0.5f;
FALLTHROUGH;
case ODOLWA_DEATH_CS_STATE_PLAY_ANIM_AND_FALL_FORWARD:
if (this->cutsceneTimer < 15) {
@@ -2170,11 +2169,11 @@ void Boss01_DeathCutscene(Boss01* this, PlayState* play) {
}
FALLTHROUGH;
case ODOLWA_DEATH_CS_STATE_BURST_INTO_FLAMES_AND_SHRINK:
Math_ApproachF(&this->deathCsSubCamRot, 1.3f, 0.1f, 0.008f);
Math_ApproachF(&this->deathCsSubCamRotY, 1.3f, 0.1f, 0.008f);
subCamOffset.x = 0.0f;
subCamOffset.y = 30.0f;
subCamOffset.z = 300.0f;
Matrix_RotateYF(this->deathCsInitialSubCamRot + this->deathCsSubCamRot, MTXMODE_NEW);
Matrix_RotateYF(this->deathCsInitialSubCamRotY + this->deathCsSubCamRotY, MTXMODE_NEW);
Matrix_MultVec3f(&subCamOffset, &this->subCamEyeNext);
this->subCamEyeNext.x += this->pelvisPos.x;
this->subCamEyeNext.y += this->pelvisPos.y;
@@ -2327,7 +2326,7 @@ void Boss01_Thaw(Boss01* this, PlayState* play) {
* Returns true if Odolwa's model is rotated such that he is looking at the player *and* if the player's model is
* rotated such that they are looking at Odolwa.
*/
s32 Boss01_ArePlayerAndOdolwaFacing(Boss01* this, PlayState* play) {
s32 Boss01_ArePlayerAndActorFacing(Boss01* this, PlayState* play) {
Player* player = GET_PLAYER(play);
if ((ABS_ALT(BINANG_SUB(this->actor.yawTowardsPlayer, this->actor.shape.rot.y)) < 0x3000) &&
@@ -2440,7 +2439,7 @@ void Boss01_Update(Actor* thisx, PlayState* play2) {
// normally evades attacks, so long as the player is far enough to the side or behind him.
if (this->canGuardOrEvade &&
((player->unk_D57 != 0) || ((player->unk_ADC != 0) && (this->actor.xzDistToPlayer <= 120.0f))) &&
Boss01_ArePlayerAndOdolwaFacing(this, play)) {
Boss01_ArePlayerAndActorFacing(this, play)) {
if ((Rand_ZeroOne() < 0.25f) && (this->actionFunc != Boss01_Guard)) {
Boss01_SetupJump(this, play, false);
this->disableCollisionTimer = 10;
@@ -2458,10 +2457,10 @@ void Boss01_Update(Actor* thisx, PlayState* play2) {
if (((this->frameCounter & (this->afterimageSpawnFrameMask - 1)) == 0) && (this->afterimageSpawnFrameMask != 0)) {
s16 afterimageTimer = (this->actionFunc == Boss01_SpinAttack) ? 4 : 10;
s32 pad;
Boss01* child =
(Boss01*)Actor_SpawnAsChild(&play->actorCtx, &this->actor, play, ACTOR_BOSS_01, this->actor.world.pos.x,
this->actor.world.pos.y, this->actor.world.pos.z, this->actor.world.rot.x,
this->actor.world.rot.y, afterimageTimer, ODOLWA_TYPE_AFTERIMAGE);
Boss01* child = (Boss01*)Actor_SpawnAsChild(
&play->actorCtx, &this->actor, play, ACTOR_BOSS_01, this->actor.world.pos.x, this->actor.world.pos.y,
this->actor.world.pos.z, this->actor.world.rot.x, this->actor.world.rot.y, afterimageTimer,
ODOLWA_PARAMS(ODOLWA_TYPE_AFTERIMAGE));
if (child != NULL) {
for (i = 0; i < ODOLWA_LIMB_MAX; i++) {
@@ -2804,22 +2803,22 @@ static s8 sLimbToBodyParts[] = {
void Boss01_PostLimbDraw(PlayState* play2, s32 limbIndex, Gfx** dList, Vec3s* rot, Actor* thisx) {
Boss01* this = THIS;
PlayState* play = play2;
s8 index;
s8 bodyPartIndex;
Vec3f pos;
if (limbIndex == ODOLWA_LIMB_HEAD) {
Matrix_MultZero(&this->actor.focus.pos);
}
index = sLimbToBodyParts[limbIndex];
if (index > BODYPART_NONE) {
Matrix_MultZero(&this->bodyPartsPos[index]);
bodyPartIndex = sLimbToBodyParts[limbIndex];
if (bodyPartIndex > BODYPART_NONE) {
Matrix_MultZero(&this->bodyPartsPos[bodyPartIndex]);
}
index = sLimbToColliderBodyParts[limbIndex];
if (index > BODYPART_NONE) {
Matrix_MultVec3f(&sLimbColliderOffsets[index], &pos);
Boss01_SetColliderSphere(index, &this->bodyCollider, &pos);
bodyPartIndex = sLimbToColliderBodyParts[limbIndex];
if (bodyPartIndex > BODYPART_NONE) {
Matrix_MultVec3f(&sLimbColliderOffsets[bodyPartIndex], &pos);
Boss01_SetColliderSphere(bodyPartIndex, &this->bodyCollider, &pos);
}
if (limbIndex == ODOLWA_LIMB_PELVIS) {
@@ -3041,7 +3040,7 @@ void Boss01_FillShadowTex(Boss01* this, u8* tex, f32 weight) {
baseY = (u16)((s32)startVec.y * 64);
if (sShadowSizes[i] == ODOLWA_SHADOW_SIZE_EXTRA_LARGE) {
for (y = 0, addY = -0x180; y < ARRAY_COUNT(sShadowExtraLargeMap); y++, addY += 0x40) {
for (y = 0, addY = -384; y < ARRAY_COUNT(sShadowExtraLargeMap); y++, addY += 64) {
for (x = -sShadowExtraLargeMap[y]; x < sShadowExtraLargeMap[y]; x++) {
index = baseX + x + baseY + addY;
if ((index >= 0) && (index < ODOLWA_SHADOW_TEX_SIZE)) {
@@ -3050,7 +3049,7 @@ void Boss01_FillShadowTex(Boss01* this, u8* tex, f32 weight) {
}
}
} else if (sShadowSizes[i] == ODOLWA_SHADOW_SIZE_LARGE) {
for (y = 0, addY = -0x100; y < ARRAY_COUNT(sShadowLargeMap); y++, addY += 0x40) {
for (y = 0, addY = -256; y < ARRAY_COUNT(sShadowLargeMap); y++, addY += 64) {
for (x = -sShadowLargeMap[y]; x < sShadowLargeMap[y]; x++) {
index = baseX + x + baseY + addY;
if ((index >= 0) && (index < ODOLWA_SHADOW_TEX_SIZE)) {
@@ -3059,7 +3058,7 @@ void Boss01_FillShadowTex(Boss01* this, u8* tex, f32 weight) {
}
}
} else if (sShadowSizes[i] == ODOLWA_SHADOW_SIZE_MEDIUM) {
for (y = 0, addY = -0xC0; y < ARRAY_COUNT(sShadowMediumMap); y++, addY += 0x40) {
for (y = 0, addY = -192; y < ARRAY_COUNT(sShadowMediumMap); y++, addY += 64) {
for (x = -sShadowMediumMap[y]; x < sShadowMediumMap[y] - 1; x++) {
index = baseX + x + baseY + addY;
if ((index >= 0) && (index < ODOLWA_SHADOW_TEX_SIZE)) {
@@ -3068,7 +3067,7 @@ void Boss01_FillShadowTex(Boss01* this, u8* tex, f32 weight) {
}
}
} else {
for (y = 0, addY = -0x80; y < ARRAY_COUNT(sShadowSmallMap); y++, addY += 0x40) {
for (y = 0, addY = -128; y < ARRAY_COUNT(sShadowSmallMap); y++, addY += 64) {
for (x = -sShadowSmallMap[y]; x < sShadowSmallMap[y] - 1; x++) {
index = baseX + x + baseY + addY;
if ((index >= 0) && (index < ODOLWA_SHADOW_TEX_SIZE)) {
+4 -3
View File
@@ -8,6 +8,7 @@ struct Boss01;
#define ODOLWA_GET_TYPE(thisx) ((thisx)->params)
#define ODOLWA_GET_AFTERIMAGE_DESPAWN_TIMER(thisx) ((thisx)->world.rot.z)
#define ODOLWA_PARAMS(type) (type)
#define ODOLWA_SHADOW_TEX_WIDTH 64
#define ODOLWA_SHADOW_TEX_HEIGHT 64
@@ -85,7 +86,7 @@ typedef struct Boss01 {
/* 0x14E */ s16 timers[3];
/* 0x154 */ f32 animMorphFrames1;
/* 0x158 */ f32 animMorphFrames2;
/* 0x15C */ s16 damagedTimer;
/* 0x15C */ s16 damagedTimer; // TODO: Revisit this name when the equivalent Player variables are named
/* 0x15E */ s16 damagedFlashTimer;
/* 0x160 */ u8 isPerformingVerticalSlash; // set, but never checked
/* 0x160 */ u8 landedFromJump;
@@ -133,8 +134,8 @@ typedef struct Boss01 {
/* 0x9F0 */ Vec3f subCamAt;
/* 0x9FC */ Vec3f subCamUp;
/* 0xA08 */ Vec3f subCamEyeNext;
/* 0xA14 */ f32 deathCsInitialSubCamRot;
/* 0xA18 */ f32 deathCsSubCamRot;
/* 0xA14 */ f32 deathCsInitialSubCamRotY;
/* 0xA18 */ f32 deathCsSubCamRotY;
/* 0xA1C */ f32 subCamVelocity;
/* 0xA20 */ f32 deathShrinkSpeed;
/* 0xA24 */ f32 screenShakeOffsetY;
File diff suppressed because it is too large Load Diff
+286 -2
View File
@@ -2,15 +2,299 @@
#define Z_BOSS_07_H
#include "global.h"
#include "assets/objects/object_boss07/object_boss07.h"
struct Boss07;
typedef void (*Boss07ActionFunc)(struct Boss07*, PlayState*);
#define MAJORA_TENTACLE_LENGTH 10
#define MAJORA_TENTACLE_COUNT_MAX 100
#define MAJORA_WHIP_LENGTH_MAX 50
#define MAJORA_DEATH_LIGHT_COUNT 30
#define MAJORA_LIMB_COUNT MAX((s32)MAJORAS_MASK_LIMB_MAX, MAX((s32)MAJORAS_INCARNATION_LIMB_MAX, (s32)MAJORAS_WRATH_LIMB_MAX))
#define MAJORAS_WRATH_SHADOW_TEX_WIDTH 64
#define MAJORAS_WRATH_SHADOW_TEX_HEIGHT 64
#define MAJORAS_WRATH_SHADOW_TEX_SIZE ((s32)sizeof(u8[MAJORAS_WRATH_SHADOW_TEX_HEIGHT][MAJORAS_WRATH_SHADOW_TEX_WIDTH]))
#define MAJORA_GET_TYPE(thisx) ((thisx)->params)
#define MAJORA_PARAMS(type) (type)
typedef void (*Boss07ActionFunc)(struct Boss07*, struct PlayState*);
typedef enum MajoraType {
/* 0 */ MAJORA_TYPE_BATTLE_INIT, // initializes effects, spawns the battle handler, etc. Becomes `MAJORA_TYPE_MASK` after one frame.
/* 10 */ MAJORA_TYPE_MASK = 10,
/* 11 */ MAJORA_TYPE_MASK_UNK, // immediately crashes if spawned
/* 20 */ MAJORA_TYPE_INCARNATION = 20,
/* 21 */ MAJORA_TYPE_INCARNATION_AFTERIMAGE,
/* 30 */ MAJORA_TYPE_WRATH = 30,
/* 100 */ MAJORA_TYPE_PROJECTILE_REMAINS = 100,
/* 101 */ MAJORA_TYPE_PROJECTILE_INCARNATION,
/* 150 */ MAJORA_TYPE_BATTLE_HANDLER = 150, // handles effects, lens flare, the Remains activation cutscene, etc.
/* 180 */ MAJORA_TYPE_TOP = 180,
/* 200 */ MAJORA_TYPE_REMAINS = 200
} MajoraType;
typedef enum MajoraRemainsType {
/* 0 */ MAJORA_REMAINS_TYPE_ODOLWA,
/* 1 */ MAJORA_REMAINS_TYPE_GYORG,
/* 2 */ MAJORA_REMAINS_TYPE_GOHT,
/* 3 */ MAJORA_REMAINS_TYPE_TWINMOLD,
/* 4 */ MAJORA_REMAINS_TYPE_MAX
} MajoraRemainsType;
typedef struct MajoraTentacle {
/* 0x00 */ Vec3f base;
/* 0x0C */ Vec3f pos[MAJORA_TENTACLE_LENGTH];
/* 0x84 */ Vec3f rot[MAJORA_TENTACLE_LENGTH];
/* 0xFC */ Vec3f velocity[MAJORA_TENTACLE_LENGTH];
} MajoraTentacle; // size = 0x174
typedef struct MajoraWhip {
/* 0x000 */ Vec3s baseRot;
/* 0x008 */ f32 gravity;
/* 0x00C */ f32 mobility;
/* 0x010 */ f32 deceleration;
/* 0x014 */ f32 tension;
/* 0x018 */ Vec3f basePos;
/* 0x024 */ Vec3f pos[MAJORA_WHIP_LENGTH_MAX];
/* 0x27C */ Vec3f rot[MAJORA_WHIP_LENGTH_MAX];
/* 0x4D4 */ Vec3f velocity[MAJORA_WHIP_LENGTH_MAX];
/* 0x72C */ f32 unk_72C[MAJORA_WHIP_LENGTH_MAX];
} MajoraWhip; // size = 0x7F4
typedef enum MajorasWrathBodyPart {
/* 0 */ MAJORAS_WRATH_BODYPART_HEAD,
/* 1 */ MAJORAS_WRATH_BODYPART_TORSO,
/* 2 */ MAJORAS_WRATH_BODYPART_PELVIS,
/* 3 */ MAJORAS_WRATH_BODYPART_LEFT_UPPER_ARM,
// This body part is redundant; it's located at the exact same position as `MAJORAS_WRATH_BODYPART_LEFT_FOREARM`.
/* 4 */ MAJORAS_WRATH_BODYPART_LEFT_LOWER_ARM_ROOT,
/* 5 */ MAJORAS_WRATH_BODYPART_LEFT_FOREARM,
/* 6 */ MAJORAS_WRATH_BODYPART_RIGHT_UPPER_ARM,
// This body part is redundant; it's located at the exact same position as `MAJORAS_WRATH_BODYPART_RIGHT_FOREARM`.
/* 7 */ MAJORAS_WRATH_BODYPART_RIGHT_LOWER_ARM_ROOT,
/* 8 */ MAJORAS_WRATH_BODYPART_RIGHT_FOREARM,
/* 9 */ MAJORAS_WRATH_BODYPART_RIGHT_THIGH,
/* 10 */ MAJORAS_WRATH_BODYPART_RIGHT_SHIN,
/* 11 */ MAJORAS_WRATH_BODYPART_RIGHT_FOOT,
/* 12 */ MAJORAS_WRATH_BODYPART_LEFT_THIGH,
/* 13 */ MAJORAS_WRATH_BODYPART_LEFT_SHIN,
/* 14 */ MAJORAS_WRATH_BODYPART_LEFT_FOOT,
/* 15 */ MAJORAS_WRATH_BODYPART_MAX
} MajorasWrathBodyPart;
typedef enum MajorasIncarnationBodyPart {
/* 0 */ MAJORAS_INCARNATION_BODYPART_EYESTALK,
// This body part is redundant; it's located at the exact same position as `MAJORAS_INCARNATION_BODYPART_LEFT_UPPER_ARM`.
// Additionally, the developers used this index for both the mask limb and the left arm root limb; since the left arm
// root limb has a larger `limbIndex` than the mask limb, that's the limb this body part ends up attached to.
/* 1 */ MAJORAS_INCARNATION_BODYPART_LEFT_ARM_ROOT,
// This body part is redundant; it's located at the exact same position as `MAJORAS_INCARNATION_BODYPART_RIGHT_THIGH`.
/* 2 */ MAJORAS_INCARNATION_BODYPART_RIGHT_LEG_ROOT,
/* 3 */ MAJORAS_INCARNATION_BODYPART_LEFT_UPPER_ARM,
/* 4 */ MAJORAS_INCARNATION_BODYPART_LEFT_FOREARM,
/* 5 */ MAJORAS_INCARNATION_BODYPART_LEFT_HAND,
/* 6 */ MAJORAS_INCARNATION_BODYPART_RIGHT_UPPER_ARM,
/* 7 */ MAJORAS_INCARNATION_BODYPART_RIGHT_FOREARM,
/* 8 */ MAJORAS_INCARNATION_BODYPART_RIGHT_HAND,
/* 9 */ MAJORAS_INCARNATION_BODYPART_RIGHT_THIGH,
/* 10 */ MAJORAS_INCARNATION_BODYPART_RIGHT_SHIN,
/* 11 */ MAJORAS_INCARNATION_BODYPART_RIGHT_FOOT,
/* 12 */ MAJORAS_INCARNATION_BODYPART_LEFT_THIGH,
/* 13 */ MAJORAS_INCARNATION_BODYPART_LEFT_SHIN,
/* 14 */ MAJORAS_INCARNATION_BODYPART_LEFT_FOOT,
/* 15 */ MAJORAS_INCARNATION_BODYPART_MAX
} MajorasIncarnationBodyPart;
#define MAJORA_BODYPART_MAX MAX((s32)MAJORAS_WRATH_BODYPART_MAX, (s32)MAJORAS_INCARNATION_BODYPART_MAX)
typedef enum MajorasWrathColliderBodyPart {
/* 0 */ MAJORAS_WRATH_COLLIDER_BODYPART_HEAD,
/* 1 */ MAJORAS_WRATH_COLLIDER_BODYPART_TORSO,
/* 2 */ MAJORAS_WRATH_COLLIDER_BODYPART_PELVIS,
/* 3 */ MAJORAS_WRATH_COLLIDER_BODYPART_LEFT_UPPER_ARM,
/* 4 */ MAJORAS_WRATH_COLLIDER_BODYPART_LEFT_FOREARM,
/* 5 */ MAJORAS_WRATH_COLLIDER_BODYPART_RIGHT_UPPER_ARM,
/* 6 */ MAJORAS_WRATH_COLLIDER_BODYPART_RIGHT_FOREARM,
/* 7 */ MAJORAS_WRATH_COLLIDER_BODYPART_LEFT_THIGH,
/* 8 */ MAJORAS_WRATH_COLLIDER_BODYPART_LEFT_SHIN,
/* 9 */ MAJORAS_WRATH_COLLIDER_BODYPART_RIGHT_THIGH,
/* 10 */ MAJORAS_WRATH_COLLIDER_BODYPART_RIGHT_SHIN,
/* 11 */ MAJORAS_WRATH_COLLIDER_BODYPART_MAX
} MajorasWrathColliderBodyPart;
typedef enum MajorasIncarnationColliderBodyPart {
/* 0 */ MAJORAS_INCARNATION_COLLIDER_BODYPART_EYESTALK,
// The developers used this index for both the mask limb and the left arm root limb; since the left arm
// root limb has a larger `limbIndex` than the mask limb, that's the limb this body part ends up initially
// attached to. However, the developers seemingly accounted for this by offsetting the collider such that
// it actually appears attached to the mask limb instead.
/* 1 */ MAJORAS_INCARNATION_COLLIDER_BODYPART_MASK,
// This collider is positioned at the room origin because it isn't attached to any of Incarnation's limbs
// within `sLimbToColliderBodyParts`; since the memory for an actor's instance is zeroed out before it's
// used, and since this collider isn't attached to any limbs, its position will remain stuck at (0, 0, 0).
// It seems like the developers *tried* to work around this by giving this collider a massive offset within
// `sLimbColliderOffsets`, but it doesn't work because the offset is only applied if the collider actually
// corresponds to a limb.
/* 2 */ MAJORAS_INCARNATION_COLLIDER_BODYPART_ROOM_ORIGIN,
/* 3 */ MAJORAS_INCARNATION_COLLIDER_BODYPART_LEFT_UPPER_ARM,
/* 4 */ MAJORAS_INCARNATION_COLLIDER_BODYPART_LEFT_FOREARM,
/* 5 */ MAJORAS_INCARNATION_COLLIDER_BODYPART_RIGHT_UPPER_ARM,
/* 6 */ MAJORAS_INCARNATION_COLLIDER_BODYPART_RIGHT_FOREARM,
/* 7 */ MAJORAS_INCARNATION_COLLIDER_BODYPART_LEFT_THIGH,
/* 8 */ MAJORAS_INCARNATION_COLLIDER_BODYPART_LEFT_SHIN,
/* 9 */ MAJORAS_INCARNATION_COLLIDER_BODYPART_RIGHT_THIGH,
/* 10 */ MAJORAS_INCARNATION_COLLIDER_BODYPART_RIGHT_SHIN,
/* 11 */ MAJORAS_INCARNATION_COLLIDER_BODYPART_MAX
} MajorasIncarnationColliderBodyPart;
#define MAJORA_COLLIDER_BODYPART_MAX MAX((s32)MAJORAS_WRATH_COLLIDER_BODYPART_MAX, (s32)MAJORAS_INCARNATION_COLLIDER_BODYPART_MAX)
typedef enum MajorasIncarnationGrowBodyPart {
/* 0 */ MAJORAS_INCARNATION_GROW_BODYPART_RIGHT_ARM,
/* 1 */ MAJORAS_INCARNATION_GROW_BODYPART_LEFT_ARM,
/* 2 */ MAJORAS_INCARNATION_GROW_BODYPART_RIGHT_LEG,
/* 3 */ MAJORAS_INCARNATION_GROW_BODYPART_LEFT_LEG,
/* 4 */ MAJORAS_INCARNATION_GROW_BODYPART_MAX
} MajorasIncarnationGrowBodyPart;
typedef enum MajorasIncarnationFoot {
/* 0 */ MAJORAS_INCARNATION_FOOT_RIGHT,
/* 1 */ MAJORAS_INCARNATION_FOOT_LEFT,
/* 2 */ MAJORAS_INCARNATION_FOOT_MAX
} MajorasIncarnationFoot;
typedef enum MajorasWrathKickCollider {
/* 0 */ MAJORAS_WARTH_KICK_COLLIDER_RIGHT_FOOT,
/* 1 */ MAJORAS_WARTH_KICK_COLLIDER_MAX
} MajorasWrathKickCollider;
typedef struct Boss07 {
/* 0x0000 */ Actor actor;
/* 0x0144 */ Boss07ActionFunc actionFunc;
/* 0x0148 */ char unk_148[0xAAD8];
/* 0x0148 */ u8 shouldStartDeath;
/* 0x0149 */ u8 shouldUpdateTentaclesOrWhips;
/* 0x014A */ u8 lightSettingsMode;
/* 0x014B */ u8 lightSettingsIndex;
/* 0x014C */ s16 frameCounter;
/* 0x014E */ u8 subAction;
/* 0x014F */ u8 whipCrackTimer;
/* 0x0150 */ s16 timers[3];
/* 0x0156 */ s16 landSfxTimer;
/* 0x0158 */ s16 disableCollisionTimer;
/* 0x015A */ s16 whipCollisionTimer;
/* 0x015C */ s16 damagedTimer; // TODO: Revisit this name when the equivalent Player variables are named
/* 0x015E */ s16 damagedFlashTimer;
/* 0x0160 */ s16 motionBlurAlpha;
/* 0x0164 */ Vec3f targetPos;
/* 0x0170 */ f32 speedToTarget;
/* 0x0174 */ u8 canEvade;
/* 0x0178 */ f32 topSpinAngle;
/* 0x017C */ f32 topSpinAngularVelocity;
/* 0x0180 */ s16 topPrecessionVelocity; // also used as a target rotation for Incarnation's various dance moves
/* 0x0184 */ f32 wrathLeanRotY;
/* 0x0188 */ f32 wrathLeanRotX;
/* 0x018C */ f32 flySpeedTarget;
/* 0x0190 */ SkelAnime skelAnime;
/* 0x01D4 */ f32 animEndFrame;
/* 0x01D8 */ s32 maxDecayPixels;
/* 0x01DC */ Vec3s jointTable[MAJORA_LIMB_COUNT];
/* 0x0284 */ Vec3s morphTable[MAJORA_LIMB_COUNT];
/* 0x032C */ f32 shockOrbScale;
/* 0x0330 */ f32 shockSparkScale;
/* 0x0334 */ Vec3f bodyPartsPos[MAJORA_BODYPART_MAX];
/* 0x03E8 */ ColliderJntSph bodyCollider;
/* 0x0408 */ ColliderJntSphElement bodyColliderElements[MAJORA_COLLIDER_BODYPART_MAX];
/* 0x06C8 */ ColliderJntSph kickCollider;
/* 0x06E8 */ ColliderJntSphElement kickColliderElements[MAJORAS_WARTH_KICK_COLLIDER_MAX];
/* 0x0728 */ ColliderCylinder unusedCollider;
/* 0x0774 */ u8 startRemainsCs;
/* 0x0778 */ s32 whipTopIndex; // unlike other index variables, this is an index from the *end* of the whip, not from the beginning of it.
/* 0x077C */ f32 whipLengthScale;
/* 0x0780 */ s32 whipShockMaxIndex;
/* 0x0784 */ s32 whipShockMinIndex;
/* 0x0788 */ MajoraWhip rightWhip;
/* 0x0F7C */ s16 whipWrapStartIndex;
/* 0x0F7E */ s16 whipWrapEndOffset;
/* 0x0F80 */ Vec3f whipGrabPos;
/* 0x0F8C */ f32 whipWrapRotY;
/* 0x0F90 */ f32 whipWrapRotX;
/* 0x0F94 */ MajoraWhip leftWhip;
/* 0x1788 */ Vec3f incarnationFeetPos[MAJORAS_INCARNATION_FOOT_MAX];
/* 0x17A0 */ Vec3f incarnationLeftHandPos;
/* 0x17AC */ Vec3f incarnationRightHandPos;
/* 0x17B8 */ f32 incarnationIntroBodyPartsScale[MAJORAS_INCARNATION_GROW_BODYPART_MAX];
/* 0x17C8 */ f32 incarnationIntroBodyPartsScaleTarget[MAJORAS_INCARNATION_GROW_BODYPART_MAX];
/* 0x17D8 */ Vec3s cutsceneHeadRot;
/* 0x17E0 */ f32 incarnationArmScale; // also has some unused functionality to scale most of Wrath's limbs, see `Boss07_Wrath_TransformLimbDraw`
/* 0x17E4 */ f32 incarnationLegScale;
/* 0x17E8 */ f32 incarnationWrathTransitionScale;
/* 0x17E8 */ f32 incarnationWrathTransitionAmplitude;
/* 0x17F0 */ f32 incarnationMaskScaleY;
/* 0x17F4 */ f32 incarnationMaskScaleX;
/* 0x17F8 */ f32 drawDmgEffScale;
/* 0x17FC */ f32 drawDmgEffFrozenSteamScale;
/* 0x1800 */ f32 drawDmgEffAlpha;
/* 0x1804 */ u8 drawDmgEffType;
/* 0x1805 */ u8 drawDmgEffState; // see `MajoraDrawDmgEffState`
/* 0x1806 */ s16 drawDmgEffTimer;
/* 0x1808 */ u8 lensFlareOn;
/* 0x180c */ f32 lensFlareScale;
/* 0x1810 */ Vec3f lensFlarePos;
/* 0x181C */ s16 projectileColorIndex;
/* 0x1820 */ ColliderCylinder generalCollider;
/* 0x186C */ s16 maskShakeTimer;
/* 0x1870 */ f32 tentacleLengthScale;
/* 0x1874 */ u8 tentacleState; // see `MajorasMaskTentacleState`
/* 0x1878 */ Vec3f tentacleBasePos;
/* 0x1884 */ s32 maskEyeTexIndex; // see `MajorasMaskEyeTexture`
/* 0x1888 */ u8 bgCheckTimer;
/* 0x188C */ f32 eyeBeamsLengthScale; // also used as a scale for the light orbs that surround the Remains during the intro cutscene
/* 0x1890 */ f32 eyeBeamsFocusOrbScale;
/* 0x1894 */ f32 beamLengthScale;
/* 0x1898 */ f32 beamBaseScale;
/* 0x189C */ Vec3f beamStartPos;
/* 0x18A8 */ Vec3f beamEndPos;
/* 0x18B4 */ Vec3f reflectedBeamEndPos;
/* 0x18C0 */ f32 reflectedBeamLengthScale;
/* 0x18C4 */ s16 reflectedBeamPitch;
/* 0x18C6 */ s16 reflectedBeamYaw;
/* 0x18C8 */ s16 introRemainsOrbRot;
/* 0x18CC */ f32 knockbackMovementX;
/* 0x18D0 */ f32 knockbackMovementZ;
/* 0x18D4 */ s16 angularVelocity;
/* 0x18D6 */ s16 fireTimer; // also used as a timer for spawning afterimages in `Boss07_Incarnation_Update`
/* 0x18D8 */ s16 beamDamageTimer;
/* 0x18DA */ u8 burnOnLanding;
/* 0x18DB */ u8 tryFireProjectile;
/* 0x18DC */ s32 effectIndex;
/* 0x18E0 */ Vec3f prevBeamTireMarkPos;
/* 0x18EC */ u8 beamTireMarkEnabled;
/* 0x18ED */ u8 prevBeamTireMarkEnabled;
/* 0x18F0 */ ColliderQuad maskFrontCollider;
/* 0x1970 */ ColliderQuad maskBackCollider;
/* 0x19F0 */ MajoraTentacle tentacles[MAJORA_TENTACLE_COUNT_MAX];
/* 0xAB40 */ s16 miscTimer; // used for making the remains bob up and down in the intro and for Incarnation running SFX
/* 0xAB44 */ f32 introPlayerOrbScale;
/* 0xAB48 */ u8 disableShadow;
/* 0xAB4C */ f32 deathOrbScale;
/* 0xAB50 */ f32 deathLightScale[MAJORA_DEATH_LIGHT_COUNT];
/* 0xABC8 */ u32 cutsceneTimer; // also used as an animation loop count in `Boss07_Incarnation_Hopak`
/* 0xABCC */ s32 sfxTimer; // also used as an index in `Boss07_Mask_IntroCutscene`
/* 0xABD0 */ s16 cutsceneState; // also used to control whether Majora's Mask should target the player or avoid them in `Boss07_Mask_SpinAttack`
/* 0xABD2 */ s16 subCamId;
/* 0xABD4 */ Vec3f subCamEye;
/* 0xABE0 */ Vec3f subCamAt;
/* 0xABEC */ Vec3f subCamEyeNext;
/* 0xABF8 */ Vec3f subCamAtNext;
/* 0xAC04 */ f32 subCamRotY;
/* 0xAC08 */ f32 subCamAngularVelocity;
/* 0xAC0C */ f32 subCamVelocity;
/* 0xAC10 */ UNK_TYPE1 unkAC10[4];
/* 0xAC14 */ f32 subCamEyeModY;
/* 0xAC18 */ UNK_TYPE1 unkAC18[8];
} Boss07; // size = 0xAC20
#endif // Z_BOSS_07_H
@@ -3603,7 +3603,7 @@ void BossHakugin_FillShadowTex(BossHakugin* this, u8* tex, f32 weight) {
baseY = (u16)((s32)startVec.y * 64);
if (sShadowSizes[i] == GOHT_SHADOW_SIZE_EXTRA_LARGE) {
for (y = 0, addY = -0x180; y < ARRAY_COUNT(sShadowExtraLargeMap); y++, addY += 0x40) {
for (y = 0, addY = -384; y < ARRAY_COUNT(sShadowExtraLargeMap); y++, addY += 64) {
for (x = -sShadowExtraLargeMap[y]; x < sShadowExtraLargeMap[y]; x++) {
index = baseX + x + baseY + addY;
if ((index >= 0) && (index < GOHT_SHADOW_TEX_SIZE)) {
@@ -3612,7 +3612,7 @@ void BossHakugin_FillShadowTex(BossHakugin* this, u8* tex, f32 weight) {
}
}
} else if (sShadowSizes[i] == GOHT_SHADOW_SIZE_LARGE) {
for (y = 0, addY = -0x100; y < ARRAY_COUNT(sShadowLargeMap); y++, addY += 0x40) {
for (y = 0, addY = -256; y < ARRAY_COUNT(sShadowLargeMap); y++, addY += 64) {
for (x = -sShadowLargeMap[y]; x < sShadowLargeMap[y]; x++) {
index = baseX + x + baseY + addY;
if ((index >= 0) && (index < GOHT_SHADOW_TEX_SIZE)) {
@@ -3621,7 +3621,7 @@ void BossHakugin_FillShadowTex(BossHakugin* this, u8* tex, f32 weight) {
}
}
} else if (sShadowSizes[i] == GOHT_SHADOW_SIZE_MEDIUM) {
for (y = 0, addY = -0xC0; y < ARRAY_COUNT(sShadowMediumMap); y++, addY += 0x40) {
for (y = 0, addY = -192; y < ARRAY_COUNT(sShadowMediumMap); y++, addY += 64) {
for (x = -sShadowMediumMap[y]; x < sShadowMediumMap[y]; x++) {
index = baseX + x + baseY + addY;
if ((index >= 0) && (index < GOHT_SHADOW_TEX_SIZE)) {
@@ -3630,7 +3630,7 @@ void BossHakugin_FillShadowTex(BossHakugin* this, u8* tex, f32 weight) {
}
}
} else {
for (y = 0, addY = -0x80; y < ARRAY_COUNT(sShadowSmallMap); y++, addY += 0x40) {
for (y = 0, addY = -128; y < ARRAY_COUNT(sShadowSmallMap); y++, addY += 64) {
for (x = -sShadowSmallMap[y]; x < sShadowSmallMap[y]; x++) {
index = baseX + x + baseY + addY;
if ((index >= 0) && (index < GOHT_SHADOW_TEX_SIZE)) {
+10 -10
View File
@@ -146,10 +146,10 @@ void func_809469C0(Player* player, u8* shadowTexture, f32 arg2) {
temp_t1 = sp7C.y * 64.0f;
if (D_80947AEC[i] == 2) {
for (j = 0, phi_a3 = -0x180; j < 12; j++, phi_a3 += 0x40) {
for (j = 0, phi_a3 = -384; j < 12; j++, phi_a3 += 64) {
for (phi_a0 = -D_80947A98[j]; phi_a0 < D_80947A98[j]; phi_a0++) {
temp_v1 = temp_t0 + phi_a0;
if ((temp_v1 >= 0) && (temp_v1 < 0x40)) {
if ((temp_v1 >= 0) && (temp_v1 < 64)) {
temp_v0 = temp_t1 + phi_a3;
if ((temp_v0 >= 0) && (temp_v0 < 0x1000)) {
shadowTexture[temp_v1 + temp_v0] = 255;
@@ -158,10 +158,10 @@ void func_809469C0(Player* player, u8* shadowTexture, f32 arg2) {
}
}
} else if (D_80947AEC[i] == 1) {
for (j = 0, phi_a3 = -0x100; j < 8; j++, phi_a3 += 0x40) {
for (j = 0, phi_a3 = -256; j < 8; j++, phi_a3 += 64) {
for (phi_a0 = -D_80947A88[j]; phi_a0 < D_80947A88[j]; phi_a0++) {
temp_v1 = temp_t0 + phi_a0;
if ((temp_v1 >= 0) && (temp_v1 < 0x40)) {
if ((temp_v1 >= 0) && (temp_v1 < 64)) {
temp_v0 = temp_t1 + phi_a3;
if ((temp_v0 >= 0) && (temp_v0 < 0x1000)) {
shadowTexture[temp_v1 + temp_v0] = 255;
@@ -170,10 +170,10 @@ void func_809469C0(Player* player, u8* shadowTexture, f32 arg2) {
}
}
} else if (D_80947AEC[i] == 0) {
for (j = 0, phi_a3 = -0xC0; j < 7; j++, phi_a3 += 0x40) {
for (j = 0, phi_a3 = -192; j < 7; j++, phi_a3 += 64) {
for (phi_a0 = -D_80947A78[j]; phi_a0 < D_80947A78[j] - 1; phi_a0++) {
temp_v1 = temp_t0 + phi_a0;
if ((temp_v1 >= 0) && (temp_v1 < 0x40)) {
if ((temp_v1 >= 0) && (temp_v1 < 64)) {
temp_v0 = temp_t1 + phi_a3;
if ((temp_v0 >= 0) && (temp_v0 < 0x1000)) {
shadowTexture[temp_v1 + temp_v0] = 255;
@@ -182,10 +182,10 @@ void func_809469C0(Player* player, u8* shadowTexture, f32 arg2) {
}
}
} else if (D_80947AEC[i] == 4) {
for (j = 0, phi_a3 = -0x1C0; j < 14; j++, phi_a3 += 0x40) {
for (j = 0, phi_a3 = -448; j < 14; j++, phi_a3 += 64) {
for (phi_a0 = -D_80947AB0[j]; phi_a0 < D_80947AB0[j]; phi_a0++) {
temp_v1 = temp_t0 + phi_a0;
if ((temp_v1 >= 0) && (temp_v1 < 0x40)) {
if ((temp_v1 >= 0) && (temp_v1 < 64)) {
temp_v0 = temp_t1 + phi_a3;
if ((temp_v0 >= 0) && (temp_v0 < 0x1000)) {
shadowTexture[temp_v1 + temp_v0] = 255;
@@ -194,10 +194,10 @@ void func_809469C0(Player* player, u8* shadowTexture, f32 arg2) {
}
}
} else {
for (j = 0, phi_a3 = -0x80; j < 6; j++, phi_a3 += 0x40) {
for (j = 0, phi_a3 = -128; j < 6; j++, phi_a3 += 64) {
for (phi_a0 = -D_80947A6C[j]; phi_a0 < D_80947A6C[j] - 1; phi_a0++) {
temp_v1 = temp_t0 + phi_a0;
if ((temp_v1 >= 0) && (temp_v1 < 0x40)) {
if ((temp_v1 >= 0) && (temp_v1 < 64)) {
temp_v0 = temp_t1 + phi_a3;
if ((temp_v0 >= 0) && (temp_v0 < 0x1000)) {
shadowTexture[temp_v1 + temp_v0] = 255;
@@ -473,10 +473,9 @@ void func_809289E4(ObjTsubo* this, PlayState* play) {
//! player->currentMask, but in this case is garbage in the collider
Player_PlaySfx((Player*)&this->actor, NA_SE_PL_PULL_UP_POT);
func_80928D6C(this);
} else if ((this->unk_19B != 0) ||
(acHit && (this->cylinderCollider.elem.acHitElem->atDmgInfo.dmgFlags & 0x058BFFBC))) {
} else if (this->unk_19B || (acHit && (this->cylinderCollider.elem.acHitElem->atDmgInfo.dmgFlags & 0x058BFFBC))) {
typeData = &sPotTypeData[type];
this->unk_19B = 0;
this->unk_19B = false;
if ((this->actor.bgCheckFlags & BGCHECKFLAG_WATER) && (this->actor.depthInWater > 15.0f)) {
typeData->breakPot3(this, play);
} else {