From 550b62dec9cfa85ed96dd91df6821d42bdd4b511 Mon Sep 17 00:00:00 2001 From: Martin Michelsen Date: Tue, 12 Sep 2023 19:10:34 -0700 Subject: [PATCH] add cheat command to remove an FC in an Ep3 battle --- README.md | 5 ++--- src/ChatCommands.cc | 23 +++++++++++++++++++++++ src/Episode3/Server.cc | 25 +++++++++++++++++++++++++ src/Episode3/Server.hh | 5 +++-- 4 files changed, 53 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 9b8906cb..6501ad3d 100644 --- a/README.md +++ b/README.md @@ -278,9 +278,7 @@ Some chat commands (see below) have the same basic function on the proxy server ### Chat commands -The server's shell supports a variety of administration commands. If the interactive shell is enabled, you can enter these commands at any time, even if the prompt isn't visible. Run `help` in the server's shell to see all of the commands and how to use them. - -newserv also supports a variety of commands players can use via the chat interface. Any chat message that begins with `$` is treated as a chat command. (If you actually want to send a chat message starting with `$`, type `$$` instead.) +newserv supports a variety of commands players can use by chatting in-game. Any chat message that begins with `$` is treated as a chat command. (If you actually want to send a chat message starting with `$`, type `$$` instead.) Some commands only work on the game server and not on the proxy server. The chat commands are: @@ -327,6 +325,7 @@ Some commands only work on the game server and not on the proxy server. The chat * `$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 ` (or `$i `): Create an item. `desc` may be a description of the item (e.g. "Hell Saber +5 0/10/25/0/10") or a string of hex data specifying the item code. 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 not be using Blue Burst for this command to work. On the game server, this command works for all versions. + * `$unset `: In an Episode 3 battle, removes one of your set cards from the field. `` is the index of the set card as it appears on your screen - 1 is the card next to your SC's icon, 2 is the card to the right of 1, etc. This does not cause a Hunters-side SC to lose HP, as they normally do when their items are destroyed. * Configuration commands * `$event `: Sets the current holiday event in the current lobby. Holiday events are documented in the "Using $event" item in the information menu. If you're on the proxy server, this applies to all lobbies and games you join, but only you will see the new event - other players will not. diff --git a/src/ChatCommands.cc b/src/ChatCommands.cc index 8a702897..8d571fbc 100644 --- a/src/ChatCommands.cc +++ b/src/ChatCommands.cc @@ -1279,6 +1279,28 @@ static void server_command_ep3_infinite_time( send_text_message(l, infinite_time_enabled ? u"$C6Infinite time enabled" : u"$C6Infinite time disabled"); } +static void server_command_ep3_unset_field_character( + shared_ptr s, shared_ptr l, shared_ptr c, const std::u16string& args) { + check_is_game(l, true); + check_is_ep3(c, true); + check_cheats_enabled(s, l); + + if (l->episode != Episode::EP3) { + throw logic_error("non-Ep3 client in Ep3 game"); + } + if (!l->ep3_server) { + send_text_message(c, u"$C6Episode 3 server\nis not initialized"); + return; + } + if (l->ep3_server->setup_phase != Episode3::SetupPhase::MAIN_BATTLE) { + send_text_message(c, u"$C6Battle has not\nyet begun"); + return; + } + + size_t index = stoull(encode_sjis(args)) - 1; + l->ep3_server->force_destroy_field_character(c->lobby_client_id, index); +} + static void server_command_surrender( shared_ptr, shared_ptr l, shared_ptr c, const std::u16string&) { check_is_game(l, true); @@ -1351,6 +1373,7 @@ 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"$unset", {server_command_ep3_unset_field_character, 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/Episode3/Server.cc b/src/Episode3/Server.cc index 50303775..1f982a42 100644 --- a/src/Episode3/Server.cc +++ b/src/Episode3/Server.cc @@ -536,6 +536,31 @@ bool Server::check_for_battle_end() { return ret; } +void Server::force_destroy_field_character(uint8_t client_id, size_t visible_index) { + auto ps = this->player_states[client_id]; + + // TODO: Is it possible for there to be gaps in the set cards array? If not, + // we could just do a direct array lookup here instead of this loop + shared_ptr set_card = nullptr; + for (size_t set_index = 0; set_index < 8; set_index++) { + if (!ps->set_cards[set_index]) { + continue; + } + if (visible_index == 0) { + set_card = ps->set_cards[set_index]; + break; + } else { + visible_index--; + } + } + + if (set_card) { + set_card->card_flags |= 2; + this->check_for_destroyed_cards_and_send_6xB4x05_6xB4x02(); + this->check_for_battle_end(); + } +} + void Server::force_battle_result(uint8_t specified_client_id, bool set_winner) { auto specified_ps = this->player_states[specified_client_id]; for (size_t z = 0; z < 4; z++) { diff --git a/src/Episode3/Server.hh b/src/Episode3/Server.hh index 4b95d6ea..ea063323 100644 --- a/src/Episode3/Server.hh +++ b/src/Episode3/Server.hh @@ -100,9 +100,11 @@ public: this->send(&cmd, cmd.header.size * 4); } void send(const void* data, size_t size) const; - void send_commands_for_joining_spectator(Channel& ch, bool is_trial) const; + void force_battle_result(uint8_t surrendered_client_id, bool set_winner); + void force_destroy_field_character(uint8_t client_id, size_t set_index); + __attribute__((format(printf, 2, 3))) void send_debug_message_printf(const char* fmt, ...) const; __attribute__((format(printf, 2, 3))) void send_info_message_printf(const char* fmt, ...) const; void send_debug_command_received_message( @@ -124,7 +126,6 @@ public: uint16_t card_id_for_card_ref(uint16_t card_ref) const; bool card_ref_is_empty_or_has_valid_card_id(uint16_t card_ref) const; bool check_for_battle_end(); - void force_battle_result(uint8_t surrendered_client_id, bool set_winner); void check_for_destroyed_cards_and_send_6xB4x05_6xB4x02(); bool check_presence_entry(uint8_t client_id) const; void clear_player_flags_after_dice_phase();