diff --git a/src/game/interaction.c b/src/game/interaction.c index a16f6d59b..2404a48a0 100644 --- a/src/game/interaction.c +++ b/src/game/interaction.c @@ -635,7 +635,7 @@ u32 determine_knockback_action(struct MarioState *m, UNUSED s32 arg) { m->forwardVel = mag; if (sign > 0 && terrainIndex == 1) { mag *= -1.0f; } m->vel[0] = mag * sins(angleToObject); - m->vel[1] = abs(mag); + m->vel[1] = (mag < 0) ? -mag : mag; m->vel[2] = mag * coss(angleToObject); } @@ -1150,14 +1150,14 @@ static u8 resolve_player_collision(struct MarioState* m, struct MarioState* m2) f32 marioRelY = localTorso[1] - remoteTorso[1]; if (marioRelY < 0) { marioRelY = -marioRelY; } - if (marioRelY >= extentY) { return; } + if (marioRelY >= extentY) { return FALSE; } f32 marioRelX = localTorso[0] - remoteTorso[0]; f32 marioRelZ = localTorso[2] - remoteTorso[2]; f32 marioDist = sqrtf(sqr(marioRelX) + sqr(marioRelZ)); - if (marioDist >= radius) { return; } + if (marioDist >= radius) { return FALSE; } // bounce u32 interaction = determine_interaction(m, m2->marioObj); diff --git a/src/menu/file_select.c b/src/menu/file_select.c index 234b20025..3c947331a 100644 --- a/src/menu/file_select.c +++ b/src/menu/file_select.c @@ -22,8 +22,6 @@ #include "text_strings.h" #include "game/ingame_menu.h" -#include "pc/controller/controller_keyboard.h" -#include "pc/network/network.h" #include "eu_translation.h" #ifdef VERSION_EU @@ -31,6 +29,11 @@ #define LANGUAGE_FUNCTION sLanguageMode #endif +#include +#include "pc/configfile.h" +#include "pc/controller/controller_keyboard.h" +#include "pc/network/network.h" + /** * @file file_select.c * This file implements how the file select and it's menus render and function. @@ -404,8 +407,12 @@ void join_server_as_client(void) { char delims[] = { ' ' }; + // copy input + char buffer[MAX_TEXT_INPUT] = { 0 }; + strncpy(buffer, gTextInput, MAX_TEXT_INPUT); + char* text = buffer; + // trim whitespace - char* text = textInput; while (*text == ' ') { text++; } // grab IP @@ -414,16 +421,23 @@ void join_server_as_client(void) { exit_join_to_network_menu(); return; } + strncpy(configJoinIp, ip, MAX_CONFIG_STRING); // grab port char* port = strtok(NULL, delims); - if (port != NULL && atoi(port) == 0) { - exit_join_to_network_menu(); - return; + if (port != NULL) { + unsigned int intPort = atoi(port); + if (intPort == 0) { + exit_join_to_network_menu(); + return; + } + configJoinPort = intPort; + } else { + configJoinPort = DEFAULT_PORT; } keyboard_stop_text_input(); - network_init(NT_CLIENT, textInput, port); + network_init(NT_CLIENT, configJoinIp, configJoinPort); } void joined_server_as_client(s16 fileIndex) { @@ -467,7 +481,16 @@ void check_network_mode_menu_clicked_buttons(struct Object* networkModeButton) { play_sound(SOUND_MENU_CAMERA_ZOOM_IN, gDefaultSoundArgs); sMainMenuButtons[buttonID]->oMenuButtonState = MENU_BUTTON_STATE_GROWING; sSelectedButtonID = buttonID; + + // start input keyboard_start_text_input(TIM_IP, keyboard_exit_join_to_network_menu, join_server_as_client); + + // fill in config ip/port + static u8 openedJoinMenu = FALSE; + if (!openedJoinMenu && strlen(configJoinIp) > 0) { + if (configJoinPort == 0) { configJoinPort = DEFAULT_PORT; } + sprintf(gTextInput, "%s %d", configJoinIp, configJoinPort); + } } sCurrentMenuLevel = MENU_LAYER_SUBMENU; @@ -494,8 +517,8 @@ void print_network_mode_menu_strings(void) { gSPDisplayList(gDisplayListHead++, dl_ia_text_begin); -#define TEXT_HOST 0x11,0x18,0x1C,0x1D,0xFF -#define TEXT_JOIN 0x13,0x18,0x12,0x17,0xFF + #define TEXT_HOST 0x11,0x18,0x1C,0x1D,0xFF + #define TEXT_JOIN 0x13,0x18,0x12,0x17,0xFF static unsigned char textNetworkModes[][5] = { { TEXT_HOST }, { TEXT_JOIN } }; // Print network mode names @@ -535,9 +558,12 @@ void print_join_mode_menu_strings(void) { // Print level name print_generic_ascii_string(JOIN_LEVEL_NAME_X, 191 - (12 * 0), "Type or paste the host's IP."); - print_generic_ascii_string(JOIN_LEVEL_NAME_X, 191 - (12 * 2), textInput); + print_generic_ascii_string(JOIN_LEVEL_NAME_X, 191 - (12 * 2), gTextInput); - if (strlen(textInput) > 0) { + // Print status + if (networkType == NT_CLIENT) { + print_generic_ascii_string(JOIN_LEVEL_NAME_X, 191 - (12 * 14), "Connecting..."); + } else if (strlen(gTextInput) > 0) { print_generic_ascii_string(JOIN_LEVEL_NAME_X, 191 - (12 * 14), "Press (ENTER) to join."); } @@ -1304,7 +1330,8 @@ void check_sound_mode_menu_clicked_buttons(struct Object *soundModeButton) { void load_main_menu_save_file(struct Object *fileButton, s32 fileNum) { if (fileButton->oMenuButtonState == MENU_BUTTON_STATE_FULLSCREEN) { sSelectedFileNum = fileNum; - network_init(NT_SERVER, "", NETWORK_DEFAULT_PORT); + configHostSaveSlot = fileNum; + network_init(NT_SERVER, "", configHostPort); } } @@ -3092,7 +3119,7 @@ s32 lvl_init_menu_values_and_cursor_pos(UNUSED s32 arg, UNUSED s32 unused) { // immediately jump in if (networkType == NT_SERVER) { - sSelectedFileNum = 1; + sSelectedFileNum = configHostSaveSlot; } //! no return value diff --git a/src/pc/cliopts.c b/src/pc/cliopts.c index c3c7e3c55..3f20f911a 100644 --- a/src/pc/cliopts.c +++ b/src/pc/cliopts.c @@ -57,12 +57,12 @@ void parse_cli_opts(int argc, char* argv[]) { else if (strcmp(argv[i], "--server") == 0 && (i + 1) < argc) { // Host server gCLIOpts.Network = NT_SERVER; - arg_string("--server ", argv[++i], gCLIOpts.NetworkPort, PORT_MAX_LEN); + arg_uint("--server ", argv[++i], &gCLIOpts.NetworkPort); } else if (strcmp(argv[i], "--client") == 0 && (i + 2) < argc) { // Join server gCLIOpts.Network = NT_CLIENT; arg_string("--client ", argv[++i], gCLIOpts.JoinIp, IP_MAX_LEN); - arg_string("--client ", argv[++i], gCLIOpts.NetworkPort, PORT_MAX_LEN); + arg_uint("--client ", argv[++i], &gCLIOpts.NetworkPort); } else if (strcmp(argv[i], "--cheats") == 0) // Enable cheats menu Cheats.EnableCheats = true; diff --git a/src/pc/cliopts.h b/src/pc/cliopts.h index d0d300557..916e19b12 100644 --- a/src/pc/cliopts.h +++ b/src/pc/cliopts.h @@ -17,7 +17,7 @@ struct PCCLIOptions { unsigned int FullScreen; enum NetworkType Network; char JoinIp[IP_MAX_LEN]; - char NetworkPort[PORT_MAX_LEN]; + unsigned int NetworkPort; unsigned int PoolSize; char ConfigFile[SYS_MAX_PATH]; char SavePath[SYS_MAX_PATH]; diff --git a/src/pc/configfile.c b/src/pc/configfile.c index 4b41760a4..e04e15dc6 100644 --- a/src/pc/configfile.c +++ b/src/pc/configfile.c @@ -21,6 +21,7 @@ enum ConfigOptionType { CONFIG_TYPE_UINT, CONFIG_TYPE_FLOAT, CONFIG_TYPE_BIND, + CONFIG_TYPE_STRING, }; struct ConfigOption { @@ -29,7 +30,8 @@ struct ConfigOption { union { bool *boolValue; unsigned int *uintValue; - float *floatValue; + float* floatValue; + char* stringValue; }; }; @@ -83,7 +85,7 @@ unsigned int configCameraAggr = 0; unsigned int configCameraPan = 0; unsigned int configCameraDegrade = 50; // 0 - 100% bool configCameraInvertX = false; -bool configCameraInvertY = false; +bool configCameraInvertY = true; bool configEnableCamera = true; bool configCameraAnalog = true; bool configCameraMouse = false; @@ -93,6 +95,12 @@ bool configHUD = true; #ifdef DISCORDRPC bool configDiscordRPC = true; #endif +// coop-specific +char configJoinIp[MAX_CONFIG_STRING] = ""; +unsigned int configJoinPort = DEFAULT_PORT; +unsigned int configHostPort = DEFAULT_PORT; +unsigned int configHostSaveSlot = 1; +unsigned int configPlayerInteraction = 1; static const struct ConfigOption options[] = { {.name = "fullscreen", .type = CONFIG_TYPE_BOOL, .boolValue = &configWindow.fullscreen}, @@ -141,6 +149,12 @@ static const struct ConfigOption options[] = { #ifdef DISCORDRPC {.name = "discordrpc_enable", .type = CONFIG_TYPE_BOOL, .boolValue = &configDiscordRPC}, #endif + // coop-specific + {.name = "coop_join_ip", .type = CONFIG_TYPE_STRING, .stringValue = (char*)&configJoinIp}, + {.name = "coop_join_port", .type = CONFIG_TYPE_UINT , .uintValue = &configJoinPort}, + {.name = "coop_host_port", .type = CONFIG_TYPE_UINT , .uintValue = &configHostPort}, + {.name = "coop_host_save_slot", .type = CONFIG_TYPE_UINT , .uintValue = &configHostSaveSlot}, + {.name = "coop_player_interaction", .type = CONFIG_TYPE_UINT , .uintValue = &configPlayerInteraction}, }; // Reads an entire line from a file (excluding the newline character) and returns an allocated string @@ -281,6 +295,10 @@ void configfile_load(const char *filename) { case CONFIG_TYPE_FLOAT: sscanf(tokens[1], "%f", option->floatValue); break; + case CONFIG_TYPE_STRING: + memset(option->stringValue, '\0', MAX_CONFIG_STRING); + strncpy(option->stringValue, tokens[1], MAX_CONFIG_STRING); + break; default: assert(0); // bad type } @@ -328,6 +346,9 @@ void configfile_save(const char *filename) { fprintf(file, "%04x ", option->uintValue[i]); fprintf(file, "\n"); break; + case CONFIG_TYPE_STRING: + fprintf(file, "%s %s\n", option->name, option->stringValue); + break; default: assert(0); // unknown type } diff --git a/src/pc/configfile.h b/src/pc/configfile.h index b92ae7bea..b5f30e7a7 100644 --- a/src/pc/configfile.h +++ b/src/pc/configfile.h @@ -7,6 +7,9 @@ #define MAX_BINDS 3 #define MAX_VOLUME 127 +#define MAX_CONFIG_STRING 64 + +#define DEFAULT_PORT 7777 typedef struct { unsigned int x, y, w, h; @@ -59,6 +62,11 @@ extern bool configSkipIntro; #ifdef DISCORDRPC extern bool configDiscordRPC; #endif +extern char configJoinIp[]; +extern unsigned int configJoinPort; +extern unsigned int configHostPort; +extern unsigned int configHostSaveSlot; +extern unsigned int configPlayerInteraction; void configfile_load(const char *filename); void configfile_save(const char *filename); diff --git a/src/pc/controller/controller_keyboard.c b/src/pc/controller/controller_keyboard.c index 1cc5d646c..08d0676c0 100644 --- a/src/pc/controller/controller_keyboard.c +++ b/src/pc/controller/controller_keyboard.c @@ -29,7 +29,7 @@ static int num_keybinds = 0; static u32 keyboard_lastkey = VK_INVALID; -char textInput[MAX_TEXT_INPUT]; +char gTextInput[MAX_TEXT_INPUT]; static bool inTextInput = false; u8 held_ctrl, held_shift, held_alt; @@ -77,7 +77,7 @@ bool keyboard_on_key_down(int scancode) { // perform text-input-specific actions switch (scancode) { case SCANCODE_BACKSPACE: - textInput[max(strlen(textInput) - 1, 0)] = '\0'; + gTextInput[max(strlen(gTextInput) - 1, 0)] = '\0'; break; case SCANCODE_ESCAPE: if (textInputOnEscape != NULL) { textInputOnEscape(); } @@ -129,7 +129,7 @@ char* keyboard_start_text_input(enum TextInputMode inInputMode, void (*onEscape) textInputOnEnter = onEnter; // clear buffer - for (int i = 0; i < MAX_TEXT_INPUT; i++) { textInput[i] = '\0'; } + for (int i = 0; i < MAX_TEXT_INPUT; i++) { gTextInput[i] = '\0'; } // clear held-value for modifiers held_ctrl = 0; @@ -182,14 +182,14 @@ void keyboard_on_text_input(char* text) { // sanity check input if (text == NULL) { return; } - int i = strlen(textInput); + int i = strlen(gTextInput); while (*text != '\0') { // make sure we don't overrun the buffer if (i >= MAX_TEXT_INPUT) { break; } // copy over character if we're allowed to input it if (keyboard_allow_character_input(*text)) { - textInput[i++] = *text; + gTextInput[i++] = *text; } text++; diff --git a/src/pc/controller/controller_keyboard.h b/src/pc/controller/controller_keyboard.h index f148ab384..43213630c 100644 --- a/src/pc/controller/controller_keyboard.h +++ b/src/pc/controller/controller_keyboard.h @@ -11,7 +11,7 @@ extern "C" { #endif #define MAX_TEXT_INPUT 256 -extern char textInput[]; +extern char gTextInput[]; enum TextInputMode { TIM_IP, diff --git a/src/pc/network/network.c b/src/pc/network/network.c index 52ac3bb00..1086c14f6 100644 --- a/src/pc/network/network.c +++ b/src/pc/network/network.c @@ -3,6 +3,7 @@ #include "object_fields.h" #include "object_constants.h" #include "socket/socket.h" +#include "pc/configfile.h" enum NetworkType networkType; static SOCKET gSocket; @@ -16,12 +17,19 @@ struct ServerSettings gServerSettings = { .playerInteractions = PLAYER_INTERACTIONS_SOLID, }; -void network_init(enum NetworkType inNetworkType, char* ip, char* port) { +void network_init(enum NetworkType inNetworkType, char* ip, unsigned int port) { networkType = inNetworkType; if (networkType == NT_NONE) { return; } - if (port == NULL) { - port = NETWORK_DEFAULT_PORT; + + // sanity check port + if (port == 0) { + port = (networkType == NT_CLIENT) ? configJoinPort : configHostPort; + if (port == 0) { port = DEFAULT_PORT; } + } + + if (networkType == NT_SERVER) { + gServerSettings.playerInteractions = configPlayerInteraction; } // Create a receiver socket to receive datagrams @@ -30,12 +38,12 @@ void network_init(enum NetworkType inNetworkType, char* ip, char* port) { // Bind the socket to any address and the specified port. if (networkType == NT_SERVER) { - int rc = socket_bind(gSocket, atoi(port)); + int rc = socket_bind(gSocket, port); if (rc != NO_ERROR) { return; } } else { // Save the port to send to txAddr.sin_family = AF_INET; - txAddr.sin_port = htons(atoi(port)); + txAddr.sin_port = htons(port); txAddr.sin_addr.s_addr = inet_addr(ip); } diff --git a/src/pc/network/network.h b/src/pc/network/network.h index f0e045541..ec2f0a693 100644 --- a/src/pc/network/network.h +++ b/src/pc/network/network.h @@ -14,7 +14,6 @@ #define MAX_SYNC_OBJECT_FIELDS 64 #define PACKET_LENGTH 1024 #define NETWORKTYPESTR (networkType == NT_CLIENT ? "Client" : "Server") -#define NETWORK_DEFAULT_PORT "7777" enum PacketType { PACKET_ACK, @@ -82,7 +81,7 @@ extern bool networkLevelLoaded; extern struct ServerSettings gServerSettings; -void network_init(enum NetworkType inNetworkType, char* ip, char* port); +void network_init(enum NetworkType inNetworkType, char* ip, unsigned int port); void network_on_init_level(void); void network_on_loaded_level(void);