summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTharo <17233964+Thar0@users.noreply.github.com>2024-05-19 18:18:34 +0100
committerGitHub <noreply@github.com>2024-05-19 10:18:34 -0700
commit44057c087a4e57bff4ece44b9aa9da06e2db3a57 (patch)
tree0481cf6fae9f62a1e813486f1e70088fc0eb5b4a
parentfd3431fa486543ea8ced10b946a4e41d49698d10 (diff)
ovl_En_Wdhand (#1629)
* 2 non-matching * Matching Co-authored-by: Derek Hensley <hensley.derek58@gmail.com> * Cleanup + docs * Suggested changes * Format * Update EnWdhand_GetInitVelocity --------- Co-authored-by: Derek Hensley <hensley.derek58@gmail.com>
-rw-r--r--assets/xml/objects/object_wdhand.xml26
-rw-r--r--spec3
-rw-r--r--src/overlays/actors/ovl_En_Wdhand/z_en_wdhand.c841
-rw-r--r--src/overlays/actors/ovl_En_Wdhand/z_en_wdhand.h26
-rw-r--r--tools/disasm/variables.txt3
5 files changed, 802 insertions, 97 deletions
diff --git a/assets/xml/objects/object_wdhand.xml b/assets/xml/objects/object_wdhand.xml
index 311d9299f..0662718ec 100644
--- a/assets/xml/objects/object_wdhand.xml
+++ b/assets/xml/objects/object_wdhand.xml
@@ -1,14 +1,14 @@
<Root>
<File Name="object_wdhand" Segment="6">
- <Animation Name="object_wdhand_Anim_0000F4" Offset="0xF4" />
+ <Animation Name="gDexihandCloseAnim" Offset="0xF4" />
<Animation Name="object_wdhand_Anim_000364" Offset="0x364" />
- <Animation Name="object_wdhand_Anim_000534" Offset="0x534" />
- <Animation Name="object_wdhand_Anim_000854" Offset="0x854" />
+ <Animation Name="gDexihandOpenAnim" Offset="0x534" />
+ <Animation Name="gDexihandIdleAnim" Offset="0x854" />
<Texture Name="object_wdhand_Tex_000870" OutName="tex_000870" Format="rgba16" Width="16" Height="32" Offset="0x870" />
<Texture Name="object_wdhand_Tex_000C70" OutName="tex_000C70" Format="rgba16" Width="16" Height="32" Offset="0xC70" />
<Texture Name="object_wdhand_Tex_001070" OutName="tex_001070" Format="rgba16" Width="16" Height="32" Offset="0x1070" />
- <DList Name="object_wdhand_DL_0014C0" Offset="0x14C0" />
- <DList Name="object_wdhand_DL_0015B0" Offset="0x15B0" />
+ <DList Name="gDexihandBaseDL" Offset="0x14C0" />
+ <DList Name="gDexihandArmSegmentDL" Offset="0x15B0" />
<DList Name="object_wdhand_DL_001908" Offset="0x1908" />
<DList Name="object_wdhand_DL_001998" Offset="0x1998" />
<DList Name="object_wdhand_DL_001A20" Offset="0x1A20" />
@@ -16,13 +16,13 @@
<DList Name="object_wdhand_DL_001B80" Offset="0x1B80" />
<DList Name="object_wdhand_DL_001C40" Offset="0x1C40" />
<DList Name="object_wdhand_DL_001CF0" Offset="0x1CF0" />
- <Limb Name="object_wdhand_Standardlimb_001DB0" Type="Standard" EnumName="OBJECT_WDHAND_LIMB_01" Offset="0x1DB0" />
- <Limb Name="object_wdhand_Standardlimb_001DBC" Type="Standard" EnumName="OBJECT_WDHAND_LIMB_02" Offset="0x1DBC" />
- <Limb Name="object_wdhand_Standardlimb_001DC8" Type="Standard" EnumName="OBJECT_WDHAND_LIMB_03" Offset="0x1DC8" />
- <Limb Name="object_wdhand_Standardlimb_001DD4" Type="Standard" EnumName="OBJECT_WDHAND_LIMB_04" Offset="0x1DD4" />
- <Limb Name="object_wdhand_Standardlimb_001DE0" Type="Standard" EnumName="OBJECT_WDHAND_LIMB_05" Offset="0x1DE0" />
- <Limb Name="object_wdhand_Standardlimb_001DEC" Type="Standard" EnumName="OBJECT_WDHAND_LIMB_06" Offset="0x1DEC" />
- <Limb Name="object_wdhand_Standardlimb_001DF8" Type="Standard" EnumName="OBJECT_WDHAND_LIMB_07" Offset="0x1DF8" />
- <Skeleton Name="object_wdhand_Skel_001E20" Type="Flex" LimbType="Standard" LimbNone="OBJECT_WDHAND_LIMB_NONE" LimbMax="OBJECT_WDHAND_LIMB_MAX" EnumName="ObjectWdhandLimb" Offset="0x1E20" />
+ <Limb Name="object_wdhand_Standardlimb_001DB0" Type="Standard" EnumName="DEXIHAND_LIMB_01" Offset="0x1DB0" />
+ <Limb Name="object_wdhand_Standardlimb_001DBC" Type="Standard" EnumName="DEXIHAND_LIMB_02" Offset="0x1DBC" />
+ <Limb Name="object_wdhand_Standardlimb_001DC8" Type="Standard" EnumName="DEXIHAND_LIMB_03" Offset="0x1DC8" />
+ <Limb Name="object_wdhand_Standardlimb_001DD4" Type="Standard" EnumName="DEXIHAND_LIMB_04" Offset="0x1DD4" />
+ <Limb Name="object_wdhand_Standardlimb_001DE0" Type="Standard" EnumName="DEXIHAND_LIMB_05" Offset="0x1DE0" />
+ <Limb Name="object_wdhand_Standardlimb_001DEC" Type="Standard" EnumName="DEXIHAND_LIMB_06" Offset="0x1DEC" />
+ <Limb Name="object_wdhand_Standardlimb_001DF8" Type="Standard" EnumName="DEXIHAND_LIMB_07" Offset="0x1DF8" />
+ <Skeleton Name="gDexihandSkel" Type="Flex" LimbType="Standard" LimbNone="DEXIHAND_LIMB_NONE" LimbMax="DEXIHAND_LIMB_MAX" EnumName="DexihandLimb" Offset="0x1E20" />
</File>
</Root>
diff --git a/spec b/spec
index 08433ecd4..1672e4092 100644
--- a/spec
+++ b/spec
@@ -3432,8 +3432,7 @@ beginseg
name "ovl_En_Wdhand"
compress
include "$(BUILD_DIR)/src/overlays/actors/ovl_En_Wdhand/z_en_wdhand.o"
- include "$(BUILD_DIR)/data/ovl_En_Wdhand/ovl_En_Wdhand.data.o"
- include "$(BUILD_DIR)/data/ovl_En_Wdhand/ovl_En_Wdhand.reloc.o"
+ include "$(BUILD_DIR)/src/overlays/actors/ovl_En_Wdhand/ovl_En_Wdhand_reloc.o"
endseg
beginseg
diff --git a/src/overlays/actors/ovl_En_Wdhand/z_en_wdhand.c b/src/overlays/actors/ovl_En_Wdhand/z_en_wdhand.c
index ae491fbf0..fe39b96c5 100644
--- a/src/overlays/actors/ovl_En_Wdhand/z_en_wdhand.c
+++ b/src/overlays/actors/ovl_En_Wdhand/z_en_wdhand.c
@@ -15,7 +15,23 @@ void EnWdhand_Destroy(Actor* thisx, PlayState* play);
void EnWdhand_Update(Actor* thisx, PlayState* play);
void EnWdhand_Draw(Actor* thisx, PlayState* play);
-#if 0
+void EnWdhand_ReturnToIdle(EnWdhand* this, PlayState* play);
+void EnWdhand_Idle(EnWdhand* this, PlayState* play);
+void EnWdhand_LungeForPlayer(EnWdhand* this, PlayState* play);
+void EnWdhand_FailedToGrabPlayer(EnWdhand* this, PlayState* play);
+void EnWdhand_GrabbedPlayer(EnWdhand* this, PlayState* play);
+void EnWdhand_Die(EnWdhand* this, PlayState* play);
+
+void EnWdhand_SetupReturnToIdle(EnWdhand* this);
+void EnWdhand_SetupIdle(EnWdhand* this);
+void EnWdhand_SetupLungeForPlayer(EnWdhand* this);
+void EnWdhand_SetupFailedToGrabPlayer(EnWdhand* this);
+void EnWdhand_SetupGrabbedPlayer(EnWdhand* this, PlayState* play);
+void EnWdhand_SetupDie(EnWdhand* this);
+
+void EnWdhand_GetInitVelocity(EnWdhand* this, Vec3f* dst);
+void EnWdhand_Vec3fToVec3s(Vec3s* dst, Vec3f* src);
+
ActorInit En_Wdhand_InitVars = {
/**/ ACTOR_EN_WDHAND,
/**/ ACTORCAT_ENEMY,
@@ -28,49 +44,102 @@ ActorInit En_Wdhand_InitVars = {
/**/ EnWdhand_Draw,
};
-// static ColliderJntSphElementInit sJntSphElementsInit[7] = {
-static ColliderJntSphElementInit D_80AF63E0[7] = {
+static ColliderJntSphElementInit sJntSphElementsInit[EN_WDHAND_NUM_COLLIDER_ELEMENTS] = {
{
- { ELEMTYPE_UNK1, { 0xF7CFFFFF, 0x00, 0x00 }, { 0xF7CFFFFF, 0x00, 0x00 }, TOUCH_ON | TOUCH_SFX_NONE, BUMP_ON, OCELEM_ON, },
+ {
+ ELEMTYPE_UNK1,
+ { 0xF7CFFFFF, 0x00, 0x00 },
+ { 0xF7CFFFFF, 0x00, 0x00 },
+ TOUCH_ON | TOUCH_SFX_NONE,
+ BUMP_ON,
+ OCELEM_ON,
+ },
{ 50, { { 0, 575, 0 }, 10 }, 100 },
},
{
- { ELEMTYPE_UNK1, { 0xF7CFFFFF, 0x00, 0x00 }, { 0xF7CFFFFF, 0x00, 0x00 }, TOUCH_ON | TOUCH_SFX_NONE, BUMP_ON, OCELEM_ON, },
+ {
+ ELEMTYPE_UNK1,
+ { 0xF7CFFFFF, 0x00, 0x00 },
+ { 0xF7CFFFFF, 0x00, 0x00 },
+ TOUCH_ON | TOUCH_SFX_NONE,
+ BUMP_ON,
+ OCELEM_ON,
+ },
{ 50, { { 0, 1725, 0 }, 10 }, 100 },
},
{
- { ELEMTYPE_UNK1, { 0xF7CFFFFF, 0x00, 0x00 }, { 0xF7CFFFFF, 0x00, 0x00 }, TOUCH_ON | TOUCH_SFX_NONE, BUMP_ON, OCELEM_ON, },
+ {
+ ELEMTYPE_UNK1,
+ { 0xF7CFFFFF, 0x00, 0x00 },
+ { 0xF7CFFFFF, 0x00, 0x00 },
+ TOUCH_ON | TOUCH_SFX_NONE,
+ BUMP_ON,
+ OCELEM_ON,
+ },
{ 50, { { 0, 575, 0 }, 10 }, 100 },
},
{
- { ELEMTYPE_UNK1, { 0xF7CFFFFF, 0x00, 0x00 }, { 0xF7CFFFFF, 0x00, 0x00 }, TOUCH_ON | TOUCH_SFX_NONE, BUMP_ON, OCELEM_ON, },
+ {
+ ELEMTYPE_UNK1,
+ { 0xF7CFFFFF, 0x00, 0x00 },
+ { 0xF7CFFFFF, 0x00, 0x00 },
+ TOUCH_ON | TOUCH_SFX_NONE,
+ BUMP_ON,
+ OCELEM_ON,
+ },
{ 50, { { 0, 1725, 0 }, 10 }, 100 },
},
{
- { ELEMTYPE_UNK1, { 0xF7CFFFFF, 0x00, 0x00 }, { 0xF7CFFFFF, 0x00, 0x00 }, TOUCH_ON | TOUCH_SFX_NONE, BUMP_ON, OCELEM_ON, },
+ {
+ ELEMTYPE_UNK1,
+ { 0xF7CFFFFF, 0x00, 0x00 },
+ { 0xF7CFFFFF, 0x00, 0x00 },
+ TOUCH_ON | TOUCH_SFX_NONE,
+ BUMP_ON,
+ OCELEM_ON,
+ },
{ 50, { { 0, 575, 0 }, 10 }, 100 },
},
{
- { ELEMTYPE_UNK1, { 0xF7CFFFFF, 0x00, 0x00 }, { 0xF7CFFFFF, 0x00, 0x00 }, TOUCH_ON | TOUCH_SFX_NONE, BUMP_ON, OCELEM_ON, },
+ {
+ ELEMTYPE_UNK1,
+ { 0xF7CFFFFF, 0x00, 0x00 },
+ { 0xF7CFFFFF, 0x00, 0x00 },
+ TOUCH_ON | TOUCH_SFX_NONE,
+ BUMP_ON,
+ OCELEM_ON,
+ },
{ 50, { { 0, 1725, 0 }, 10 }, 100 },
},
{
- { ELEMTYPE_UNK1, { 0xF7CFFFFF, 0x00, 0x00 }, { 0xF7CFFFFF, 0x00, 0x00 }, TOUCH_ON | TOUCH_SFX_NONE, BUMP_ON, OCELEM_ON, },
+ {
+ ELEMTYPE_UNK1,
+ { 0xF7CFFFFF, 0x00, 0x00 },
+ { 0xF7CFFFFF, 0x00, 0x00 },
+ TOUCH_ON | TOUCH_SFX_NONE,
+ BUMP_ON,
+ OCELEM_ON,
+ },
{ 50, { { 0, 1000, 0 }, 15 }, 100 },
},
};
-// static ColliderJntSphInit sJntSphInit = {
-static ColliderJntSphInit D_80AF64DC = {
- { COLTYPE_HIT0, AT_NONE | AT_TYPE_ENEMY, AC_ON | AC_TYPE_PLAYER, OC1_ON | OC1_TYPE_ALL, OC2_TYPE_1, COLSHAPE_JNTSPH, },
- ARRAY_COUNT(sJntSphElementsInit), D_80AF63E0, // sJntSphElementsInit,
+static ColliderJntSphInit sJntSphInit = {
+ {
+ COLTYPE_HIT0,
+ AT_NONE | AT_TYPE_ENEMY,
+ AC_ON | AC_TYPE_PLAYER,
+ OC1_ON | OC1_TYPE_ALL,
+ OC2_TYPE_1,
+ COLSHAPE_JNTSPH,
+ },
+ ARRAY_COUNT(sJntSphElementsInit),
+ sJntSphElementsInit,
};
-// sColChkInfoInit
-static CollisionCheckInfoInit D_80AF64EC = { 1, 25, 25, MASS_HEAVY };
+static CollisionCheckInfoInit sColChkInfoInit = { 1, 25, 25, MASS_HEAVY };
-// static DamageTable sDamageTable = {
-static DamageTable D_80AF64F4 = {
+static DamageTable sDamageTable = {
/* Deku Nut */ DMG_ENTRY(0, 0x0),
/* Deku Stick */ DMG_ENTRY(0, 0x0),
/* Horse trample */ DMG_ENTRY(0, 0x0),
@@ -105,63 +174,679 @@ static DamageTable D_80AF64F4 = {
/* Powder Keg */ DMG_ENTRY(1, 0x0),
};
-#endif
-
-extern ColliderJntSphElementInit D_80AF63E0[7];
-extern ColliderJntSphInit D_80AF64DC;
-extern CollisionCheckInfoInit D_80AF64EC;
-extern DamageTable D_80AF64F4;
-
-extern UNK_TYPE D_060000F4;
-extern UNK_TYPE D_06000364;
-extern UNK_TYPE D_06000534;
-extern UNK_TYPE D_06000854;
-extern UNK_TYPE D_060014C0;
-
-#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Wdhand/EnWdhand_Init.s")
-
-#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Wdhand/EnWdhand_Destroy.s")
-
-#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Wdhand/func_80AF4608.s")
-
-#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Wdhand/func_80AF4670.s")
-
-#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Wdhand/func_80AF46F0.s")
-
-#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Wdhand/func_80AF488C.s")
-
-#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Wdhand/func_80AF48D0.s")
-
-#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Wdhand/func_80AF4964.s")
-
-#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Wdhand/func_80AF4A88.s")
-
-#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Wdhand/func_80AF4C18.s")
-
-#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Wdhand/func_80AF4C64.s")
-
-#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Wdhand/func_80AF4ED0.s")
-
-#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Wdhand/func_80AF4F30.s")
-
-#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Wdhand/func_80AF4F6C.s")
-
-#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Wdhand/func_80AF4FF8.s")
-
-#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Wdhand/func_80AF5130.s")
-
-#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Wdhand/func_80AF520C.s")
-
-#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Wdhand/func_80AF5650.s")
-
-#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Wdhand/func_80AF56A0.s")
-
-#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Wdhand/func_80AF5820.s")
-
-#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Wdhand/func_80AF5E3C.s")
-
-#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Wdhand/EnWdhand_Update.s")
-
-#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Wdhand/func_80AF5FE4.s")
-
-#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Wdhand/EnWdhand_Draw.s")
+void EnWdhand_Init(Actor* thisx, PlayState* play) {
+ EnWdhand* this = THIS;
+ s32 i;
+ Vec3f initVel;
+
+ SkelAnime_InitFlex(play, &this->skelAnime, &gDexihandSkel, &gDexihandIdleAnim, this->jointTable, this->morphTable,
+ DEXIHAND_LIMB_MAX);
+ CollisionCheck_SetInfo(&this->actor.colChkInfo, &sDamageTable, &sColChkInfoInit);
+
+ // Constructs an affine transformation that maps world origin to actor origin and rotation
+ // (model -> world but without scaling)
+ Matrix_Translate(this->actor.world.pos.x, this->actor.world.pos.y, this->actor.world.pos.z, MTXMODE_NEW);
+ Matrix_RotateYS(this->actor.shape.rot.y, MTXMODE_APPLY);
+ Matrix_RotateXS(this->actor.shape.rot.x, MTXMODE_APPLY);
+ Matrix_RotateZS(this->actor.shape.rot.z, MTXMODE_APPLY);
+ // Get a world position offset by 3 units
+ Matrix_MultVecY(3.0f, &this->endPoints[EN_WDHAND_HAND_POINT]);
+ // Save this matrix for later
+ Matrix_MtxFCopy(&this->relativeToWorldTransform, Matrix_GetCurrent());
+ // Write the rotation back to the actor
+ Matrix_MtxFToYXZRot(&this->relativeToWorldTransform, &this->actor.shape.rot, false);
+ // Transpose the matrix, since it's a rotation matrix this creates the inverse rotation matrix
+ Matrix_Transpose(&this->relativeToWorldTransform);
+
+ this->actor.world.rot.y = this->actor.shape.rot.y;
+
+ EnWdhand_GetInitVelocity(this, &initVel);
+ this->actor.speed = initVel.z;
+ this->actor.velocity.y = initVel.y;
+ this->actor.velocity.x = Math_SinS(this->actor.world.rot.y) * this->actor.speed;
+ this->actor.velocity.z = Math_CosS(this->actor.world.rot.y) * this->actor.speed;
+
+ Collider_InitAndSetJntSph(play, &this->collider, &this->actor, &sJntSphInit, this->colliderElements);
+
+ for (i = 0; i < ARRAY_COUNT(this->colliderElements); i++) {
+ ColliderJntSphElement* elem = &this->collider.elements[i];
+
+ elem->dim.worldSphere.radius = elem->dim.modelSphere.radius;
+ EnWdhand_Vec3fToVec3s(&elem->dim.worldSphere.center, &this->actor.world.pos);
+ }
+
+ for (i = 0; i < EN_WDHAND_NUM_SEGMENTS; i++) {
+ this->limbScaleFactors[i] = 1.0f;
+ }
+
+ this->limbIndexBeforeCut = -1;
+ this->limbIndexAfterCut = 0;
+
+ this->actor.world.rot.x = 0;
+ this->actor.world.rot.z =
+ Math_Atan2S_XY(this->relativeToWorldTransform.mf[2][1], this->relativeToWorldTransform.mf[0][1]);
+ this->actor.hintId = TATL_HINT_ID_DEXIHAND;
+ EnWdhand_SetupIdle(this);
+}
+
+void EnWdhand_Destroy(Actor* thisx, PlayState* play) {
+ EnWdhand* this = THIS;
+
+ Collider_DestroyJntSph(play, &this->collider);
+}
+
+void EnWdhand_GetInitVelocity(EnWdhand* this, Vec3f* dst) {
+ s32 param;
+
+ param = EN_WDHAND_GET_Y_INIT_VELOCITY(&this->actor);
+ if (param == EN_WDHAND_INIT_VELOCITY_MAX) {
+ param = 40;
+ }
+ dst->y = param * 0.2f;
+
+ param = EN_WDHAND_GET_Z_INIT_VELOCITY(&this->actor);
+ if (param == EN_WDHAND_INIT_VELOCITY_MAX) {
+ param = 40;
+ }
+ dst->z = param * 0.2f;
+
+ dst->x = 0.0f;
+}
+
+void EnWdhand_GetRelativeRotationsToPlayerRightFoot(EnWdhand* this, Player* player, s16* pitchOut, s16* yawOut) {
+ Vec3f diffToPlayerRightFoot;
+ Vec3f diffToPlayerRightFootRelative;
+
+ // Get the difference in world positions
+ Math_Vec3f_Diff(&player->bodyPartsPos[PLAYER_BODYPART_RIGHT_FOOT], &this->actor.world.pos, &diffToPlayerRightFoot);
+ // Re-express the difference in actor-relative coordinates
+ Matrix_Put(&this->relativeToWorldTransform);
+ Matrix_MultVec3f(&diffToPlayerRightFoot, &diffToPlayerRightFootRelative);
+ // Return actor-relative yaw and pitch
+ *yawOut = Actor_WorldYawTowardPoint(&this->actor, &diffToPlayerRightFootRelative);
+ *pitchOut = Actor_WorldPitchTowardPoint(&this->actor, &diffToPlayerRightFootRelative) + 0x4000;
+}
+
+void EnWdhand_SetTransform(EnWdhand* this, s32 limbIndex, s32 arg2, Vec3f* translation) {
+ MtxF* currentMatrix = Matrix_GetCurrent();
+
+ Matrix_RotateZYX(this->limbRotations[limbIndex].x, this->limbRotations[limbIndex].y, 0, MTXMODE_APPLY);
+ if (arg2) {
+ Matrix_RotateYS(-this->limbRotations[limbIndex].y, MTXMODE_APPLY);
+ }
+
+ if (limbIndex == DEXIHAND_LIMB_03) {
+ if (this->globalLimbScaleFactor > 1.0f) {
+ f32 scale = CLAMP_MAX(this->globalLimbScaleFactor, 1.5f);
+
+ Matrix_Scale(scale, scale, scale, MTXMODE_APPLY);
+ }
+ } else if ((this->limbScaleFactors[limbIndex] < 1.0f) || (this->globalLimbScaleFactor > 1.0f)) {
+ if (this->limbScaleFactors[limbIndex] < 0.1f) {
+ Matrix_Scale(0.0f, this->globalLimbScaleFactor * this->limbScaleFactors[limbIndex], 0.0f, MTXMODE_APPLY);
+ } else {
+ Matrix_Scale(1.0f, this->globalLimbScaleFactor * this->limbScaleFactors[limbIndex], 1.0f, MTXMODE_APPLY);
+ }
+ }
+
+ currentMatrix->mf[3][0] = translation->x;
+ currentMatrix->mf[3][1] = translation->y;
+ currentMatrix->mf[3][2] = translation->z;
+}
+
+void EnWdhand_Vec3fToVec3s(Vec3s* dst, Vec3f* src) {
+ dst->x = src->x;
+ dst->y = src->y;
+ dst->z = src->z;
+}
+
+s16 EnWdhand_GetLimbXRotation(EnWdhand* this, s32 limbIndex) {
+ return this->limbRotations[limbIndex].z * Math_SinF((this->timer - limbIndex * 20) * (M_PI / 40));
+}
+
+void EnWdhand_SetupIdle(EnWdhand* this) {
+ s32 i;
+
+ Animation_MorphToLoop(&this->skelAnime, &gDexihandIdleAnim, -5.0f);
+
+ if (this->actionFunc != EnWdhand_ReturnToIdle) {
+ this->timer = 80;
+ this->limbRotations[0].y = Rand_Next() >> 16;
+
+ for (i = 1; i < ARRAY_COUNT(this->limbRotations); i++) {
+ this->limbRotations[i].y = this->limbRotations[i - 1].y + (s32)Rand_ZeroFloat(0x2000) + 0x8000;
+ }
+
+ for (i = 0; i < ARRAY_COUNT(this->limbRotations); i++) {
+ this->limbRotations[i].z = Rand_S16Offset(0x1800, 0x1000);
+ }
+ }
+
+ for (i = 0; i < ARRAY_COUNT(this->limbRotations); i++) {
+ this->limbRotations[i].x = EnWdhand_GetLimbXRotation(this, i);
+ }
+
+ this->actionFunc = EnWdhand_Idle;
+ this->globalLimbScaleFactor = 1.0f;
+}
+
+void EnWdhand_Idle(EnWdhand* this, PlayState* play) {
+ Player* player = GET_PLAYER(play);
+ s32 i;
+ s16 pitchToPlayerRightFoot;
+ s16 yawToPlayerRightFoot;
+
+ SkelAnime_Update(&this->skelAnime);
+
+ this->timer--;
+
+ for (i = 0; i < ARRAY_COUNT(this->limbRotations); i++) {
+ this->limbRotations[i].x = EnWdhand_GetLimbXRotation(this, i);
+
+ if (this->timer == 20 * i) {
+ if (i != 0) {
+ this->limbRotations[i].y = this->limbRotations[i - 1].y + (s32)Rand_CenteredFloat(16384.0f);
+ this->limbRotations[i].y -= 0x8000;
+ } else {
+ this->limbRotations[0].y += (s16)(s32)Rand_CenteredFloat(16384.0f);
+ }
+ this->limbRotations[i].z = Rand_S16Offset(0x1800, 0x1000);
+ }
+ }
+
+ if (this->timer == 0) {
+ this->timer = 80;
+ }
+
+ if (!(player->stateFlags2 & PLAYER_STATE2_80) && (this->actor.xyzDistToPlayerSq < SQ(120.75f))) {
+ EnWdhand_GetRelativeRotationsToPlayerRightFoot(this, player, &pitchToPlayerRightFoot, &yawToPlayerRightFoot);
+ if (ABS_ALT(pitchToPlayerRightFoot) <= 0x4000) {
+ EnWdhand_SetupLungeForPlayer(this);
+ }
+ }
+}
+
+void EnWdhand_SetupLungeForPlayer(EnWdhand* this) {
+ Animation_MorphToPlayOnce(&this->skelAnime, &gDexihandOpenAnim, -5.0f);
+ this->timer = 5;
+ this->actionFunc = EnWdhand_LungeForPlayer;
+}
+
+void EnWdhand_LungeForPlayer(EnWdhand* this, PlayState* play) {
+ Player* player = GET_PLAYER(play);
+ s32 allStepsDone = true;
+ s32 i;
+ s16 pitchToPlayerRightFoot;
+ s16 yawToPlayerRightFoot;
+
+ SkelAnime_Update(&this->skelAnime);
+
+ // Only activate the collider and grab check after a short delay
+ if (this->timer > 0) {
+ this->timer--;
+ if (this->timer == 0) {
+ this->collider.base.atFlags |= AT_ON;
+ }
+ return;
+ }
+
+ Math_StepToF(&this->globalLimbScaleFactor, 1.5f, 0.05f);
+ EnWdhand_GetRelativeRotationsToPlayerRightFoot(this, player, &pitchToPlayerRightFoot, &yawToPlayerRightFoot);
+
+ for (i = 0; i < ARRAY_COUNT(this->limbRotations); i++) {
+ s16 yawDiff = yawToPlayerRightFoot - this->limbRotations[i].y;
+
+ if (ABS_ALT(yawDiff) < 0x4000) {
+ allStepsDone &=
+ Math_ScaledStepToS(&this->limbRotations[i].x, pitchToPlayerRightFoot, (i * 0.1f + 1.0f) * 1920.0f);
+ allStepsDone &= Math_ScaledStepToS(&this->limbRotations[i].y, yawToPlayerRightFoot, 0x800);
+ } else {
+ allStepsDone &=
+ Math_ScaledStepToS(&this->limbRotations[i].x, -pitchToPlayerRightFoot, (i * 0.1f + 1.0f) * 1920.0f);
+ allStepsDone &= Math_ScaledStepToS(&this->limbRotations[i].y, yawToPlayerRightFoot + 0x8000, 0x800);
+ }
+ }
+
+ if ((this->collider.base.atFlags & AT_HIT) && play->grabPlayer(play, player)) {
+ // Touched the player, grab
+ EnWdhand_SetupGrabbedPlayer(this, play);
+ } else if (allStepsDone) {
+ // Failed to grab player in time
+ EnWdhand_SetupFailedToGrabPlayer(this);
+ }
+
+ if (this->collider.base.atFlags & AT_HIT) {
+ this->collider.base.atFlags &= ~AT_HIT;
+ }
+}
+
+void EnWdhand_SetupFailedToGrabPlayer(EnWdhand* this) {
+ Animation_PlayOnce(&this->skelAnime, &gDexihandCloseAnim);
+ this->collider.base.atFlags &= ~AT_ON;
+ this->collider.base.atFlags &= ~AT_HIT;
+ this->actionFunc = EnWdhand_FailedToGrabPlayer;
+ this->globalLimbScaleFactor = 1.5f;
+}
+
+void EnWdhand_FailedToGrabPlayer(EnWdhand* this, PlayState* play) {
+ if (SkelAnime_Update(&this->skelAnime)) {
+ EnWdhand_SetupReturnToIdle(this);
+ }
+}
+
+void EnWdhand_SetupReturnToIdle(EnWdhand* this) {
+ s32 i;
+
+ Animation_MorphToLoop(&this->skelAnime, &gDexihandIdleAnim, -10.0f);
+
+ for (i = 0; i < ARRAY_COUNT(this->limbRotations); i++) {
+ this->limbRotations[i].z = Rand_S16Offset(0x1800, 0x1000);
+ }
+ this->timer = 80;
+ this->actionFunc = EnWdhand_ReturnToIdle;
+}
+
+void EnWdhand_ReturnToIdle(EnWdhand* this, PlayState* play) {
+ s32 i;
+ s32 allStepsDone;
+
+ SkelAnime_Update(&this->skelAnime);
+
+ this->timer--;
+
+ allStepsDone = Math_ScaledStepToS(&this->limbRotations[0].x, EnWdhand_GetLimbXRotation(this, 0), 0x200);
+
+ for (i = 1; i < ARRAY_COUNT(this->limbRotations); i++) {
+ allStepsDone &= Math_ScaledStepToS(&this->limbRotations[i].x, EnWdhand_GetLimbXRotation(this, i), 0x300);
+ if (this->timer == 20 * i) {
+ this->limbRotations[i].z = Rand_S16Offset(0x1800, 0x1000);
+ }
+ }
+
+ if (this->timer == 0) {
+ this->timer = 80;
+ this->limbRotations[0].z = Rand_S16Offset(0x1800, 0x1000);
+ }
+
+ Math_StepToF(&this->globalLimbScaleFactor, 1.0f, 0.05f);
+
+ if (allStepsDone) {
+ EnWdhand_SetupIdle(this);
+ }
+}
+
+void EnWdhand_SetupGrabbedPlayer(EnWdhand* this, PlayState* play) {
+ Player* player = GET_PLAYER(play);
+ s32 i;
+
+ this->collider.base.atFlags &= ~AT_ON;
+ this->collider.base.atFlags &= ~AT_HIT;
+ this->collider.base.ocFlags1 &= ~OC1_ON;
+ Animation_PlayOnce(&this->skelAnime, &gDexihandCloseAnim);
+
+ for (i = 0; i < ARRAY_COUNT(this->limbRotations); i++) {
+ this->limbRotations[i].z = Rand_S16Offset(0x2000, 0x1000);
+ }
+ this->timer = 80;
+ player->actor.parent = &this->actor;
+ // Return to original state as set in init, that is relative -> world
+ Matrix_Transpose(&this->relativeToWorldTransform);
+ this->globalLimbScaleFactor = 1.5f;
+
+ Actor_PlaySfx(&this->actor, NA_SE_EN_HANDW_GET);
+ this->actionFunc = EnWdhand_GrabbedPlayer;
+}
+
+void EnWdhand_GrabbedPlayer(EnWdhand* this, PlayState* play) {
+ Player* player = GET_PLAYER(play);
+ s32 i;
+ s32 t;
+
+ SkelAnime_Update(&this->skelAnime);
+
+ this->timer--;
+ player->av2.actionVar2 = 0;
+ t = this->timer;
+
+ for (i = 0; i < ARRAY_COUNT(this->limbRotations); i++) {
+ if (this->timer < 76) {
+ this->limbRotations[i].x = this->limbRotations[i].z * Math_SinF(t * (M_PI / 8));
+ } else {
+ Math_ScaledStepToS(&this->limbRotations[i].x, this->limbRotations[i].z * Math_SinF(t * (M_PI / 8)), 0x400);
+ }
+ if (t % 16 == 0) {
+ if (t == 16) {
+ this->limbRotations[i].y = 0;
+ } else if (i != 0) {
+ this->limbRotations[i].y = this->limbRotations[i - 1].y + (s32)Rand_CenteredFloat(12288.0f);
+ } else {
+ this->limbRotations[0].y += (s16)(s32)Rand_CenteredFloat(12288.0f);
+ }
+ this->limbRotations[i].z = Rand_S16Offset(0x2000, 0x1000);
+ }
+ t += 2;
+ }
+
+ if (this->timer < 4) {
+ Math_StepToF(&this->globalLimbScaleFactor, 1.5f, 1.0f / 8);
+ } else if (this->timer < 16) {
+ Math_StepToF(&this->globalLimbScaleFactor, 2.0f, 1.0f / 24);
+ }
+
+ if (this->timer == 0) {
+ this->collider.base.ocFlags1 |= OC1_ON;
+ EnWdhand_SetupReturnToIdle(this);
+ } else if (this->timer >= 4) {
+ Vec3f limbPos;
+
+ // Create a model -> world matrix
+ Matrix_Put(&this->relativeToWorldTransform);
+ Matrix_Scale(0.01f, 0.01f, 0.01f, MTXMODE_APPLY);
+
+ Matrix_MultVecY(300.0f, &limbPos);
+
+ for (i = 0; i < EN_WDHAND_NUM_SEGMENTS; i++) {
+ Matrix_Push();
+ // Further rotate and translate
+ EnWdhand_SetTransform(this, i, false, &limbPos);
+ Matrix_MultVecY(2300.0f, &limbPos);
+ Matrix_Pop();
+ }
+
+ // Set transform for the hand
+ EnWdhand_SetTransform(this, EN_WDHAND_NUM_SEGMENTS, true, &limbPos);
+ // Copy the hand rotation to player shape rotation
+ Matrix_MtxFToYXZRot(Matrix_GetCurrent(), &player->actor.shape.rot, false);
+
+ if (this->globalLimbScaleFactor > 1.0f) {
+ f32 zRotFactor = CLAMP_MAX(this->globalLimbScaleFactor, 1.5f);
+
+ Matrix_RotateZS((zRotFactor - 1.0f) * -32768.0f, MTXMODE_APPLY);
+ }
+ Matrix_MultVecY(1000.0f, &player->actor.world.pos);
+
+ if ((this->timer == 4) && (player->actor.parent == &this->actor)) {
+ // Throws the player, releasing them
+ player->av2.actionVar2 = 100;
+ player->actor.parent = NULL;
+ // Transpose again
+ Matrix_Transpose(&this->relativeToWorldTransform);
+ player->actor.shape.rot.x = 0;
+ player->actor.shape.rot.z = 0;
+ player->actor.world.pos.x += 2.0f * this->actor.velocity.x;
+ player->actor.world.pos.y += 2.0f * this->actor.velocity.y;
+ player->actor.world.pos.z += 2.0f * this->actor.velocity.z;
+ func_800B8D50(play, &this->actor, this->actor.speed, this->actor.world.rot.y, this->actor.velocity.y, 0);
+ Actor_PlaySfx(&this->actor, NA_SE_EN_HANDW_RELEASE);
+ } else if (this->timer == 2) {
+ Animation_PlayOnce(&this->skelAnime, &object_wdhand_Anim_000364);
+ }
+ }
+}
+
+s32 EnWdhand_ShrinkLimb(EnWdhand* this, s32 limbIndex) {
+ this->limbScaleFactors[limbIndex] -= 0.1f;
+ if (this->limbScaleFactors[limbIndex] <= 0.05f) {
+ this->limbScaleFactors[limbIndex] = 0.05f;
+ return true;
+ }
+ return false;
+}
+
+void EnWdhand_SetupDie(EnWdhand* this) {
+ s32 i;
+
+ this->actor.flags &= ~ACTOR_FLAG_TARGETABLE;
+ this->actor.flags |= ACTOR_FLAG_10;
+
+ // Finds the particular collider that was hit
+ for (i = 0; i < ARRAY_COUNT(this->colliderElements); i++) {
+ if (this->collider.elements[i].info.bumperFlags & BUMP_HIT) {
+ break;
+ }
+ }
+
+ // Record the limb indices immediately to either side of the cut point
+ this->limbIndexAfterCut = ((i + 1) / 2) % 4;
+ this->limbIndexBeforeCut = this->limbIndexAfterCut - 1;
+
+ // Create model -> world transform
+ Matrix_Put(&this->relativeToWorldTransform);
+ Matrix_Scale(0.01f, 0.01f, 0.01f, MTXMODE_APPLY);
+
+ Matrix_MultVecY(300.0f, &this->endPoints[EN_WDHAND_HAND_POINT]);
+
+ for (i = 0; i < this->limbIndexAfterCut; i++) {
+ Matrix_Push();
+ EnWdhand_SetTransform(this, i, false, &this->endPoints[EN_WDHAND_HAND_POINT]);
+ Matrix_MultVecY(2300.0f, &this->endPoints[EN_WDHAND_HAND_POINT]);
+ Matrix_Pop();
+ }
+
+ this->actor.velocity.y = 2.45f;
+ this->actor.velocity.x = 2.0f * Math_SinS(this->actor.world.rot.z);
+ this->actor.velocity.z = 2.0f * Math_CosS(this->actor.world.rot.z);
+ this->timer = 5;
+ this->actionFunc = EnWdhand_Die;
+}
+
+void EnWdhand_Die(EnWdhand* this, PlayState* play) {
+ static Vec3f sEffectVelocity = { 0.0f, 0.0f, 0.0f };
+ static Vec3f sEffectAccel = { 0.0f, 0.05f, 0.0f };
+ Vec3s* handCollider = &this->collider.elements[6].dim.worldSphere.center;
+ Vec3f spA0;
+ Vec3f sp94;
+ s16 effectScale;
+ s32 pointIndex;
+ s32 i;
+ s32 t;
+ Vec3f* endPoint = &this->endPoints[EN_WDHAND_HAND_POINT];
+ s32 limbIndex;
+ Vec3f effPos;
+
+ spA0.x = (endPoint->x - handCollider->x) * 0.5f;
+ spA0.y = (endPoint->y - handCollider->y) * 0.5f;
+ spA0.z = (endPoint->z - handCollider->z) * 0.5f;
+ Matrix_RotateXS(0x100, MTXMODE_NEW);
+ Matrix_MultVec3f(&spA0, &sp94);
+ endPoint->x = spA0.x + sp94.x + handCollider->x;
+ endPoint->y = spA0.y + sp94.y + handCollider->y;
+ endPoint->z = spA0.z + sp94.z + handCollider->z;
+ if (this->actor.velocity.y > -2.0f) {
+ this->actor.velocity.y += -0.15f;
+ }
+ Math_Vec3f_Sum(endPoint, &this->actor.velocity, endPoint);
+
+ this->actor.world.rot.x += 0x100;
+
+ if (this->limbIndexBeforeCut >= 0 && EnWdhand_ShrinkLimb(this, this->limbIndexBeforeCut)) {
+ this->limbIndexBeforeCut--;
+ }
+
+ limbIndex = this->limbIndexAfterCut;
+
+ if (this->limbIndexAfterCut < EN_WDHAND_NUM_SEGMENTS) {
+ if (EnWdhand_ShrinkLimb(this, this->limbIndexAfterCut)) {
+ this->limbIndexAfterCut++;
+ }
+ Matrix_RotateZYX(this->actor.world.rot.x, this->actor.world.rot.z, 0, MTXMODE_NEW);
+ Matrix_RotateYS(-this->actor.world.rot.z, MTXMODE_APPLY);
+ Matrix_Mult(&this->relativeToWorldTransform, MTXMODE_APPLY);
+ EnWdhand_SetTransform(this, limbIndex, false, endPoint);
+ Matrix_MultVecY(2.3f / this->limbScaleFactors[limbIndex], endPoint);
+ }
+
+ this->timer--;
+
+ limbIndex = this->limbIndexBeforeCut + 1;
+ t = this->timer;
+ for (i = 0; i < limbIndex; i++) {
+ if (this->timer > 0) {
+ Math_ScaledStepToS(&this->limbRotations[i].x, this->limbRotations[i].z * Math_SinF(t * (2 * M_PI / 7)),
+ 0x200);
+ } else if (Rand_ZeroOne() < 0.65f) {
+ this->limbRotations[i].x = this->limbRotations[i].z * Math_SinF(t * (2 * M_PI / 7));
+ }
+ if (t % 7 == 0) {
+ if (i != 0) {
+ this->limbRotations[i].y = this->limbRotations[i - 1].y + (s32)Rand_CenteredFloat(12288.0f);
+ } else {
+ this->limbRotations[0].y += (s16)(s32)Rand_CenteredFloat(12288.0f);
+ }
+ this->limbRotations[i].z = Rand_S16Offset(i * 0x100 + 0xC00, 0x800);
+ }
+ t += 2;
+ }
+
+ if ((this->limbIndexBeforeCut < 0) && (this->limbIndexAfterCut >= EN_WDHAND_NUM_SEGMENTS)) {
+ if (Math_StepToF(&this->actor.scale.x, 0.0f, 0.001f)) {
+ for (pointIndex = 0; pointIndex < ARRAY_COUNT(this->endPoints); pointIndex++) {
+ for (i = 0; i < 5; i++) {
+ endPoint = &this->endPoints[pointIndex];
+
+ sEffectVelocity.y = Rand_ZeroOne() + 1.0f;
+ effectScale = Rand_S16Offset(0x28, 0x28);
+ effPos.x = endPoint->x + Rand_CenteredFloat(12.0f);
+ effPos.y = endPoint->y + Rand_CenteredFloat(12.0f);
+ effPos.z = endPoint->z + Rand_CenteredFloat(12.0f);
+ EffectSsDtBubble_SpawnColorProfile(play, &effPos, &sEffectVelocity, &sEffectAccel, effectScale, 25,
+ 2, true);
+ }
+ }
+
+ Actor_Kill(&this->actor);
+ } else {
+ this->actor.scale.z = this->actor.scale.y = this->actor.scale.x;
+ }
+ }
+
+ for (i = 0; i < ARRAY_COUNT(this->endPoints); i++) {
+ sEffectVelocity.y = Rand_ZeroOne() + 1.0f;
+ EffectSsDtBubble_SpawnColorProfile(play, &this->endPoints[i], &sEffectVelocity, &sEffectAccel,
+ Rand_S16Offset(40, 40), 25, 2, true);
+ }
+}
+
+void EnWdhand_UpdateDamage(EnWdhand* this, PlayState* play) {
+ if (this->collider.base.acFlags & AC_HIT) {
+ Player* player = GET_PLAYER(play);
+
+ this->collider.base.acFlags &= ~AT_ON;
+ this->collider.base.acFlags &= ~AC_HIT;
+ this->collider.base.atFlags &= ~AT_ON;
+ this->collider.base.ocFlags1 &= ~AT_ON;
+
+ Actor_SetDropFlagJntSph(&this->actor, &this->collider);
+ Enemy_StartFinishingBlow(play, &this->actor);
+
+ if ((player->stateFlags2 & PLAYER_STATE2_80) && (&this->actor == player->actor.parent)) {
+ // Drop the player
+ player->av2.actionVar2 = 100;
+ player->actor.parent = NULL;
+ player->actor.shape.rot.x = 0;
+ player->actor.shape.rot.z = 0;
+ func_800B8D50(play, &this->actor, this->actor.speed, this->actor.world.rot.y, this->actor.velocity.y, 0);
+ } else {
+ // Only transpose if player is not grabbed, since it is already in the correct state if so.
+ Matrix_Transpose(&this->relativeToWorldTransform);
+ }
+
+ EnWdhand_SetupDie(this);
+ }
+}
+
+void EnWdhand_Update(Actor* thisx, PlayState* play) {
+ EnWdhand* this = THIS;
+
+ EnWdhand_UpdateDamage(this, play);
+
+ this->actionFunc(this, play);
+
+ if (this->collider.base.atFlags & AT_ON) {
+ CollisionCheck_SetAT(play, &play->colChkCtx, &this->collider.base);
+ }
+ if (this->collider.base.acFlags & AC_ON) {
+ CollisionCheck_SetAC(play, &play->colChkCtx, &this->collider.base);
+ }
+ if (this->collider.base.ocFlags1 & OC1_ON) {
+ CollisionCheck_SetOC(play, &play->colChkCtx, &this->collider.base);
+ }
+}
+
+void EnWdhand_UpdateColliderLocationsForLimb(EnWdhand* this, s32 limbIndex, Vec3f* limbPos) {
+ EnWdhand_SetTransform(this, limbIndex, true, limbPos);
+ Matrix_MultVecY(575.0f, limbPos);
+ EnWdhand_Vec3fToVec3s(&this->collider.elements[2 * limbIndex + 0].dim.worldSphere.center, limbPos);
+ Matrix_MultVecY(1725.0f, limbPos);
+ EnWdhand_Vec3fToVec3s(&this->collider.elements[2 * limbIndex + 1].dim.worldSphere.center, limbPos);
+ Matrix_MultVecY(2300.0f, limbPos);
+}
+
+void EnWdhand_Draw(Actor* thisx, PlayState* play) {
+ EnWdhand* this = THIS;
+ Vec3f limbPos;
+ Gfx* gfx;
+ s32 limbIndex;
+ s32 i;
+
+ OPEN_DISPS(play->state.gfxCtx);
+
+ gfx = POLY_OPA_DISP;
+
+ gSPDisplayList(&gfx[0], gSetupDLs[25]);
+ gSPMatrix(&gfx[1], Matrix_NewMtx(play->state.gfxCtx), G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW);
+ gSPDisplayList(&gfx[2], gDexihandBaseDL);
+
+ Matrix_MultVecY(300.0f, &limbPos);
+
+ gfx = &gfx[3];
+
+ limbIndex = this->limbIndexBeforeCut + 1;
+ for (i = 0; i < limbIndex; i++) {
+ Matrix_Push();
+ EnWdhand_UpdateColliderLocationsForLimb(this, i, &limbPos);
+ gSPMatrix(gfx++, Matrix_NewMtx(play->state.gfxCtx), G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW);
+ gSPDisplayList(gfx++, gDexihandArmSegmentDL);
+ Matrix_Pop();
+ }
+
+ Math_Vec3f_Copy(&this->endPoints[EN_WDHAND_CUT_POINT], &limbPos);
+ Math_Vec3f_Copy(&limbPos, &this->endPoints[EN_WDHAND_HAND_POINT]);
+
+ if (this->actor.world.rot.x != 0) {
+ Matrix_RotateZYX(this->actor.world.rot.x, this->actor.world.rot.z, 0, MTXMODE_NEW);
+ Matrix_RotateYS(-this->actor.world.rot.z, MTXMODE_APPLY);
+ Matrix_Mult(&this->relativeToWorldTransform, MTXMODE_APPLY);
+ Matrix_Scale(this->actor.scale.x, this->actor.scale.y, this->actor.scale.z, MTXMODE_APPLY);
+ }
+
+ for (i = this->limbIndexAfterCut; i < EN_WDHAND_NUM_SEGMENTS; i++) {
+ Matrix_Push();
+ EnWdhand_UpdateColliderLocationsForLimb(this, i, &limbPos);
+ gSPMatrix(gfx++, Matrix_NewMtx(play->state.gfxCtx), G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW);
+ gSPDisplayList(gfx++, gDexihandArmSegmentDL);
+ Matrix_Pop();
+ }
+
+ EnWdhand_SetTransform(this, EN_WDHAND_NUM_SEGMENTS, true, &limbPos);
+
+ if (this->globalLimbScaleFactor > 1.0f) {
+ s32 pad;
+ f32 scale = CLAMP_MAX(this->globalLimbScaleFactor, 1.5f);
+
+ Matrix_RotateZS((scale - 1.0f) * -32768.0f, MTXMODE_APPLY);
+ }
+ if (this->actor.scale.x < 0.01f) {
+ Matrix_Translate(0.0f, (10.0f / this->actor.scale.x) - 1000.0f, 0.0f, MTXMODE_APPLY);
+ }
+
+ Math_Vec3f_Copy(&this->actor.focus.pos, &limbPos);
+ Matrix_MultVecY(1000.0f, &limbPos);
+ EnWdhand_Vec3fToVec3s(&this->collider.elements[6].dim.worldSphere.center, &limbPos);
+
+ POLY_OPA_DISP = gfx;
+ SkelAnime_DrawFlexOpa(play, this->skelAnime.skeleton, this->skelAnime.jointTable, this->skelAnime.dListCount, NULL,
+ NULL, &this->actor);
+
+ CLOSE_DISPS(play->state.gfxCtx);
+}
diff --git a/src/overlays/actors/ovl_En_Wdhand/z_en_wdhand.h b/src/overlays/actors/ovl_En_Wdhand/z_en_wdhand.h
index 5eb02fa1a..1d479fc77 100644
--- a/src/overlays/actors/ovl_En_Wdhand/z_en_wdhand.h
+++ b/src/overlays/actors/ovl_En_Wdhand/z_en_wdhand.h
@@ -2,16 +2,38 @@
#define Z_EN_WDHAND_H
#include "global.h"
+#include "objects/object_wdhand/object_wdhand.h"
struct EnWdhand;
typedef void (*EnWdhandActionFunc)(struct EnWdhand*, PlayState*);
+#define EN_WDHAND_NUM_SEGMENTS 3
+#define EN_WDHAND_NUM_COLLIDER_ELEMENTS (2 * EN_WDHAND_NUM_SEGMENTS + 1)
+
+#define EN_WDHAND_CUT_POINT 0
+#define EN_WDHAND_HAND_POINT 1
+
+#define EN_WDHAND_INIT_VELOCITY_MAX 0x7F
+#define EN_WDHAND_GET_Y_INIT_VELOCITY(thisx) (((thisx)->params >> 0) & 0x7F)
+#define EN_WDHAND_GET_Z_INIT_VELOCITY(thisx) (((thisx)->params >> 7) & 0x7F)
+
typedef struct EnWdhand {
/* 0x000 */ Actor actor;
- /* 0x144 */ char unk_144[0xA4];
+ /* 0x144 */ SkelAnime skelAnime;
+ /* 0x188 */ Vec3s jointTable[DEXIHAND_LIMB_MAX];
+ /* 0x1B8 */ Vec3s morphTable[DEXIHAND_LIMB_MAX];
/* 0x1E8 */ EnWdhandActionFunc actionFunc;
- /* 0x1EC */ char unk_1EC[0x268];
+ /* 0x1EC */ s16 limbIndexBeforeCut;
+ /* 0x1EE */ s16 limbIndexAfterCut;
+ /* 0x1F0 */ s16 timer;
+ /* 0x1F2 */ Vec3s limbRotations[EN_WDHAND_NUM_SEGMENTS + 1];
+ /* 0x20C */ f32 globalLimbScaleFactor;
+ /* 0x20C */ f32 limbScaleFactors[EN_WDHAND_NUM_SEGMENTS];
+ /* 0x21C */ MtxF relativeToWorldTransform;
+ /* 0x25C */ Vec3f endPoints[2];
+ /* 0x274 */ ColliderJntSph collider;
+ /* 0x294 */ ColliderJntSphElement colliderElements[EN_WDHAND_NUM_COLLIDER_ELEMENTS];
} EnWdhand; // size = 0x454
#endif // Z_EN_WDHAND_H
diff --git a/tools/disasm/variables.txt b/tools/disasm/variables.txt
index 61d7a39cb..576f0cd53 100644
--- a/tools/disasm/variables.txt
+++ b/tools/disasm/variables.txt
@@ -13198,8 +13198,7 @@
0x80AF64DC:("D_80AF64DC","UNK_TYPE1","",0x1),
0x80AF64EC:("D_80AF64EC","UNK_TYPE1","",0x1),
0x80AF64F4:("D_80AF64F4","UNK_TYPE1","",0x1),
- 0x80AF6514:("D_80AF6514","UNK_TYPE1","",0x1),
- 0x80AF6518:("D_80AF6518","f32","",0x4),
+ 0x80AF6514:("D_80AF6514","Vec3f","",0xC),
0x80AF6520:("D_80AF6520","UNK_TYPE1","",0x1),
0x80AF6530:("D_80AF6530","f32","",0x4),
0x80AF6534:("D_80AF6534","f32","",0x4),