From 9f943cf5d8d96eafde757d27d9d0b25493c97734 Mon Sep 17 00:00:00 2001 From: Martin Michelsen Date: Sun, 3 Sep 2023 22:44:36 -0700 Subject: [PATCH] add $surrender command --- README.md | 7 ++++--- src/ChatCommands.cc | 27 +++++++++++++++++++++++++++ src/Episode3/Server.cc | 21 ++++++++++++++++++--- src/Episode3/Server.hh | 1 + 4 files changed, 50 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index aea93cdb..926fb824 100644 --- a/README.md +++ b/README.md @@ -308,9 +308,10 @@ Some commands only work on the game server and not on the proxy server. The chat * `$maxlevel `: Sets the maximum level for players to join the current game. (This only applies when joining; if a player joins and then levels up past this level during the game, they are not kicked out, but won't be able to rejoin if they leave.) * `$minlevel `: Sets the minimum level for players to join the current game. * `$password `: Sets the game's join password. To unlock the game, run `$password` with nothing after it. - * `$spec`: Toggles the allow spectators flag. If any players are spectating when this flag is disabled, they will be sent back to the lobby. - * `$saverec `: Save the recording of the last Episode 3 battle. - * `$playrec `: Play a battle recording. This command creates a spectator team and replays the specified battle log within it. There is a known issue which causes spectators to crash in some cases, so use of this command is currently not recommended. + * `$spec`: Toggles the allow spectators flag for Episode 3 games. If any players are spectating when this flag is disabled, they will be sent back to the lobby. + * `$surrender`: Causes your team to immediately lose the current battle. (Episode 3 only) + * `$saverec `: Saves the recording of the last Episode 3 battle. + * `$playrec `: Plays a battle recording. This command creates a spectator team and replays the specified battle log within it. There is a known issue which causes spectators to crash in some cases, so use of this command is currently not recommended. * Cheat mode commands * `$cheat`: Enables or disables cheat mode for the current game. All other cheat mode commands do nothing if cheat mode is disabled. By default, cheat mode is off in new games but can be enabled; there is an option in config.json that allows you to disable cheat mode entirely, or set it to on by default in new games. diff --git a/src/ChatCommands.cc b/src/ChatCommands.cc index 78016ea6..d62ef718 100644 --- a/src/ChatCommands.cc +++ b/src/ChatCommands.cc @@ -1259,6 +1259,32 @@ static void server_command_enable_ep3_battle_debug_menu( } } +static void server_command_surrender( + shared_ptr, shared_ptr l, shared_ptr c, const std::u16string&) { + check_is_game(l, true); + check_is_ep3(c, true); + if (l->episode != Episode::EP3) { + throw logic_error("non-Ep3 client in Ep3 game"); + } + auto base = l->ep3_server_base; + if (!base) { + send_text_message(c, u"$C6Episode 3 server\nis not initialized"); + return; + } + auto server = base->server; + if (!server) { + send_text_message(c, u"$C6Episode 3 server\nis not initialized"); + return; + } + if (server->setup_phase != Episode3::SetupPhase::MAIN_BATTLE) { + send_text_message(c, u"$C6Battle has not\nyet started"); + return; + } + string name = encode_sjis(c->game_data.player()->disp.name); + send_text_message_printf(l, "$C6%s has\nsurrendered", name.c_str()); + server->force_battle_result(c->lobby_client_id, false); +} + //////////////////////////////////////////////////////////////////////////////// typedef void (*server_handler_t)(shared_ptr s, shared_ptr l, @@ -1307,6 +1333,7 @@ static const unordered_map chat_commands({ {u"$song", {server_command_song, proxy_command_song}}, {u"$spec", {server_command_spec, nullptr}}, {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}}, diff --git a/src/Episode3/Server.cc b/src/Episode3/Server.cc index c7a6dbf0..a00956d0 100644 --- a/src/Episode3/Server.cc +++ b/src/Episode3/Server.cc @@ -524,6 +524,21 @@ bool Server::check_for_battle_end() { return ret; } +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++) { + auto ps = this->player_states[z]; + if (ps) { + ps->assist_flags &= 0xFFFFB7FB; + if ((ps->get_team_id() == specified_ps->get_team_id()) == set_winner) { + ps->assist_flags |= 4; + } + ps->update_hand_and_equip_state_and_send_6xB4x02_if_needed(true); + } + } + this->set_battle_ended(); +} + void Server::check_for_destroyed_cards_and_send_6xB4x05_6xB4x02() { for (size_t z = 0; z < 4; z++) { if (this->player_states[z]) { @@ -706,15 +721,15 @@ void Server::draw_phase_after() { } if (this->overall_time_expired || (this->round_num >= 1000)) { - bool unknown_v1 = true; + bool no_winner_specified = true; for (size_t z = 0; z < 4; z++) { auto ps = this->player_states[z]; if (ps && (ps->assist_flags & 4)) { - unknown_v1 = false; + no_winner_specified = false; break; } } - if (unknown_v1) { + if (no_winner_specified) { this->compute_losing_team_id_and_add_winner_flags(0); } this->round_num--; diff --git a/src/Episode3/Server.hh b/src/Episode3/Server.hh index d43f6ea9..de68ce2c 100644 --- a/src/Episode3/Server.hh +++ b/src/Episode3/Server.hh @@ -145,6 +145,7 @@ 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();