diff --git a/src/Episode3/AssistServer.hh b/src/Episode3/AssistServer.hh index 83dcbfa9..9296bda9 100644 --- a/src/Episode3/AssistServer.hh +++ b/src/Episode3/AssistServer.hh @@ -39,17 +39,17 @@ private: public: parray assist_effects; - std::shared_ptr assist_card_defs[4]; + bcarray, 4> assist_card_defs; uint32_t num_assist_cards_set; parray client_ids_with_assists; parray active_assist_effects; - std::shared_ptr active_assist_card_defs[4]; + bcarray, 4> active_assist_card_defs; uint32_t num_active_assists; - std::shared_ptr hand_and_equip_states[4]; - std::shared_ptr> card_short_statuses[4]; - std::shared_ptr deck_entries[4]; - std::shared_ptr> set_card_action_chains[4]; - std::shared_ptr> set_card_action_metadatas[4]; + bcarray, 4> hand_and_equip_states; + bcarray>, 4> card_short_statuses; + bcarray, 4> deck_entries; + bcarray>, 4> set_card_action_chains; + bcarray>, 4> set_card_action_metadatas; }; } // namespace Episode3 diff --git a/src/Episode3/BattleRecord.hh b/src/Episode3/BattleRecord.hh index 65770448..994aaa5a 100644 --- a/src/Episode3/BattleRecord.hh +++ b/src/Episode3/BattleRecord.hh @@ -96,9 +96,7 @@ private: class BattleRecordPlayer { public: - BattleRecordPlayer( - std::shared_ptr rec, - std::shared_ptr base); + BattleRecordPlayer(std::shared_ptr rec, std::shared_ptr base); ~BattleRecordPlayer() = default; std::shared_ptr get_record() const; diff --git a/src/Episode3/CardSpecial.cc b/src/Episode3/CardSpecial.cc index e9d47748..c425a731 100644 --- a/src/Episode3/CardSpecial.cc +++ b/src/Episode3/CardSpecial.cc @@ -393,9 +393,7 @@ bool CardSpecial::apply_defense_condition( string expr = orig_eff->expr.decode(); int16_t expr_value = this->evaluate_effect_expr(astats, expr.c_str(), dice_roll); - this->execute_effect( - *defender_cond, defender_card, expr_value, defender_cond->value, - orig_eff->type, flags, attacker_card_ref); + this->execute_effect(*defender_cond, defender_card, expr_value, defender_cond->value, orig_eff->type, flags, attacker_card_ref); if (flags & 4) { if (is_nte || !(defender_card->card_flags & 2)) { defender_card->compute_action_chain_results(true, false); @@ -2461,13 +2459,13 @@ bool CardSpecial::execute_effect( [[fallthrough]]; case ConditionType::SLAYERS_ASSASSINS: if (is_nte) { - auto card = s->card_for_set_card_ref(attacker_card_ref); + auto set_card = s->card_for_set_card_ref(attacker_card_ref); bool card_found = false; - if (!card) { + if (!set_card) { card_found = false; } else { - for (size_t z = 0; z < card->action_chain.chain.target_card_ref_count; z++) { - if (card->action_chain.chain.target_card_refs[z] == card->get_card_ref()) { + for (size_t z = 0; z < set_card->action_chain.chain.target_card_ref_count; z++) { + if (set_card->action_chain.chain.target_card_refs[z] == card->get_card_ref()) { card_found = true; break; } @@ -3511,8 +3509,7 @@ void CardSpecial::on_card_set(shared_ptr ps, uint16_t card_ref) { this->evaluate_and_apply_effects(0x01, card_ref, as, sc_card_ref); } -const CardDefinition::Effect* CardSpecial::original_definition_for_condition( - const Condition& cond) const { +const CardDefinition::Effect* CardSpecial::original_definition_for_condition(const Condition& cond) const { auto ce = this->server()->definition_for_card_ref(cond.card_ref); if (!ce) { return nullptr; @@ -3526,8 +3523,7 @@ bool CardSpecial::card_ref_has_ability_trap(const Condition& cond) const { if (!card) { return false; } else { - return this->card_has_condition_with_ref( - card, ConditionType::ABILITY_TRAP, 0xFFFF, 0xFFFF); + return this->card_has_condition_with_ref(card, ConditionType::ABILITY_TRAP, 0xFFFF, 0xFFFF); } } @@ -3567,8 +3563,7 @@ void CardSpecial::send_6xB4x06_for_card_destroyed( this->server()->send(cmd); } -uint16_t CardSpecial::send_6xB4x06_if_card_ref_invalid( - uint16_t card_ref, int16_t value) const { +uint16_t CardSpecial::send_6xB4x06_if_card_ref_invalid(uint16_t card_ref, int16_t value) const { auto s = this->server(); if (!s->options.is_nte() && !s->card_ref_is_empty_or_has_valid_card_id(card_ref)) { if (value != 0) { @@ -4115,7 +4110,7 @@ void CardSpecial::evaluate_and_apply_effects( // bug probably does nothing in any reasonable scenario, since the // target card refs array immediately precedes the conditions array, // and the target card refs array is excessively long, so OR'ing a - // value that is amost certainly already 0xFFFF with 1 would do + // value that is almost certainly already 0xFFFF with 1 would do // nothing. In our implementation, however, we bounds-check // everything, so we've moved this check inside the relevant if block. if (dice_roll.value_used_in_expr) { @@ -4140,8 +4135,7 @@ void CardSpecial::evaluate_and_apply_effects( if (any_expr_used_dice_roll) { dice_cmd.effect.flags = 0x08; - dice_cmd.effect.attacker_card_ref = this->send_6xB4x06_if_card_ref_invalid( - as_attacker_card_ref, 0x15); + dice_cmd.effect.attacker_card_ref = this->send_6xB4x06_if_card_ref_invalid(as_attacker_card_ref, 0x15); dice_cmd.effect.dice_roll_value = dice_roll.value; s->send(dice_cmd); } @@ -4671,8 +4665,7 @@ void CardSpecial::unknown_8024AAB8(const ActionState& as) { log.debug("as=%s", as_str.c_str()); for (size_t z = 0; (z < 8) && (as.action_card_refs[z] != 0xFFFF); z++) { - uint16_t card_ref = this->send_6xB4x06_if_card_ref_invalid( - as.action_card_refs[z], 0x1E); + uint16_t card_ref = this->send_6xB4x06_if_card_ref_invalid(as.action_card_refs[z], 0x1E); if (card_ref == 0xFFFF) { break; } @@ -4941,8 +4934,7 @@ void CardSpecial::check_for_attack_interference(shared_ptr unknown_p2) { G_ApplyConditionEffect_Ep3_6xB4x06 cmd; cmd.effect.flags = 0x04; - cmd.effect.attacker_card_ref = this->send_6xB4x06_if_card_ref_invalid( - unknown_p2->get_card_ref(), 0x11); + cmd.effect.attacker_card_ref = this->send_6xB4x06_if_card_ref_invalid(unknown_p2->get_card_ref(), 0x11); cmd.effect.target_card_ref = unknown_p2->get_card_ref(); cmd.effect.value = 0; cmd.effect.operation = 0x7D; diff --git a/src/Episode3/PlayerState.hh b/src/Episode3/PlayerState.hh index 35e25449..cbdc4188 100644 --- a/src/Episode3/PlayerState.hh +++ b/src/Episode3/PlayerState.hh @@ -148,7 +148,7 @@ private: public: std::shared_ptr sc_card; - std::shared_ptr set_cards[8]; + bcarray, 8> set_cards; uint8_t client_id; uint16_t num_mulligans_allowed; CardType sc_card_type; diff --git a/src/Episode3/RulerServer.hh b/src/Episode3/RulerServer.hh index 11035a62..d6b34a09 100644 --- a/src/Episode3/RulerServer.hh +++ b/src/Episode3/RulerServer.hh @@ -198,11 +198,11 @@ private: std::weak_ptr w_server; public: - std::shared_ptr hand_and_equip_states[4]; - std::shared_ptr> short_statuses[4]; - std::shared_ptr deck_entries[4]; - std::shared_ptr> set_card_action_chains[4]; - std::shared_ptr> set_card_action_metadatas[4]; + bcarray, 4> hand_and_equip_states; + bcarray>, 4> short_statuses; + bcarray, 4> deck_entries; + bcarray>, 4> set_card_action_chains; + bcarray>, 4> set_card_action_metadatas; std::shared_ptr map_and_rules; std::shared_ptr state_flags; std::shared_ptr assist_server; diff --git a/src/Episode3/Server.cc b/src/Episode3/Server.cc index c2dc0c33..5b39aff6 100644 --- a/src/Episode3/Server.cc +++ b/src/Episode3/Server.cc @@ -265,30 +265,26 @@ void Server::send(const void* data, size_t size, uint8_t command, bool enable_ma void Server::send_6xB4x46() const { // Note: This function is not part of the original implementation; it was // factored out from its callsites in this file and the strings were changed. - if (this->options.is_nte()) { - G_ServerVersionStrings_Ep3NTE_6xB4x46 cmd; - cmd.version_signature.encode(VERSION_SIGNATURE_NTE, 1); - cmd.date_str1.encode(format_time(this->options.card_index->definitions_mtime() * 1000000), 1); - this->send(cmd); + + // NTE doesn't have the date_str2 field, but we send it anyway to make + // debugging easier. + G_ServerVersionStrings_Ep3_6xB4x46 cmd; + cmd.version_signature.encode(this->options.is_nte() ? VERSION_SIGNATURE_NTE : VERSION_SIGNATURE, 1); + cmd.date_str1.encode(format_time(this->options.card_index->definitions_mtime() * 1000000), 1); + string date_str2; + if (this->options.opt_rand_crypt) { + date_str2 = string_printf( + "Random:%08" PRIX32 "+%08" PRIX32, + this->options.opt_rand_crypt->seed(), + this->options.opt_rand_crypt->absolute_offset()); } else { - G_ServerVersionStrings_Ep3_6xB4x46 cmd; - cmd.version_signature.encode(VERSION_SIGNATURE, 1); - cmd.date_str1.encode(format_time(this->options.card_index->definitions_mtime() * 1000000), 1); - string date_str2; - if (this->options.opt_rand_crypt) { - date_str2 = string_printf( - "Random:%08" PRIX32 "+%08" PRIX32, - this->options.opt_rand_crypt->seed(), - this->options.opt_rand_crypt->absolute_offset()); - } else { - date_str2 = "Random:"; - } - if (this->last_chosen_map) { - date_str2 += string_printf(" Map:%08" PRIX32, this->last_chosen_map->map_number); - } - cmd.date_str2.encode(date_str2, 1); - this->send(cmd); + date_str2 = "Random:"; } + if (this->last_chosen_map) { + date_str2 += string_printf(" Map:%08" PRIX32, this->last_chosen_map->map_number); + } + cmd.date_str2.encode(date_str2, 1); + this->send(cmd); } string Server::prepare_6xB6x41_map_definition(shared_ptr map, uint8_t language, bool is_nte) { @@ -2498,8 +2494,7 @@ void Server::handle_CAx34_subtract_ally_atk_points(shared_ptr, const str attacker_card->card_flags |= 0x400; attacker_card->player_state()->send_6xB4x04_if_needed(); } - uint16_t card_ref = this->send_6xB4x06_if_card_ref_invalid( - pa.original_attacker_card_ref, 9); + uint16_t card_ref = this->send_6xB4x06_if_card_ref_invalid(pa.original_attacker_card_ref, 9); auto orig_attacker_card = this->card_for_set_card_ref(card_ref); auto target_card = this->card_for_set_card_ref(pa.target_card_refs[0]); if (orig_attacker_card && target_card) { @@ -2800,11 +2795,9 @@ uint32_t Server::get_team_exp(uint8_t team_id) const { return this->team_exp[team_id]; } -uint32_t Server::send_6xB4x06_if_card_ref_invalid( - uint16_t card_ref, int16_t negative_value) { +uint32_t Server::send_6xB4x06_if_card_ref_invalid(uint16_t card_ref, int16_t negative_value) { if (this->card_special) { - return this->card_special->send_6xB4x06_if_card_ref_invalid( - card_ref, -negative_value); + return this->card_special->send_6xB4x06_if_card_ref_invalid(card_ref, -negative_value); } return card_ref; } diff --git a/src/Episode3/Server.hh b/src/Episode3/Server.hh index e32360fb..fc0ba7cc 100644 --- a/src/Episode3/Server.hh +++ b/src/Episode3/Server.hh @@ -292,7 +292,7 @@ public: void clear(); } __attribute__((packed)); std::shared_ptr map_and_rules; - std::shared_ptr deck_entries[4]; + bcarray, 4> deck_entries; parray presence_entries; uint8_t num_clients_present; parray name_entries; @@ -311,7 +311,7 @@ public: RegistrationPhase registration_phase; ActionSubphase action_subphase; uint8_t current_team_turn2; - ActionState pending_attacks[0x20]; + bcarray pending_attacks; uint32_t num_pending_attacks; parray client_done_enqueuing_attacks; parray player_ready_to_end_phase; @@ -327,8 +327,8 @@ public: std::array, 4> player_states; parray clients_done_in_mulligan_phase; uint32_t num_pending_attacks_with_cards; - std::shared_ptr attack_cards[0x20]; - ActionState pending_attacks_with_cards[0x20]; + bcarray, 0x20> attack_cards; + bcarray pending_attacks_with_cards; uint32_t unknown_a14; uint32_t unknown_a15; parray defense_list_ended_for_client; @@ -346,7 +346,7 @@ public: parray, 8>, 5> trap_tile_locs; parray, 0x10> trap_tile_locs_nte; size_t num_trap_tiles_nte; - ActionState pb_action_states[4]; + bcarray pb_action_states; parray has_done_pb; parray, 4> has_done_pb_with_client; mutable uint32_t num_6xB4x06_commands_sent; diff --git a/src/Text.hh b/src/Text.hh index adf36147..5e287cee 100644 --- a/src/Text.hh +++ b/src/Text.hh @@ -247,6 +247,90 @@ struct parray { } } __attribute__((packed)); +template +struct bcarray { + ItemT items[Count]; + + bcarray(ItemT v) { + this->clear(v); + } + bcarray(std::initializer_list init_items) { + for (size_t z = 0; z < init_items.size(); z++) { + this->items[z] = std::data(init_items)[z]; + } + this->clear_after(init_items.size()); + } + template + requires(std::is_arithmetic_v || is_converted_endian_sc_v) + bcarray() { + this->clear(0); + } + template + requires std::is_pointer_v + bcarray() { + this->clear(nullptr); + } + template + requires(!std::is_arithmetic_v && !std::is_pointer_v && !is_converted_endian_sc_v) + bcarray() {} + + bcarray(const bcarray& other) { + this->operator=(other); + } + bcarray(bcarray&& other) { + this->operator=(std::move(other)); + } + + constexpr static size_t size() { + return Count; + } + + ItemT& operator[](size_t index) { + if (index >= Count) { + throw std::out_of_range("array index out of bounds"); + } + return *&this->items[index]; + } + const ItemT& operator[](size_t index) const { + if (index >= Count) { + throw std::out_of_range("array index out of bounds"); + } + return *&this->items[index]; + } + + ItemT& at(size_t index) { + return this->operator[](index); + } + const ItemT& at(size_t index) const { + return this->operator[](index); + } + + bcarray& operator=(const bcarray& s) { + for (size_t x = 0; x < Count; x++) { + this->items[x] = s.items[x]; + } + return *this; + } + bcarray& operator=(bcarray&& s) { + for (size_t x = 0; x < Count; x++) { + this->items[x] = std::move(s.items[x]); + } + return *this; + } + + bool operator==(const bcarray& s) const { + for (size_t x = 0; x < Count; x++) { + if (this->items[x] != s.items[x]) { + return false; + } + } + return true; + } + bool operator!=(const bcarray& s) const { + return !this->operator==(s); + } +} __attribute__((packed)); + // Packed text objects for use in protocol structs enum class TextEncoding {