diff --git a/README.md b/README.md index f9c2ba44..85ef4789 100644 --- a/README.md +++ b/README.md @@ -297,6 +297,7 @@ Some commands only work on the game server and not on the proxy server. The chat * `$arrow `: Changes your lobby arrow color. * `$secid `: Sets your override section ID. After running this command, any games you create will use your override section ID for rare drops instead of your character's actual section ID. To revert to your actual section id, run `$secid` with no name after it. On the proxy server, this will not work if the remote server controls item drops (e.g. on BB, or on Schtserv with server drops enabled). * `$rand `: Sets your override random seed (specified as a 32-bit hex value). This will make any games you create use the given seed for rare enemies. This also makes item drops deterministic in Blue Burst games hosted by newserv. On the proxy server, this command can cause desyncs with other players in the same game, since they will not see the overridden random seed. To remove the override, run `$rand` with no arguments. + * `$ln [name-or-type]`: Sets the lobby number. Visible only to you. This command exists because some non-lobby maps can be loaded as lobbies with invalid lobby numbers. See the "GC lobby types" and "Ep3 lobby types" entries in the information menu for acceptable values here. Note that non-lobby maps do not have a lobby counter, so there's no way to exit the lobby without using either `$ln` again or `$exit`. On the game server, `$ln` reloads the lobby immediately; on the proxy server, it doesn't take effect until you load another lobby yourself (which means you'll like have to use `$exit` to escape). Run this command with no argument to return to the default lobby. * `$exit`: If you're in a lobby, sends you to the main menu (which ends your proxy session, if you're in one). If you're in a game or spectator team, sends you to the lobby (but does not end your proxy session if you're in one). Does nothing if you're in a non-Episode 3 game and no quest is in progress. * `$patch `: Run a patch on your client. `` must exactly match the name of a patch on the server. diff --git a/src/ChatCommands.cc b/src/ChatCommands.cc index d62ef718..8cd0317c 100644 --- a/src/ChatCommands.cc +++ b/src/ChatCommands.cc @@ -528,24 +528,28 @@ static void server_command_lobby_event_all(shared_ptr s, shared_ptr static void server_command_lobby_type(shared_ptr, shared_ptr l, shared_ptr c, const std::u16string& args) { check_is_game(l, false); - check_privileges(c, Privilege::CHANGE_EVENT); - uint8_t new_type = lobby_type_for_name(args); + uint8_t new_type = args.empty() ? 0 : lobby_type_for_name(args); if (new_type == 0x80) { - send_text_message(c, u"$C6No such lobby type."); + send_text_message(c, u"$C6No such lobby type"); return; } - l->type = new_type; - if (l->type < (l->is_ep3() ? 20 : 15)) { - l->type = l->block - 1; + uint8_t max_standard_type = ((c->flags & Client::Flag::IS_EPISODE_3) ? 20 : 15); + c->options.override_lobby_number = (new_type < max_standard_type) ? -1 : new_type; + send_join_lobby(c, l); +} + +static void proxy_command_lobby_type(shared_ptr, + ProxyServer::LinkedSession& session, const std::u16string& args) { + uint8_t new_type = args.empty() ? 0 : lobby_type_for_name(args); + if (new_type == 0x80) { + send_text_message(session.client_channel, u"$C6No such lobby type"); + return; } - for (size_t x = 0; x < l->max_clients; x++) { - if (l->clients[x]) { - send_join_lobby(l->clients[x], l); - } - } + uint8_t max_standard_type = ((session.newserv_client_config.cfg.flags & Client::Flag::IS_EPISODE_3) ? 20 : 15); + session.options.override_lobby_number = (new_type < max_standard_type) ? -1 : new_type; } static void server_command_saverec(shared_ptr, shared_ptr l, @@ -1317,6 +1321,7 @@ static const unordered_map chat_commands({ {u"$i", {server_command_item, proxy_command_item}}, {u"$kick", {server_command_kick, nullptr}}, {u"$li", {server_command_lobby_info, proxy_command_lobby_info}}, + {u"$ln", {server_command_lobby_type, proxy_command_lobby_type}}, {u"$ep3battledebug", {server_command_enable_ep3_battle_debug_menu, nullptr}}, {u"$maxlevel", {server_command_max_level, nullptr}}, {u"$minlevel", {server_command_min_level, nullptr}}, @@ -1335,7 +1340,6 @@ static const unordered_map chat_commands({ {u"$ss", {nullptr, proxy_command_send_server}}, {u"$surrender", {server_command_surrender, nullptr}}, {u"$swa", {server_command_switch_assist, proxy_command_switch_assist}}, - {u"$type", {server_command_lobby_type, nullptr}}, {u"$warp", {server_command_warpme, proxy_command_warpme}}, {u"$warpme", {server_command_warpme, proxy_command_warpme}}, {u"$warpall", {server_command_warpall, proxy_command_warpall}}, diff --git a/src/Client.hh b/src/Client.hh index 30cce253..e7965dab 100644 --- a/src/Client.hh +++ b/src/Client.hh @@ -26,9 +26,9 @@ struct ClientOptions { bool infinite_hp; bool infinite_tp; bool debug; - int16_t override_section_id; - int16_t override_lobby_event; - int16_t override_lobby_number; + int16_t override_section_id; // -1 = no override + int16_t override_lobby_event; // -1 = no override + int16_t override_lobby_number; // -1 = no override int64_t override_random_seed; // Options used only on proxy server diff --git a/src/CommonItemSet.hh b/src/CommonItemSet.hh index 084a7b9a..bdd81d74 100644 --- a/src/CommonItemSet.hh +++ b/src/CommonItemSet.hh @@ -103,7 +103,7 @@ public: // This table specifies how many areas each weapon subtype appears in. For // example, if Sword (subtype 02, which is index 1 in this table and the - // table above) has a subtype base of -2 and a subtype area lneght of 4, + // table above) has a subtype base of -2 and a subtype area length of 4, // then Sword items can be found when area - 1 is 2, 3, 4, or 5 (Cave 1 // through Mine 1), and Gigush (the next sword subtype) can be found in Mine // 1 through Ruins 3. diff --git a/src/Episode3/DataIndexes.hh b/src/Episode3/DataIndexes.hh index 6a5fb03b..38f59d92 100644 --- a/src/Episode3/DataIndexes.hh +++ b/src/Episode3/DataIndexes.hh @@ -862,7 +862,7 @@ struct MapDefinition { // .mnmd format; also the format of (decompressed) quests // 0D = (Castor/Pollux map) ("REAL BOSS") // 0E = Dolor Odor ("STOMACH") // 0F = Ravum Aedes Sacra ("SACRAMENT") - // 10 = (Amplum Umbla map) ("RUIN") + // 10 = (Amplum Umbra map) ("RUIN") // 11 = Via Tubus ("METRO") // 12 = Morgue ("NORMAL MORGUE") // Environment numbers above 12 are replaced with 0B (Cyber) if specified in diff --git a/src/Lobby.cc b/src/Lobby.cc index e1afba77..16a4dbe7 100644 --- a/src/Lobby.cc +++ b/src/Lobby.cc @@ -25,7 +25,6 @@ Lobby::Lobby(uint32_t id) random_seed(random_object()), event(0), block(0), - type(0), leader_id(0), max_clients(12), flags(0) { diff --git a/src/Lobby.hh b/src/Lobby.hh index bcc6f5b1..98742a86 100644 --- a/src/Lobby.hh +++ b/src/Lobby.hh @@ -100,7 +100,6 @@ struct Lobby : public std::enable_shared_from_this { // Lobby stuff uint8_t event; uint8_t block; - uint8_t type; // number to give to PSO for the lobby number uint8_t leader_id; uint8_t max_clients; uint32_t flags; diff --git a/src/SendCommands.cc b/src/SendCommands.cc index bca85ec2..e51cbfb1 100644 --- a/src/SendCommands.cc +++ b/src/SendCommands.cc @@ -1638,16 +1638,18 @@ void send_join_lobby_t(shared_ptr c, shared_ptr l, send_player_records_t(c, l, joining_client); } - uint8_t lobby_type = (l->type > 14) ? (l->block - 1) : l->type; + uint8_t lobby_type = (c->options.override_lobby_number >= 0) + ? c->options.override_lobby_number + : l->block - 1; // Allow non-canonical lobby types on GC. They may work on other versions too, // but I haven't verified which values don't crash on each version. if (c->version() == GameVersion::GC) { if (c->flags & Client::Flag::IS_EPISODE_3) { - if ((l->type > 0x14) && (l->type < 0xE9)) { + if ((lobby_type > 0x14) && (lobby_type < 0xE9)) { lobby_type = l->block - 1; } } else { - if ((l->type > 0x11) && (l->type != 0x67) && (l->type != 0xD4) && (l->type < 0xFC)) { + if ((lobby_type > 0x11) && (lobby_type != 0x67) && (lobby_type != 0xD4) && (lobby_type < 0xFC)) { lobby_type = l->block - 1; } } diff --git a/src/ServerState.cc b/src/ServerState.cc index 4935919f..eb531778 100644 --- a/src/ServerState.cc +++ b/src/ServerState.cc @@ -55,7 +55,6 @@ ServerState::ServerState(const char* config_filename, bool is_replay) Lobby::Flag::PERSISTENT | (is_non_v1_only ? Lobby::Flag::NON_V1_ONLY : 0); l->block = x + 1; - l->type = x; l->name = lobby_name; l->max_clients = 12; if (is_ep3_only) { diff --git a/src/StaticGameData.cc b/src/StaticGameData.cc index 203159ef..59c26ff9 100644 --- a/src/StaticGameData.cc +++ b/src/StaticGameData.cc @@ -153,13 +153,13 @@ const unordered_map lobby_type_to_name({ {0xF1, "windpower"}, {0xF2, "overview"}, {0xF3, "seaside"}, - {0xF4, "some?"}, + {0xF4, "fons"}, {0xF5, "dmorgue"}, {0xF6, "caelum"}, - {0xF8, "digital"}, + {0xF8, "cyber"}, {0xF9, "boss1"}, {0xFA, "boss2"}, - {0xFB, "boss3"}, + {0xFB, "dolor"}, {0xFC, "dragon"}, {0xFD, "derolle"}, {0xFE, "volopt"}, @@ -186,14 +186,14 @@ const unordered_map name_to_lobby_type({ {"windpower", 0xF1}, {"overview", 0xF2}, {"seaside", 0xF3}, - {"some?", 0xF4}, + {"fons", 0xF4}, {"dmorgue", 0xF5}, {"caelum", 0xF6}, - {"digital", 0xF8}, + {"cyber", 0xF8}, {"boss1", 0xF9}, {"boss2", 0xFA}, - {"boss3", 0xFB}, - {"knight", 0xFC}, + {"dolor", 0xFB}, + {"ravum", 0xFC}, {"sky", 0xFE}, {"morgue", 0xFF}, }); @@ -289,8 +289,8 @@ uint8_t lobby_type_for_name(const string& name) { } catch (const out_of_range&) { } try { - uint64_t x = stoul(name); - if (x < lobby_type_to_name.size()) { + uint64_t x = stoul(name, nullptr, 0); + if (lobby_type_to_name.count(x)) { return x; } } catch (const invalid_argument&) { diff --git a/system/config.example.json b/system/config.example.json index dd478da9..66e24bf8 100644 --- a/system/config.example.json +++ b/system/config.example.json @@ -250,8 +250,8 @@ ["Using $bbchar", "$C7Show how to use\nthe %sbbchar command", "Using the %sbbchar command\n\n%sbbchar is used to convert a character from an\nolder version of PSO to Blue Burst format and save\nit on this server. Use the command like this:\n\n%sbbchar \n\nIf the username and password are correct, the\ncharacter that you're currently playing as will be\nconverted to PSOBB format and saved under that\naccount, in the specified character slot (1-4)."], ["Arrow colors", "$C7Display lobby arrow\ncolor list", "$C7These values can be used with the $C6%sarrow$C7 command.\n\n0: no marker\n1: red\n2: blue\n3: green\n4: yellow\n5: purple\n6: cyan\n7: orange\n8: pink\n9: white\n10: white\n11: white\n12: black"], ["Event values", "$C7Display lobby event\nlist", "These values can be used with the $C6%sevent$C7 command.\n\nnone - no event\nxmas - Christmas event\nval - Valentine's Day\neaster - Easter Sunday event\nhallo - Halloween event\nsonic - Sonic Adventure DX event\nnewyear - New Year's event\nbval - White Day\nwedding - Wedding Day event\nspring - spring event\ns-spring - spring event with striped background\nsummer - summer event\ns-summer - summer event with striped background\nfall - fall event"], - ["GC lobby types", "$C7Display lobby type\nlist for Episodes\nI & II", "These values can be used with the %stype command.\n$C6*$C7 indicates lobbies where players can't move.\n$C2Green$C7 indicates Episode 1 & 2 (GC) only lobbies.\n\nnormal - standard lobby\n$C2inormal$C7 - under standard lobby $C6*$C7\n$C2ipc$C7 - under PC lobby $C6*$C7\n$C2iball$C7 - under soccer lobby $C6*$C7\n$C2cave1$C7 - Cave 1 $C6*$C7\n$C2cave2u$C7 - Cave 2 Ultimate $C6*$C7\n$C2dragon$C7 - Dragon stage (floor is black)\n$C2derolle$C7 - De Rol Le stage (water/walls are gone)\n$C2volopt$C7 - Vol Opt stage\n$C2darkfalz$C7 - Dark Falz stage"], - ["Ep3 lobby types", "$C7Display lobby type\nlist for Episode\nIII", "These values can be used with the %sln command.\n$C6*$C7 indicates lobbies where players can't move.\n$C8Pink$C7 indicates Episode 3 only lobbies.\n\nnormal - standard lobby\n$C8planet$C7 - Blank Ragol Lobby\n$C8clouds$C7 - Blank Sky Lobby\n$C8cave$C7 - Unguis Lapis\n$C8jungle$C7 - Episode 2 Jungle\n$C8forest2-1$C7 - Episode 1 Forest 2 (ground)\n$C8forest2-2$C7 - Episode 1 Forest 2 (near Dome)\n$C8windpower$C7\n$C8overview$C7\n$C8seaside$C7 - Episode 2 Seaside\n$C8some?$C7\n$C8dmorgue$C7 - Destroyed Morgue\n$C8caelum$C7 - Caelum\n$C8digital$C7\n$C8boss1$C7\n$C8boss2$C7\n$C8boss3$C7\n$C8knight$C7 - Leukon Knight stage\n$C8sky$C7 - Via Tubus\n$C8morgue$C7 - Morgue"], + ["GC lobby types", "$C7Display lobby type\nlist for Episodes\nI & II", "These values can be used with the %sln command.\n$C6*$C7 indicates lobbies where players can't move.\n$C2Green$C7 indicates Episode 1 & 2 (GC) only lobbies.\n\nnormal - standard lobby\n$C2inormal$C7 - under standard lobby $C6*$C7\n$C2ipc$C7 - under PC lobby $C6*$C7\n$C2iball$C7 - under soccer lobby $C6*$C7\n$C2cave1$C7 - Cave 1 $C6*$C7\n$C2cave2u$C7 - Cave 2 Ultimate $C6*$C7\n$C2dragon$C7 - Dragon stage (floor is black)\n$C2derolle$C7 - De Rol Le stage (water/walls are gone)\n$C2volopt$C7 - Vol Opt stage\n$C2darkfalz$C7 - Dark Falz stage"], + ["Ep3 lobby types", "$C7Display lobby type\nlist for Episode III", "These values can be used with the %sln command.\n$C8Pink$C7 indicates Episode 3 only lobbies.\n\nnormal - Standard lobby\n$C8planet$C7 - Blank Ragol lobby\n$C8clouds$C7 - Blank sky lobby\n$C8cave$C7 - Unguis Lapis (platform missing)\n$C8jungle$C7 - Nebula Montana 1 (Ep2 Jungle)\n$C8forest2-1$C7 - Lupus Silva 2 (Ep1 Forest 2)\n$C8forest2-2$C7 - Lupus Silva 1 (Ep1 Forest 2)\n$C8windpower$C7 - Molae Venti\n$C8overview$C7 - Nebula Montana 2\n$C8seaside$C7 - Tener Sinus (Ep2 Seaside)\n$C8fons$C7 - Mortis Fons\n$C8dmorgue$C7 - Destroyed Morgue (column missing)\n$C8caelum$C7 - Tower of Caelum (top)\n$C8cyber$C7 - Cyber\n$C8boss1$C7 - Castor/Pollux map\n$C8boss2$C7 - Amplum Umbra map\n$C8dolor$C7 - Dolor Odor\n$C8ravum$C7 - Ravum Aedes Sacra\n$C8sky$C7 - Via Tubus (tube missing)\n$C8morgue$C7 - Morgue (column missing)"], ["Area list", "$C7Display stage code\nlist", "These values can be used with the $C6%swarp$C7 command.\n\n$C2Green$C7 areas will be empty unless you are in a quest.\n$C6Yellow$C7 areas will not allow you to move.\n\n $C8Episode 1 / Episode 2 / Episode 4$C7\n0: Pioneer 2 / Pioneer 2 / Pioneer 2\n1: Forest 1 / Temple Alpha / Crater East\n2: Forest 2 / Temple Beta / Crater West\n3: Caves 1 / Spaceship Alpha / Crater South\n4: Caves 2 / Spaceship Beta / Crater North\n5: Caves 3 / CCA / Crater Interior\n6: Mines 1 / Jungle North / Desert 1\n7: Mines 2 / Jungle South / Desert 2\n8: Ruins 1 / Mountain / Desert 3\n9: Ruins 2 / Seaside / Saint Million\n10: Ruins 3 / Seabed Upper / $C6Purgatory$C7\n11: Dragon / Seabed Lower\n12: De Rol Le / Gal Gryphon\n13: Vol Opt / Olga Flow\n14: Dark Falz / Barba Ray\n15: $C2Lobby$C7 / Gol Dragon\n16: $C6Battle 1$C7 / $C6Seaside Night$C7\n17: $C6Battle 2$C7 / $C2Tower$C7"], ["Debug commands", "$C7Display commands\nfor debugging\nnewserv itself", "The following commands may be useful for\ninvestigating bugs in newserv.\n\n%sdbgid: Enable or disable high ID preference.\n When enabled, you'll be placed into the\n latest slot in lobbies/games instead of\n the earliest.\n%sgc: Send your own Guild Card to yourself.\n%srand : Set the random seed for\n all games you create."] ],