Added configurable player name, model, and palette

This commit is contained in:
MysterD 2021-08-02 22:32:32 -07:00
parent 4d997ba05e
commit d7b0945410
20 changed files with 317 additions and 87 deletions

View file

@ -3957,6 +3957,7 @@
<ClCompile Include="..\src\pc\djui\djui_panel_join_message.c" />
<ClCompile Include="..\src\pc\djui\djui_panel_menu.c" />
<ClCompile Include="..\src\pc\djui\djui_panel_pause.c" />
<ClCompile Include="..\src\pc\djui\djui_panel_player.c" />
<ClCompile Include="..\src\pc\djui\djui_popup.c" />
<ClCompile Include="..\src\pc\djui\djui_selectionbox.c" />
<ClCompile Include="..\src\pc\djui\djui_cursor.c" />
@ -4405,6 +4406,7 @@
<ClInclude Include="..\src\pc\djui\djui_panel_join_message.h" />
<ClInclude Include="..\src\pc\djui\djui_panel_menu.h" />
<ClInclude Include="..\src\pc\djui\djui_panel_pause.h" />
<ClInclude Include="..\src\pc\djui\djui_panel_player.h" />
<ClInclude Include="..\src\pc\djui\djui_popup.h" />
<ClInclude Include="..\src\pc\djui\djui_selectionbox.h" />
<ClInclude Include="..\src\pc\djui\djui_cursor.h" />

View file

@ -15270,6 +15270,9 @@
<ClCompile Include="..\src\pc\audio\audio_sdl.c">
<Filter>Source Files\src\pc\controller</Filter>
</ClCompile>
<ClCompile Include="..\src\pc\djui\djui_panel_player.c">
<Filter>Source Files\src\pc\djui\panel</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClCompile Include="..\actors\common0.h">
@ -16360,5 +16363,8 @@
<ClInclude Include="..\src\pc\djui\djui_chat_message.h">
<Filter>Source Files\src\pc\djui\component\compound</Filter>
</ClInclude>
<ClInclude Include="..\src\pc\djui\djui_panel_player.h">
<Filter>Source Files\src\pc\djui\panel</Filter>
</ClInclude>
</ItemGroup>
</Project>

View file

@ -2130,8 +2130,9 @@ static void init_single_mario(struct MarioState* m) {
}
// set mario/luigi model
enum CharacterType characterType = (globalIndex == 0) ? CT_MARIO : CT_LUIGI;
m->character = &gCharacters[characterType];
u8 modelIndex = gNetworkPlayers[playerIndex].modelIndex;
if (modelIndex >= CT_MAX) { modelIndex = 0; }
m->character = &gCharacters[modelIndex];
m->marioObj->header.gfx.sharedChild = gLoadedGraphNodes[m->character->modelId];
}

View file

@ -2501,7 +2501,7 @@ static void end_peach_cutscene_kiss_from_peach(struct MarioState *m) {
}
static void end_peach_cutscene_star_dance(struct MarioState *m) {
u8 nonMario = (m->character != &gCharacters[CT_MARIO]);
u8 nonMario = (gNetworkPlayers[m->playerIndex].globalIndex != 0);
s32 animFrame = set_mario_animation(m, nonMario ? MARIO_ANIM_START_SLEEP_SITTING : MARIO_ANIM_CREDITS_PEACE_SIGN);
if (animFrame == (nonMario ? 0 : 77)) {
@ -2555,7 +2555,7 @@ 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 nonMario = (m->character != &gCharacters[CT_MARIO]);
u8 nonMario = (gNetworkPlayers[m->playerIndex].globalIndex != 0);
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);
@ -2593,7 +2593,7 @@ static void end_peach_cutscene_dialog_3(struct MarioState *m) {
// "Mario!"
static void end_peach_cutscene_run_to_castle(struct MarioState *m) {
u8 nonMario = (m->character != &gCharacters[CT_MARIO]);
u8 nonMario = (gNetworkPlayers[m->playerIndex].globalIndex != 0);
if (nonMario) {
set_mario_animation(m, m->actionState == 0 ? MARIO_ANIM_SLEEP_START_LYING
: MARIO_ANIM_SLEEP_LYING);

View file

@ -90,27 +90,28 @@ struct PlayerColor gPlayerColors[] = {
DEFINE_PLAYER_COLOR(0xff, 0x00, 0x00, /**/ 0x00, 0x00, 0xff),
// default luigi
DEFINE_PLAYER_COLOR(0x00, 0x98, 0x00, /**/ 0x00, 0x00, 0xfe),
#if MAX_PLAYERS > 2
// fake waluigi
DEFINE_PLAYER_COLOR(0x6d, 0x3c, 0x9a, /**/ 0x2c, 0x26, 0x3f),
// fake wario
DEFINE_PLAYER_COLOR(0xf9, 0xeb, 0x30, /**/ 0x7f, 0x20, 0x7a),
// light blue
DEFINE_PLAYER_COLOR(0x00, 0xdf, 0xff, /**/ 0x00, 0x00, 0xf0),
// sponge
DEFINE_PLAYER_COLOR(0xff, 0x7f, 0x00, /**/ 0x00, 0x7f, 0xa0),
// blue man group
DEFINE_PLAYER_COLOR(0x00, 0x00, 0xf0, /**/ 0x00, 0x00, 0x4f),
// thanks doc
DEFINE_PLAYER_COLOR(0xff, 0x00, 0xff, /**/ 0x00, 0xff, 0x00),
// white
DEFINE_PLAYER_COLOR(0xff, 0xff, 0xff, /**/ 0x10, 0x10, 0x10),
// grey
DEFINE_PLAYER_COLOR(0x6f, 0x6f, 0x6f, /**/ 0xe0, 0xe0, 0xe0),
#endif
DEFINE_PLAYER_COLOR(0x00, 0x2f, 0xc8, /**/ 0xbf, 0xde, 0xff),
DEFINE_PLAYER_COLOR(0xc1, 0x2c, 0x72, /**/ 0x34, 0x16, 0x0d),
DEFINE_PLAYER_COLOR(0x4c, 0xff, 0x4c, /**/ 0x81, 0x00, 0x00),
DEFINE_PLAYER_COLOR(0xa9, 0x78, 0xfc, /**/ 0x61, 0x3d, 0x2e),
DEFINE_PLAYER_COLOR(0x84, 0x60, 0x00, /**/ 0x00, 0x46, 0x5c),
DEFINE_PLAYER_COLOR(0x5a, 0x94, 0xff, /**/ 0x4f, 0x31, 0x8b),
DEFINE_PLAYER_COLOR(0x68, 0x0a, 0x17, /**/ 0x23, 0x11, 0x03),
DEFINE_PLAYER_COLOR(0x95, 0xd0, 0x8f, /**/ 0x53, 0x39, 0x3d),
DEFINE_PLAYER_COLOR(0x37, 0x32, 0x42, /**/ 0xe6, 0xe3, 0xff),
DEFINE_PLAYER_COLOR(0xff, 0x8a, 0x00, /**/ 0x00, 0x51, 0x10),
DEFINE_PLAYER_COLOR(0x65, 0xfa, 0xff, /**/ 0x4c, 0x1e, 0x3f),
DEFINE_PLAYER_COLOR(0xe6, 0xe6, 0xe6, /**/ 0xb2, 0x28, 0x18),
};
static const size_t gNumPlayerColors = sizeof(gPlayerColors) / sizeof(*gPlayerColors);
const size_t gNumPlayerColors = sizeof(gPlayerColors) / sizeof(*gPlayerColors);
// This whole file is weirdly organized. It has to be the same file due
// to rodata boundaries and function aligns, which means the programmer
@ -123,14 +124,14 @@ static const size_t gNumPlayerColors = sizeof(gPlayerColors) / sizeof(*gPlayerCo
* The 4th component is the shade factor (difference between ambient and diffuse),
* usually set to 1.
*/
void set_player_colors(u8 globalIndex, const u8 shirt[4], const u8 pants[4]) {
void set_player_colors(u8 paletteIndex, const u8 shirt[4], const u8 pants[4]) {
// choose the last color in the table for extra players
if (globalIndex >= gNumPlayerColors) globalIndex = gNumPlayerColors - 1;
if (paletteIndex >= gNumPlayerColors) paletteIndex = gNumPlayerColors - 1;
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 =
gPlayerColors[paletteIndex].pants =
(Lights1) gdSPDefLights1(pAmb[0], pAmb[1], pAmb[2], pants[0], pants[1], pants[2], 0x28, 0x28, 0x28);
gPlayerColors[globalIndex].shirt =
gPlayerColors[paletteIndex].shirt =
(Lights1) gdSPDefLights1(sAmb[0], sAmb[1], sAmb[2], shirt[0], shirt[1], shirt[2], 0x28, 0x28, 0x28);
}
@ -139,13 +140,13 @@ void set_player_colors(u8 globalIndex, const u8 shirt[4], const u8 pants[4]) {
* 0 = shirt, 1 = pants
* Returns RGB, not RGBA!
*/
u8 *get_player_color(u8 globalIndex, const int which) {
u8 *get_player_color(u8 paletteIndex, const int which) {
// choose the last color in the table for extra players
if (globalIndex >= gNumPlayerColors) globalIndex = gNumPlayerColors - 1;
if (paletteIndex >= gNumPlayerColors) paletteIndex = gNumPlayerColors - 1;
if (which == 0)
return gPlayerColors[globalIndex].shirt.l[0].l.col;
return gPlayerColors[paletteIndex].shirt.l[0].l.col;
else
return gPlayerColors[globalIndex].pants.l[0].l.col;
return gPlayerColors[paletteIndex].pants.l[0].l.col;
}
/**
@ -802,7 +803,7 @@ Gfx* geo_mario_set_player_colors(s32 callContext, struct GraphNode* node, UNUSED
struct GraphNodeGenerated* asGenerated = (struct GraphNodeGenerated*) node;
Gfx* gfx = NULL;
u8 index = geo_get_processing_object_index();
u8 colorIndex = gNetworkPlayers[index].globalIndex;
u8 colorIndex = gNetworkPlayers[index].paletteIndex;
struct MarioBodyState* bodyState = &gBodyStates[index];
if (callContext == GEO_CONTEXT_RENDER) {

View file

@ -8,9 +8,10 @@
extern struct GraphNodeObject gMirrorMario[MAX_PLAYERS];
extern struct MarioBodyState gBodyStates[MAX_PLAYERS];
extern const size_t gNumPlayerColors;
void set_player_colors(u8 globalIndex, const u8 shirt[4], const u8 pants[4]);
u8 *get_player_color(u8 globalIndex, const int which);
void set_player_colors(u8 paletteIndex, const u8 shirt[4], const u8 pants[4]);
u8 *get_player_color(u8 paletteIndex, const int which);
Gfx *geo_draw_mario_head_goddard(s32 callContext, struct GraphNode *node, Mat4 *c);
void bhv_toad_message_loop(void);

View file

@ -107,6 +107,9 @@ unsigned int configPlayerInteraction = 1;
unsigned int configPlayerKnockbackStrength = 25;
bool configStayInLevelAfterStar = 0;
unsigned int configNetworkSystem = 0;
char configPlayerName[MAX_PLAYER_STRING] = "";
unsigned int configPlayerModel = 0;
unsigned int configPlayerPalette = 0;
static const struct ConfigOption options[] = {
{.name = "fullscreen", .type = CONFIG_TYPE_BOOL, .boolValue = &configWindow.fullscreen},
@ -167,6 +170,9 @@ static const struct ConfigOption options[] = {
{.name = "coop_player_knockback_strength", .type = CONFIG_TYPE_UINT , .uintValue = &configPlayerKnockbackStrength},
{.name = "coop_stay_in_level_after_star", .type = CONFIG_TYPE_UINT , .boolValue = &configStayInLevelAfterStar},
{.name = "coop_network_system", .type = CONFIG_TYPE_UINT , .uintValue = &configNetworkSystem},
{.name = "coop_player_name", .type = CONFIG_TYPE_STRING, .stringValue = (char*)&configPlayerName},
{.name = "coop_player_model", .type = CONFIG_TYPE_UINT , .uintValue = &configPlayerModel},
{.name = "coop_player_palette", .type = CONFIG_TYPE_UINT , .uintValue = &configPlayerPalette},
};
// Reads an entire line from a file (excluding the newline character) and returns an allocated string

View file

@ -8,6 +8,7 @@
#define MAX_BINDS 3
#define MAX_VOLUME 127
#define MAX_CONFIG_STRING 64
#define MAX_PLAYER_STRING 20
#define DEFAULT_PORT 7777
@ -73,6 +74,9 @@ extern unsigned int configPlayerInteraction;
extern unsigned int configPlayerKnockbackStrength;
extern bool configStayInLevelAfterStar;
extern unsigned int configNetworkSystem;
extern char configPlayerName[];
extern unsigned int configPlayerModel;
extern unsigned int configPlayerPalette;
void configfile_load(const char *filename);
void configfile_save(const char *filename);

View file

@ -42,6 +42,7 @@
#include "djui_panel_join_message.h"
#include "djui_panel_pause.h"
#include "djui_panel_options.h"
#include "djui_panel_player.h"
#include "djui_panel_camera.h"
#include "djui_panel_controls.h"
#include "djui_panel_display.h"

View file

@ -44,11 +44,10 @@ static void djui_chat_message_destroy(struct DjuiBase* base) {
}
struct DjuiChatMessage* djui_chat_message_create_from(u8 globalIndex, char* message) {
u8* rgb = get_player_color(globalIndex, 0);
u8 rgb2[3] = { 0 };
for (int i = 0; i < 3; i++) { rgb2[i] = fmin((f32)rgb[i] * 1.3f + 32.0f, 255); }
struct NetworkPlayer* np = network_player_from_global_index(globalIndex);
u8* rgb = get_player_color(np->paletteIndex, 0);
char chatMsg[256] = { 0 };
snprintf(chatMsg, 256, "\\#%02x%02x%02x\\%s:\\#dcdcdc\\ %s", rgb2[0], rgb2[1], rgb2[2], "Player", message);
snprintf(chatMsg, 256, "\\#%02x%02x%02x\\%s:\\#dcdcdc\\ %s", rgb[0], rgb[1], rgb[2], (np != NULL) ? np->name : "Player", message);
play_sound((globalIndex == gNetworkPlayerLocal->globalIndex) ? SOUND_MENU_MESSAGE_DISAPPEAR : SOUND_MENU_MESSAGE_APPEAR, gDefaultSoundArgs);
return djui_chat_message_create(chatMsg);
}

View file

@ -1,5 +1,6 @@
#include "djui.h"
#include "src/pc/utils/misc.h"
#include "pc/network/network.h"
#include "pc/utils/misc.h"
void djui_panel_options_back(struct DjuiBase* caller) {
configfile_save(configfile_name());
@ -8,21 +9,29 @@ void djui_panel_options_back(struct DjuiBase* caller) {
void djui_panel_options_create(struct DjuiBase* caller) {
f32 bodyHeight = 64 * 5 + 16 * 4;
if (gNetworkType == NT_NONE) {
bodyHeight += 64 + 16;
}
struct DjuiBase* defaultBase = NULL;
struct DjuiThreePanel* panel = djui_panel_menu_create(bodyHeight, "\\#ff0800\\O\\#1be700\\P\\#00b3ff\\T\\#ffef00\\I\\#ff0800\\O\\#1be700\\N\\#00b3ff\\S");
struct DjuiFlowLayout* body = (struct DjuiFlowLayout*)djui_three_panel_get_body(panel);
{
/*struct DjuiButton* button1 = djui_button_create(&body->base, "Player");
if (gNetworkType == NT_NONE) {
struct DjuiButton* button1 = djui_button_create(&body->base, "Player");
djui_base_set_size_type(&button1->base, DJUI_SVT_RELATIVE, DJUI_SVT_ABSOLUTE);
djui_base_set_size(&button1->base, 1.0f, 64);
defaultBase = &button1->base;*/
djui_interactable_hook_click(&button1->base, djui_panel_player_create);
defaultBase = &button1->base;
}
struct DjuiButton* button2 = djui_button_create(&body->base, "Camera");
djui_base_set_size_type(&button2->base, DJUI_SVT_RELATIVE, DJUI_SVT_ABSOLUTE);
djui_base_set_size(&button2->base, 1.0f, 64);
djui_interactable_hook_click(&button2->base, djui_panel_camera_create);
if (defaultBase == NULL) {
defaultBase = &button2->base;
}
struct DjuiButton* button3 = djui_button_create(&body->base, "Controls");
djui_base_set_size_type(&button3->base, DJUI_SVT_RELATIVE, DJUI_SVT_ABSOLUTE);

View file

@ -0,0 +1,115 @@
#include <stdio.h>
#include "djui.h"
#include "pc/configfile.h"
#include "pc/network/network_player.h"
#include "game/level_update.h"
#include "game/area.h"
static bool djui_panel_player_name_valid(char* buffer) {
if (buffer[0] == '\0') { return false; }
while (*buffer != '\0') {
if (*buffer >= '!' && *buffer <= '~') {
buffer++;
continue;
}
return false;
}
return true;
}
static void djui_panel_player_name_text_change(struct DjuiBase* caller) {
struct DjuiInputbox* inputbox1 = (struct DjuiInputbox*)caller;
if (djui_panel_player_name_valid(inputbox1->buffer)) {
djui_inputbox_set_text_color(inputbox1, 0, 0, 0, 255);
} else {
djui_inputbox_set_text_color(inputbox1, 255, 0, 0, 255);
}
}
static void djui_panel_player_name_on_focus_end(struct DjuiBase* caller) {
struct DjuiInputbox* inputbox1 = (struct DjuiInputbox*)caller;
if (!djui_panel_player_name_valid(inputbox1->buffer)) {
djui_inputbox_set_text(inputbox1, "Player");
}
snprintf(configPlayerName, 20, "%s", inputbox1->buffer);
djui_inputbox_set_text_color(inputbox1, 0, 0, 0, 255);
}
void djui_panel_player_value_changed(struct DjuiBase* caller) {
struct MarioState* m = &gMarioStates[0];
if (configPlayerModel >= CT_MAX) { configPlayerModel = 0; }
gNetworkPlayers[0].modelIndex = configPlayerModel;
gNetworkPlayers[0].paletteIndex = configPlayerPalette;
network_player_update_model(0);
}
void djui_panel_player_create(struct DjuiBase* caller) {
f32 bodyHeight = 32 * 3 + 64 * 1 + 16 * 4;
struct DjuiBase* defaultBase = NULL;
struct DjuiThreePanel* panel = djui_panel_menu_create(bodyHeight, "\\#ff0800\\P\\#1be700\\L\\#00b3ff\\A\\#ffef00\\Y\\#ff0800\\E\\#1be700\\R");
struct DjuiFlowLayout* body = (struct DjuiFlowLayout*)djui_three_panel_get_body(panel);
{
struct DjuiRect* rect1 = djui_rect_create(&body->base);
djui_base_set_size_type(&rect1->base, DJUI_SVT_RELATIVE, DJUI_SVT_ABSOLUTE);
djui_base_set_size(&rect1->base, 1.0f, 32);
djui_base_set_color(&rect1->base, 0, 0, 0, 0);
{
struct DjuiText* text1 = djui_text_create(&rect1->base, "Name");
djui_base_set_size_type(&text1->base, DJUI_SVT_RELATIVE, DJUI_SVT_ABSOLUTE);
djui_base_set_color(&text1->base, 200, 200, 200, 255);
djui_base_set_size(&text1->base, 0.485f, 64);
djui_base_set_alignment(&text1->base, DJUI_HALIGN_LEFT, DJUI_VALIGN_TOP);
struct DjuiInputbox* inputbox1 = djui_inputbox_create(&rect1->base, 20);
djui_base_set_size_type(&inputbox1->base, DJUI_SVT_RELATIVE, DJUI_SVT_ABSOLUTE);
djui_base_set_size(&inputbox1->base, 0.5f, 32);
djui_base_set_alignment(&inputbox1->base, DJUI_HALIGN_RIGHT, DJUI_VALIGN_TOP);
if (djui_panel_player_name_valid(configPlayerName)) {
djui_inputbox_set_text(inputbox1, configPlayerName);
} else {
djui_inputbox_set_text(inputbox1, "Player");
}
djui_interactable_hook_value_change(&inputbox1->base, djui_panel_player_name_text_change);
djui_interactable_hook_focus(&inputbox1->base, NULL, NULL, djui_panel_player_name_on_focus_end);
}
char* modelChoices[2] = { "Mario", "Luigi" };
struct DjuiSelectionbox* selectionbox1 = djui_selectionbox_create(&body->base, "Model", modelChoices, 2, &configPlayerModel);
djui_base_set_size_type(&selectionbox1->base, DJUI_SVT_RELATIVE, DJUI_SVT_ABSOLUTE);
djui_base_set_size(&selectionbox1->base, 1.0f, 32);
djui_interactable_hook_value_change(&selectionbox1->base, djui_panel_player_value_changed);
char* paletteChoices[16] = {
"mario",
"luigi",
"waluigi",
"wario",
"cobalt",
"hot pink",
"seafoam",
"lilac",
"copper",
"azure",
"burgundy",
"mint",
"eggplant",
"orange",
"arctic",
"fire",
};
struct DjuiSelectionbox* selectionbox2 = djui_selectionbox_create(&body->base, "Palette", paletteChoices, 16, &configPlayerPalette);
djui_base_set_size_type(&selectionbox2->base, DJUI_SVT_RELATIVE, DJUI_SVT_ABSOLUTE);
djui_base_set_size(&selectionbox2->base, 1.0f, 32);
djui_interactable_hook_value_change(&selectionbox2->base, djui_panel_player_value_changed);
struct DjuiButton* button6 = djui_button_create(&body->base, "Back");
djui_base_set_size_type(&button6->base, DJUI_SVT_RELATIVE, DJUI_SVT_ABSOLUTE);
djui_base_set_size(&button6->base, 1.0f, 64);
djui_button_set_style(button6, 1);
djui_interactable_hook_click(&button6->base, djui_panel_menu_back);
}
djui_panel_add(caller, &panel->base, defaultBase);
}

View file

@ -0,0 +1,4 @@
#pragma once
#include "djui.h"
void djui_panel_player_create(struct DjuiBase* caller);

View file

@ -80,13 +80,13 @@ bool network_init(enum NetworkType inNetworkType) {
gNetworkType = inNetworkType;
if (gNetworkType == NT_SERVER) {
network_player_connected(NPT_LOCAL, 0);
network_player_connected(NPT_LOCAL, 0, configPlayerModel, configPlayerPalette, configPlayerName);
extern u8* gOverrideEeprom;
gOverrideEeprom = NULL;
djui_chat_box_create();
} else if (gNetworkType == NT_CLIENT) {
network_player_connected(NPT_SERVER, 0);
network_player_connected(NPT_SERVER, 0, 0, 0, "Player");
}
LOG_INFO("initialized");

View file

@ -5,10 +5,41 @@
#include "pc/djui/djui.h"
#include "pc/debuglog.h"
#include "pc/utils/misc.h"
#include "game/area.h"
struct NetworkPlayer gNetworkPlayers[MAX_PLAYERS] = { 0 };
struct NetworkPlayer* gNetworkPlayerLocal = NULL;
struct NetworkPlayer* gNetworkPlayerServer = NULL;
static char sDefaultPlayerName[] = "Player";
void network_player_init(void) {
gNetworkPlayers[0].modelIndex = configPlayerModel;
gNetworkPlayers[0].paletteIndex = configPlayerPalette;
}
void network_player_update_model(u8 localIndex) {
struct MarioState* m = &gMarioStates[localIndex];
if (m == NULL) { return; }
m->character = &gCharacters[gNetworkPlayers[localIndex].modelIndex];
if (m->marioObj == NULL) { return; }
m->marioObj->header.gfx.sharedChild = gLoadedGraphNodes[m->character->modelId];
}
u8 network_player_unique_palette(u8 palette) {
u16 iterations = 0;
retry_palette:
for (int i = 0; i < MAX_PLAYERS; i++) {
if (!gNetworkPlayers[i].connected) { continue; }
if (gNetworkPlayers[i].paletteIndex == palette) {
palette = (palette + 1) % gNumPlayerColors;
if (iterations++ >= gNumPlayerColors) {
return palette;
}
goto retry_palette;
}
}
return palette;
}
bool network_player_any_connected(void) {
for (int i = 1; i < MAX_PLAYERS; i++) {
@ -116,7 +147,12 @@ void network_player_update(void) {
//#endif
}
u8 network_player_connected(enum NetworkPlayerType type, u8 globalIndex) {
u8 network_player_connected(enum NetworkPlayerType type, u8 globalIndex, u8 modelIndex, u8 paletteIndex, char* name) {
// ensure that a name is given
if (name[0] == '\0') {
name = sDefaultPlayerName;
}
if (type == NPT_LOCAL) {
struct NetworkPlayer* np = &gNetworkPlayers[0];
if (np->connected) {
@ -137,6 +173,10 @@ u8 network_player_connected(enum NetworkPlayerType type, u8 globalIndex) {
np->currAreaIndex = gCurrAreaIndex;
np->currLevelSyncValid = false;
np->currAreaSyncValid = false;
np->modelIndex = modelIndex;
np->paletteIndex = paletteIndex;
snprintf(np->name, MAX_PLAYER_STRING, "%s", name);
network_player_update_model(0);
gNetworkPlayerLocal = np;
@ -155,6 +195,10 @@ u8 network_player_connected(enum NetworkPlayerType type, u8 globalIndex) {
np->localIndex = i;
np->lastReceived = clock_elapsed();
np->lastSent = clock_elapsed();
np->modelIndex = modelIndex;
np->paletteIndex = paletteIndex;
snprintf(np->name, MAX_PLAYER_STRING, "%s", name);
network_player_update_model(i);
if (gNetworkType == NT_SERVER || type == NPT_SERVER) { gNetworkSystem->save_id(i, 0); }
LOG_ERROR("player connected, reusing local %d, global %d, duplicate event?", i, globalIndex);
return i;
@ -181,17 +225,19 @@ u8 network_player_connected(enum NetworkPlayerType type, u8 globalIndex) {
np->type = type;
np->lastReceived = clock_elapsed();
np->lastSent = clock_elapsed();
np->modelIndex = modelIndex;
np->paletteIndex = paletteIndex;
snprintf(np->name, MAX_PLAYER_STRING, "%s", name);
network_player_update_model(i);
if (gNetworkType == NT_SERVER || type == NPT_SERVER) { gNetworkSystem->save_id(i, 0); }
for (int j = 0; j < MAX_SYNC_OBJECTS; j++) { gSyncObjects[j].rxEventId[i] = 0; }
if (type == NPT_SERVER) {
gNetworkPlayerServer = np;
} else {
// display popup
u8* rgb = get_player_color(np->globalIndex, 0);
u8 rgb2[3] = { 0 };
for (int i = 0; i < 3; i++) { rgb2[i] = fmin((f32)rgb[i] * 1.3f + 32.0f, 255); }
u8* rgb = get_player_color(np->paletteIndex, 0);
char popupMsg[128] = { 0 };
snprintf(popupMsg, 128, "\\#%02x%02x%02x\\%s\\#dcdcdc\\ connected.", rgb2[0], rgb2[1], rgb2[2], "Player");
snprintf(popupMsg, 128, "\\#%02x%02x%02x\\%s\\#dcdcdc\\ connected.", rgb[0], rgb[1], rgb[2], np->name);
djui_popup_create(popupMsg, 1);
}
LOG_INFO("player connected, local %d, global %d", i, np->globalIndex);
@ -235,11 +281,9 @@ u8 network_player_disconnected(u8 globalIndex) {
LOG_INFO("player disconnected, local %d, global %d", i, globalIndex);
// display popup
u8* rgb = get_player_color(np->globalIndex, 0);
u8 rgb2[3] = { 0 };
for (int i = 0; i < 3; i++) { rgb2[i] = fmin((f32)rgb[i] * 1.3f + 32.0f, 255); }
u8* rgb = get_player_color(np->paletteIndex, 0);
char popupMsg[128] = { 0 };
snprintf(popupMsg, 128, "\\#%02x%02x%02x\\%s\\#dcdcdc\\ disconnected.", rgb2[0], rgb2[1], rgb2[2], "Player");
snprintf(popupMsg, 128, "\\#%02x%02x%02x\\%s\\#dcdcdc\\ disconnected.", rgb[0], rgb[1], rgb[2], np->name);
djui_popup_create(popupMsg, 1);
packet_ordered_clear(globalIndex);

View file

@ -3,6 +3,7 @@
#include <stdbool.h>
#include "network.h"
#include "pc/configfile.h"
#define UNKNOWN_LOCAL_INDEX ((u8)-1)
#define UNKNOWN_GLOBAL_INDEX ((u8)-1)
@ -19,7 +20,7 @@ enum NetworkPlayerType {
struct NetworkPlayer {
bool connected;
enum NetworkPlayerType type;
u8 type;
u8 localIndex;
u8 globalIndex;
f32 lastReceived;
@ -32,14 +33,20 @@ struct NetworkPlayer {
bool currLevelSyncValid;
bool currAreaSyncValid;
u8 fadeOpacity;
u16 rxSeqIds[MAX_RX_SEQ_IDS];
u8 onRxSeqId;
u8 modelIndex;
u8 paletteIndex;
char name[MAX_PLAYER_STRING];
u16 rxSeqIds[MAX_RX_SEQ_IDS];
};
extern struct NetworkPlayer gNetworkPlayers[];
extern struct NetworkPlayer* gNetworkPlayerLocal;
extern struct NetworkPlayer* gNetworkPlayerServer;
void network_player_init(void);
void network_player_update_model(u8 localIndex);
u8 network_player_unique_palette(u8 palette);
bool network_player_any_connected(void);
u8 network_player_connected_count(void);
struct NetworkPlayer* network_player_from_global_index(u8 globalIndex);
@ -47,7 +54,7 @@ struct NetworkPlayer* get_network_player_from_level(s16 courseNum, s16 actNum, s
struct NetworkPlayer* get_network_player_from_area(s16 courseNum, s16 actNum, s16 levelNum, s16 areaIndex);
struct NetworkPlayer* get_network_player_smallest_global(void);
void network_player_update(void);
u8 network_player_connected(enum NetworkPlayerType type, u8 globalIndex);
u8 network_player_connected(enum NetworkPlayerType type, u8 globalIndex, u8 modelIndex, u8 paletteIndex, char* name);
u8 network_player_disconnected(u8 globalIndex);
void network_player_shutdown(void);

View file

@ -20,6 +20,10 @@
extern u8* gOverrideEeprom;
static u8 eeprom[512] = { 0 };
static u8 sJoinRequestPlayerModel;
static u8 sJoinRequestPlayerPalette;
static char sJoinRequestPlayerName[MAX_PLAYER_STRING];
void network_send_join_request(void) {
assert(gNetworkType == NT_CLIENT);
@ -27,6 +31,11 @@ void network_send_join_request(void) {
struct Packet p;
packet_init(&p, PACKET_JOIN_REQUEST, true, false);
packet_write(&p, &configPlayerModel, sizeof(u8));
packet_write(&p, &configPlayerPalette, sizeof(u8));
packet_write(&p, &configPlayerName, sizeof(u8) * MAX_PLAYER_STRING);
network_send_to((gNetworkPlayerServer != NULL) ? gNetworkPlayerServer->localIndex : 0, &p);
LOG_INFO("sending join request");
}
@ -34,14 +43,28 @@ void network_send_join_request(void) {
void network_receive_join_request(struct Packet* p) {
assert(gNetworkType == NT_SERVER);
LOG_INFO("received join request");
if (p->dataLength > 5) {
packet_read(p, &sJoinRequestPlayerModel, sizeof(u8));
packet_read(p, &sJoinRequestPlayerPalette, sizeof(u8));
packet_read(p, &sJoinRequestPlayerName, sizeof(u8) * MAX_PLAYER_STRING);
} else {
sJoinRequestPlayerModel = 0;
sJoinRequestPlayerPalette = 0;
snprintf(sJoinRequestPlayerName, MAX_PLAYER_STRING, "%s", "Player");
}
network_send_join(p);
}
void network_send_join(struct Packet* joinRequestPacket) {
assert(gNetworkType == NT_SERVER);
// make palette unique
sJoinRequestPlayerPalette = network_player_unique_palette(sJoinRequestPlayerPalette);
// do connection event
joinRequestPacket->localIndex = network_player_connected(NPT_CLIENT, joinRequestPacket->localIndex);
joinRequestPacket->localIndex = network_player_connected(NPT_CLIENT, joinRequestPacket->localIndex, sJoinRequestPlayerModel, sJoinRequestPlayerPalette, sJoinRequestPlayerName);
if (joinRequestPacket->localIndex == UNKNOWN_LOCAL_INDEX) {
network_send_kick(EKT_FULL_PARTY);
return;
@ -177,8 +200,8 @@ void network_receive_join(struct Packet* p) {
}
string_linked_list_free(&head);
network_player_connected(NPT_SERVER, 0);
network_player_connected(NPT_LOCAL, myGlobalIndex);
network_player_connected(NPT_SERVER, 0, 0, 0, "Player");
network_player_connected(NPT_LOCAL, myGlobalIndex, configPlayerModel, configPlayerPalette, configPlayerName);
djui_chat_box_create();
save_file_load_all(TRUE);

View file

@ -4,6 +4,7 @@
#include "behavior_data.h"
#include "src/game/behavior_actions.h"
#include "pc/debuglog.h"
#include "pc/configfile.h"
static void network_send_to_network_players(u8 sendToLocalIndex) {
assert(gNetworkType == NT_SERVER);
@ -30,6 +31,9 @@ static void network_send_to_network_players(u8 sendToLocalIndex) {
packet_write(&p, &gNetworkPlayers[i].currLevelSyncValid, sizeof(u8));
packet_write(&p, &gNetworkPlayers[i].currAreaSyncValid, sizeof(u8));
packet_write(&p, &networkId, sizeof(s64));
packet_write(&p, &gNetworkPlayers[i].modelIndex, sizeof(u8));
packet_write(&p, &gNetworkPlayers[i].paletteIndex, sizeof(u8));
packet_write(&p, &gNetworkPlayers[i].name, sizeof(u8) * MAX_PLAYER_STRING);
LOG_INFO("send network player [%d == %d]", gNetworkPlayers[i].globalIndex, npType);
}
@ -60,6 +64,9 @@ void network_receive_network_players(struct Packet* p) {
s16 courseNum, actNum, levelNum, areaIndex;
u8 levelSyncValid, areaSyncValid;
s64 networkId;
u8 modelIndex, paletteIndex;
char playerName[MAX_PLAYER_STRING] = { 0 };
packet_read(p, &npType, sizeof(u8));
packet_read(p, &globalIndex, sizeof(u8));
packet_read(p, &levelAreaSeqId, sizeof(u16));
@ -70,11 +77,15 @@ void network_receive_network_players(struct Packet* p) {
packet_read(p, &levelSyncValid, sizeof(u8));
packet_read(p, &areaSyncValid, sizeof(u8));
packet_read(p, &networkId, sizeof(s64));
packet_read(p, &modelIndex, sizeof(u8));
packet_read(p, &paletteIndex, sizeof(u8));
packet_read(p, &playerName, sizeof(u8) * MAX_PLAYER_STRING);
u8 localIndex = network_player_connected(npType, globalIndex);
u8 localIndex = network_player_connected(npType, globalIndex, modelIndex, paletteIndex, playerName);
LOG_INFO("received network player [%d == %d] (%d)", globalIndex, npType, localIndex);
if (localIndex != UNKNOWN_GLOBAL_INDEX && localIndex != 0) {
if (localIndex != UNKNOWN_GLOBAL_INDEX) {
struct NetworkPlayer* np = &gNetworkPlayers[localIndex];
if (localIndex != 0) {
np->currLevelAreaSeqId = levelAreaSeqId;
np->currCourseNum = courseNum;
np->currActNum = actNum;
@ -88,4 +99,5 @@ void network_receive_network_players(struct Packet* p) {
}
}
}
}
}

View file

@ -325,11 +325,9 @@ void network_receive_player(struct Packet* p) {
// inform of player death
if (oldData.action != ACT_BUBBLED && data.action == ACT_BUBBLED) {
// display popup
u8* rgb = get_player_color(np->globalIndex, 0);
u8 rgb2[3] = { 0 };
for (int i = 0; i < 3; i++) { rgb2[i] = fmin((f32)rgb[i] * 1.3f + 32.0f, 255); }
u8* rgb = get_player_color(np->paletteIndex, 0);
char popupMsg[128] = { 0 };
snprintf(popupMsg, 128, "\\#%02x%02x%02x\\%s\\#dcdcdc\\ died.", rgb2[0], rgb2[1], rgb2[2], "Player");
snprintf(popupMsg, 128, "\\#%02x%02x%02x\\%s\\#dcdcdc\\ died.", rgb[0], rgb[1], rgb[2], np->name);
djui_popup_create(popupMsg, 1);
}
@ -337,11 +335,6 @@ void network_receive_player(struct Packet* p) {
if (m->action != oldData.action) {
m->actionTimer = 0;
}
// set model
enum CharacterType characterType = (np->globalIndex == 0) ? CT_MARIO : CT_LUIGI;
m->character = &gCharacters[characterType];
m->marioObj->header.gfx.sharedChild = gLoadedGraphNodes[m->character->modelId];
}
void network_update_player(void) {

View file

@ -42,6 +42,7 @@
#include "pc/discord/discordrpc.h"
#endif
#include "pc/network/version.h"
#include "pc/network/network_player.h"
#include "pc/djui/djui.h"
OSMesg D_80339BEC;
@ -288,6 +289,7 @@ void main_func(void) {
audio_init();
sound_init();
network_player_init();
thread5_game_loop(NULL);