diff --git a/src/game/chat.c b/src/game/chat.c index bfca10662..1f346237a 100644 --- a/src/game/chat.c +++ b/src/game/chat.c @@ -5,6 +5,7 @@ #include "chat.h" #include "game_init.h" #include "ingame_menu.h" +#include "mario_misc.h" #include "segment2.h" #include "gfx_dimensions.h" #include "config.h" @@ -23,6 +24,7 @@ struct ChatMessage { u8 dialog[CHAT_DIALOG_MAX]; enum ChatMessageType type; u16 life; + u8 color[3]; }; static char inputMessage[CHAT_DIALOG_MAX] = { 0 }; @@ -70,21 +72,34 @@ static void render_chat_message(struct ChatMessage* chatMessage, u8 index) { u8 textR, textG, textB; switch (chatMessage->type) { - case CMT_LOCAL: textR = 200; textG = 200; textB = 255; break; - case CMT_INPUT: textR = 0; textG = 0; textB = 0; break; - case CMT_SYSTEM: textR = 255; textG = 255; textB = 190; break; - default: textR = 255; textG = 255; textB = 255; + case CMT_LOCAL: textR = 200; textG = 200; textB = 255; break; + case CMT_INPUT: textR = 0; textG = 0; textB = 0; break; + case CMT_SYSTEM: textR = 255; textG = 255; textB = 190; break; + default: textR = 255; textG = 255; textB = 255; break; } gSPDisplayList(gDisplayListHead++, dl_ia_text_begin); + gDPSetEnvColor(gDisplayListHead++, textR, textG, textB, 255 * alphaScale); print_generic_string(CHAT_X, CHAT_Y, chatMessage->dialog); + + if (chatMessage->type == CMT_REMOTE || chatMessage->type == CMT_SYSTEM) { + // if it's someone else's message, highlight the icon with their color + u8 starR = chatMessage->color[0]; + u8 starG = chatMessage->color[1]; + u8 starB = chatMessage->color[2]; + gDPSetEnvColor(gDisplayListHead++, starR, starG, starB, 255 * alphaScale); + create_dl_translation_matrix(MENU_MTX_PUSH, CHAT_X, CHAT_Y, 0.0f); + render_generic_char(chatMessage->dialog[0]); + gSPPopMatrix(gDisplayListHead++, G_MTX_MODELVIEW); + } + gSPDisplayList(gDisplayListHead++, dl_ia_text_end); gSPPopMatrix(gDisplayListHead++, G_MTX_MODELVIEW); } -void chat_add_message(char* ascii, enum ChatMessageType chatMessageType) { +void chat_add_message_ext(char* ascii, enum ChatMessageType chatMessageType, const u8 color[3]) { u8 character = '?'; switch (chatMessageType) { case CMT_INPUT: @@ -98,10 +113,18 @@ void chat_add_message(char* ascii, enum ChatMessageType chatMessageType) { str_ascii_to_dialog(ascii, &msg->dialog[2], MIN(strlen(ascii), CHAT_DIALOG_MAX - 3)); msg->life = (sSelectedFileNum != 0) ? CHAT_LIFE_MAX : CHAT_LIFE_MAX / 3; msg->type = chatMessageType; + msg->color[0] = color[0]; + msg->color[1] = color[1]; + msg->color[2] = color[2]; onMessageIndex = (onMessageIndex + 1) % CHAT_MESSAGES_MAX; play_sound((msg->type == CMT_LOCAL) ? SOUND_MENU_MESSAGE_DISAPPEAR : SOUND_MENU_MESSAGE_APPEAR, gDefaultSoundArgs); } +void chat_add_message(char* ascii, enum ChatMessageType chatMessageType) { + const u8 defaultColor[3] = { 255, 255, 255 }; + chat_add_message_ext(ascii, chatMessageType, defaultColor); +} + static void chat_stop_input(void) { sInChatInput = FALSE; keyboard_stop_text_input(); @@ -112,7 +135,8 @@ static void chat_send_input(void) { keyboard_stop_text_input(); if (strlen(gTextInput) == 0) { return; } chat_add_message(gTextInput, CMT_LOCAL); - network_send_chat(gTextInput); + // our message has the same color as our shirt + network_send_chat(gTextInput, get_player_color(gNetworkPlayerLocal->globalIndex, 0)); } void chat_start_input(void) { diff --git a/src/game/chat.h b/src/game/chat.h index e1dfd0a17..4e9034fd7 100644 --- a/src/game/chat.h +++ b/src/game/chat.h @@ -10,6 +10,7 @@ enum ChatMessageType { void render_chat(void); void chat_add_message(char* ascii, enum ChatMessageType chatMessageType); +void chat_add_message_ext(char* ascii, enum ChatMessageType chatMessageType, const u8 color[3]); void chat_start_input(void); #endif \ No newline at end of file diff --git a/src/game/mario_misc.c b/src/game/mario_misc.c index d4661926c..4c9b04de2 100644 --- a/src/game/mario_misc.c +++ b/src/game/mario_misc.c @@ -53,8 +53,8 @@ enum UnlockDoorStarStates { }; struct PlayerColor { - Lights1 pants; Lights1 shirt; + Lights1 pants; }; /** @@ -80,13 +80,13 @@ struct GraphNodeObject gMirrorMario[MAX_PLAYERS]; // copy of Mario's geo node f struct PlayerColor gPlayerColors[MAX_PLAYERS] = { // default mario { - gdSPDefLights1(0x00, 0x00, 0x7f, 0x00, 0x00, 0xff, 0x28, 0x28, 0x28), gdSPDefLights1(0x7f, 0x00, 0x00, 0xff, 0x00, 0x00, 0x28, 0x28, 0x28), + gdSPDefLights1(0x00, 0x00, 0x7f, 0x00, 0x00, 0xff, 0x28, 0x28, 0x28), }, // default luigi { - gdSPDefLights1(0x00, 0x00, 0x7f, 0x00, 0x00, 0xfe, 0x28, 0x28, 0x28), gdSPDefLights1(0x00, 0x4c, 0x00, 0x00, 0x98, 0x00, 0x28, 0x28, 0x28), + gdSPDefLights1(0x00, 0x00, 0x7f, 0x00, 0x00, 0xfe, 0x28, 0x28, 0x28), }, }; @@ -101,7 +101,7 @@ struct PlayerColor gPlayerColors[MAX_PLAYERS] = { * The 4th component is the shade factor (difference between ambient and diffuse), * usually set to 1. */ -void set_player_colors(u8 globalIndex, const u8 pants[4], const u8 shirt[4]) { +void set_player_colors(u8 globalIndex, const u8 shirt[4], const u8 pants[4]) { const u8 pAmb[3] = { pants[0] >> pants[4], pants[1] >> pants[4], pants[2] >> pants[4] }; const u8 sAmb[3] = { shirt[0] >> shirt[4], shirt[1] >> shirt[4], shirt[2] >> shirt[4] }; gPlayerColors[globalIndex].pants = @@ -110,6 +110,20 @@ void set_player_colors(u8 globalIndex, const u8 pants[4], const u8 shirt[4]) { (Lights1) gdSPDefLights1(sAmb[0], sAmb[1], sAmb[2], shirt[0], shirt[1], shirt[2], 0x28, 0x28, 0x28); } +/** + * Return the specified color for player globalIndex. + * 0 = shirt, 1 = pants + * Returns RGB, not RGBA! + */ +u8 *get_player_color(u8 globalIndex, const int which) { + if (globalIndex >= MAX_PLAYERS) + globalIndex = 0; + if (which == 0) + return gPlayerColors[globalIndex].shirt.l[0].l.col; + else + return gPlayerColors[globalIndex].pants.l[0].l.col; +} + /** * Geo node script that draws Mario's head on the title screen. */ diff --git a/src/game/mario_misc.h b/src/game/mario_misc.h index 37ca3361a..3c4a76b6b 100644 --- a/src/game/mario_misc.h +++ b/src/game/mario_misc.h @@ -9,7 +9,9 @@ extern struct GraphNodeObject gMirrorMario[MAX_PLAYERS]; extern struct MarioBodyState gBodyStates[MAX_PLAYERS]; -void set_player_colors(u8 globalIndex, const u8 pants[4], const u8 shirt[4]); +void set_player_colors(u8 globalIndex, const u8 shirt[4], const u8 pants[4]); +u8 *get_player_color(u8 globalIndex, const int which); + Gfx *geo_draw_mario_head_goddard(s32 callContext, struct GraphNode *node, Mat4 *c); void bhv_toad_message_loop(void); void bhv_toad_message_init(void); diff --git a/src/pc/network/network_player.c b/src/pc/network/network_player.c index 7c85fdbb6..8c8716ba9 100644 --- a/src/pc/network/network_player.c +++ b/src/pc/network/network_player.c @@ -1,6 +1,7 @@ #include #include "network_player.h" #include "game/chat.h" +#include "game/mario_misc.h" #include "pc/debuglog.h" struct NetworkPlayer gNetworkPlayers[MAX_PLAYERS] = { 0 }; @@ -105,7 +106,7 @@ u8 network_player_connected(enum NetworkPlayerType type, u8 globalIndex) { gNetworkSystem->save_id(i); for (int j = 0; j < MAX_SYNC_OBJECTS; j++) { gSyncObjects[j].rxEventId[i] = 0; } if (type == NPT_SERVER) { gNetworkPlayerServer = np; } - else { chat_add_message("player connected", CMT_SYSTEM); } + else { chat_add_message_ext("player connected", CMT_SYSTEM, get_player_color(np->globalIndex, 0)); } LOG_INFO("player connected, local %d, global %d", i, np->globalIndex); extern s16 sCurrPlayMode; if (gNetworkType == NT_SERVER && sCurrPlayMode == PLAY_MODE_SYNC_LEVEL) { @@ -142,7 +143,7 @@ u8 network_player_disconnected(u8 globalIndex) { gNetworkSystem->clear_id(i); for (int j = 0; j < MAX_SYNC_OBJECTS; j++) { gSyncObjects[j].rxEventId[i] = 0; } LOG_INFO("player disconnected, local %d, global %d", i, globalIndex); - chat_add_message("player disconnected", CMT_SYSTEM); + chat_add_message_ext("player disconnected", CMT_SYSTEM, get_player_color(globalIndex, 0)); return i; } return UNKNOWN_GLOBAL_INDEX; diff --git a/src/pc/network/packets/packet.h b/src/pc/network/packets/packet.h index 2f2835f90..77734d2dc 100644 --- a/src/pc/network/packets/packet.h +++ b/src/pc/network/packets/packet.h @@ -141,7 +141,7 @@ void network_send_custom(u8 customId, bool reliable, bool levelAreaMustMatch, vo void network_receive_custom(struct Packet* p); // packet_chat.c -void network_send_chat(char* message); +void network_send_chat(char* message, u8 rgb[3]); void network_receive_chat(struct Packet* p); // packet_kick.c diff --git a/src/pc/network/packets/packet_chat.c b/src/pc/network/packets/packet_chat.c index 59b0a5813..ed98c6dc4 100644 --- a/src/pc/network/packets/packet_chat.c +++ b/src/pc/network/packets/packet_chat.c @@ -17,10 +17,11 @@ static void print_sync_object_table(void) { } #endif -void network_send_chat(char* message) { +void network_send_chat(char* message, u8 rgb[3]) { u16 messageLength = strlen(message); struct Packet p; packet_init(&p, PACKET_CHAT, true, false); + packet_write(&p, rgb, 3 * sizeof(u8)); packet_write(&p, &messageLength, sizeof(u16)); packet_write(&p, message, messageLength * sizeof(u8)); network_send(&p); @@ -34,13 +35,15 @@ void network_send_chat(char* message) { void network_receive_chat(struct Packet* p) { u16 remoteMessageLength = 0; char remoteMessage[255] = { 0 }; + u8 rgb[3] = { 255, 255, 255}; + packet_read(p, rgb, 3 * sizeof(u8)); packet_read(p, &remoteMessageLength, sizeof(u16)); if (remoteMessageLength > 255) { remoteMessageLength = 254; } packet_read(p, &remoteMessage, remoteMessageLength * sizeof(u8)); // add the message - chat_add_message(remoteMessage, CMT_REMOTE); + chat_add_message_ext(remoteMessage, CMT_REMOTE, rgb); LOG_INFO("rx chat: %s", remoteMessage); #ifdef DEVELOPMENT diff --git a/src/pc/network/packets/packet_player.c b/src/pc/network/packets/packet_player.c index 28ad72beb..1f5101784 100644 --- a/src/pc/network/packets/packet_player.c +++ b/src/pc/network/packets/packet_player.c @@ -10,6 +10,7 @@ #include "engine/surface_collision.h" #include "game/object_list_processor.h" #include "game/chat.h" +#include "game/mario_misc.h" #include "pc/configfile.h" #pragma pack(1) @@ -336,7 +337,7 @@ void network_receive_player(struct Packet* p) { // inform of player death if (oldData.action != ACT_BUBBLED && data.action == ACT_BUBBLED) { - chat_add_message("player died", CMT_SYSTEM); + chat_add_message_ext("player died", CMT_SYSTEM, get_player_color(globalIndex, 0)); } // action changed, reset timer