diff --git a/build-windows-visual-studio/sm64ex.vcxproj b/build-windows-visual-studio/sm64ex.vcxproj index d925fbdf..b4dca766 100644 --- a/build-windows-visual-studio/sm64ex.vcxproj +++ b/build-windows-visual-studio/sm64ex.vcxproj @@ -3846,6 +3846,7 @@ + @@ -4326,6 +4327,7 @@ + diff --git a/build-windows-visual-studio/sm64ex.vcxproj.filters b/build-windows-visual-studio/sm64ex.vcxproj.filters index 844a2f38..f064ced0 100644 --- a/build-windows-visual-studio/sm64ex.vcxproj.filters +++ b/build-windows-visual-studio/sm64ex.vcxproj.filters @@ -15084,6 +15084,9 @@ Source Files\src\pc\network + + Source Files\src\game + @@ -16045,5 +16048,8 @@ Header Files\src\pc\network + + Header Files\src\game + \ No newline at end of file diff --git a/include/types.h b/include/types.h index 6c614eb1..a809d9ce 100644 --- a/include/types.h +++ b/include/types.h @@ -6,7 +6,7 @@ #include #include "macros.h" - +#include "src/game/characters.h" // Certain functions are marked as having return values, but do not // actually return a value. This causes undefined behavior, which we'd rather @@ -377,6 +377,7 @@ struct MarioState /*????*/ int splineState; /*????*/ Vec3f nonInstantWarpPos; + /*????*/ struct Character* character; }; #define PLAY_MODE_NORMAL 0 diff --git a/src/game/characters.c b/src/game/characters.c new file mode 100644 index 00000000..3b507ae8 --- /dev/null +++ b/src/game/characters.c @@ -0,0 +1,16 @@ +#include "characters.h" +#include "hud.h" +#include "model_ids.h" + +struct Character gCharacters[CT_MAX] = { + [CT_MARIO] = { + .hudHead = ',', + .cameraHudHead = GLYPH_CAM_MARIO_HEAD, + .modelId = MODEL_MARIO, + }, + [CT_LUIGI] = { + .hudHead = '.', + .cameraHudHead = GLYPH_CAM_LUIGI_HEAD, + .modelId = MODEL_LUIGI, + }, +}; \ No newline at end of file diff --git a/src/game/characters.h b/src/game/characters.h new file mode 100644 index 00000000..7f099893 --- /dev/null +++ b/src/game/characters.h @@ -0,0 +1,22 @@ +#ifndef CHARACTERS_H +#define CHARACTERS_H +#include "PR/ultratypes.h" +// NOTE: do not include any additional headers + +enum CharacterType { + CT_MARIO, + CT_LUIGI, + + // must be last + CT_MAX +}; + +struct Character { + char hudHead; + u32 cameraHudHead; + u32 modelId; +}; + +extern struct Character gCharacters[]; + +#endif // CHARACTERS_H diff --git a/src/game/hud.c b/src/game/hud.c index a5d8338a..632a85ff 100644 --- a/src/game/hud.c +++ b/src/game/hud.c @@ -292,11 +292,10 @@ void render_hud_power_meter(void) { * Renders the amount of lives Mario has. */ void render_hud_mario_lives(void) { - // two-player hack #ifdef VERSION_JP char* displayHead = ","; #else - char* displayHead = (gNetworkType == NT_SERVER) ? "," : "."; + char* displayHead = (gMarioStates[0].character) ? &gMarioStates[0].character->hudHead : ","; #endif print_text(GFX_DIMENSIONS_RECT_FROM_LEFT_EDGE(22), HUD_TOP_Y, displayHead); // 'Mario Head' glyph if (gHudDisplay.lives == -1) { @@ -436,7 +435,7 @@ void render_hud_camera_status(void) { switch (sCameraHUD.status & CAM_STATUS_MODE_GROUP) { case CAM_STATUS_MARIO: - render_hud_tex_lut(x + 16, y, (*cameraLUT)[(gNetworkType == NT_SERVER) ? GLYPH_CAM_MARIO_HEAD : GLYPH_CAM_LUIGI_HEAD]); + render_hud_tex_lut(x + 16, y, (*cameraLUT)[(gMarioStates[0].character) ? gMarioStates[0].character->cameraHudHead : GLYPH_CAM_MARIO_HEAD]); break; case CAM_STATUS_LAKITU: render_hud_tex_lut(x + 16, y, (*cameraLUT)[GLYPH_CAM_LAKITU_HEAD]); diff --git a/src/game/mario.c b/src/game/mario.c index 9d6d3e79..ad46e044 100644 --- a/src/game/mario.c +++ b/src/game/mario.c @@ -2123,8 +2123,9 @@ static void init_single_mario(struct MarioState* m) { } // set mario/luigi model - // two-player hack - m->marioObj->header.gfx.sharedChild = gLoadedGraphNodes[(gNetworkPlayers[0].globalIndex == 1) ? MODEL_LUIGI : MODEL_MARIO]; + enum CharacterType characterType = (gNetworkPlayers[0].globalIndex == 1) ? CT_LUIGI : CT_MARIO; + m->character = &gCharacters[characterType]; + m->marioObj->header.gfx.sharedChild = gLoadedGraphNodes[m->character->modelId]; } void init_mario(void) { diff --git a/src/game/mario_actions_cutscene.c b/src/game/mario_actions_cutscene.c index d8d38bea..aebd4b4e 100644 --- a/src/game/mario_actions_cutscene.c +++ b/src/game/mario_actions_cutscene.c @@ -2494,16 +2494,16 @@ static void end_peach_cutscene_kiss_from_peach(struct MarioState *m) { } static void end_peach_cutscene_star_dance(struct MarioState *m) { - u8 sadLuigi = (gNetworkType == NT_SERVER) ? (m->playerIndex != 0) : (m->playerIndex == 0); - s32 animFrame = set_mario_animation(m, sadLuigi ? MARIO_ANIM_START_SLEEP_SITTING : MARIO_ANIM_CREDITS_PEACE_SIGN); + u8 nonMario = (m->character != &gCharacters[CT_MARIO]); + s32 animFrame = set_mario_animation(m, nonMario ? MARIO_ANIM_START_SLEEP_SITTING : MARIO_ANIM_CREDITS_PEACE_SIGN); - if (animFrame == (sadLuigi ? 0 : 77)) { + if (animFrame == (nonMario ? 0 : 77)) { cutscene_put_cap_on(m); } if (animFrame == 88 && m->playerIndex == 0) { play_sound(SOUND_MARIO_HERE_WE_GO, m->marioObj->header.gfx.cameraToObject); } - if (!sadLuigi && animFrame >= 98) { + if (!nonMario && animFrame >= 98) { m->marioBodyState->handState = MARIO_HAND_PEACE_SIGN; } @@ -2548,8 +2548,8 @@ static void end_peach_cutscene_star_dance(struct MarioState *m) { // "let's bake a delicious cake..." // "...for Mario..." static void end_peach_cutscene_dialog_3(struct MarioState *m) { - u8 sadLuigi = (gNetworkType == NT_SERVER) ? (m->playerIndex != 0) : (m->playerIndex == 0); - set_mario_animation(m, sadLuigi ? MARIO_ANIM_SLEEP_IDLE : MARIO_ANIM_FIRST_PERSON); + u8 nonMario = (m->character != &gCharacters[CT_MARIO]); + set_mario_animation(m, nonMario ? MARIO_ANIM_SLEEP_IDLE : MARIO_ANIM_FIRST_PERSON); if (m->playerIndex != 0) { return; } sEndPeachObj->oPosY = end_obj_set_visual_pos(sEndPeachObj); sEndRightToadObj->oPosY = end_obj_set_visual_pos(sEndRightToadObj); @@ -2586,8 +2586,8 @@ static void end_peach_cutscene_dialog_3(struct MarioState *m) { // "Mario!" static void end_peach_cutscene_run_to_castle(struct MarioState *m) { - u8 sadLuigi = (gNetworkType == NT_SERVER) ? (m->playerIndex != 0) : (m->playerIndex == 0); - if (sadLuigi) { + u8 nonMario = (m->character != &gCharacters[CT_MARIO]); + if (nonMario) { set_mario_animation(m, m->actionState == 0 ? MARIO_ANIM_SLEEP_START_LYING : MARIO_ANIM_SLEEP_LYING); } else { diff --git a/src/pc/network/packets/packet_player.c b/src/pc/network/packets/packet_player.c index af020518..8606ec9a 100644 --- a/src/pc/network/packets/packet_player.c +++ b/src/pc/network/packets/packet_player.c @@ -330,7 +330,9 @@ void network_receive_player(struct Packet* p) { } // set model - m->marioObj->header.gfx.sharedChild = gLoadedGraphNodes[(np->globalIndex == 1) ? MODEL_LUIGI : MODEL_MARIO]; + enum CharacterType characterType = (np->globalIndex == 1) ? CT_LUIGI : CT_MARIO; + m->character = &gCharacters[characterType]; + m->marioObj->header.gfx.sharedChild = gLoadedGraphNodes[m->character->modelId]; } void network_update_player(void) {