diff --git a/README.md b/README.md index 27df28a4..4a78f0d7 100644 --- a/README.md +++ b/README.md @@ -197,7 +197,7 @@ Some commands only work on the game server and not on the proxy server. The chat * `$cheat`: Enables or disables cheat mode for the current game. All other cheat mode commands do nothing if cheat mode is disabled. This command does nothing on the proxy server - cheat commands are always available there. * `$infhp` / `$inftp`: Enables or disables infinite HP or TP mode. Applies to only you. In infinite HP mode, one-hit KO attacks will still kill you. * `$warp `: Warps yourself to the given area. - * `$next` (game server only): Warps yourself to the next area. + * `$next`: Warps yourself to the next area. * `$swa`: Enables or disables switch assist. When enabled, the server will attempt to automatically unlock two-player doors in solo games if you step on both switches sequentially. * `$item `: Sets the next item to be dropped from an enemy or box. Item codes are 16 hex bytes; at least 2 bytes must be specified, and all unspecified bytes are zeroes. If you are on the proxy server, you must be the game leader and not using Blue Burst for this command to work. On the game server, this command works for all versions, and you do not have to be the game leader. diff --git a/src/ChatCommands.cc b/src/ChatCommands.cc index 985ab284..d8af0d43 100644 --- a/src/ChatCommands.cc +++ b/src/ChatCommands.cc @@ -758,8 +758,13 @@ static void server_command_warp(shared_ptr, shared_ptr l, static void proxy_command_warp(shared_ptr, ProxyServer::LinkedSession& session, const std::u16string& args) { + if (!session.is_in_game) { + send_text_message(session.client_channel, u"$C6You must be in a\ngame to use this\ncommand"); + return; + } uint32_t area = stoul(encode_sjis(args), nullptr, 0); send_warp(session.client_channel, session.lobby_client_id, area); + session.area = area; } static void server_command_next(shared_ptr, shared_ptr l, @@ -768,7 +773,7 @@ static void server_command_next(shared_ptr, shared_ptr l, check_cheats_enabled(l); if (!l->episode || (l->episode > 3)) { - return; + throw runtime_error("invalid episode number"); } uint8_t new_area = c->area + 1; @@ -781,6 +786,17 @@ static void server_command_next(shared_ptr, shared_ptr l, send_warp(c, new_area); } +static void proxy_command_next(shared_ptr, + ProxyServer::LinkedSession& session, const std::u16string&) { + if (!session.is_in_game) { + send_text_message(session.client_channel, u"$C6You must be in a\ngame to use this\ncommand"); + return; + } + + session.area++; + send_warp(session.client_channel, session.lobby_client_id, session.area); +} + static void server_command_what(shared_ptr, shared_ptr l, shared_ptr c, const std::u16string&) { check_is_game(l, true); @@ -972,8 +988,7 @@ static const unordered_map chat_commands({ {u"$li", {server_command_lobby_info, proxy_command_lobby_info, u"Usage:\nli"}}, {u"$maxlevel", {server_command_max_level, nullptr, u"Usage:\nmax_level "}}, {u"$minlevel", {server_command_min_level, nullptr, u"Usage:\nmin_level "}}, - // TODO: implement this on proxy server - {u"$next", {server_command_next, nullptr, u"Usage:\nnext"}}, + {u"$next", {server_command_next, proxy_command_next, u"Usage:\nnext"}}, {u"$password", {server_command_password, nullptr, u"Usage:\nlock [password]\nomit password to\nunlock game"}}, {u"$persist", {server_command_persist, nullptr, u"Usage:\npersist"}}, {u"$proxygc", {server_command_proxygc, proxy_command_proxygc, u"Usage:\nproxygc "}}, diff --git a/src/ProxyCommands.cc b/src/ProxyCommands.cc index 997cfb60..5f8075ec 100644 --- a/src/ProxyCommands.cc +++ b/src/ProxyCommands.cc @@ -1045,6 +1045,7 @@ static HandlerResult S_65_67_68(shared_ptr, if (command == 0x67) { session.clear_lobby_players(12); session.is_in_game = false; + session.area = 0x0F; // This command can cause the client to no longer send D6 responses when // 1A/D5 large message boxes are closed. newserv keeps track of this @@ -1117,6 +1118,7 @@ static HandlerResult S_64(shared_ptr, } session.clear_lobby_players(4); + session.area = 0; session.is_in_game = true; bool modified = false; @@ -1181,6 +1183,7 @@ static HandlerResult S_66_69(shared_ptr, static HandlerResult C_98(shared_ptr, ProxyServer::LinkedSession& session, uint16_t, uint32_t, string&) { + session.area = 0x0F; session.is_in_game = false; return HandlerResult::Type::FORWARD; } @@ -1281,7 +1284,11 @@ static HandlerResult C_6x(shared_ptr s, } if (!data.empty()) { - if (data[0] == 0x2F || data[0] == 0x4B || data[0] == 0x4C) { + if (data[0] == 0x21) { + const auto& cmd = check_size_t(data); + session.area = cmd.area; + + } else if (data[0] == 0x2F || data[0] == 0x4B || data[0] == 0x4C) { if (session.infinite_hp) { send_player_stats_change(session.client_channel, session.lobby_client_id, PlayerStatsChange::ADD_HP, 2550); diff --git a/src/ProxyServer.hh b/src/ProxyServer.hh index 2b7ee125..95526c86 100644 --- a/src/ProxyServer.hh +++ b/src/ProxyServer.hh @@ -86,6 +86,7 @@ public: std::vector lobby_players; size_t lobby_client_id; size_t leader_client_id; + uint16_t area; bool is_in_game; std::shared_ptr detector_crypt;