diff --git a/assets/xml/objects/object_link_boy.xml b/assets/xml/objects/object_link_boy.xml index cbdeaab2dc..7e7d50c08f 100644 --- a/assets/xml/objects/object_link_boy.xml +++ b/assets/xml/objects/object_link_boy.xml @@ -225,17 +225,17 @@ - - - - - + + + + + - - - - + + + + diff --git a/assets/xml/objects/object_link_child.xml b/assets/xml/objects/object_link_child.xml index 23a07b3855..046be98ff3 100644 --- a/assets/xml/objects/object_link_child.xml +++ b/assets/xml/objects/object_link_child.xml @@ -186,17 +186,17 @@ - - - - - + + + + + - - - - + + + + diff --git a/assets/xml/scenes/dungeons/ganon_tou.xml b/assets/xml/scenes/dungeons/ganon_tou.xml index 6642a89020..11b67b47e7 100644 --- a/assets/xml/scenes/dungeons/ganon_tou.xml +++ b/assets/xml/scenes/dungeons/ganon_tou.xml @@ -3,6 +3,7 @@ + diff --git a/assets/xml/scenes/dungeons/jyasinzou.xml b/assets/xml/scenes/dungeons/jyasinzou.xml index 556f99900a..5614bc8936 100644 --- a/assets/xml/scenes/dungeons/jyasinzou.xml +++ b/assets/xml/scenes/dungeons/jyasinzou.xml @@ -4,6 +4,8 @@ + + diff --git a/assets/xml/scenes/indoors/daiyousei_izumi.xml b/assets/xml/scenes/indoors/daiyousei_izumi.xml index e9c8d7ef52..0c5ce31435 100644 --- a/assets/xml/scenes/indoors/daiyousei_izumi.xml +++ b/assets/xml/scenes/indoors/daiyousei_izumi.xml @@ -4,6 +4,7 @@ + diff --git a/assets/xml/scenes/indoors/hairal_niwa.xml b/assets/xml/scenes/indoors/hairal_niwa.xml index ff8fab363a..2ae5add651 100644 --- a/assets/xml/scenes/indoors/hairal_niwa.xml +++ b/assets/xml/scenes/indoors/hairal_niwa.xml @@ -2,6 +2,7 @@ + diff --git a/assets/xml/scenes/misc/hiral_demo.xml b/assets/xml/scenes/misc/hiral_demo.xml index 1331fdd4c5..32c55fac4b 100644 --- a/assets/xml/scenes/misc/hiral_demo.xml +++ b/assets/xml/scenes/misc/hiral_demo.xml @@ -1,6 +1,9 @@ + + + diff --git a/assets/xml/scenes/overworld/spot00.xml b/assets/xml/scenes/overworld/spot00.xml index 7e94ff3a61..0ffdc18871 100644 --- a/assets/xml/scenes/overworld/spot00.xml +++ b/assets/xml/scenes/overworld/spot00.xml @@ -9,6 +9,7 @@ + diff --git a/assets/xml/scenes/overworld/spot15.xml b/assets/xml/scenes/overworld/spot15.xml index f17e76d55a..3998cdc42a 100644 --- a/assets/xml/scenes/overworld/spot15.xml +++ b/assets/xml/scenes/overworld/spot15.xml @@ -2,6 +2,7 @@ + diff --git a/assets/xml/scenes/overworld/spot16.xml b/assets/xml/scenes/overworld/spot16.xml index b6a105c655..57a64323b2 100644 --- a/assets/xml/scenes/overworld/spot16.xml +++ b/assets/xml/scenes/overworld/spot16.xml @@ -5,6 +5,7 @@ + diff --git a/include/face_change.h b/include/face_change.h new file mode 100644 index 0000000000..6a5573765a --- /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 9b3e0bf72c..35b378a7a8 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 088a90ab75..73643c3508 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/z64cutscene_commands.h b/include/z64cutscene_commands.h index d77416cf58..5de3d3c835 100644 --- a/include/z64cutscene_commands.h +++ b/include/z64cutscene_commands.h @@ -121,10 +121,10 @@ * The lighting change will take place immediately with no blending. * @note `endFrame` is not used in the implementation of the command, so its value does not matter */ -#define CS_LIGHT_SETTING(lightSetting, startFrame, endFrame, unused0, unused1, unused2, unused3, unused4, unused5, unused6, unused7) \ +#define CS_LIGHT_SETTING(lightSetting, startFrame, endFrame, unused0, unused1, unused2, unused3, unused4, unused5, unused6, unused7, unused8, unused9, unused10) \ CMD_BBH(0, (lightSetting + 1), startFrame), CMD_HH(endFrame, unused0), \ CMD_W(unused1), CMD_W(unused2), CMD_W(unused3), CMD_W(unused4), CMD_W(unused5), \ - CMD_W(unused6), CMD_W(unused7), 0x00000000, 0x00000000, 0x00000000 + CMD_W(unused6), CMD_W(unused7), CMD_W(unused8), CMD_W(unused9), CMD_W(unused10) /** * Declares a list of `CS_RUMBLE_CONTROLLER` entries. diff --git a/include/z64player.h b/include/z64player.h index f47160bdba..099476ac26 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; @@ -228,6 +229,52 @@ typedef enum { /* 3 */ PLAYER_DOORTYPE_FAKE } 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 @@ -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/audio/general.c b/src/audio/general.c index 46c3252781..83ada03616 100644 --- a/src/audio/general.c +++ b/src/audio/general.c @@ -100,7 +100,11 @@ f32 D_801305E4[4] = { 1.0f, 1.12246f, 1.33484f, 1.33484f }; // 2**({0, 2, 5, 5}/ f32 D_801305F4 = 1.0f; u8 sGanonsTowerLevelsVol[8] = { 127, 80, 75, 73, 70, 68, 65, 60 }; u8 sEnterGanonsTowerTimer = 0; +#if OOT_DEBUG s8 sSoundMode = SOUNDMODE_SURROUND; +#else +s8 sSoundMode = SOUNDMODE_STEREO; +#endif s8 D_80130608 = 0; s8 sAudioCutsceneFlag = 0; s8 sSpecReverb = 0; diff --git a/src/boot/build.c b/src/boot/build.c index ee6de4e7a5..91585b4ebe 100644 --- a/src/boot/build.c +++ b/src/boot/build.c @@ -1,3 +1,10 @@ const char gBuildTeam[] = "zelda@srd022j"; + +// TODO: Use per-version preprocessor defines +#if OOT_DEBUG // gc-eu-mq-dbg const char gBuildDate[] = "03-02-21 00:16:31"; +#else // gc-eu-mq +const char gBuildDate[] = "03-02-21 20:37:19"; +#endif + const char gBuildMakeOption[] = ""; diff --git a/src/code/code_800FC620.c b/src/code/code_800FC620.c index 462179b388..eafbe5080e 100644 --- a/src/code/code_800FC620.c +++ b/src/code/code_800FC620.c @@ -13,7 +13,11 @@ typedef struct InitFunc { // .data void* sInitFuncs = NULL; +#if OOT_DEBUG char sNew[] = "new"; +#else +char sNew[] = ""; +#endif char D_80134488[0x18] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7F, 0x80, 0x00, 0x00, diff --git a/src/code/z_actor.c b/src/code/z_actor.c index d9b7f579c5..128fa94d87 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); +/** + * 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 ((arg0[1] - arg3) > 0) { - arg0[0] = 0; - } else if (((arg0[1] - arg3) > -2) || (arg0[1] < 2)) { - arg0[0] = 1; + 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]++; +/** + * 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 ((arg0[0] % 3) == 0) { - arg0[0] = (s32)(Rand_ZeroOne() * arg3) * 3; + 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 5fc1c4863d..77f0cd0356 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_Bg_Toki_Swd/z_bg_toki_swd_cutscene_data_1.c b/src/overlays/actors/ovl_Bg_Toki_Swd/z_bg_toki_swd_cutscene_data_1.c index a435e36abe..f6f5e3da76 100644 --- a/src/overlays/actors/ovl_Bg_Toki_Swd/z_bg_toki_swd_cutscene_data_1.c +++ b/src/overlays/actors/ovl_Bg_Toki_Swd/z_bg_toki_swd_cutscene_data_1.c @@ -7,7 +7,7 @@ CutsceneData D_808BB2F0[] = { CS_PLAYER_CUE_LIST(1), CS_PLAYER_CUE(PLAYER_CUEID_12, 0, 256, 0x0000, 0x0000, 0x0000, 0, 54, 52, 0, 54, 52, CS_FLOAT(0x0, 0.0f), CS_FLOAT(0x0, 0.0f), CS_FLOAT(0x0, 0.0f)), CS_LIGHT_SETTING_LIST(1), - CS_LIGHT_SETTING(0x0001, 110, 111, 0x0000, 0x00000000, 0x00000000, 0xFFFFFFE3, 0xFFFFFFC5, 0x00000000, 0xFFFFFFE3, 0xFFFFFFC5), + CS_LIGHT_SETTING(0x0001, 110, 111, 0x0000, 0x00000000, 0x00000000, 0xFFFFFFE3, 0xFFFFFFC5, 0x00000000, 0xFFFFFFE3, 0xFFFFFFC5, 0x00000000, 0x00000000, 0x00000000), CS_MISC_LIST(1), CS_MISC(CS_MISC_SET_CSFLAG_1, 110, 111, 0x0000, 0x00000000, 0x00000000, 0x0000002E, 0xFFFFFFE6, 0x00000000, 0x0000002E, 0xFFFFFFE6, 0x00000000, 0x00000000, 0x00000000), CS_DESTINATION(CS_DEST_TEMPLE_OF_TIME_FROM_MASTER_SWORD, 230, 231), diff --git a/src/overlays/actors/ovl_Bg_Toki_Swd/z_bg_toki_swd_cutscene_data_2.c b/src/overlays/actors/ovl_Bg_Toki_Swd/z_bg_toki_swd_cutscene_data_2.c index ca1686e28a..ca4c06b775 100644 --- a/src/overlays/actors/ovl_Bg_Toki_Swd/z_bg_toki_swd_cutscene_data_2.c +++ b/src/overlays/actors/ovl_Bg_Toki_Swd/z_bg_toki_swd_cutscene_data_2.c @@ -89,7 +89,7 @@ CutsceneData D_808BB7A0[] = { CS_PLAYER_CUE_LIST(1), CS_PLAYER_CUE(PLAYER_CUEID_12, 0, 180, 0x0000, 0x0000, 0x0000, 0, 28, -10, 0, -14, 9, CS_FLOAT(0x0, 0.0f), CS_FLOAT(0xBE6EEEEF, -0.23333333f), CS_FLOAT(0x0, 0.0f)), CS_LIGHT_SETTING_LIST(1), - CS_LIGHT_SETTING(0x0001, 90, 91, 0x0000, 0x00000000, 0x00000000, 0xFFFFFFF2, 0x00000024, 0x00000000, 0xFFFFFFF2, 0x00000024), + CS_LIGHT_SETTING(0x0001, 90, 91, 0x0000, 0x00000000, 0x00000000, 0xFFFFFFF2, 0x00000024, 0x00000000, 0xFFFFFFF2, 0x00000024, 0x00000000, 0x00000000, 0x00000000), CS_MISC_LIST(1), CS_MISC(CS_MISC_SET_CSFLAG_1, 90, 91, 0x0000, 0x00000000, 0x00000000, 0xFFFFFFF8, 0xFFFFFFDD, 0x00000000, 0xFFFFFFF8, 0xFFFFFFDD, 0x00000000, 0x00000000, 0x00000000), CS_TRANSITION(CS_TRANS_GRAY_FILL_IN, 190, 210), diff --git a/src/overlays/actors/ovl_Demo_Du/z_demo_du_cutscene_data.inc.c b/src/overlays/actors/ovl_Demo_Du/z_demo_du_cutscene_data.inc.c index 7e90542d83..37506612a3 100644 --- a/src/overlays/actors/ovl_Demo_Du/z_demo_du_cutscene_data.inc.c +++ b/src/overlays/actors/ovl_Demo_Du/z_demo_du_cutscene_data.inc.c @@ -25,8 +25,8 @@ static CutsceneData D_8096C1A4[] = { CS_TRANSITION(CS_TRANS_GRAY_FILL_IN, 530, 539), CS_TRANSITION(CS_TRANS_GRAY_FILL_OUT, 540, 570), CS_LIGHT_SETTING_LIST(2), - CS_LIGHT_SETTING(0x0000, 0, 10, 0x0000, 0x00000000, 0xFFFFFFDC, 0x00000000, 0x00000018, 0xFFFFFFDC, 0x00000000, 0x00000018), - CS_LIGHT_SETTING(0x0000, 10, 3000, 0x0000, 0x00000000, 0xFFFFFFDC, 0x00000000, 0x00000018, 0xFFFFFFDC, 0x00000000, 0x00000018), + CS_LIGHT_SETTING(0x0000, 0, 10, 0x0000, 0x00000000, 0xFFFFFFDC, 0x00000000, 0x00000018, 0xFFFFFFDC, 0x00000000, 0x00000018, 0x00000000, 0x00000000, 0x00000000), + CS_LIGHT_SETTING(0x0000, 10, 3000, 0x0000, 0x00000000, 0xFFFFFFDC, 0x00000000, 0x00000018, 0xFFFFFFDC, 0x00000000, 0x00000018, 0x00000000, 0x00000000, 0x00000000), CS_ACTOR_CUE_LIST(39, 1), CS_ACTOR_CUE(0x0001, 0, 3000, 0x0000, 0x0000, 0x0000, 0, 0, -2, 0, 0, -2, CS_FLOAT(0x0, 0.0f), CS_FLOAT(0x0, 0.0f), CS_FLOAT(0x0, 0.0f)), CS_TRANSITION(CS_TRANS_GRAY_FILL_IN, 805, 835), diff --git a/src/overlays/actors/ovl_Demo_Im/z_demo_im.c b/src/overlays/actors/ovl_Demo_Im/z_demo_im.c index b274d4182b..8d85486225 100644 --- a/src/overlays/actors/ovl_Demo_Im/z_demo_im.c +++ b/src/overlays/actors/ovl_Demo_Im/z_demo_im.c @@ -58,7 +58,9 @@ static void* sEyeTextures[] = { gImpaEyeClosedTex, }; +#if OOT_DEBUG static u32 D_8098783C = 0; +#endif static ColliderCylinderInitType1 sCylinderInit = { { diff --git a/src/overlays/actors/ovl_Demo_Im/z_demo_im_cutscene_data.inc.c b/src/overlays/actors/ovl_Demo_Im/z_demo_im_cutscene_data.inc.c index 96df8b6c4a..46b08bc125 100644 --- a/src/overlays/actors/ovl_Demo_Im/z_demo_im_cutscene_data.inc.c +++ b/src/overlays/actors/ovl_Demo_Im/z_demo_im_cutscene_data.inc.c @@ -23,8 +23,8 @@ static CutsceneData D_8098786C[] = { CS_ACTOR_CUE_LIST(49, 1), CS_ACTOR_CUE(0x0001, 0, 3000, 0x0000, 0x0000, 0x0000, -22, 0, -55, -22, 0, -55, CS_FLOAT(0x0, 0.0f), CS_FLOAT(0x0, 0.0f), CS_FLOAT(0x0, 0.0f)), CS_LIGHT_SETTING_LIST(2), - CS_LIGHT_SETTING(0x0001, 0, 10, 0x0000, 0x00000000, 0xFFFFFFFE, 0x00000000, 0x0000000D, 0xFFFFFFFE, 0x00000000, 0x0000000D), - CS_LIGHT_SETTING(0x0001, 10, 3000, 0x0000, 0x00000000, 0xFFFFFFFE, 0x00000000, 0x0000000D, 0xFFFFFFFE, 0x00000000, 0x0000000D), + CS_LIGHT_SETTING(0x0001, 0, 10, 0x0000, 0x00000000, 0xFFFFFFFE, 0x00000000, 0x0000000D, 0xFFFFFFFE, 0x00000000, 0x0000000D, 0x00000000, 0x00000000, 0x00000000), + CS_LIGHT_SETTING(0x0001, 10, 3000, 0x0000, 0x00000000, 0xFFFFFFFE, 0x00000000, 0x0000000D, 0xFFFFFFFE, 0x00000000, 0x0000000D, 0x00000000, 0x00000000, 0x00000000), CS_TRANSITION(CS_TRANS_GRAY_FILL_OUT, 694, 724), CS_TRANSITION(CS_TRANS_GRAY_FILL_IN, 960, 990), CS_TRANSITION(CS_TRANS_GRAY_FILL_IN, 683, 692), diff --git a/src/overlays/actors/ovl_Demo_Sa/z_demo_sa.c b/src/overlays/actors/ovl_Demo_Sa/z_demo_sa.c index ba19c5c25d..b930f0365a 100644 --- a/src/overlays/actors/ovl_Demo_Sa/z_demo_sa.c +++ b/src/overlays/actors/ovl_Demo_Sa/z_demo_sa.c @@ -69,7 +69,9 @@ static void* sMouthTextures[] = { gSariaMouthSmilingOpenTex, gSariaMouthFrowningTex, }; +#if OOT_DEBUG static u32 D_80990108 = 0; +#endif #include "z_demo_sa_cutscene_data.inc.c" diff --git a/src/overlays/actors/ovl_En_Nb/z_en_nb.c b/src/overlays/actors/ovl_En_Nb/z_en_nb.c index 5c0631fb69..336aad8d15 100644 --- a/src/overlays/actors/ovl_En_Nb/z_en_nb.c +++ b/src/overlays/actors/ovl_En_Nb/z_en_nb.c @@ -83,7 +83,9 @@ static void* sEyeTextures[] = { gNabooruEyeClosedTex, }; +#if OOT_DEBUG static s32 D_80AB4318 = 0; +#endif #include "z_en_nb_cutscene_data.inc.c" diff --git a/src/overlays/actors/ovl_En_Nb/z_en_nb_cutscene_data.inc.c b/src/overlays/actors/ovl_En_Nb/z_en_nb_cutscene_data.inc.c index 7c057a84cc..13614e7c31 100644 --- a/src/overlays/actors/ovl_En_Nb/z_en_nb_cutscene_data.inc.c +++ b/src/overlays/actors/ovl_En_Nb/z_en_nb_cutscene_data.inc.c @@ -19,7 +19,7 @@ static CutsceneData D_80AB431C[] = { CS_ACTOR_CUE_LIST(49, 1), CS_ACTOR_CUE(0x0001, 0, 3000, 0x0000, 0x0000, 0x0000, 0, -16, -121, 0, -16, -121, CS_FLOAT(0x0, 0.0f), CS_FLOAT(0x0, 0.0f), CS_FLOAT(0x0, 0.0f)), CS_LIGHT_SETTING_LIST(1), - CS_LIGHT_SETTING(0x0003, 0, 3000, 0x0000, 0x00000000, 0xFFFFFF9E, 0x00000000, 0x0000002F, 0xFFFFFF9E, 0x00000000, 0x0000002F), + CS_LIGHT_SETTING(0x0003, 0, 3000, 0x0000, 0x00000000, 0xFFFFFF9E, 0x00000000, 0x0000002F, 0xFFFFFF9E, 0x00000000, 0x0000002F, 0x00000000, 0x00000000, 0x00000000), CS_ACTOR_CUE_LIST(39, 1), CS_ACTOR_CUE(0x0001, 0, 3000, 0x0000, 0x0000, 0x0000, 0, 0, -2, 0, 0, -2, CS_FLOAT(0x0, 0.0f), CS_FLOAT(0x0, 0.0f), CS_FLOAT(0x0, 0.0f)), CS_ACTOR_CUE_LIST(40, 3), diff --git a/src/overlays/actors/ovl_En_Ru2/z_en_ru2.c b/src/overlays/actors/ovl_En_Ru2/z_en_ru2.c index 00cb959f12..c2c23b2b90 100644 --- a/src/overlays/actors/ovl_En_Ru2/z_en_ru2.c +++ b/src/overlays/actors/ovl_En_Ru2/z_en_ru2.c @@ -61,7 +61,9 @@ static void* sEyeTextures[] = { gAdultRutoEyeClosedTex, }; +#if OOT_DEBUG static UNK_TYPE D_80AF4118 = 0; +#endif #include "z_en_ru2_cutscene_data.inc.c" diff --git a/src/overlays/actors/ovl_En_Ru2/z_en_ru2_cutscene_data.inc.c b/src/overlays/actors/ovl_En_Ru2/z_en_ru2_cutscene_data.inc.c index 42538a1e0a..5a46e41014 100644 --- a/src/overlays/actors/ovl_En_Ru2/z_en_ru2_cutscene_data.inc.c +++ b/src/overlays/actors/ovl_En_Ru2/z_en_ru2_cutscene_data.inc.c @@ -21,11 +21,11 @@ static CutsceneData D_80AF411C[] = { CS_ACTOR_CUE_LIST(49, 1), CS_ACTOR_CUE(0x0001, 0, 3000, 0x0000, 0x0000, 0x0000, 0, -16, -121, 0, -16, -121, CS_FLOAT(0x0, 0.0f), CS_FLOAT(0x0, 0.0f), CS_FLOAT(0x0, 0.0f)), CS_LIGHT_SETTING_LIST(5), - CS_LIGHT_SETTING(0x0004, 0, 384, 0x0000, 0x00000000, 0xFFFFFFA1, 0x00000000, 0x00000058, 0xFFFFFFA1, 0x00000000, 0x00000058), - CS_LIGHT_SETTING(0x0005, 384, 454, 0x0000, 0x00000000, 0xFFFFFFA1, 0x00000000, 0x00000058, 0xFFFFFFA1, 0x00000000, 0x00000058), - CS_LIGHT_SETTING(0x0004, 454, 554, 0x0000, 0x00000000, 0xFFFFFFA1, 0x00000000, 0x00000058, 0xFFFFFFA1, 0x00000000, 0x00000058), - CS_LIGHT_SETTING(0x0005, 554, 624, 0x0000, 0x00000000, 0xFFFFFFA1, 0x00000000, 0x00000058, 0xFFFFFFA1, 0x00000000, 0x00000058), - CS_LIGHT_SETTING(0x0004, 624, 3001, 0x0000, 0x00000000, 0xFFFFFFA1, 0x00000000, 0x00000058, 0xFFFFFFA1, 0x00000000, 0x00000058), + CS_LIGHT_SETTING(0x0004, 0, 384, 0x0000, 0x00000000, 0xFFFFFFA1, 0x00000000, 0x00000058, 0xFFFFFFA1, 0x00000000, 0x00000058, 0x00000000, 0x00000000, 0x00000000), + CS_LIGHT_SETTING(0x0005, 384, 454, 0x0000, 0x00000000, 0xFFFFFFA1, 0x00000000, 0x00000058, 0xFFFFFFA1, 0x00000000, 0x00000058, 0x00000000, 0x00000000, 0x00000000), + CS_LIGHT_SETTING(0x0004, 454, 554, 0x0000, 0x00000000, 0xFFFFFFA1, 0x00000000, 0x00000058, 0xFFFFFFA1, 0x00000000, 0x00000058, 0x00000000, 0x00000000, 0x00000000), + CS_LIGHT_SETTING(0x0005, 554, 624, 0x0000, 0x00000000, 0xFFFFFFA1, 0x00000000, 0x00000058, 0xFFFFFFA1, 0x00000000, 0x00000058, 0x00000000, 0x00000000, 0x00000000), + CS_LIGHT_SETTING(0x0004, 624, 3001, 0x0000, 0x00000000, 0xFFFFFFA1, 0x00000000, 0x00000058, 0xFFFFFFA1, 0x00000000, 0x00000058, 0x00000000, 0x00000000, 0x00000000), CS_ACTOR_CUE_LIST(39, 1), CS_ACTOR_CUE(0x0001, 0, 3000, 0x0000, 0x0000, 0x0000, 0, 0, -2, 0, 0, -2, CS_FLOAT(0x0, 0.0f), CS_FLOAT(0x0, 0.0f), CS_FLOAT(0x0, 0.0f)), CS_ACTOR_CUE_LIST(42, 3), diff --git a/src/overlays/actors/ovl_En_Xc/z_en_xc.c b/src/overlays/actors/ovl_En_Xc/z_en_xc.c index b2b8dda8c1..3809daae4d 100644 --- a/src/overlays/actors/ovl_En_Xc/z_en_xc.c +++ b/src/overlays/actors/ovl_En_Xc/z_en_xc.c @@ -472,7 +472,6 @@ void EnXc_SetColossusWindSFX(PlayState* play) { if (gSaveContext.sceneLayer == 4) { static s32 D_80B41D90 = 0; static Vec3f sPos = { 0.0f, 0.0f, 0.0f }; - static f32 sMaxSpeed = 0.0f; static Vec3f D_80B42DB0; s32 pad; s16 sceneId = play->sceneId; @@ -487,8 +486,9 @@ void EnXc_SetColossusWindSFX(PlayState* play) { if (D_80B41D90 != 0) { f32 speed = Math3D_Vec3f_DistXYZ(&D_80B42DB0, eye) / 7.058922f; - #if OOT_DEBUG + static f32 sMaxSpeed = 0.0f; + sMaxSpeed = CLAMP_MIN(sMaxSpeed, speed); PRINTF("MAX speed = %f\n", sMaxSpeed); #endif diff --git a/src/overlays/actors/ovl_player_actor/z_player.c b/src/overlays/actors/ovl_player_actor/z_player.c index ece01de630..8e52430596 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/ZAPD/.github/workflows/main.yml b/tools/ZAPD/.github/workflows/main.yml index 31a0f635a0..604c18c961 100644 --- a/tools/ZAPD/.github/workflows/main.yml +++ b/tools/ZAPD/.github/workflows/main.yml @@ -22,40 +22,51 @@ jobs: - name: Checkout oot run: | + cd ../ + rm -rf oot/ git clone https://github.com/zeldaret/oot.git cd oot + echo $(pwd) git submodule update --init --recursive - name: Checkout mm run: | + cd ../ + rm -rf mm/ git clone https://github.com/zeldaret/mm.git cd mm + echo $(pwd) - name: Set up repos run: echo "Set up repos" - name: Setup OOT run: | + cd ../ cd oot + echo $(pwd) mkdir -p baseroms/gc-eu-mq-dbg/segments cp ~/baserom_original.z64 ./baseroms/gc-eu-mq-dbg/baserom.z64 - make venv - make -C tools -j - cp ../ZAPD.out tools/ZAPD/ - .venv/bin/python3 tools/decompress_baserom.py gc-eu-mq-dbg - .venv/bin/python3 tools/extract_baserom.py baseroms/gc-eu-mq-dbg/baserom-decompressed.z64 -o baseroms/gc-eu-mq-dbg/segments --dmadata-start 0x12f70 --dmadata-names baseroms/gc-eu-mq-dbg/dmadata_names.txt - .venv/bin/python3 extract_assets.py -j 4 - .venv/bin/python3 tools/msgdis.py --text-out assets/text/message_data.h --staff-text-out assets/text/message_data_staff.h + cd tools + rm -rf ZAPD/ + ln -s ../../ZAPD + cd ../ + make -j $(nproc) setup - name: Setup MM run: | + cd ../ cd mm + echo $(pwd) python3 -m venv .mm-env source .mm-env/bin/activate python3 -m pip install -r requirements.txt cp ~/baserom.mm.us.rev1.z64 ./baserom.mm.us.rev1.z64 + cd tools + rm -rf ZAPD/ + ln -s ../../ZAPD + cd ../ make -C tools -j - cp ../ZAPD.out tools/ZAPD/ python3 tools/fixbaserom.py python3 tools/extract_baserom.py python3 tools/decompress_yars.py @@ -66,13 +77,17 @@ jobs: - name: Build oot run: | + cd ../ cd oot + echo $(pwd) make venv make -j - name: Build mm run: | + cd ../ cd mm + echo $(pwd) python3 -m venv .mm-env source .mm-env/bin/activate python3 -m pip install -r requirements.txt diff --git a/tools/ZAPD/.gitrepo b/tools/ZAPD/.gitrepo index 994cf48d74..9b6f9bb9bd 100644 --- a/tools/ZAPD/.gitrepo +++ b/tools/ZAPD/.gitrepo @@ -6,7 +6,7 @@ [subrepo] remote = https://github.com/zeldaret/ZAPD.git branch = master - commit = b3bfa14cf432115a0a675d243f3a1b3197f17cbd - parent = 59017f201eae4a1bc9212ea2c7dc51d4a036108b + commit = 1300a4f36584627aa784cbc252d1c8ecd7b40e68 + parent = 4522ee2cae12b2d23b7ef0134f24f7c3e26935f0 method = merge cmdver = 0.4.6 diff --git a/tools/ZAPD/ZAPD/OtherStructs/CutsceneOoT_Commands.cpp b/tools/ZAPD/ZAPD/OtherStructs/CutsceneOoT_Commands.cpp index f9a5c4f2d5..668657e7aa 100644 --- a/tools/ZAPD/ZAPD/OtherStructs/CutsceneOoT_Commands.cpp +++ b/tools/ZAPD/ZAPD/OtherStructs/CutsceneOoT_Commands.cpp @@ -15,7 +15,7 @@ const std::unordered_map csCom {CutsceneOoT_CommandType::CS_CMD_MISC, {"CS_MISC", "(%s, %i, %i, %i, %i, %i, %i, %i, %i, %i, %i, %i, %i, %i)"}}, {CutsceneOoT_CommandType::CS_CMD_LIGHT_SETTING, - {"CS_LIGHT_SETTING", "(0x%02X, %i, %i, %i, %i, %i, %i, %i, %i, %i, %i)"}}, + {"CS_LIGHT_SETTING", "(0x%02X, %i, %i, %i, %i, %i, %i, %i, %i, %i, %i, %i, %i, %i)"}}, {CutsceneOoT_CommandType::CS_CMD_START_SEQ, {"CS_START_SEQ", "(%s, %i, %i, %i, %i, %i, %i, %i, %i, %i, %i)"}}, {CutsceneOoT_CommandType::CS_CMD_STOP_SEQ, diff --git a/tools/ZAPD/ZAPD/ZCutscene.cpp b/tools/ZAPD/ZAPD/ZCutscene.cpp index 4cf375997a..0bf0363dfb 100644 --- a/tools/ZAPD/ZAPD/ZCutscene.cpp +++ b/tools/ZAPD/ZAPD/ZCutscene.cpp @@ -24,7 +24,7 @@ std::string ZCutscene::GetBodySourceCode() const { std::string output = ""; - output += StringHelper::Sprintf(" CS_BEGIN_CUTSCENE(%i, %i),\n", commands.size(), endFrame); + output += StringHelper::Sprintf(" CS_BEGIN_CUTSCENE(%i, %i),\n", numCommands, endFrame); for (size_t i = 0; i < commands.size(); i++) { @@ -32,7 +32,7 @@ std::string ZCutscene::GetBodySourceCode() const output += " " + cmd->GenerateSourceCode(); } - output += StringHelper::Sprintf(" CS_END(),", commands.size(), endFrame); + output += StringHelper::Sprintf(" CS_END(),"); return output; } diff --git a/tools/bss_reordering.py b/tools/check_ordering.py similarity index 84% rename from tools/bss_reordering.py rename to tools/check_ordering.py index d0eb77fc6e..cfd2913780 100755 --- a/tools/bss_reordering.py +++ b/tools/check_ordering.py @@ -94,10 +94,11 @@ def read_s16(f: BinaryIO, offset: int) -> int: def main(): parser = argparse.ArgumentParser( - description="Report BSS reorderings between the baserom and the current build " + description="Report data/bss reorderings between the baserom and the current build " "by parsing relocations from the built object files and comparing their final values " "between the baserom and the current build. " - "Assumes that the only differences are due to BSS ordering." + "Assumes that the only differences are due to ordering and that the text sections of the " + "ROMS are not shifted." ) parser.add_argument( "--oot-version", @@ -118,30 +119,34 @@ def main(): mapfile = mapfile_parser.mapfile.MapFile() mapfile.readMapFile(f"build/{version}/oot-{version}.map") - reloc_mapfile_segments = [] + # Segments built from source code (filtering out assets) + source_code_segments = [] for mapfile_segment in mapfile: - if args.segment and mapfile_segment.name != f"..{args.segment}": - continue - if not ( - mapfile_segment.name == "..boot" - or mapfile_segment.name == "..code" - or ( - mapfile_segment.name.startswith("..ovl_") - and not mapfile_segment.name.endswith(".bss") - ) + if ( + args.segment + and mapfile_segment.name != f"..{args.segment}" + and mapfile_segment.name != f"..{args.segment}.bss" ): continue - reloc_mapfile_segments.append(mapfile_segment) + if not ( + mapfile_segment.name.startswith("..boot") + or mapfile_segment.name.startswith("..code") + or mapfile_segment.name.startswith("..ovl_") + ): + continue + source_code_segments.append(mapfile_segment) base = open(f"baseroms/{version}/baserom-decompressed.z64", "rb") build = open(f"build/{version}/oot-{version}.z64", "rb") # Find all pointers with different values pointers = [] - for mapfile_segment in reloc_mapfile_segments: + for mapfile_segment in source_code_segments: for file in mapfile_segment: if not str(file.filepath).endswith(".o"): continue + if file.sectionType == ".bss": + continue for reloc in read_relocs(file.filepath, file.sectionType): if reloc.offset_32 is not None: base_value = read_u32(base, file.vrom + reloc.offset_32) @@ -153,8 +158,8 @@ def main(): build, file.vrom + reloc.offset_hi16 ): print( - f"Error: Relocation for {reloc.name} in {file.filepath} references a shifted portion of the ROM.\n" - "Please ensure that the only differences between the baserom and the current build are due to BSS reordering.", + f"Error: Reference to {reloc.name} in {file.filepath} is in a shifted portion of the ROM.\n" + "Please ensure that the only differences between the baserom and the current build are due to data ordering.", file=sys.stderr, ) sys.exit(1) @@ -177,20 +182,16 @@ def main(): pointers = list({p.base_value: p for p in pointers}.values()) pointers.sort(key=lambda p: p.base_value) - # Go through BSS sections and report differences - i = 0 - for mapfile_segment in mapfile: + # Go through sections and report differences + for mapfile_segment in source_code_segments: for file in mapfile_segment: - if not file.sectionType == ".bss": - continue - pointers_in_section = [ p for p in pointers if file.vram <= p.build_value < file.vram + file.size ] if not pointers_in_section: continue - print(f"{file.filepath} BSS is reordered:") + print(f"{file.filepath} {file.sectionType} is reordered:") for i, p in enumerate(pointers_in_section): if p.addend > 0: addend_str = f"+0x{p.addend:X}" diff --git a/tools/csdis.py b/tools/csdis.py index cca1e1fec4..f63ea7cdfc 100755 --- a/tools/csdis.py +++ b/tools/csdis.py @@ -491,7 +491,7 @@ cutscene_command_macros = { "CS_MISC(%h2:1:e4, %h1:1:s, %h2:2:s, %h1:2:x, %w1:3:x, %w1:4:x, %w1:5:x, %w1:6:x, %w1:7:x, %w1:8:x, %w1:9:x, %w1:10:x, %w1:11:x, %w1:12:x)", 12), 4: ("CS_LIGHT_SETTING_LIST(%w1:1:s)", 2, None, 0, - "CS_LIGHT_SETTING(%h2:1:x-1, %h1:1:s, %h2:2:s, %h1:2:x, %w1:3:x, %w1:4:x, %w1:5:x, %w1:6:x, %w1:7:x, %w1:8:x, %w1:9:x)", 12), + "CS_LIGHT_SETTING(%h2:1:x-1, %h1:1:s, %h2:2:s, %h1:2:x, %w1:3:x, %w1:4:x, %w1:5:x, %w1:6:x, %w1:7:x, %w1:8:x, %w1:9:x, %w1:10:x, %w1:11:x, %w1:12:x)", 12), 86: ("CS_START_SEQ_LIST(%w1:1:s)", 2, None, 0, "CS_START_SEQ(%h2:1:e3, %h1:1:s, %h2:2:s, %h1:2:x, %w1:3:x, %w1:4:x, %w1:5:x, %w1:6:x, %w1:7:x, %w1:8:x, %w1:9:x)", 12), diff --git a/tools/disasm/gc-eu-mq/functions.txt b/tools/disasm/gc-eu-mq/functions.txt index 88a45efc38..fef42f92c3 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 diff --git a/tools/fado/.gitrepo b/tools/fado/.gitrepo index 0f548ed09d..5fac8601da 100644 --- a/tools/fado/.gitrepo +++ b/tools/fado/.gitrepo @@ -6,7 +6,7 @@ [subrepo] remote = git@github.com:EllipticEllipsis/fado.git branch = master - commit = 8d896ee97d565508755584803c409fc33bb0c953 - parent = 9f09505d34619883748a7dab05071883281c14fd + commit = 7fad57f834a86b6a752292996f99f08771f29df4 + parent = 17d683780d3878159959a87a9c4a2683d8781ef2 method = merge - cmdver = 0.4.5 + cmdver = 0.4.6 diff --git a/tools/fado/Makefile b/tools/fado/Makefile index 135f512513..8f61a209eb 100644 --- a/tools/fado/Makefile +++ b/tools/fado/Makefile @@ -57,7 +57,7 @@ clean: $(RM) -r build $(ELF) format: - clang-format-11 -i $(C_FILES) $(H_FILES) lib/fairy/* + clang-format-14 -i $(C_FILES) $(H_FILES) lib/fairy/* .PHONY: all clean format diff --git a/tools/fado/include/mips_elf.h b/tools/fado/include/mips_elf.h index 122e98d25f..f76a69b795 100644 --- a/tools/fado/include/mips_elf.h +++ b/tools/fado/include/mips_elf.h @@ -476,9 +476,9 @@ typedef struct { /* Relocation table entry with addend (in section of type SHT_RELA). */ typedef struct { - Elf32_Addr r_offset; /* Address */ - Elf32_Word r_info; /* Relocation type and symbol index */ - Elf32_Sword r_addend; /* Addend */ + Elf32_Addr r_offset; /* Address */ + Elf32_Word r_info; /* Relocation type and symbol index */ + Elf32_Sword r_addend; /* Addend */ } Elf32_Rela; /* How to extract and insert information held in the r_info field. */ diff --git a/tools/fado/lib/fairy/fairy_print.c b/tools/fado/lib/fairy/fairy_print.c index 80b8fcd9ea..0d04802253 100644 --- a/tools/fado/lib/fairy/fairy_print.c +++ b/tools/fado/lib/fairy/fairy_print.c @@ -368,7 +368,7 @@ void Fairy_PrintSectionSizes(FairySecHeader* sectionTable, FILE* inputFile, size } } /* Can use symbols here too */ - puts(".section .ovl"); + puts(".section .ovl, \"a\""); printf("# OverlayInfo\n"); printf(".word 0x%08X # .text size\n", textSize); printf(".word 0x%08X # .data size\n", dataSize); diff --git a/tools/fado/src/fado.c b/tools/fado/src/fado.c index 464f8855b5..f6daaaa1cc 100644 --- a/tools/fado/src/fado.c +++ b/tools/fado/src/fado.c @@ -17,16 +17,6 @@ /* String-finding-related functions */ -bool Fado_CheckInProgBitsSections(Elf32_Section section, vc_vector* progBitsSections) { - Elf32_Section* i; - VC_FOREACH(i, progBitsSections) { - if (*i == section) { - return true; - } - } - return false; -} - /** * For each input file, construct a vector of pointers to the starts of the strings defined in that file. */ @@ -41,8 +31,7 @@ void Fado_ConstructStringVectors(vc_vector** stringVectors, FairyFileInfo* fileI /* Build a vector of pointers to defined symbols' names */ for (currentSym = 0; currentSym < fileInfo[currentFile].symtabInfo.sectionEntryCount; currentSym++) { - if ((symtab[currentSym].st_shndx != STN_UNDEF) && - Fado_CheckInProgBitsSections(symtab[currentSym].st_shndx, fileInfo[currentFile].progBitsSections)) { + if (symtab[currentSym].st_shndx != STN_UNDEF) { /* Have to pass a double pointer so it copies the pointer instead of the start of the string */ char* stringPtr = &fileInfo[currentFile].strtab[symtab[currentSym].st_name]; assert(vc_vector_push_back(stringVectors[currentFile], &stringPtr)); @@ -251,7 +240,7 @@ void Fado_Relocs(FILE* outputFile, int inputFilesCount, FILE** inputFiles, const { /* Write header */ - fprintf(outputFile, ".section .ovl\n"); + fprintf(outputFile, ".section .ovl, \"a\"\n"); fprintf(outputFile, "# %sOverlayInfo\n", ovlName); fprintf(outputFile, ".word _%sSegmentTextSize\n", ovlName); fprintf(outputFile, ".word _%sSegmentDataSize\n", ovlName); diff --git a/tools/fado/src/version.inc b/tools/fado/src/version.inc index 9bc9fbf30f..5e46b03ef8 100644 --- a/tools/fado/src/version.inc +++ b/tools/fado/src/version.inc @@ -1,5 +1,5 @@ /* Copyright (C) 2021 Elliptic Ellipsis */ /* SPDX-License-Identifier: AGPL-3.0-only */ -const char versionNumber[] = "1.3.1"; +const char versionNumber[] = "1.3.2"; const char credits[] = "Written by Elliptic Ellipsis\nwith additions from AngheloAlf and Tharo"; const char repo[] = "https://github.com/EllipticEllipsis/fado/";