diff options
| author | fig02 <fig02srl@gmail.com> | 2024-03-23 12:21:45 -0400 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2024-03-23 12:21:45 -0400 |
| commit | bd0941405d116ba14efacb6aeccea067958366fe (patch) | |
| tree | 390c14cb27ea407063fd1780bac8d080d65a643e | |
| parent | 07505dae371a99abef82f7ba3b7acc0d5253eeca (diff) | |
Document Player's Face and z_actor FaceChange functions (#1928)
* create some enums
* gonna try struct instead of array
* struct works. add docs too
* inline function comments
* fix function comment
* name faces, move enums
* rename textures
* outnames
* remove comments
* change comment slightly
* fixup face comments
* review
* offset comments
* add and use PLAYER_FACE_MAX
* typo
* more comment on blinkDuration
* another change to the comment
| -rw-r--r-- | assets/xml/objects/object_link_boy.xml | 18 | ||||
| -rw-r--r-- | assets/xml/objects/object_link_child.xml | 18 | ||||
| -rw-r--r-- | include/face_change.h | 12 | ||||
| -rw-r--r-- | include/functions.h | 1 | ||||
| -rw-r--r-- | include/z64actor.h | 2 | ||||
| -rw-r--r-- | include/z64player.h | 49 | ||||
| -rw-r--r-- | src/code/z_actor.c | 69 | ||||
| -rw-r--r-- | src/code/z_player_lib.c | 119 | ||||
| -rw-r--r-- | src/overlays/actors/ovl_player_actor/z_player.c | 4 | ||||
| -rw-r--r-- | tools/disasm/gc-eu-mq/functions.txt | 4 |
10 files changed, 223 insertions, 73 deletions
diff --git a/assets/xml/objects/object_link_boy.xml b/assets/xml/objects/object_link_boy.xml index cbdeaab2d..7e7d50c08 100644 --- a/assets/xml/objects/object_link_boy.xml +++ b/assets/xml/objects/object_link_boy.xml @@ -225,17 +225,17 @@ <Texture Name="gLinkAdultEyesOpenTex" OutName="eyes_open" Format="ci8" Width="64" Height="32" Offset="0x0000" TlutOffset="0x5C00"/> <Texture Name="gLinkAdultEyesHalfTex" OutName="eyes_half" Format="ci8" Width="64" Height="32" Offset="0x0800" TlutOffset="0x5C00"/> <Texture Name="gLinkAdultEyesClosedfTex" OutName="eyes_closed" Format="ci8" Width="64" Height="32" Offset="0x1000" TlutOffset="0x5C00"/> - <Texture Name="gLinkAdultEyesRollLeftTex" OutName="eyes_roll_left" Format="ci8" Width="64" Height="32" Offset="0x1800" TlutOffset="0x5C00"/><!--Left from links perspective--> - <Texture Name="gLinkAdultEyesRollRightTex" OutName="eyes_roll_right" Format="ci8" Width="64" Height="32" Offset="0x2000" TlutOffset="0x5C00"/><!--Right from links perspective--> - <Texture Name="gLinkAdultEyesShockTex" OutName="eyes_shock" Format="ci8" Width="64" Height="32" Offset="0x2800" TlutOffset="0x5C00"/> - <Texture Name="gLinkAdultEyesUnk1Tex" OutName="eyes_unk_1" Format="ci8" Width="64" Height="32" Offset="0x3000" TlutOffset="0x5C00"/> - <Texture Name="gLinkAdultEyesUnk2Tex" OutName="eyes_unk_2" Format="ci8" Width="64" Height="32" Offset="0x3800" TlutOffset="0x5C00"/> + <Texture Name="gLinkAdultEyesLeftTex" OutName="eyes_left" Format="ci8" Width="64" Height="32" Offset="0x1800" TlutOffset="0x5C00"/> + <Texture Name="gLinkAdultEyesRightTex" OutName="eyes_right" Format="ci8" Width="64" Height="32" Offset="0x2000" TlutOffset="0x5C00"/> + <Texture Name="gLinkAdultEyesWideTex" OutName="eyes_wide" Format="ci8" Width="64" Height="32" Offset="0x2800" TlutOffset="0x5C00"/> + <Texture Name="gLinkAdultEyesDownTex" OutName="eyes_down" Format="ci8" Width="64" Height="32" Offset="0x3000" TlutOffset="0x5C00"/> + <Texture Name="gLinkAdultEyesWincingTex" OutName="eyes_wincing" Format="ci8" Width="64" Height="32" Offset="0x3800" TlutOffset="0x5C00"/> <!--Mouth--> - <Texture Name="gLinkAdultMouth1Tex" OutName="mouth_1" Format="ci8" Width="32" Height="32" Offset="0x4000" TlutOffset="0x5C00"/> - <Texture Name="gLinkAdultMouth2Tex" OutName="mouth_2" Format="ci8" Width="32" Height="32" Offset="0x4400" TlutOffset="0x5C00"/> - <Texture Name="gLinkAdultMouth3Tex" OutName="mouth_3" Format="ci8" Width="32" Height="32" Offset="0x4800" TlutOffset="0x5C00"/> - <Texture Name="gLinkAdultMouth4Tex" OutName="mouth_4" Format="ci8" Width="32" Height="32" Offset="0x4C00" TlutOffset="0x5C00"/> + <Texture Name="gLinkAdultMouthClosedTex" OutName="mouth_closed" Format="ci8" Width="32" Height="32" Offset="0x4000" TlutOffset="0x5C00"/> + <Texture Name="gLinkAdultMouthHalfTex" OutName="mouth_half" Format="ci8" Width="32" Height="32" Offset="0x4400" TlutOffset="0x5C00"/> + <Texture Name="gLinkAdultMouthOpenTex" OutName="mouth_open" Format="ci8" Width="32" Height="32" Offset="0x4800" TlutOffset="0x5C00"/> + <Texture Name="gLinkAdultMouthSmileTex" OutName="mouth_smile" Format="ci8" Width="32" Height="32" Offset="0x4C00" TlutOffset="0x5C00"/> <Texture Name="gLinkAdultEarTex" OutName="ear" Format="ci8" Width="16" Height="16" Offset="0x5000" TlutOffset="0x5C00"/> <Texture Name="gLinkAdultNoseTex" OutName="nose" Format="ci8" Width="16" Height="16" Offset="0x5100" TlutOffset="0x5C00"/> diff --git a/assets/xml/objects/object_link_child.xml b/assets/xml/objects/object_link_child.xml index 23a07b385..046be98ff 100644 --- a/assets/xml/objects/object_link_child.xml +++ b/assets/xml/objects/object_link_child.xml @@ -186,17 +186,17 @@ <Texture Name="gLinkChildEyesOpenTex" OutName="eyes_open" Format="ci8" Width="64" Height="32" Offset="0x0000" TlutOffset="0x5500"/> <Texture Name="gLinkChildEyesHalfTex" OutName="eyes_half" Format="ci8" Width="64" Height="32" Offset="0x0800" TlutOffset="0x5500"/> <Texture Name="gLinkChildEyesClosedfTex" OutName="eyes_closed" Format="ci8" Width="64" Height="32" Offset="0x1000" TlutOffset="0x5500"/> - <Texture Name="gLinkChildEyesRollLeftTex" OutName="eyes_roll_left" Format="ci8" Width="64" Height="32" Offset="0x1800" TlutOffset="0x5500"/><!--Left from links perspective--> - <Texture Name="gLinkChildEyesRollRightTex" OutName="eyes_roll_right" Format="ci8" Width="64" Height="32" Offset="0x2000" TlutOffset="0x5500"/><!--Right from links perspective--> - <Texture Name="gLinkChildEyesShockTex" OutName="eyes_shock" Format="ci8" Width="64" Height="32" Offset="0x2800" TlutOffset="0x5500"/> - <Texture Name="gLinkChildEyesUnk1Tex" OutName="eyes_unk_1" Format="ci8" Width="64" Height="32" Offset="0x3000" TlutOffset="0x5500"/> - <Texture Name="gLinkChildEyesUnk2Tex" OutName="eyes_unk_2" Format="ci8" Width="64" Height="32" Offset="0x3800" TlutOffset="0x5500"/> + <Texture Name="gLinkChildEyesLeftTex" OutName="eyes_left" Format="ci8" Width="64" Height="32" Offset="0x1800" TlutOffset="0x5500"/> + <Texture Name="gLinkChildEyesRightTex" OutName="eyes_right" Format="ci8" Width="64" Height="32" Offset="0x2000" TlutOffset="0x5500"/> + <Texture Name="gLinkChildEyesWideTex" OutName="eyes_wide" Format="ci8" Width="64" Height="32" Offset="0x2800" TlutOffset="0x5500"/> + <Texture Name="gLinkChildEyesDownTex" OutName="eyes_down" Format="ci8" Width="64" Height="32" Offset="0x3000" TlutOffset="0x5500"/> + <Texture Name="gLinkChildEyesWincingTex" OutName="eyes_wincing" Format="ci8" Width="64" Height="32" Offset="0x3800" TlutOffset="0x5500"/> <!--Mouth--> - <Texture Name="gLinkChildMouth1Tex" OutName="mouth_1" Format="ci8" Width="32" Height="32" Offset="0x4000" TlutOffset="0x5500"/> - <Texture Name="gLinkChildMouth2Tex" OutName="mouth_2" Format="ci8" Width="32" Height="32" Offset="0x4400" TlutOffset="0x5500"/> - <Texture Name="gLinkChildMouth3Tex" OutName="mouth_3" Format="ci8" Width="32" Height="32" Offset="0x4800" TlutOffset="0x5500"/> - <Texture Name="gLinkChildMouth4Tex" OutName="mouth_4" Format="ci8" Width="32" Height="32" Offset="0x4C00" TlutOffset="0x5500"/> + <Texture Name="gLinkChildMouthClosedTex" OutName="mouth_closed" Format="ci8" Width="32" Height="32" Offset="0x4000" TlutOffset="0x5500"/> + <Texture Name="gLinkChildMouthHalfTex" OutName="mouth_half" Format="ci8" Width="32" Height="32" Offset="0x4400" TlutOffset="0x5500"/> + <Texture Name="gLinkChildMouthOpenTex" OutName="mouth_open" Format="ci8" Width="32" Height="32" Offset="0x4800" TlutOffset="0x5500"/> + <Texture Name="gLinkChildMouthSmileTex" OutName="mouth_smile" Format="ci8" Width="32" Height="32" Offset="0x4C00" TlutOffset="0x5500"/> <!--Unused Vtx--> <Array Name="gLinkChildVtx_019E08" Count="35" Offset="0x19E08" Static="On"> diff --git a/include/face_change.h b/include/face_change.h new file mode 100644 index 000000000..6a5573765 --- /dev/null +++ b/include/face_change.h @@ -0,0 +1,12 @@ +#ifndef FACE_CHANGE_H +#define FACE_CHANGE_H + +typedef struct { + /* 0x00 */ s16 face; + /* 0x02 */ s16 timer; +} FaceChange; // size = 0x4 + +s16 FaceChange_UpdateBlinking(FaceChange* faceChange, s16 blinkIntervalBase, s16 blinkIntervalRandRange, s16 blinkDuration); +s16 FaceChange_UpdateRandomSet(FaceChange* faceChange, s16 changeTimerBase, s16 changeTimerRandRange, s16 faceSetRange); + +#endif diff --git a/include/functions.h b/include/functions.h index 9b3e0bf72..35b378a7a 100644 --- a/include/functions.h +++ b/include/functions.h @@ -443,7 +443,6 @@ Actor* Actor_Delete(ActorContext* actorCtx, Actor* actor, PlayState* play); Actor* func_80032AF0(PlayState* play, ActorContext* actorCtx, Actor** actorPtr, Player* player); Actor* Actor_Find(ActorContext* actorCtx, s32 actorId, s32 actorCategory); void Enemy_StartFinishingBlow(PlayState* play, Actor* actor); -s16 func_80032CB4(s16* arg0, s16 arg1, s16 arg2, s16 arg3); void BodyBreak_Alloc(BodyBreak* bodyBreak, s32 count, PlayState* play); void BodyBreak_SetInfo(BodyBreak* bodyBreak, s32 limbIndex, s32 minLimbIndex, s32 maxLimbIndex, u32 count, Gfx** dList, s16 objectSlot); diff --git a/include/z64actor.h b/include/z64actor.h index 088a90ab7..73643c350 100644 --- a/include/z64actor.h +++ b/include/z64actor.h @@ -134,7 +134,7 @@ typedef struct { typedef struct { /* 0x00 */ Vec3s rot; // Current actor shape rotation - /* 0x06 */ s16 face; // Used to index eyebrow/eye/mouth textures. Only used by player + /* 0x06 */ s16 face; // Used to index eyes and mouth textures. Only used by player /* 0x08 */ f32 yOffset; // Model y axis offset. Represents model space units /* 0x0C */ ActorShadowFunc shadowDraw; // Shadow draw function /* 0x10 */ f32 shadowScale; // Changes the size of the shadow diff --git a/include/z64player.h b/include/z64player.h index f47160bdb..099476ac2 100644 --- a/include/z64player.h +++ b/include/z64player.h @@ -3,6 +3,7 @@ #include "z64actor.h" #include "alignment.h" +#include "face_change.h" struct Player; @@ -229,6 +230,52 @@ typedef enum { } PlayerDoorType; typedef enum { + /* 0 */ PLAYER_FACEPART_EYES, + /* 1 */ PLAYER_FACEPART_MOUTH, + /* 2 */ PLAYER_FACEPART_MAX +} PlayerFacePart; + +typedef enum { + /* 0 */ PLAYER_EYES_OPEN, + /* 1 */ PLAYER_EYES_HALF, + /* 2 */ PLAYER_EYES_CLOSED, + /* 3 */ PLAYER_EYES_LEFT, + /* 4 */ PLAYER_EYES_RIGHT, + /* 5 */ PLAYER_EYES_WIDE, + /* 6 */ PLAYER_EYES_DOWN, + /* 7 */ PLAYER_EYES_WINCING, + /* 8 */ PLAYER_EYES_MAX +} PlayerEyes; + +typedef enum { + /* 0 */ PLAYER_MOUTH_CLOSED, + /* 1 */ PLAYER_MOUTH_HALF, + /* 2 */ PLAYER_MOUTH_OPEN, + /* 3 */ PLAYER_MOUTH_SMILE, + /* 4 */ PLAYER_MOUTH_MAX +} PlayerMouth; + +typedef enum { + /* 0 */ PLAYER_FACE_NEUTRAL, // eyes open and mouth closed + /* 1 */ PLAYER_FACE_NEUTRAL_BLINKING_HALF, // eyes half open and mouth closed + /* 2 */ PLAYER_FACE_NEUTRAL_BLINKING_CLOSED, // eyes and mouth closed + /* 3 */ PLAYER_FACE_NEUTRAL_2, // same as `PLAYER_FACE_NEUTRAL` + /* 4 */ PLAYER_FACE_NEUTRAL_BLINKING_HALF_2, // same as `PLAYER_FACE_NEUTRAL_BLINKING_HALF` + /* 5 */ PLAYER_FACE_NEUTRAL_BLINKING_CLOSED_2, // same as `PLAYER_FACE_NEUTRAL_BLINKING_CLOSED` + /* 6 */ PLAYER_FACE_LOOK_RIGHT, // eyes looking right and mouth closed + /* 7 */ PLAYER_FACE_SURPRISED, // wide eyes and grimacing mouth + /* 8 */ PLAYER_FACE_HURT, // eyes wincing in pain and mouth open + /* 9 */ PLAYER_FACE_GASP, // eyes and mouth open + /* 10 */ PLAYER_FACE_LOOK_LEFT, // eyes looking left and mouth closed + /* 11 */ PLAYER_FACE_LOOK_RIGHT_2, // duplicate of `PLAYER_FACE_LOOK_RIGHT` + /* 12 */ PLAYER_FACE_EYES_CLOSED_MOUTH_OPEN, // eyes closed and mouth open + /* 13 */ PLAYER_FACE_OPENING, // eyes and mouth both halfway open + /* 14 */ PLAYER_FACE_EYES_AND_MOUTH_OPEN, // eyes and mouth open + /* 15 */ PLAYER_FACE_NEUTRAL_3, // same as `PLAYER_FACE_NEUTRAL` and `PLAYER_FACE_NEUTRAL_2` + /* 16 */ PLAYER_FACE_MAX +} PlayerFace; + +typedef enum { /* 0x00 */ PLAYER_MODELGROUP_0, // unused (except for a bug in `Player_OverrideLimbDrawPause`) /* 0x01 */ PLAYER_MODELGROUP_CHILD_HYLIAN_SHIELD, //hold sword only. used for holding sword only as child link with hylian shield equipped /* 0x02 */ PLAYER_MODELGROUP_SWORD_AND_SHIELD, // hold sword and shield or just sword if no shield is equipped @@ -705,7 +752,7 @@ typedef struct Player { /* 0x01F8 */ Vec3s jointTable[PLAYER_LIMB_BUF_COUNT]; /* 0x0288 */ Vec3s morphTable[PLAYER_LIMB_BUF_COUNT]; /* 0x0318 */ Vec3s blendTable[PLAYER_LIMB_BUF_COUNT]; - /* 0x03A8 */ s16 unk_3A8[2]; + /* 0x03A8 */ FaceChange faceChange; /* 0x03AC */ Actor* heldActor; /* 0x03B0 */ Vec3f leftHandPos; /* 0x03BC */ Vec3s unk_3BC; diff --git a/src/code/z_actor.c b/src/code/z_actor.c index d9b7f579c..128fa94d8 100644 --- a/src/code/z_actor.c +++ b/src/code/z_actor.c @@ -3189,33 +3189,64 @@ void Enemy_StartFinishingBlow(PlayState* play, Actor* actor) { SfxSource_PlaySfxAtFixedWorldPos(play, &actor->world.pos, 20, NA_SE_EN_LAST_DAMAGE); } -s16 func_80032CB4(s16* arg0, s16 arg1, s16 arg2, s16 arg3) { - if (DECR(arg0[1]) == 0) { - arg0[1] = Rand_S16Offset(arg1, arg2); - } - - if ((arg0[1] - arg3) > 0) { - arg0[0] = 0; - } else if (((arg0[1] - arg3) > -2) || (arg0[1] < 2)) { - arg0[0] = 1; +/** + * Updates `FaceChange` data for a blinking pattern. + * This system expects that the actor using the system has defined 3 faces in this exact order: + * "eyes open", "eyes half open", "eyes closed". + * + * @param faceChange pointer to an actor's faceChange data + * @param blinkIntervalBase The base number of frames between blinks + * @param blinkIntervalRandRange The range for a random number of frames that can be added to `blinkIntervalBase` + * @param blinkDuration The number of frames it takes for a single blink to occur + */ +s16 FaceChange_UpdateBlinking(FaceChange* faceChange, s16 blinkIntervalBase, s16 blinkIntervalRandRange, + s16 blinkDuration) { + if (DECR(faceChange->timer) == 0) { + faceChange->timer = Rand_S16Offset(blinkIntervalBase, blinkIntervalRandRange); + } + + if ((faceChange->timer - blinkDuration) > 0) { + // `timer - duration` is positive so this is the default state: "eyes open" face + faceChange->face = 0; + } else if (((faceChange->timer - blinkDuration) > -2) || (faceChange->timer < 2)) { + // This condition aims to catch both cases where the "eyes half open" face is needed. + // Note that the comparison assumes the duration of the "eyes half open" phase is 2 frames, irrespective of the + // value of `blinkDuration`. The duration for the "eyes closed" phase is `blinkDuration - 4`. + // For Player's use case `blinkDuration` is 6, so the "eyes closed" phase happens to have + // the same duration as each "eyes half open" phase. + faceChange->face = 1; } else { - arg0[0] = 2; + // If both conditions above fail, the only possibility left is the "eyes closed" face + faceChange->face = 2; } - return arg0[0]; + return faceChange->face; } -s16 func_80032D60(s16* arg0, s16 arg1, s16 arg2, s16 arg3) { - if (DECR(arg0[1]) == 0) { - arg0[1] = Rand_S16Offset(arg1, arg2); - arg0[0]++; - - if ((arg0[0] % 3) == 0) { - arg0[0] = (s32)(Rand_ZeroOne() * arg3) * 3; +/** + * Updates `FaceChange` data for randomly selected face sets. + * Each set contains 3 faces. After the timer runs out, the next face in the set is used. + * After the third face in a set is used, a new face set is randomly chosen. + * + * @param faceChange pointer to an actor's faceChange data + * @param changeTimerBase The base number of frames between each face change + * @param changeTimerRandRange The range for a random number of frames that can be added to `changeTimerBase` + * @param faceSetRange The max number of face sets that will be chosen from + */ +s16 FaceChange_UpdateRandomSet(FaceChange* faceChange, s16 changeTimerBase, s16 changeTimerRandRange, + s16 faceSetRange) { + if (DECR(faceChange->timer) == 0) { + faceChange->timer = Rand_S16Offset(changeTimerBase, changeTimerRandRange); + faceChange->face++; + + if ((faceChange->face % 3) == 0) { + // Randomly chose a "set number", then multiply by 3 because each set has 3 faces. + // This will use the first face in the newly chosen set. + faceChange->face = (s32)(Rand_ZeroOne() * faceSetRange) * 3; } } - return arg0[0]; + return faceChange->face; } void BodyBreak_Alloc(BodyBreak* bodyBreak, s32 count, PlayState* play) { diff --git a/src/code/z_player_lib.c b/src/code/z_player_lib.c index 5fc1c4863..77f0cd035 100644 --- a/src/code/z_player_lib.c +++ b/src/code/z_player_lib.c @@ -813,41 +813,94 @@ s32 Player_GetEnvironmentalHazard(PlayState* play) { return envHazard + 1; } -u8 sEyeMouthIndices[][2] = { - { 0, 0 }, { 1, 0 }, { 2, 0 }, { 0, 0 }, { 1, 0 }, { 2, 0 }, { 4, 0 }, { 5, 1 }, - { 7, 2 }, { 0, 2 }, { 3, 0 }, { 4, 0 }, { 2, 2 }, { 1, 1 }, { 0, 2 }, { 0, 0 }, +u8 sPlayerFaces[PLAYER_FACE_MAX][PLAYER_FACEPART_MAX] = { + // The first 6 faces defined must be default blinking faces. See relevant code in `Player_UpdateCommon`. + { PLAYER_EYES_OPEN, PLAYER_MOUTH_CLOSED }, // PLAYER_FACE_NEUTRAL + { PLAYER_EYES_HALF, PLAYER_MOUTH_CLOSED }, // PLAYER_FACE_NEUTRAL_BLINKING_HALF + { PLAYER_EYES_CLOSED, PLAYER_MOUTH_CLOSED }, // PLAYER_FACE_NEUTRAL_BLINKING_CLOSED + + // This duplicate set of blinking faces is defined because Player will choose between the first and second set + // based on gameplayFrames. See relevant code in `Player_UpdateCommon`. + // This, in theory, allows for psuedo-random variance in the faces used. But in practice, duplicate faces are used. + { PLAYER_EYES_OPEN, PLAYER_MOUTH_CLOSED }, // PLAYER_FACE_NEUTRAL_2 + { PLAYER_EYES_HALF, PLAYER_MOUTH_CLOSED }, // PLAYER_FACE_NEUTRAL_BLINKING_HALF_2 + { PLAYER_EYES_CLOSED, PLAYER_MOUTH_CLOSED }, // PLAYER_FACE_NEUTRAL_BLINKING_CLOSED_2 + + // The rest of these faces go unused. Face data encoded within animations handles all other faces. + { PLAYER_EYES_RIGHT, PLAYER_MOUTH_CLOSED }, // PLAYER_FACE_LOOK_RIGHT + { PLAYER_EYES_WIDE, PLAYER_MOUTH_HALF }, // PLAYER_FACE_SURPRISED + { PLAYER_EYES_WINCING, PLAYER_MOUTH_OPEN }, // PLAYER_FACE_HURT + { PLAYER_EYES_OPEN, PLAYER_MOUTH_OPEN }, // PLAYER_FACE_GASP + { PLAYER_EYES_LEFT, PLAYER_MOUTH_CLOSED }, // PLAYER_FACE_LOOK_LEFT + { PLAYER_EYES_RIGHT, PLAYER_MOUTH_CLOSED }, // PLAYER_FACE_LOOK_RIGHT_2 + { PLAYER_EYES_CLOSED, PLAYER_MOUTH_OPEN }, // PLAYER_FACE_EYES_CLOSED_MOUTH_OPEN + { PLAYER_EYES_HALF, PLAYER_MOUTH_HALF }, // PLAYER_FACE_OPENING + { PLAYER_EYES_OPEN, PLAYER_MOUTH_OPEN }, // PLAYER_FACE_EYES_AND_MOUTH_OPEN + { PLAYER_EYES_OPEN, PLAYER_MOUTH_CLOSED }, // PLAYER_FACE_NEUTRAL_3 }; /** - * Link's eye and mouth textures are placed at the exact same place in adult and child Link's respective object files. + * Link's eyes and mouth textures are placed at the exact same place in adult and child Link's respective object files. * This allows the array to only contain the symbols for one file and have it apply to both. This is a problem for * shiftability, and changes will need to be made in the code to account for this in a modding scenario. The symbols * from adult Link's object are used here. */ #ifndef AVOID_UB -void* sEyeTextures[] = { - gLinkAdultEyesOpenTex, gLinkAdultEyesHalfTex, gLinkAdultEyesClosedfTex, gLinkAdultEyesRollLeftTex, - gLinkAdultEyesRollRightTex, gLinkAdultEyesShockTex, gLinkAdultEyesUnk1Tex, gLinkAdultEyesUnk2Tex, +void* sEyeTextures[PLAYER_EYES_MAX] = { + gLinkAdultEyesOpenTex, // PLAYER_EYES_OPEN + gLinkAdultEyesHalfTex, // PLAYER_EYES_HALF + gLinkAdultEyesClosedfTex, // PLAYER_EYES_CLOSED + gLinkAdultEyesLeftTex, // PLAYER_EYES_LEFT + gLinkAdultEyesRightTex, // PLAYER_EYES_RIGHT + gLinkAdultEyesWideTex, // PLAYER_EYES_WIDE + gLinkAdultEyesDownTex, // PLAYER_EYES_DOWN + gLinkAdultEyesWincingTex, // PLAYER_EYES_WINCING }; -void* sMouthTextures[] = { - gLinkAdultMouth1Tex, - gLinkAdultMouth2Tex, - gLinkAdultMouth3Tex, - gLinkAdultMouth4Tex, +void* sMouthTextures[PLAYER_MOUTH_MAX] = { + gLinkAdultMouthClosedTex, // PLAYER_MOUTH_CLOSED + gLinkAdultMouthHalfTex, // PLAYER_MOUTH_HALF + gLinkAdultMouthOpenTex, // PLAYER_MOUTH_OPEN + gLinkAdultMouthSmileTex, // PLAYER_MOUTH_SMILE }; #else // Defining `AVOID_UB` will use a 2D array instead and properly use the child link pointers to allow for shifting. -void* sEyeTextures[][8] = { - { gLinkAdultEyesOpenTex, gLinkAdultEyesHalfTex, gLinkAdultEyesClosedfTex, gLinkAdultEyesRollLeftTex, - gLinkAdultEyesRollRightTex, gLinkAdultEyesShockTex, gLinkAdultEyesUnk1Tex, gLinkAdultEyesUnk2Tex }, - { gLinkChildEyesOpenTex, gLinkChildEyesHalfTex, gLinkChildEyesClosedfTex, gLinkChildEyesRollLeftTex, - gLinkChildEyesRollRightTex, gLinkChildEyesShockTex, gLinkChildEyesUnk1Tex, gLinkChildEyesUnk2Tex }, +void* sEyeTextures[][PLAYER_EYES_MAX] = { + { + gLinkAdultEyesOpenTex, // PLAYER_EYES_OPEN + gLinkAdultEyesHalfTex, // PLAYER_EYES_HALF + gLinkAdultEyesClosedfTex, // PLAYER_EYES_CLOSED + gLinkAdultEyesLeftTex, // PLAYER_EYES_LEFT + gLinkAdultEyesRightTex, // PLAYER_EYES_RIGHT + gLinkAdultEyesWideTex, // PLAYER_EYES_WIDE + gLinkAdultEyesDownTex, // PLAYER_EYES_DOWN + gLinkAdultEyesWincingTex, // PLAYER_EYES_WINCING + }, + { + gLinkChildEyesOpenTex, // PLAYER_EYES_OPEN + gLinkChildEyesHalfTex, // PLAYER_EYES_HALF + gLinkChildEyesClosedfTex, // PLAYER_EYES_CLOSED + gLinkChildEyesLeftTex, // PLAYER_EYES_LEFT + gLinkChildEyesRightTex, // PLAYER_EYES_RIGHT + gLinkChildEyesWideTex, // PLAYER_EYES_WIDE + gLinkChildEyesDownTex, // PLAYER_EYES_DOWN + gLinkChildEyesWincingTex, // PLAYER_EYES_WINCING + }, }; -void* sMouthTextures[][4] = { - { gLinkAdultMouth1Tex, gLinkAdultMouth2Tex, gLinkAdultMouth3Tex, gLinkAdultMouth4Tex }, - { gLinkChildMouth1Tex, gLinkChildMouth2Tex, gLinkChildMouth3Tex, gLinkChildMouth4Tex }, +void* sMouthTextures[][PLAYER_MOUTH_MAX] = { + { + gLinkAdultMouthClosedTex, // PLAYER_MOUTH_CLOSED + gLinkAdultMouthHalfTex, // PLAYER_MOUTH_HALF + gLinkAdultMouthOpenTex, // PLAYER_MOUTH_OPEN + gLinkAdultMouthSmileTex, // PLAYER_MOUTH_SMILE + }, + { + gLinkChildMouthClosedTex, // PLAYER_MOUTH_CLOSED + gLinkChildMouthHalfTex, // PLAYER_MOUTH_HALF + gLinkChildMouthOpenTex, // PLAYER_MOUTH_OPEN + gLinkChildMouthSmileTex, // PLAYER_MOUTH_SMILE + }, }; #endif @@ -870,23 +923,31 @@ Gfx* sBootDListGroups[][2] = { void Player_DrawImpl(PlayState* play, void** skeleton, Vec3s* jointTable, s32 dListCount, s32 lod, s32 tunic, s32 boots, s32 face, OverrideLimbDrawOpa overrideLimbDraw, PostLimbDrawOpa postLimbDraw, void* data) { Color_RGB8* color; - s32 eyeIndex = (jointTable[22].x & 0xF) - 1; - s32 mouthIndex = (jointTable[22].x >> 4) - 1; + s32 eyesIndex; + s32 mouthIndex; + + // Player's animation data includes eyes and mouth indices for which texture to use on a given frame. + // Despite being accessed as "the x component of the 22nd limb", the eyes and mouth indices are stored in 2 + // additional bytes tacked onto the end of the limb rotation data for a given animation frame. + eyesIndex = (jointTable[22].x & 0xF) - 1; + mouthIndex = (jointTable[22].x >> 4) - 1; OPEN_DISPS(play->state.gfxCtx, "../z_player_lib.c", 1721); - if (eyeIndex < 0) { - eyeIndex = sEyeMouthIndices[face][0]; + // If the eyes index provided by the animation is negative, use the value provided by the `face` argument instead + if (eyesIndex < 0) { + eyesIndex = sPlayerFaces[face][PLAYER_FACEPART_EYES]; } #ifndef AVOID_UB - gSPSegment(POLY_OPA_DISP++, 0x08, SEGMENTED_TO_VIRTUAL(sEyeTextures[eyeIndex])); + gSPSegment(POLY_OPA_DISP++, 0x08, SEGMENTED_TO_VIRTUAL(sEyeTextures[eyesIndex])); #else - gSPSegment(POLY_OPA_DISP++, 0x08, SEGMENTED_TO_VIRTUAL(sEyeTextures[gSaveContext.save.linkAge][eyeIndex])); + gSPSegment(POLY_OPA_DISP++, 0x08, SEGMENTED_TO_VIRTUAL(sEyeTextures[gSaveContext.save.linkAge][eyesIndex])); #endif + // If the mouth index provided by the animation is negative, use the value provided by the `face` argument instead if (mouthIndex < 0) { - mouthIndex = sEyeMouthIndices[face][1]; + mouthIndex = sPlayerFaces[face][PLAYER_FACEPART_MOUTH]; } #ifndef AVOID_UB @@ -1810,8 +1871,8 @@ void Player_DrawPauseImpl(PlayState* play, void* gameplayKeep, void* linkObject, gSPSegment(POLY_OPA_DISP++, 0x0C, gCullBackDList); - Player_DrawImpl(play, skelAnime->skeleton, skelAnime->jointTable, skelAnime->dListCount, 0, tunic, boots, 0, - Player_OverrideLimbDrawPause, NULL, &playerSwordAndShield); + Player_DrawImpl(play, skelAnime->skeleton, skelAnime->jointTable, skelAnime->dListCount, 0, tunic, boots, + PLAYER_FACE_NEUTRAL, Player_OverrideLimbDrawPause, NULL, &playerSwordAndShield); gSPEndDisplayList(POLY_OPA_DISP++); gSPEndDisplayList(POLY_XLU_DISP++); diff --git a/src/overlays/actors/ovl_player_actor/z_player.c b/src/overlays/actors/ovl_player_actor/z_player.c index ece01de63..8e5243059 100644 --- a/src/overlays/actors/ovl_player_actor/z_player.c +++ b/src/overlays/actors/ovl_player_actor/z_player.c @@ -11007,9 +11007,9 @@ void Player_UpdateCommon(Player* this, PlayState* play, Input* input) { } Math_ScaledStepToS(&this->unk_6C2, 0, 400); - func_80032CB4(this->unk_3A8, 20, 80, 6); - this->actor.shape.face = this->unk_3A8[0] + ((play->gameplayFrames & 32) ? 0 : 3); + FaceChange_UpdateBlinking(&this->faceChange, 20, 80, 6); + this->actor.shape.face = this->faceChange.face + ((play->gameplayFrames & 32) ? 0 : 3); if (this->currentMask == PLAYER_MASK_BUNNY) { Player_UpdateBunnyEars(this); diff --git a/tools/disasm/gc-eu-mq/functions.txt b/tools/disasm/gc-eu-mq/functions.txt index 88a45efc3..fef42f92c 100644 --- a/tools/disasm/gc-eu-mq/functions.txt +++ b/tools/disasm/gc-eu-mq/functions.txt @@ -465,8 +465,8 @@ func_800328D4 = 0x800255F8; // type:func func_80032AF0 = 0x80025814; // type:func Actor_Find = 0x80025964; // type:func Enemy_StartFinishingBlow = 0x800259A4; // type:func -func_80032CB4 = 0x800259DC; // type:func -func_80032D60 = 0x80025A90; // type:func +FaceChange_UpdateBlinking = 0x800259DC; // type:func +FaceChange_UpdateRandomSet = 0x80025A90; // type:func BodyBreak_Alloc = 0x80025B5C; // type:func BodyBreak_SetInfo = 0x80025C54; // type:func BodyBreak_SpawnParts = 0x80025D5C; // type:func |
