diff --git a/assets/xml/objects/gameplay_keep.xml b/assets/xml/objects/gameplay_keep.xml index f3ed5c8984..134cbc0e39 100644 --- a/assets/xml/objects/gameplay_keep.xml +++ b/assets/xml/objects/gameplay_keep.xml @@ -766,59 +766,62 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/include/variables.h b/include/variables.h index 9ee10419a4..d7ae1e7a3a 100644 --- a/include/variables.h +++ b/include/variables.h @@ -3866,14 +3866,6 @@ extern UNK_TYPE D_0400E3D8; extern UNK_TYPE D_0400E408; extern UNK_TYPE D_0400E410; extern UNK_TYPE D_0400E418; -extern CollisionHeader D_0400E710; // Pink Deku Flower collision -extern AnimationHeader D_0400EB7C; // Deku Flower intense flutter animation -extern Gfx D_0400ED80; // Pink Deku Flower display list -extern SkeletonHeader D_04011518; // Pink Deku Flower skeleton -extern AnimationHeader D_040117A8; // Deku Flower small flutter animation -extern CollisionHeader D_040118D8; // Gold Deku Flower collision -extern Gfx D_04011BD0; // Gold Deku Flower display list -extern SkeletonHeader D_040127E8; // Gold Deku Flower skeleton extern UNK_TYPE D_04012860; extern UNK_TYPE D_040128BC; extern u64 D_04014570[]; diff --git a/src/overlays/actors/ovl_Obj_Etcetera/z_obj_etcetera.c b/src/overlays/actors/ovl_Obj_Etcetera/z_obj_etcetera.c index a4eb9ad9ac..56f9b9f7a4 100644 --- a/src/overlays/actors/ovl_Obj_Etcetera/z_obj_etcetera.c +++ b/src/overlays/actors/ovl_Obj_Etcetera/z_obj_etcetera.c @@ -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; diff --git a/src/overlays/actors/ovl_Obj_Etcetera/z_obj_etcetera.h b/src/overlays/actors/ovl_Obj_Etcetera/z_obj_etcetera.h index f5642ff282..a52f5ae2ef 100644 --- a/src/overlays/actors/ovl_Obj_Etcetera/z_obj_etcetera.h +++ b/src/overlays/actors/ovl_Obj_Etcetera/z_obj_etcetera.h @@ -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; diff --git a/tools/disasm/functions.txt b/tools/disasm/functions.txt index ef8f7630c3..2911e3e105 100644 --- a/tools/disasm/functions.txt +++ b/tools/disasm/functions.txt @@ -11100,10 +11100,10 @@ 0x80A7BC70:("ObjEtcetera_Init",), 0x80A7BD80:("ObjEtcetera_Destroy",), 0x80A7BDC8:("ObjEtcetera_DoNormalOscillation",), - 0x80A7BE8C:("ObjEtcetera_StartSmallFlutterAnimation",), + 0x80A7BE8C:("ObjEtcetera_StartRustleAnimation",), 0x80A7BF08:("ObjEtcetera_Idle",), - 0x80A7C168:("ObjEtcetera_PlaySmallFlutterAnimation",), - 0x80A7C1F0:("ObjEtcetera_DoIntenseOscillation",), + 0x80A7C168:("ObjEtcetera_PlayRustleAnimation",), + 0x80A7C1F0:("ObjEtcetera_DoBounceOscillation",), 0x80A7C308:("ObjEtcetera_Setup",), 0x80A7C5EC:("ObjEtcetera_Update",), 0x80A7C690:("ObjEtcetera_DrawIdle",),