add $setassist command

This commit is contained in:
Martin Michelsen
2023-12-30 15:18:42 -08:00
parent 111260cdf3
commit f54d7b0476
6 changed files with 96 additions and 37 deletions
+50 -4
View File
@@ -1762,6 +1762,54 @@ static void server_command_ep3_set_def_dice_range(shared_ptr<Client> c, const st
}
}
static void server_command_ep3_replace_assist_card(shared_ptr<Client> c, const std::string& args) {
auto s = c->require_server_state();
auto l = c->require_lobby();
check_is_game(l, true);
check_is_ep3(c, true);
check_cheats_enabled(l, c);
if (l->episode != Episode::EP3) {
throw logic_error("non-Ep3 client in Ep3 game");
}
if (!l->ep3_server) {
send_text_message(c, "$C6Episode 3 server\nis not initialized");
return;
}
if (l->ep3_server->setup_phase != Episode3::SetupPhase::MAIN_BATTLE) {
send_text_message(c, "$C6Battle has not\nyet begun");
return;
}
if (args.empty()) {
send_text_message(c, "$C6Missing arguments");
return;
}
uint8_t client_id;
string card_name;
if (isdigit(args[0])) {
auto tokens = split(args, ' ', 1);
client_id = stoul(tokens.at(0), nullptr, 0);
card_name = tokens.at(1);
} else {
client_id = c->lobby_client_id;
card_name = args;
}
shared_ptr<const Episode3::CardIndex::CardEntry> ce;
try {
ce = l->ep3_server->options.card_index->definition_for_name_normalized(card_name);
} catch (const out_of_range&) {
send_text_message(c, "$C6Card not found");
return;
}
if (ce->def.type != Episode3::CardType::ASSIST) {
send_text_message(c, "$C6Card is not an\nAssist card");
return;
}
l->ep3_server->force_replace_assist_card(client_id, ce->def.card_id);
}
static void server_command_ep3_unset_field_character(shared_ptr<Client> c, const std::string& args) {
auto s = c->require_server_state();
auto l = c->require_lobby();
@@ -1823,10 +1871,7 @@ static void server_command_get_ep3_battle_stat(shared_ptr<Client> c, const std::
send_text_message(c, "$C6Battle has not\nyet started");
return;
}
if (c->lobby_client_id >= 4) {
throw logic_error("client ID is too large");
}
auto ps = l->ep3_server->player_states[c->lobby_client_id];
auto ps = l->ep3_server->player_states.at(c->lobby_client_id);
if (!ps) {
send_text_message(c, "$C6Player is missing");
return;
@@ -1950,6 +1995,7 @@ static const unordered_map<string, ChatCommandDefinition> chat_commands({
{"$saverec", {server_command_saverec, nullptr}},
{"$sc", {server_command_send_client, proxy_command_send_client}},
{"$secid", {server_command_secid, proxy_command_secid}},
{"$setassist", {server_command_ep3_replace_assist_card, nullptr}},
{"$si", {server_command_server_info, nullptr}},
{"$silence", {server_command_silence, nullptr}},
{"$song", {server_command_song, proxy_command_song}},
+7 -7
View File
@@ -1850,7 +1850,7 @@ bool CardSpecial::execute_effect(
if (client_id == 0xFF) {
return false;
}
auto ps = this->server()->player_states[client_id];
auto ps = this->server()->player_states.at(client_id);
if (!ps) {
return false;
}
@@ -1993,7 +1993,7 @@ bool CardSpecial::execute_effect(
if (client_id == 0xFF) {
return false;
}
auto ps = this->server()->player_states[client_id];
auto ps = this->server()->player_states.at(client_id);
if (!ps) {
return false;
}
@@ -2034,8 +2034,8 @@ bool CardSpecial::execute_effect(
uint8_t attacker_client_id = client_id_for_card_ref(cond.card_ref);
uint8_t target_client_id = client_id_for_card_ref(card->get_card_ref());
if ((attacker_client_id != 0xFF) && (target_client_id != 0xFF)) {
auto attacker_ps = this->server()->player_states[attacker_client_id];
auto target_ps = this->server()->player_states[target_client_id];
auto attacker_ps = this->server()->player_states.at(attacker_client_id);
auto target_ps = this->server()->player_states.at(target_client_id);
if (attacker_ps && target_ps) {
uint8_t attacker_team_id = attacker_ps->get_team_id();
uint8_t target_team_id = target_ps->get_team_id();
@@ -2157,8 +2157,8 @@ bool CardSpecial::execute_effect(
case ConditionType::GIVE_OR_TAKE_EXP:
if (unknown_p7 & 4) {
uint8_t client_id = client_id_for_card_ref(card->get_card_ref());
if ((client_id != 0xFF) && this->server()->player_states[client_id]) {
uint8_t team_id = this->server()->player_states[client_id]->get_team_id();
if ((client_id != 0xFF) && this->server()->player_states.at(client_id)) {
uint8_t team_id = this->server()->player_states.at(client_id)->get_team_id();
int32_t existing_exp = this->server()->team_exp[team_id];
if ((clamped_expr_value + existing_exp) < 0) {
clamped_expr_value = -existing_exp;
@@ -3672,7 +3672,7 @@ void CardSpecial::evaluate_and_apply_effects(
DiceRoll dice_roll;
uint8_t client_id = client_id_for_card_ref(dice_cmd.effect.target_card_ref);
auto set_card_ps = (client_id == 0xFF) ? nullptr : this->server()->player_states[client_id];
auto set_card_ps = (client_id == 0xFF) ? nullptr : this->server()->player_states.at(client_id);
dice_roll.value = 1;
if (set_card_ps) {
+3 -3
View File
@@ -42,7 +42,7 @@ PlayerState::PlayerState(uint8_t client_id, shared_ptr<Server> server)
void PlayerState::init() {
auto s = this->server();
if (s->player_states[this->client_id].get() != this) {
if (s->player_states.at(this->client_id).get() != this) {
// Note: The original code handles this, but we don't. This appears not to
// ever happen, so we didn't bother implementing it.
throw logic_error("replacing a player state object is not permitted");
@@ -1267,7 +1267,7 @@ bool PlayerState::set_card_from_hand(
return false;
}
auto target_ps = s->player_states[assist_target_client_id];
auto target_ps = s->player_states.at(assist_target_client_id);
if (target_ps) {
uint16_t prev_assist_card_ref = target_ps->card_refs[6];
target_ps->discard_set_assist_card();
@@ -1752,7 +1752,7 @@ void PlayerState::unknown_8023C174() {
this->send_set_card_updates(0);
}
void PlayerState::handle_homesick_assist_effect(shared_ptr<Card> card) {
void PlayerState::handle_homesick_assist_effect_from_bomb(shared_ptr<Card> card) {
if (!card) {
return;
}
+1 -1
View File
@@ -139,7 +139,7 @@ public:
int16_t get_assist_turns_remaining();
bool set_action_cards_for_action_state(const ActionState& pa);
void unknown_8023C174();
void handle_homesick_assist_effect(std::shared_ptr<Card> card);
void handle_homesick_assist_effect_from_bomb(std::shared_ptr<Card> card);
void apply_main_die_assist_effects(uint8_t* die_value) const;
void roll_main_dice();
void unknown_8023C110();
+33 -21
View File
@@ -418,7 +418,7 @@ shared_ptr<Card> Server::card_for_set_card_ref(uint16_t card_ref) {
if (client_id == 0xFF) {
return nullptr;
}
auto ps = this->player_states[client_id];
auto ps = this->player_states.at(client_id);
if (!ps) {
return nullptr;
}
@@ -444,7 +444,7 @@ shared_ptr<const Card> Server::card_for_set_card_ref(uint16_t card_ref) const {
if (client_id == 0xFF) {
return nullptr;
}
auto ps = this->player_states[client_id];
auto ps = this->player_states.at(client_id);
if (!ps) {
return nullptr;
}
@@ -464,10 +464,11 @@ shared_ptr<const Card> Server::card_for_set_card_ref(uint16_t card_ref) const {
uint16_t Server::card_id_for_card_ref(uint16_t card_ref) const {
uint8_t client_id = client_id_for_card_ref(card_ref);
if (client_id != 0xFF) {
if (!this->player_states[client_id]) {
auto ps = this->player_states.at(client_id);
if (!ps) {
return 0xFFFF;
}
auto deck = this->player_states[client_id]->get_deck();
auto deck = ps->get_deck();
if (deck) {
return deck->card_id_for_card_ref(card_ref);
}
@@ -558,8 +559,19 @@ bool Server::check_for_battle_end() {
return ret;
}
void Server::force_replace_assist_card(uint8_t client_id, uint16_t card_id) {
auto ps = this->player_states.at(client_id);
if (!ps) {
throw runtime_error("player does not exist");
}
ps->replace_assist_card_by_id(card_id);
}
void Server::force_destroy_field_character(uint8_t client_id, size_t visible_index) {
auto ps = this->player_states[client_id];
auto ps = this->player_states.at(client_id);
if (!ps) {
throw runtime_error("player does not exist");
}
// 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
@@ -584,7 +596,7 @@ void Server::force_destroy_field_character(uint8_t client_id, size_t visible_ind
}
void Server::force_battle_result(uint8_t specified_client_id, bool set_winner) {
auto specified_ps = this->player_states[specified_client_id];
auto specified_ps = this->player_states.at(specified_client_id);
for (size_t z = 0; z < 4; z++) {
auto ps = this->player_states[z];
if (ps) {
@@ -824,7 +836,7 @@ void Server::end_attack_list_for_client(uint8_t client_id) {
return;
}
auto ps = this->player_states[client_id];
auto ps = this->player_states.at(client_id);
if (!ps) {
return;
}
@@ -1670,10 +1682,11 @@ void Server::handle_CAx0B_mulligan_hand(shared_ptr<Client>, const string& data)
error_code = -0x78;
}
if (error_code == 0) {
if (!this->player_states[in_cmd.client_id]) {
auto ps = this->player_states.at(in_cmd.client_id);
if (!ps) {
error_code = -0x72;
} else {
this->player_states[in_cmd.client_id]->do_mulligan();
ps->do_mulligan();
}
}
@@ -1709,18 +1722,17 @@ void Server::handle_CAx0C_end_mulligan_phase(shared_ptr<Client>, const string& d
this->send(out_cmd_ack);
if (error_code == 0) {
if (!this->player_states[in_cmd.client_id]) {
auto ps = this->player_states.at(in_cmd.client_id);
if (!ps) {
error_code = -0x72;
} else {
this->clients_done_in_mulligan_phase[in_cmd.client_id] = true;
auto ps = this->player_states[in_cmd.client_id];
ps->assist_flags |= AssistFlag::READY_TO_END_PHASE;
ps->update_hand_and_equip_state_and_send_6xB4x02_if_needed();
bool all_clients_ready = true;
for (size_t z = 0; z < 4; z++) {
if (this->player_states[z] &&
!this->clients_done_in_mulligan_phase[z]) {
if (this->player_states[z] && !this->clients_done_in_mulligan_phase[z]) {
all_clients_ready = false;
break;
}
@@ -1781,7 +1793,7 @@ void Server::handle_CAx0E_discard_card_from_hand(shared_ptr<Client>, const strin
}
if (error_code == 0) {
auto ps = this->player_states[in_cmd.client_id];
auto ps = this->player_states.at(in_cmd.client_id);
if (!ps) {
error_code = -0x72;
} else if (!(ps->assist_flags & AssistFlag::IS_SKIPPING_TURN)) {
@@ -1824,11 +1836,11 @@ void Server::handle_CAx0F_set_card_from_hand(shared_ptr<Client>, const string& d
}
if (error_code == 0) {
this->ruler_server->error_code1 = 0;
if (!this->player_states[in_cmd.client_id]) {
auto ps = this->player_states.at(in_cmd.client_id);
if (!ps) {
this->ruler_server->error_code1 = -0x72;
} else {
this->player_states[in_cmd.client_id]->set_card_from_hand(
in_cmd.card_ref, in_cmd.set_index, &in_cmd.loc, in_cmd.assist_target_player, 0);
ps->set_card_from_hand(in_cmd.card_ref, in_cmd.set_index, &in_cmd.loc, in_cmd.assist_target_player, 0);
}
} else {
this->ruler_server->error_code1 = error_code;
@@ -1861,12 +1873,12 @@ void Server::handle_CAx10_move_fc_to_location(shared_ptr<Client>, const string&
error_code = -0x78;
}
if (error_code == 0) {
if (!this->player_states[in_cmd.client_id]) {
auto ps = this->player_states.at(in_cmd.client_id);
if (!ps) {
this->ruler_server->error_code2 = -0x72;
} else {
this->ruler_server->error_code2 = 0;
this->player_states[in_cmd.client_id]->move_card_to_location_by_card_index(
in_cmd.set_index, in_cmd.loc);
ps->move_card_to_location_by_card_index(in_cmd.set_index, in_cmd.loc);
}
} else {
this->ruler_server->error_code2 = error_code;
@@ -2655,7 +2667,7 @@ void Server::execute_bomb_assist_effect() {
auto card = ps->get_set_card(set_index);
if (card && !(card->card_flags & 2) &&
((card->get_current_hp() == max_hp) || (card->get_current_hp() == min_hp))) {
card->player_state()->handle_homesick_assist_effect(card);
card->player_state()->handle_homesick_assist_effect_from_bomb(card);
}
}
}
+2 -1
View File
@@ -115,6 +115,7 @@ public:
void send_commands_for_joining_spectator(Channel& ch) const;
void force_battle_result(uint8_t surrendered_client_id, bool set_winner);
void force_replace_assist_card(uint8_t client_id, uint16_t card_id);
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;
@@ -288,7 +289,7 @@ public:
uint32_t should_copy_prev_states_to_current_states;
std::shared_ptr<CardSpecial> card_special;
std::shared_ptr<StateFlags> state_flags;
std::shared_ptr<PlayerState> player_states[4];
std::array<std::shared_ptr<PlayerState>, 4> player_states;
parray<uint32_t, 4> clients_done_in_mulligan_phase;
uint32_t num_pending_attacks_with_cards;
std::shared_ptr<Card> attack_cards[0x20];