mirror of
https://github.com/zeldaret/oot.git
synced 2024-12-25 06:06:05 +00:00
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
This commit is contained in:
parent
07505dae37
commit
bd0941405d
10 changed files with 220 additions and 70 deletions
|
@ -225,17 +225,17 @@
|
||||||
<Texture Name="gLinkAdultEyesOpenTex" OutName="eyes_open" Format="ci8" Width="64" Height="32" Offset="0x0000" TlutOffset="0x5C00"/>
|
<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="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="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="gLinkAdultEyesLeftTex" OutName="eyes_left" Format="ci8" Width="64" Height="32" Offset="0x1800" TlutOffset="0x5C00"/>
|
||||||
<Texture Name="gLinkAdultEyesRollRightTex" OutName="eyes_roll_right" Format="ci8" Width="64" Height="32" Offset="0x2000" TlutOffset="0x5C00"/><!--Right from links perspective-->
|
<Texture Name="gLinkAdultEyesRightTex" OutName="eyes_right" Format="ci8" Width="64" Height="32" Offset="0x2000" TlutOffset="0x5C00"/>
|
||||||
<Texture Name="gLinkAdultEyesShockTex" OutName="eyes_shock" Format="ci8" Width="64" Height="32" Offset="0x2800" TlutOffset="0x5C00"/>
|
<Texture Name="gLinkAdultEyesWideTex" OutName="eyes_wide" 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="gLinkAdultEyesDownTex" OutName="eyes_down" 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="gLinkAdultEyesWincingTex" OutName="eyes_wincing" Format="ci8" Width="64" Height="32" Offset="0x3800" TlutOffset="0x5C00"/>
|
||||||
|
|
||||||
<!--Mouth-->
|
<!--Mouth-->
|
||||||
<Texture Name="gLinkAdultMouth1Tex" OutName="mouth_1" Format="ci8" Width="32" Height="32" Offset="0x4000" TlutOffset="0x5C00"/>
|
<Texture Name="gLinkAdultMouthClosedTex" OutName="mouth_closed" 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="gLinkAdultMouthHalfTex" OutName="mouth_half" 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="gLinkAdultMouthOpenTex" OutName="mouth_open" 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="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="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"/>
|
<Texture Name="gLinkAdultNoseTex" OutName="nose" Format="ci8" Width="16" Height="16" Offset="0x5100" TlutOffset="0x5C00"/>
|
||||||
|
|
|
@ -186,17 +186,17 @@
|
||||||
<Texture Name="gLinkChildEyesOpenTex" OutName="eyes_open" Format="ci8" Width="64" Height="32" Offset="0x0000" TlutOffset="0x5500"/>
|
<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="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="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="gLinkChildEyesLeftTex" OutName="eyes_left" Format="ci8" Width="64" Height="32" Offset="0x1800" TlutOffset="0x5500"/>
|
||||||
<Texture Name="gLinkChildEyesRollRightTex" OutName="eyes_roll_right" Format="ci8" Width="64" Height="32" Offset="0x2000" TlutOffset="0x5500"/><!--Right from links perspective-->
|
<Texture Name="gLinkChildEyesRightTex" OutName="eyes_right" Format="ci8" Width="64" Height="32" Offset="0x2000" TlutOffset="0x5500"/>
|
||||||
<Texture Name="gLinkChildEyesShockTex" OutName="eyes_shock" Format="ci8" Width="64" Height="32" Offset="0x2800" TlutOffset="0x5500"/>
|
<Texture Name="gLinkChildEyesWideTex" OutName="eyes_wide" 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="gLinkChildEyesDownTex" OutName="eyes_down" 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="gLinkChildEyesWincingTex" OutName="eyes_wincing" Format="ci8" Width="64" Height="32" Offset="0x3800" TlutOffset="0x5500"/>
|
||||||
|
|
||||||
<!--Mouth-->
|
<!--Mouth-->
|
||||||
<Texture Name="gLinkChildMouth1Tex" OutName="mouth_1" Format="ci8" Width="32" Height="32" Offset="0x4000" TlutOffset="0x5500"/>
|
<Texture Name="gLinkChildMouthClosedTex" OutName="mouth_closed" 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="gLinkChildMouthHalfTex" OutName="mouth_half" 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="gLinkChildMouthOpenTex" OutName="mouth_open" 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="gLinkChildMouthSmileTex" OutName="mouth_smile" Format="ci8" Width="32" Height="32" Offset="0x4C00" TlutOffset="0x5500"/>
|
||||||
|
|
||||||
<!--Unused Vtx-->
|
<!--Unused Vtx-->
|
||||||
<Array Name="gLinkChildVtx_019E08" Count="35" Offset="0x19E08" Static="On">
|
<Array Name="gLinkChildVtx_019E08" Count="35" Offset="0x19E08" Static="On">
|
||||||
|
|
12
include/face_change.h
Normal file
12
include/face_change.h
Normal file
|
@ -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
|
|
@ -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* func_80032AF0(PlayState* play, ActorContext* actorCtx, Actor** actorPtr, Player* player);
|
||||||
Actor* Actor_Find(ActorContext* actorCtx, s32 actorId, s32 actorCategory);
|
Actor* Actor_Find(ActorContext* actorCtx, s32 actorId, s32 actorCategory);
|
||||||
void Enemy_StartFinishingBlow(PlayState* play, Actor* actor);
|
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_Alloc(BodyBreak* bodyBreak, s32 count, PlayState* play);
|
||||||
void BodyBreak_SetInfo(BodyBreak* bodyBreak, s32 limbIndex, s32 minLimbIndex, s32 maxLimbIndex, u32 count, Gfx** dList,
|
void BodyBreak_SetInfo(BodyBreak* bodyBreak, s32 limbIndex, s32 minLimbIndex, s32 maxLimbIndex, u32 count, Gfx** dList,
|
||||||
s16 objectSlot);
|
s16 objectSlot);
|
||||||
|
|
|
@ -134,7 +134,7 @@ typedef struct {
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
/* 0x00 */ Vec3s rot; // Current actor shape rotation
|
/* 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
|
/* 0x08 */ f32 yOffset; // Model y axis offset. Represents model space units
|
||||||
/* 0x0C */ ActorShadowFunc shadowDraw; // Shadow draw function
|
/* 0x0C */ ActorShadowFunc shadowDraw; // Shadow draw function
|
||||||
/* 0x10 */ f32 shadowScale; // Changes the size of the shadow
|
/* 0x10 */ f32 shadowScale; // Changes the size of the shadow
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
|
|
||||||
#include "z64actor.h"
|
#include "z64actor.h"
|
||||||
#include "alignment.h"
|
#include "alignment.h"
|
||||||
|
#include "face_change.h"
|
||||||
|
|
||||||
struct Player;
|
struct Player;
|
||||||
|
|
||||||
|
@ -228,6 +229,52 @@ typedef enum {
|
||||||
/* 3 */ PLAYER_DOORTYPE_FAKE
|
/* 3 */ PLAYER_DOORTYPE_FAKE
|
||||||
} PlayerDoorType;
|
} 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 {
|
typedef enum {
|
||||||
/* 0x00 */ PLAYER_MODELGROUP_0, // unused (except for a bug in `Player_OverrideLimbDrawPause`)
|
/* 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
|
/* 0x01 */ PLAYER_MODELGROUP_CHILD_HYLIAN_SHIELD, //hold sword only. used for holding sword only as child link with hylian shield equipped
|
||||||
|
@ -705,7 +752,7 @@ typedef struct Player {
|
||||||
/* 0x01F8 */ Vec3s jointTable[PLAYER_LIMB_BUF_COUNT];
|
/* 0x01F8 */ Vec3s jointTable[PLAYER_LIMB_BUF_COUNT];
|
||||||
/* 0x0288 */ Vec3s morphTable[PLAYER_LIMB_BUF_COUNT];
|
/* 0x0288 */ Vec3s morphTable[PLAYER_LIMB_BUF_COUNT];
|
||||||
/* 0x0318 */ Vec3s blendTable[PLAYER_LIMB_BUF_COUNT];
|
/* 0x0318 */ Vec3s blendTable[PLAYER_LIMB_BUF_COUNT];
|
||||||
/* 0x03A8 */ s16 unk_3A8[2];
|
/* 0x03A8 */ FaceChange faceChange;
|
||||||
/* 0x03AC */ Actor* heldActor;
|
/* 0x03AC */ Actor* heldActor;
|
||||||
/* 0x03B0 */ Vec3f leftHandPos;
|
/* 0x03B0 */ Vec3f leftHandPos;
|
||||||
/* 0x03BC */ Vec3s unk_3BC;
|
/* 0x03BC */ Vec3s unk_3BC;
|
||||||
|
|
|
@ -3189,33 +3189,64 @@ void Enemy_StartFinishingBlow(PlayState* play, Actor* actor) {
|
||||||
SfxSource_PlaySfxAtFixedWorldPos(play, &actor->world.pos, 20, NA_SE_EN_LAST_DAMAGE);
|
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) {
|
* Updates `FaceChange` data for a blinking pattern.
|
||||||
arg0[1] = Rand_S16Offset(arg1, arg2);
|
* 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 ((arg0[1] - arg3) > 0) {
|
if ((faceChange->timer - blinkDuration) > 0) {
|
||||||
arg0[0] = 0;
|
// `timer - duration` is positive so this is the default state: "eyes open" face
|
||||||
} else if (((arg0[1] - arg3) > -2) || (arg0[1] < 2)) {
|
faceChange->face = 0;
|
||||||
arg0[0] = 1;
|
} 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 {
|
} 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) {
|
* Updates `FaceChange` data for randomly selected face sets.
|
||||||
arg0[1] = Rand_S16Offset(arg1, arg2);
|
* Each set contains 3 faces. After the timer runs out, the next face in the set is used.
|
||||||
arg0[0]++;
|
* 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 ((arg0[0] % 3) == 0) {
|
if ((faceChange->face % 3) == 0) {
|
||||||
arg0[0] = (s32)(Rand_ZeroOne() * arg3) * 3;
|
// 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) {
|
void BodyBreak_Alloc(BodyBreak* bodyBreak, s32 count, PlayState* play) {
|
||||||
|
|
|
@ -813,41 +813,94 @@ s32 Player_GetEnvironmentalHazard(PlayState* play) {
|
||||||
return envHazard + 1;
|
return envHazard + 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
u8 sEyeMouthIndices[][2] = {
|
u8 sPlayerFaces[PLAYER_FACE_MAX][PLAYER_FACEPART_MAX] = {
|
||||||
{ 0, 0 }, { 1, 0 }, { 2, 0 }, { 0, 0 }, { 1, 0 }, { 2, 0 }, { 4, 0 }, { 5, 1 },
|
// The first 6 faces defined must be default blinking faces. See relevant code in `Player_UpdateCommon`.
|
||||||
{ 7, 2 }, { 0, 2 }, { 3, 0 }, { 4, 0 }, { 2, 2 }, { 1, 1 }, { 0, 2 }, { 0, 0 },
|
{ 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
|
* 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
|
* 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.
|
* from adult Link's object are used here.
|
||||||
*/
|
*/
|
||||||
#ifndef AVOID_UB
|
#ifndef AVOID_UB
|
||||||
void* sEyeTextures[] = {
|
void* sEyeTextures[PLAYER_EYES_MAX] = {
|
||||||
gLinkAdultEyesOpenTex, gLinkAdultEyesHalfTex, gLinkAdultEyesClosedfTex, gLinkAdultEyesRollLeftTex,
|
gLinkAdultEyesOpenTex, // PLAYER_EYES_OPEN
|
||||||
gLinkAdultEyesRollRightTex, gLinkAdultEyesShockTex, gLinkAdultEyesUnk1Tex, gLinkAdultEyesUnk2Tex,
|
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[] = {
|
void* sMouthTextures[PLAYER_MOUTH_MAX] = {
|
||||||
gLinkAdultMouth1Tex,
|
gLinkAdultMouthClosedTex, // PLAYER_MOUTH_CLOSED
|
||||||
gLinkAdultMouth2Tex,
|
gLinkAdultMouthHalfTex, // PLAYER_MOUTH_HALF
|
||||||
gLinkAdultMouth3Tex,
|
gLinkAdultMouthOpenTex, // PLAYER_MOUTH_OPEN
|
||||||
gLinkAdultMouth4Tex,
|
gLinkAdultMouthSmileTex, // PLAYER_MOUTH_SMILE
|
||||||
};
|
};
|
||||||
#else
|
#else
|
||||||
// Defining `AVOID_UB` will use a 2D array instead and properly use the child link pointers to allow for shifting.
|
// Defining `AVOID_UB` will use a 2D array instead and properly use the child link pointers to allow for shifting.
|
||||||
void* sEyeTextures[][8] = {
|
void* sEyeTextures[][PLAYER_EYES_MAX] = {
|
||||||
{ gLinkAdultEyesOpenTex, gLinkAdultEyesHalfTex, gLinkAdultEyesClosedfTex, gLinkAdultEyesRollLeftTex,
|
{
|
||||||
gLinkAdultEyesRollRightTex, gLinkAdultEyesShockTex, gLinkAdultEyesUnk1Tex, gLinkAdultEyesUnk2Tex },
|
gLinkAdultEyesOpenTex, // PLAYER_EYES_OPEN
|
||||||
{ gLinkChildEyesOpenTex, gLinkChildEyesHalfTex, gLinkChildEyesClosedfTex, gLinkChildEyesRollLeftTex,
|
gLinkAdultEyesHalfTex, // PLAYER_EYES_HALF
|
||||||
gLinkChildEyesRollRightTex, gLinkChildEyesShockTex, gLinkChildEyesUnk1Tex, gLinkChildEyesUnk2Tex },
|
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] = {
|
void* sMouthTextures[][PLAYER_MOUTH_MAX] = {
|
||||||
{ gLinkAdultMouth1Tex, gLinkAdultMouth2Tex, gLinkAdultMouth3Tex, gLinkAdultMouth4Tex },
|
{
|
||||||
{ gLinkChildMouth1Tex, gLinkChildMouth2Tex, gLinkChildMouth3Tex, gLinkChildMouth4Tex },
|
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
|
#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,
|
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) {
|
s32 face, OverrideLimbDrawOpa overrideLimbDraw, PostLimbDrawOpa postLimbDraw, void* data) {
|
||||||
Color_RGB8* color;
|
Color_RGB8* color;
|
||||||
s32 eyeIndex = (jointTable[22].x & 0xF) - 1;
|
s32 eyesIndex;
|
||||||
s32 mouthIndex = (jointTable[22].x >> 4) - 1;
|
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);
|
OPEN_DISPS(play->state.gfxCtx, "../z_player_lib.c", 1721);
|
||||||
|
|
||||||
if (eyeIndex < 0) {
|
// If the eyes index provided by the animation is negative, use the value provided by the `face` argument instead
|
||||||
eyeIndex = sEyeMouthIndices[face][0];
|
if (eyesIndex < 0) {
|
||||||
|
eyesIndex = sPlayerFaces[face][PLAYER_FACEPART_EYES];
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifndef AVOID_UB
|
#ifndef AVOID_UB
|
||||||
gSPSegment(POLY_OPA_DISP++, 0x08, SEGMENTED_TO_VIRTUAL(sEyeTextures[eyeIndex]));
|
gSPSegment(POLY_OPA_DISP++, 0x08, SEGMENTED_TO_VIRTUAL(sEyeTextures[eyesIndex]));
|
||||||
#else
|
#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
|
#endif
|
||||||
|
|
||||||
|
// If the mouth index provided by the animation is negative, use the value provided by the `face` argument instead
|
||||||
if (mouthIndex < 0) {
|
if (mouthIndex < 0) {
|
||||||
mouthIndex = sEyeMouthIndices[face][1];
|
mouthIndex = sPlayerFaces[face][PLAYER_FACEPART_MOUTH];
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifndef AVOID_UB
|
#ifndef AVOID_UB
|
||||||
|
@ -1810,8 +1871,8 @@ void Player_DrawPauseImpl(PlayState* play, void* gameplayKeep, void* linkObject,
|
||||||
|
|
||||||
gSPSegment(POLY_OPA_DISP++, 0x0C, gCullBackDList);
|
gSPSegment(POLY_OPA_DISP++, 0x0C, gCullBackDList);
|
||||||
|
|
||||||
Player_DrawImpl(play, skelAnime->skeleton, skelAnime->jointTable, skelAnime->dListCount, 0, tunic, boots, 0,
|
Player_DrawImpl(play, skelAnime->skeleton, skelAnime->jointTable, skelAnime->dListCount, 0, tunic, boots,
|
||||||
Player_OverrideLimbDrawPause, NULL, &playerSwordAndShield);
|
PLAYER_FACE_NEUTRAL, Player_OverrideLimbDrawPause, NULL, &playerSwordAndShield);
|
||||||
|
|
||||||
gSPEndDisplayList(POLY_OPA_DISP++);
|
gSPEndDisplayList(POLY_OPA_DISP++);
|
||||||
gSPEndDisplayList(POLY_XLU_DISP++);
|
gSPEndDisplayList(POLY_XLU_DISP++);
|
||||||
|
|
|
@ -11007,9 +11007,9 @@ void Player_UpdateCommon(Player* this, PlayState* play, Input* input) {
|
||||||
}
|
}
|
||||||
|
|
||||||
Math_ScaledStepToS(&this->unk_6C2, 0, 400);
|
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) {
|
if (this->currentMask == PLAYER_MASK_BUNNY) {
|
||||||
Player_UpdateBunnyEars(this);
|
Player_UpdateBunnyEars(this);
|
||||||
|
|
|
@ -465,8 +465,8 @@ func_800328D4 = 0x800255F8; // type:func
|
||||||
func_80032AF0 = 0x80025814; // type:func
|
func_80032AF0 = 0x80025814; // type:func
|
||||||
Actor_Find = 0x80025964; // type:func
|
Actor_Find = 0x80025964; // type:func
|
||||||
Enemy_StartFinishingBlow = 0x800259A4; // type:func
|
Enemy_StartFinishingBlow = 0x800259A4; // type:func
|
||||||
func_80032CB4 = 0x800259DC; // type:func
|
FaceChange_UpdateBlinking = 0x800259DC; // type:func
|
||||||
func_80032D60 = 0x80025A90; // type:func
|
FaceChange_UpdateRandomSet = 0x80025A90; // type:func
|
||||||
BodyBreak_Alloc = 0x80025B5C; // type:func
|
BodyBreak_Alloc = 0x80025B5C; // type:func
|
||||||
BodyBreak_SetInfo = 0x80025C54; // type:func
|
BodyBreak_SetInfo = 0x80025C54; // type:func
|
||||||
BodyBreak_SpawnParts = 0x80025D5C; // type:func
|
BodyBreak_SpawnParts = 0x80025D5C; // type:func
|
||||||
|
|
Loading…
Reference in a new issue