From e447332cec8c5290e7f480ba6c46b75170414dd5 Mon Sep 17 00:00:00 2001 From: MegaMech Date: Fri, 16 Oct 2020 03:58:57 -0600 Subject: [PATCH] Added server settings: shared lives and skip intro Adds button to the host menu to allow shared lives. Resolves #37 Buttons are now resizeable. Use gButtonScale. (large, medium, or small). It could be argued that we don't need the small size. However, it may be beneficial for the future if the menu becomes more complex. large is the normal default size. Or at least it was the size already being used by sm64ex-coop (0.11111111f) Note: Buttons for changing menu's should be gButtonScale.large as the menu animation is made for large buttons. To keep consistency it's probably a good idea for buttons that transfer you to a new menu to always be set to large. As such, I didn't feel it necessary to extend this feature to these methods: bhv_menu_button_growing_from_custom and bhv_menu_button_shrinking_to_custom. Resolves #60 --- src/game/level_update.c | 2 +- src/game/mario.c | 3 ++ src/menu/custom_menu.c | 55 +++++++++++++++++---------- src/menu/custom_menu_system.c | 30 +++++++++------ src/menu/custom_menu_system.h | 11 +++++- src/pc/configfile.c | 2 + src/pc/configfile.h | 1 + src/pc/network/network.c | 4 ++ src/pc/network/network.h | 2 + src/pc/network/packets/packet.c | 3 +- src/pc/network/packets/packet.h | 1 + src/pc/network/packets/packet_death.c | 20 ++++++++++ src/pc/network/packets/packet_join.c | 4 ++ 13 files changed, 103 insertions(+), 35 deletions(-) create mode 100644 src/pc/network/packets/packet_death.c diff --git a/src/game/level_update.c b/src/game/level_update.c index 47480020b..52d8def9f 100644 --- a/src/game/level_update.c +++ b/src/game/level_update.c @@ -1356,7 +1356,7 @@ s32 init_level(void) { if (gMarioState->action != ACT_UNINITIALIZED) { if (save_file_exists(gCurrSaveFileNum - 1)) { set_mario_action(gMarioState, ACT_IDLE, 0); - } else if (gCLIOpts.SkipIntro == 0 && configSkipIntro == 0) { + } else if (gCLIOpts.SkipIntro == 0 && configSkipIntro == 0 && gServerSettings.skipIntro == 0) { set_mario_action(gMarioState, ACT_INTRO_CUTSCENE, 0); val4 = 1; } diff --git a/src/game/mario.c b/src/game/mario.c index 0d06fba5c..3e947d735 100644 --- a/src/game/mario.c +++ b/src/game/mario.c @@ -391,6 +391,9 @@ void mario_set_bubbled(struct MarioState* m) { set_mario_action(m, ACT_BUBBLED, 0); if (m->numLives != -1) { m->numLives--; + if (gServerSettings.shareLives) { + network_send_death(); + } } m->healCounter = 0; m->hurtCounter = 31; diff --git a/src/menu/custom_menu.c b/src/menu/custom_menu.c index 98892b3ea..111277e84 100644 --- a/src/menu/custom_menu.c +++ b/src/menu/custom_menu.c @@ -26,6 +26,7 @@ char sConnectionJoinError[128] = { 0 }; char gConnectionText[128] = { 0 }; struct CustomMenu* sConnectMenu = NULL; + u8 gOpenConnectMenu = FALSE; s8 sGotoGame = 0; @@ -42,9 +43,9 @@ static void menu_main_draw_strings(void) { static void host_menu_draw_strings(void) { #ifdef DISCORD_SDK - #define HOST_MENU_MAX_ITEMS 4 + #define HOST_MENU_MAX_ITEMS 6 #else - #define HOST_MENU_MAX_ITEMS 3 + #define HOST_MENU_MAX_ITEMS 5 #endif // set up server setting strings @@ -66,23 +67,26 @@ static void host_menu_draw_strings(void) { buttonText[2] = configStayInLevelAfterStar ? "Stay in level after star." : "Leave level after star."; + buttonText[3] = configSkipIntro ? "Skip intro cutscene." : "Play intro cutscene."; + + buttonText[4] = configShareLives ? "Share lives." : "Lives are not shared."; + #ifdef DISCORD_SDK - buttonText[3] = (configNetworkSystem == 0) ? "Host through Discord." : "Host direct connection."; + buttonText[5] = (configNetworkSystem == 0) ? "Host through Discord." : "Host direct connection."; #endif // display server setting strings for (int i = 0; i < HOST_MENU_MAX_ITEMS; i++) { - print_generic_ascii_string(95, 158 + -35 * i, buttonText[i]); + print_generic_ascii_string(95, 173 + -29 * i, buttonText[i]); } // display direct connection warning if (configNetworkSystem != 0) { - print_generic_ascii_string(0, 30, "For direct connections -"); f32 red = (f32)fabs(sin(gGlobalTimer / 20.0f)); gDPSetEnvColor(gDisplayListHead++, 222, 222 * red, 222 * red, gMenuStringAlpha); char warning[128]; - snprintf(warning, 127, "You must forward port '%d' in your router or use Hamachi.", configHostPort); - print_generic_ascii_string(0, 15, warning); + snprintf(warning, 127, "Port forward '%d' in network router settings or use Hamachi.", configHostPort); + print_generic_ascii_string(0, 5, warning); } else if ((configNetworkSystem == 0) && gDiscordFailed) { f32 red = (f32)fabs(sin(gGlobalTimer / 20.0f)); gDPSetEnvColor(gDisplayListHead++, 222, 222 * red, 222 * red, gMenuStringAlpha); @@ -134,6 +138,14 @@ static void host_menu_setting_stay_in_level(void) { configStayInLevelAfterStar = (configStayInLevelAfterStar == 0) ? 1 : 0; } +static void host_menu_setting_skip_intro(void) { + configSkipIntro = (configSkipIntro == 1) ? 0 : 1; +} + +static void host_menu_setting_share_lives(void) { + configShareLives = (configShareLives == 0) ? 1 : 0; +} + #ifdef DISCORD_SDK static void join_menu_draw_strings(void) { print_generic_ascii_string(30, 155, "Accept a Discord game invite in order to join."); @@ -217,7 +229,7 @@ static void connect_menu_on_click(void) { // fill in our last attempt if (configJoinPort == 0 || configJoinPort > 65535) { configJoinPort = DEFAULT_PORT; } - + // only print custom port if (configJoinPort == DEFAULT_PORT) { sprintf(gTextInput, "%s", configJoinIp); @@ -243,29 +255,32 @@ void custom_menu_init(struct CustomMenu* head) { head->draw_strings = menu_main_draw_strings; // create sub menus and buttons - struct CustomMenu* hostMenu = custom_menu_create(head, "HOST", -266, 0); + struct CustomMenu* hostMenu = custom_menu_create(head, "HOST", -266, 0, gButtonScale.large); + hostMenu->headerY = 30; hostMenu->draw_strings = host_menu_draw_strings; - custom_menu_create_button(hostMenu, "CANCEL", 700, -400 + (250 * 3), SOUND_MENU_CAMERA_ZOOM_OUT, custom_menu_close); - custom_menu_create_button(hostMenu, "HOST", 700, -400, SOUND_MENU_CAMERA_ZOOM_IN, host_menu_do_host); - custom_menu_create_button(hostMenu, "", -700, -400 + (250 * 3), SOUND_ACTION_BONK, host_menu_setting_interaction); - custom_menu_create_button(hostMenu, "", -700, -400 + (250 * 2), SOUND_ACTION_BONK, host_menu_setting_knockback); - custom_menu_create_button(hostMenu, "", -700, -400 + (250 * 1), SOUND_ACTION_BONK, host_menu_setting_stay_in_level); + custom_menu_create_button(hostMenu, "CANCEL", 700, -196 + (210 * 3), gButtonScale.large, SOUND_MENU_CAMERA_ZOOM_OUT, custom_menu_close); + custom_menu_create_button(hostMenu, "HOST", 700, -220, gButtonScale.large, SOUND_MENU_CAMERA_ZOOM_IN, host_menu_do_host); + custom_menu_create_button(hostMenu, "", -700, -180 + (210 * 3), gButtonScale.medium, SOUND_ACTION_BONK, host_menu_setting_interaction); + custom_menu_create_button(hostMenu, "", -700, -180 + (210 * 2), gButtonScale.medium, SOUND_ACTION_BONK, host_menu_setting_knockback); + custom_menu_create_button(hostMenu, "", -700, -180 + (210 * 1), gButtonScale.medium, SOUND_ACTION_BONK, host_menu_setting_stay_in_level); + custom_menu_create_button(hostMenu, "", -700, -180 + (210 * 0), gButtonScale.medium, SOUND_ACTION_BONK, host_menu_setting_skip_intro); + custom_menu_create_button(hostMenu, "", -700, -180 + (210 * -1), gButtonScale.medium, SOUND_ACTION_BONK, host_menu_setting_share_lives); #ifdef DISCORD_SDK - custom_menu_create_button(hostMenu, "", -700, -400 + (250 * 0), SOUND_ACTION_BONK, host_menu_setting_network_system); + custom_menu_create_button(hostMenu, "", -700, -180 + (210 * -2), gButtonScale.medium, SOUND_ACTION_BONK, host_menu_setting_network_system); #endif #ifdef DISCORD_SDK - struct CustomMenu* joinMenu = custom_menu_create(head, "JOIN", 266, 0); - custom_menu_create_button(joinMenu, "CANCEL", -266, -320, SOUND_MENU_CAMERA_ZOOM_OUT, custom_menu_close); + struct CustomMenu* joinMenu = custom_menu_create(head, "JOIN", 266, 0, gButtonScale.large); + custom_menu_create_button(joinMenu, "CANCEL", -266, -320, gButtonScale.large, SOUND_MENU_CAMERA_ZOOM_OUT, custom_menu_close); joinMenu->draw_strings = join_menu_draw_strings; - struct CustomMenu* connectMenu = custom_menu_create(joinMenu, "CONNECT", 266, -320); + struct CustomMenu* connectMenu = custom_menu_create(joinMenu, "CONNECT", 266, -320, gButtonScale.large); #else - struct CustomMenu* connectMenu = custom_menu_create(head, "CONNECT", 266, 0); + struct CustomMenu* connectMenu = custom_menu_create(head, "CONNECT", 266, 0, gButtonScale.large); #endif connectMenu->me->on_click = connect_menu_on_click; connectMenu->on_close = connect_menu_on_close; connectMenu->draw_strings = connect_menu_draw_strings; - custom_menu_create_button(connectMenu, "CANCEL", 0, -400, SOUND_MENU_CAMERA_ZOOM_OUT, custom_menu_close); + custom_menu_create_button(connectMenu, "CANCEL", 0, -400, gButtonScale.large, SOUND_MENU_CAMERA_ZOOM_OUT, custom_menu_close); sConnectMenu = connectMenu; } diff --git a/src/menu/custom_menu_system.c b/src/menu/custom_menu_system.c index 0fa5c6b21..ce1e14cfc 100644 --- a/src/menu/custom_menu_system.c +++ b/src/menu/custom_menu_system.c @@ -20,6 +20,11 @@ static struct CustomMenu* sHead = NULL; static struct CustomMenu* sCurrentMenu = NULL; static struct CustomMenu* sLastMenu = NULL; +struct CustomMenuButtonScale gButtonScale = { + .small = 0.08111111f, + .medium = 0.09511111f, + .large = 0.11111111f, +}; u8 gMenuStringAlpha = 255; @@ -29,7 +34,7 @@ struct ErrorDialog { }; static struct ErrorDialog* sErrorDialog = NULL; -struct CustomMenuButton* custom_menu_create_button(struct CustomMenu* parent, char* label, u16 x, u16 y, s32 clickSound, void (*on_click)(void)) { +struct CustomMenuButton* custom_menu_create_button(struct CustomMenu* parent, char* label, u16 x, u16 y, f32 scale, s32 clickSound, void (*on_click)(void)) { struct CustomMenuButton* button = calloc(1, sizeof(struct CustomMenuButton)); if (parent->buttons == NULL) { parent->buttons = button; @@ -45,7 +50,8 @@ struct CustomMenuButton* custom_menu_create_button(struct CustomMenu* parent, ch button->clickSound = clickSound; struct Object* obj = spawn_object_rel_with_rot(parent->me->object, MODEL_MAIN_MENU_MARIO_NEW_BUTTON, bhvMenuButton, x * -1, y, -1, 0, 0x8000, 0); - obj->oMenuButtonScale = 0.11111111f; + + obj->oMenuButtonScale = scale; obj->oFaceAngleRoll = 0; obj->oMenuButtonTimer = 0; obj->oMenuButtonOrigPosX = obj->oParentRelativePosX; @@ -57,8 +63,8 @@ struct CustomMenuButton* custom_menu_create_button(struct CustomMenu* parent, ch return button; } -struct CustomMenu* custom_menu_create(struct CustomMenu* parent, char* label, u16 x, u16 y) { - struct CustomMenuButton* button = custom_menu_create_button(parent, label, x, y, SOUND_MENU_CAMERA_ZOOM_IN, NULL); +struct CustomMenu* custom_menu_create(struct CustomMenu* parent, char* label, u16 x, u16 y, f32 scale) { + struct CustomMenuButton* button = custom_menu_create_button(parent, label, x, y, scale, SOUND_MENU_CAMERA_ZOOM_IN, NULL); struct CustomMenu* menu = calloc(1, sizeof(struct CustomMenu)); menu->parent = parent; menu->depth = parent->depth + 1; @@ -183,13 +189,15 @@ void custom_menu_close_system(void) { static s32 cursor_inside_button(struct CustomMenuButton* button, f32 cursorX, f32 cursorY) { f32 x = button->object->oParentRelativePosX; f32 y = button->object->oParentRelativePosY; + f32 scale = button->object->oMenuButtonScale; + x *= -0.137f; y *= 0.137f; - s16 maxX = x + 25.0f; - s16 minX = x - 25.0f; - s16 maxY = y + 21.0f; - s16 minY = y - 21.0f; + s16 maxX = x + scale * 185.0f; + s16 minX = x - scale * 185.0f; + s16 maxY = y + scale * 185.0f; + s16 minY = y - scale * 101.0f; return (cursorX < maxX && minX < cursorX && cursorY < maxY && minY < cursorY); } @@ -236,7 +244,7 @@ void custom_menu_cursor_click(f32 cursorX, f32 cursorY) { } if (didSomething) { break; } - } + } button = button->next; } } @@ -254,7 +262,7 @@ void custom_menu_print_strings(void) { // figure out alpha struct Object* curObj = sCurrentMenu->me->object; struct Object* lastObj = (sLastMenu != NULL) ? sLastMenu->me->object : NULL; - + if (curObj != NULL && lastObj != NULL) { if (curObj->oMenuButtonState == MENU_BUTTON_STATE_FULLSCREEN && lastObj->oMenuButtonState != MENU_BUTTON_STATE_SHRINKING) { if (gMenuStringAlpha < 250) { @@ -398,4 +406,4 @@ void custom_menu_error(char* message) { item = item->next; } } -} \ No newline at end of file +} diff --git a/src/menu/custom_menu_system.h b/src/menu/custom_menu_system.h index 9bc5ed70d..f2e998d41 100644 --- a/src/menu/custom_menu_system.h +++ b/src/menu/custom_menu_system.h @@ -21,11 +21,18 @@ struct CustomMenu { void (*on_close)(void); }; +struct CustomMenuButtonScale { + f32 small; + f32 medium; + f32 large; +}; +extern struct CustomMenuButtonScale gButtonScale; + extern u8 gMenuStringAlpha; void custom_menu_system_init(void); -struct CustomMenu* custom_menu_create(struct CustomMenu* parent, char* label, u16 x, u16 y); -struct CustomMenuButton* custom_menu_create_button(struct CustomMenu* parent, char* label, u16 x, u16 y, s32 clickSound, void (*on_click)(void)); +struct CustomMenu* custom_menu_create(struct CustomMenu* parent, char* label, u16 x, u16 y, f32 scale); +struct CustomMenuButton* custom_menu_create_button(struct CustomMenu* parent, char* label, u16 x, u16 y, f32 scale, s32 clickSound, void (*on_click)(void)); void custom_menu_system_loop(void); void custom_menu_print_strings(void); diff --git a/src/pc/configfile.c b/src/pc/configfile.c index 0e033076a..da56a239f 100644 --- a/src/pc/configfile.c +++ b/src/pc/configfile.c @@ -92,6 +92,7 @@ bool configCameraAnalog = true; bool configCameraMouse = false; #endif bool configSkipIntro = 0; +bool configShareLives = 0; bool configHUD = true; #ifdef DISCORDRPC bool configDiscordRPC = true; @@ -151,6 +152,7 @@ static const struct ConfigOption options[] = { {.name = "bettercam_degrade", .type = CONFIG_TYPE_UINT, .uintValue = &configCameraDegrade}, #endif {.name = "skip_intro", .type = CONFIG_TYPE_BOOL, .boolValue = &configSkipIntro}, + {.name = "share_lives", .type = CONFIG_TYPE_BOOL, .boolValue = &configShareLives}, #ifdef DISCORDRPC {.name = "discordrpc_enable", .type = CONFIG_TYPE_BOOL, .boolValue = &configDiscordRPC}, #endif diff --git a/src/pc/configfile.h b/src/pc/configfile.h index 9cae3866f..a6cae6974 100644 --- a/src/pc/configfile.h +++ b/src/pc/configfile.h @@ -60,6 +60,7 @@ extern bool configCameraAnalog; #endif extern bool configHUD; extern bool configSkipIntro; +extern bool configShareLives; #ifdef DISCORDRPC extern bool configDiscordRPC; #endif diff --git a/src/pc/network/network.c b/src/pc/network/network.c index ae0153028..b9f9a6b79 100644 --- a/src/pc/network/network.c +++ b/src/pc/network/network.c @@ -28,6 +28,8 @@ struct StringLinkedList gRegisteredMods = { 0 }; struct ServerSettings gServerSettings = { .playerInteractions = PLAYER_INTERACTIONS_SOLID, .playerKnockbackStrength = 25, + .skipIntro = 0, + .shareLives = 0, }; void network_set_system(enum NetworkSystemType nsType) { @@ -51,6 +53,8 @@ bool network_init(enum NetworkType inNetworkType) { gServerSettings.playerInteractions = configPlayerInteraction; gServerSettings.playerKnockbackStrength = configPlayerKnockbackStrength; gServerSettings.stayInLevelAfterStar = configStayInLevelAfterStar; + gServerSettings.skipIntro = configSkipIntro; + gServerSettings.shareLives = configShareLives; // initialize the network system int rc = gNetworkSystem->initialize(inNetworkType); diff --git a/src/pc/network/network.h b/src/pc/network/network.h index fc82ca1ca..e8f459cb4 100644 --- a/src/pc/network/network.h +++ b/src/pc/network/network.h @@ -74,6 +74,8 @@ struct ServerSettings { enum PlayerInteractions playerInteractions; u8 playerKnockbackStrength; u8 stayInLevelAfterStar; + u8 skipIntro; + u8 shareLives; }; // Networking-specific externs diff --git a/src/pc/network/packets/packet.c b/src/pc/network/packets/packet.c index d2e185f85..800cc8db6 100644 --- a/src/pc/network/packets/packet.c +++ b/src/pc/network/packets/packet.c @@ -55,6 +55,7 @@ void packet_receive(struct Packet* p) { case PACKET_SAVE_FILE: network_receive_save_file(p); break; case PACKET_INSTANT_WARP: network_receive_instant_warp(p); break; case PACKET_NETWORK_PLAYERS: network_receive_network_players(p); break; + case PACKET_DEATH: network_receive_death(p); break; /// case PACKET_CUSTOM: network_receive_custom(p); break; default: LOG_ERROR("received unknown packet: %d", p->buffer[0]); @@ -73,4 +74,4 @@ void packet_receive(struct Packet* p) { } } } -} \ No newline at end of file +} diff --git a/src/pc/network/packets/packet.h b/src/pc/network/packets/packet.h index 969ca941f..a5b1b036e 100644 --- a/src/pc/network/packets/packet.h +++ b/src/pc/network/packets/packet.h @@ -32,6 +32,7 @@ enum PacketType { PACKET_SAVE_FILE, PACKET_INSTANT_WARP, PACKET_NETWORK_PLAYERS, + PACKET_DEATH, /// PACKET_CUSTOM = 255, }; diff --git a/src/pc/network/packets/packet_death.c b/src/pc/network/packets/packet_death.c new file mode 100644 index 000000000..67bf7cf44 --- /dev/null +++ b/src/pc/network/packets/packet_death.c @@ -0,0 +1,20 @@ +#include +#include "sm64.h" +#include "../network.h" + +extern struct MarioState gMarioStates[]; + +void network_send_death(void) { + if (gMarioStates[0].numLives < -1) { gMarioStates[0].numLives = -1; } + struct Packet p = { 0 }; + packet_init(&p, PACKET_DEATH, true, false); + packet_write(&p, &gMarioStates[0].numLives, sizeof(u8)); + network_send(&p); +} +void network_receive_death(struct Packet* p) { + u8 numLives = 0; + packet_read(p, &numLives, sizeof(u8)); + if (numLives < gMarioStates[0].numLives) { + gMarioStates[0].numLives = numLives; + } +} diff --git a/src/pc/network/packets/packet_join.c b/src/pc/network/packets/packet_join.c index fbc4aa483..ad7307ee7 100644 --- a/src/pc/network/packets/packet_join.c +++ b/src/pc/network/packets/packet_join.c @@ -61,6 +61,8 @@ void network_send_join(struct Packet* joinRequestPacket) { packet_write(&p, &gServerSettings.playerInteractions, sizeof(u8)); packet_write(&p, &gServerSettings.playerKnockbackStrength, sizeof(u8)); packet_write(&p, &gServerSettings.stayInLevelAfterStar, sizeof(u8)); + packet_write(&p, &gServerSettings.skipIntro, sizeof(u8)); + packet_write(&p, &gServerSettings.shareLives, sizeof(u8)); packet_write(&p, eeprom, sizeof(u8) * 512); u8 modCount = string_linked_list_count(&gRegisteredMods); @@ -124,6 +126,8 @@ void network_receive_join(struct Packet* p) { packet_read(p, &gServerSettings.playerInteractions, sizeof(u8)); packet_read(p, &gServerSettings.playerKnockbackStrength, sizeof(u8)); packet_read(p, &gServerSettings.stayInLevelAfterStar, sizeof(u8)); + packet_read(p, &gServerSettings.skipIntro, sizeof(u8)); + packet_read(p, &gServerSettings.shareLives, sizeof(u8)); packet_read(p, eeprom, sizeof(u8) * 512); packet_read(p, &modCount, sizeof(u8));