mirror of
https://github.com/zeldaret/mm.git
synced 2026-08-18 05:08:48 -04:00
Document Deku Flower objects and other Obj_Etcetera-related cleanup (#544)
* Document Deku Flower objects * Fix warnings, whoops * Respond to Elliptic's review * Better formatting * Small typo fix
This commit is contained in:
@@ -5,6 +5,7 @@
|
||||
*/
|
||||
|
||||
#include "z_obj_etcetera.h"
|
||||
#include "objects/gameplay_keep/gameplay_keep.h"
|
||||
|
||||
#define FLAGS 0x00000010
|
||||
|
||||
@@ -14,8 +15,8 @@ void ObjEtcetera_Init(Actor* thisx, GlobalContext* globalCtx);
|
||||
void ObjEtcetera_Destroy(Actor* thisx, GlobalContext* globalCtx);
|
||||
void ObjEtcetera_Update(Actor* thisx, GlobalContext* globalCtx);
|
||||
|
||||
void ObjEtcetera_PlaySmallFlutterAnimation(ObjEtcetera* this, GlobalContext* globalCtx);
|
||||
void ObjEtcetera_DoIntenseOscillation(ObjEtcetera* this, GlobalContext* globalCtx);
|
||||
void ObjEtcetera_PlayRustleAnimation(ObjEtcetera* this, GlobalContext* globalCtx);
|
||||
void ObjEtcetera_DoBounceOscillation(ObjEtcetera* this, GlobalContext* globalCtx);
|
||||
void ObjEtcetera_Setup(ObjEtcetera* this, GlobalContext* globalCtx);
|
||||
void ObjEtcetera_DrawIdle(Actor* thisx, GlobalContext* globalCtx);
|
||||
void ObjEtcetera_DrawAnimated(Actor* thisx, GlobalContext* globalCtx);
|
||||
@@ -105,6 +106,11 @@ void ObjEtcetera_Destroy(Actor* thisx, GlobalContext* globalCtx) {
|
||||
Collider_DestroyCylinder(globalCtx, &this->collider);
|
||||
}
|
||||
|
||||
/**
|
||||
* This function will make the flower oscillate on the X and Z axes in most situations
|
||||
* where something interacts with it. When the player launches out of the flower, the
|
||||
* oscillation is handled by ObjEtcetera_DoBounceOscillation instead.
|
||||
*/
|
||||
void ObjEtcetera_DoNormalOscillation(ObjEtcetera* this, GlobalContext* globalCtx) {
|
||||
if (this->oscillationTimer > 0) {
|
||||
s32 requiredScopeTemp;
|
||||
@@ -119,10 +125,11 @@ void ObjEtcetera_DoNormalOscillation(ObjEtcetera* this, GlobalContext* globalCtx
|
||||
}
|
||||
}
|
||||
|
||||
void ObjEtcetera_StartSmallFlutterAnimation(ObjEtcetera* this) {
|
||||
Animation_Change(&this->skelAnime, &D_040117A8, 1.0f, 0.0f, Animation_GetLastFrame(&D_040117A8), 2, 0.0f);
|
||||
void ObjEtcetera_StartRustleAnimation(ObjEtcetera* this) {
|
||||
Animation_Change(&this->skelAnime, &gDekuFlowerRustleAnim, 1.0f, 0.0f,
|
||||
Animation_GetLastFrame(&gDekuFlowerRustleAnim), 2, 0.0f);
|
||||
this->dyna.actor.draw = ObjEtcetera_DrawAnimated;
|
||||
this->actionFunc = ObjEtcetera_PlaySmallFlutterAnimation;
|
||||
this->actionFunc = ObjEtcetera_PlayRustleAnimation;
|
||||
}
|
||||
|
||||
void ObjEtcetera_Idle(ObjEtcetera* this, GlobalContext* globalCtx) {
|
||||
@@ -131,12 +138,13 @@ void ObjEtcetera_Idle(ObjEtcetera* this, GlobalContext* globalCtx) {
|
||||
|
||||
if ((player->stateFlags3 & 0x200) && (this->dyna.actor.xzDistToPlayer < 20.0f)) {
|
||||
// Player is launching out of the Deku Flower
|
||||
Animation_Change(&this->skelAnime, &D_0400EB7C, 1.0f, 0.0f, Animation_GetLastFrame(&D_0400EB7C), 2, 0.0f);
|
||||
Animation_Change(&this->skelAnime, &gDekuFlowerBounceAnim, 1.0f, 0.0f,
|
||||
Animation_GetLastFrame(&gDekuFlowerBounceAnim), 2, 0.0f);
|
||||
this->dyna.actor.draw = ObjEtcetera_DrawAnimated;
|
||||
this->actionFunc = ObjEtcetera_DoIntenseOscillation;
|
||||
this->actionFunc = ObjEtcetera_DoBounceOscillation;
|
||||
Actor_SetScale(&this->dyna.actor, 0.01f);
|
||||
this->dyna.actor.scale.y = 0.02f;
|
||||
this->intenseOscillationScale = 0.003f;
|
||||
this->bounceOscillationScale = 0.003f;
|
||||
this->oscillationTimer = 30;
|
||||
this->burrowFlag &= ~1;
|
||||
} else if ((player->stateFlags3 & 0x2000) && (this->dyna.actor.xzDistToPlayer < 30.0f) &&
|
||||
@@ -151,7 +159,7 @@ void ObjEtcetera_Idle(ObjEtcetera* this, GlobalContext* globalCtx) {
|
||||
if (!(this->burrowFlag & 1)) {
|
||||
// Player is walking onto the Deku Flower, or falling on it from a height
|
||||
this->oscillationTimer = 10;
|
||||
ObjEtcetera_StartSmallFlutterAnimation(this);
|
||||
ObjEtcetera_StartRustleAnimation(this);
|
||||
} else if ((player->actor.speedXZ > 0.1f) || ((player->unk_ABC < 0.0f) && !(player->stateFlags3 & 0x100))) {
|
||||
// Player is walking on top of the Deku Flower, is at the very start of burrowing, or is at the very
|
||||
// start of launching
|
||||
@@ -162,19 +170,19 @@ void ObjEtcetera_Idle(ObjEtcetera* this, GlobalContext* globalCtx) {
|
||||
if (this->burrowFlag & 1) {
|
||||
// Player is walking off the Deku Flower
|
||||
this->oscillationTimer = 10;
|
||||
ObjEtcetera_StartSmallFlutterAnimation(this);
|
||||
ObjEtcetera_StartRustleAnimation(this);
|
||||
}
|
||||
this->burrowFlag &= ~1;
|
||||
}
|
||||
}
|
||||
if ((this->collider.base.acFlags & AC_HIT)) {
|
||||
this->oscillationTimer = 10;
|
||||
ObjEtcetera_StartSmallFlutterAnimation(this);
|
||||
ObjEtcetera_StartRustleAnimation(this);
|
||||
}
|
||||
ObjEtcetera_DoNormalOscillation(this, globalCtx);
|
||||
}
|
||||
|
||||
void ObjEtcetera_PlaySmallFlutterAnimation(ObjEtcetera* this, GlobalContext* globalCtx) {
|
||||
void ObjEtcetera_PlayRustleAnimation(ObjEtcetera* this, GlobalContext* globalCtx) {
|
||||
if (DynaPolyActor_IsInRidingMovingState(&this->dyna)) {
|
||||
this->burrowFlag |= 1;
|
||||
} else {
|
||||
@@ -187,7 +195,12 @@ void ObjEtcetera_PlaySmallFlutterAnimation(ObjEtcetera* this, GlobalContext* glo
|
||||
ObjEtcetera_DoNormalOscillation(this, globalCtx);
|
||||
}
|
||||
|
||||
void ObjEtcetera_DoIntenseOscillation(ObjEtcetera* this, GlobalContext* globalCtx) {
|
||||
/**
|
||||
* When the bounce animation plays (either because the player launched out of the flower,
|
||||
* or because the flower spawned after killing a Mad Scrub), this function makes the
|
||||
* flower oscillate stronger than it normally does, including an oscillation on the Y-axis.
|
||||
*/
|
||||
void ObjEtcetera_DoBounceOscillation(ObjEtcetera* this, GlobalContext* globalCtx) {
|
||||
// In order to match, we are seemingly required to access scale.x at one point
|
||||
// without using this. We can create a thisx or dyna pointer to achieve that, but
|
||||
// it's more likely they used dyna given that DynaPolyActor_IsInRidingMovingState takes a DynaPolyActor.
|
||||
@@ -208,12 +221,12 @@ void ObjEtcetera_DoIntenseOscillation(ObjEtcetera* this, GlobalContext* globalCt
|
||||
Actor_SetScale(&this->dyna.actor, 0.01f);
|
||||
this->dyna.actor.scale.y = 0.02f;
|
||||
this->oscillationTimer = 0;
|
||||
this->intenseOscillationScale = 0.0f;
|
||||
this->bounceOscillationScale = 0.0f;
|
||||
return;
|
||||
}
|
||||
this->intenseOscillationScale *= 0.8f;
|
||||
this->intenseOscillationScale -= (this->dyna.actor.scale.x - 0.01f) * 0.4f;
|
||||
scaleTemp = dyna->actor.scale.x + this->intenseOscillationScale;
|
||||
this->bounceOscillationScale *= 0.8f;
|
||||
this->bounceOscillationScale -= (this->dyna.actor.scale.x - 0.01f) * 0.4f;
|
||||
scaleTemp = dyna->actor.scale.x + this->bounceOscillationScale;
|
||||
Actor_SetScale(&this->dyna.actor, scaleTemp);
|
||||
this->dyna.actor.scale.y = 2.0f * scaleTemp;
|
||||
}
|
||||
@@ -221,7 +234,12 @@ void ObjEtcetera_DoIntenseOscillation(ObjEtcetera* this, GlobalContext* globalCt
|
||||
void ObjEtcetera_Setup(ObjEtcetera* this, GlobalContext* globalCtx) {
|
||||
CollisionHeader* colHeader = NULL;
|
||||
s32 type;
|
||||
CollisionHeader* collisionHeaders[] = { &D_0400E710, &D_0400E710, &D_040118D8, &D_040118D8 };
|
||||
CollisionHeader* collisionHeaders[] = {
|
||||
&gPinkDekuFlowerCol,
|
||||
&gPinkDekuFlowerCol,
|
||||
&gGoldDekuFlowerCol,
|
||||
&gGoldDekuFlowerCol,
|
||||
};
|
||||
s32 pad;
|
||||
CollisionHeader* thisCollisionHeader;
|
||||
|
||||
@@ -244,15 +262,15 @@ void ObjEtcetera_Setup(ObjEtcetera* this, GlobalContext* globalCtx) {
|
||||
switch (type) {
|
||||
case DEKU_FLOWER_TYPE_PINK:
|
||||
case DEKU_FLOWER_TYPE_PINK_SPAWNED_FROM_MAD_SCRUB:
|
||||
SkelAnime_Init(globalCtx, &this->skelAnime, &D_04011518, &D_0400EB7C, this->jointTable,
|
||||
this->morphTable, 11);
|
||||
this->dList = &D_0400ED80;
|
||||
SkelAnime_Init(globalCtx, &this->skelAnime, &gPinkDekuFlowerSkel, &gDekuFlowerBounceAnim,
|
||||
this->jointTable, this->morphTable, DEKU_FLOWER_LIMB_MAX);
|
||||
this->dList = gPinkDekuFlowerIdleDL;
|
||||
break;
|
||||
case DEKU_FLOWER_TYPE_GOLD:
|
||||
case DEKU_FLOWER_TYPE_GOLD_SPAWNED_FROM_MAD_SCRUB:
|
||||
this->dList = &D_04011BD0;
|
||||
SkelAnime_Init(globalCtx, &this->skelAnime, &D_040127E8, &D_0400EB7C, this->jointTable,
|
||||
this->morphTable, 11);
|
||||
this->dList = gGoldDekuFlowerIdleDL;
|
||||
SkelAnime_Init(globalCtx, &this->skelAnime, &gGoldDekuFlowerSkel.sh, &gDekuFlowerBounceAnim,
|
||||
this->jointTable, this->morphTable, DEKU_FLOWER_LIMB_MAX);
|
||||
this->collider.dim.height = 20;
|
||||
break;
|
||||
}
|
||||
@@ -270,13 +288,13 @@ void ObjEtcetera_Setup(ObjEtcetera* this, GlobalContext* globalCtx) {
|
||||
break;
|
||||
case DEKU_FLOWER_TYPE_PINK_SPAWNED_FROM_MAD_SCRUB:
|
||||
case DEKU_FLOWER_TYPE_GOLD_SPAWNED_FROM_MAD_SCRUB:
|
||||
Animation_Change(&this->skelAnime, &D_0400EB7C, 1.0f, 0.0f, Animation_GetLastFrame(&D_0400EB7C), 2,
|
||||
0.0f);
|
||||
Animation_Change(&this->skelAnime, &gDekuFlowerBounceAnim, 1.0f, 0.0f,
|
||||
Animation_GetLastFrame(&gDekuFlowerBounceAnim), 2, 0.0f);
|
||||
this->dyna.actor.draw = ObjEtcetera_DrawAnimated;
|
||||
this->actionFunc = ObjEtcetera_DoIntenseOscillation;
|
||||
this->actionFunc = ObjEtcetera_DoBounceOscillation;
|
||||
Actor_SetScale(&this->dyna.actor, 0.0f);
|
||||
this->oscillationTimer = 30;
|
||||
this->intenseOscillationScale = 0.0f;
|
||||
this->bounceOscillationScale = 0.0f;
|
||||
this->dyna.actor.focus.pos.y = this->dyna.actor.home.pos.y + 10.0f;
|
||||
this->dyna.actor.targetMode = 3;
|
||||
break;
|
||||
@@ -299,6 +317,11 @@ void ObjEtcetera_Update(Actor* thisx, GlobalContext* globalCtx) {
|
||||
CollisionCheck_SetAC(globalCtx, &globalCtx->colChkCtx, &this->collider.base);
|
||||
}
|
||||
|
||||
/**
|
||||
* When the flower isn't animating, this function is used to draw it.
|
||||
* It draws the flower as a single, non-moving display list that encompasses the whole flower.
|
||||
* When an animation is finished, functions are expected to set the actor's draw function to this.
|
||||
*/
|
||||
void ObjEtcetera_DrawIdle(Actor* thisx, GlobalContext* globalCtx) {
|
||||
ObjEtcetera* this = THIS;
|
||||
|
||||
@@ -311,6 +334,11 @@ void ObjEtcetera_DrawIdle(Actor* thisx, GlobalContext* globalCtx) {
|
||||
CLOSE_DISPS(globalCtx->state.gfxCtx);
|
||||
}
|
||||
|
||||
/**
|
||||
* When the flower is animating, this function is used to draw it.
|
||||
* It draws the flower as an animated bunch of limbs using the SkelAnime system.
|
||||
* When a function wants to play an animation, it is expected to set the actor's draw function to this.
|
||||
*/
|
||||
void ObjEtcetera_DrawAnimated(Actor* thisx, GlobalContext* globalCtx) {
|
||||
ObjEtcetera* this = THIS;
|
||||
|
||||
|
||||
@@ -13,6 +13,26 @@ typedef enum {
|
||||
/* 4 */ DEKU_FLOWER_TYPE_MAX,
|
||||
} DekuFlowerType;
|
||||
|
||||
/**
|
||||
* For the petal/leaf directions, "back" is negative and "front" is positive
|
||||
* on the flower's local Z-axis. "Left" and "right" are relative to the front
|
||||
* and back.
|
||||
*/
|
||||
typedef enum {
|
||||
/* 0 */ DEKU_FLOWER_LIMB_NONE,
|
||||
/* 1 */ DEKU_FLOWER_LIMB_BASE,
|
||||
/* 2 */ DEKU_FLOWER_LIMB_CENTER,
|
||||
/* 3 */ DEKU_FLOWER_LIMB_BACK_PETAL_OR_LEAF,
|
||||
/* 4 */ DEKU_FLOWER_LIMB_FRONT_PETAL_OR_LEAF,
|
||||
/* 5 */ DEKU_FLOWER_LIMB_FRONT_RIGHT_PETAL,
|
||||
/* 6 */ DEKU_FLOWER_LIMB_BACK_RIGHT_PETAL,
|
||||
/* 7 */ DEKU_FLOWER_LIMB_RIGHT_PETAL_OR_LEAF,
|
||||
/* 8 */ DEKU_FLOWER_LIMB_FRONT_LEFT_PETAL,
|
||||
/* 9 */ DEKU_FLOWER_LIMB_LEFT_PETAL_OR_LEAF,
|
||||
/* 10 */ DEKU_FLOWER_LIMB_BACK_LEFT_PETAL,
|
||||
/* 11 */ DEKU_FLOWER_LIMB_MAX,
|
||||
} DekuFlowerLimbs;
|
||||
|
||||
struct ObjEtcetera;
|
||||
|
||||
typedef void (*ObjEtceteraActionFunc)(struct ObjEtcetera*, GlobalContext*);
|
||||
@@ -21,9 +41,9 @@ typedef struct ObjEtcetera {
|
||||
/* 0x000 */ DynaPolyActor dyna;
|
||||
/* 0x15C */ SkelAnime skelAnime;
|
||||
/* 0x1A0 */ ColliderCylinder collider;
|
||||
/* 0x1EC */ Vec3s jointTable[11];
|
||||
/* 0x22E */ Vec3s morphTable[11];
|
||||
/* 0x270 */ f32 intenseOscillationScale;
|
||||
/* 0x1EC */ Vec3s jointTable[DEKU_FLOWER_LIMB_MAX];
|
||||
/* 0x22E */ Vec3s morphTable[DEKU_FLOWER_LIMB_MAX];
|
||||
/* 0x270 */ f32 bounceOscillationScale;
|
||||
/* 0x274 */ s16 oscillationTimer;
|
||||
/* 0x276 */ u16 burrowFlag;
|
||||
/* 0x278 */ s8 objIndex;
|
||||
|
||||
Reference in New Issue
Block a user