fix using incorrect card object in 59:SLAYERS_ASSASSINS
This commit is contained in:
@@ -39,17 +39,17 @@ private:
|
||||
|
||||
public:
|
||||
parray<AssistEffect, 4> assist_effects;
|
||||
std::shared_ptr<const CardIndex::CardEntry> assist_card_defs[4];
|
||||
bcarray<std::shared_ptr<const CardIndex::CardEntry>, 4> assist_card_defs;
|
||||
uint32_t num_assist_cards_set;
|
||||
parray<uint8_t, 4> client_ids_with_assists;
|
||||
parray<AssistEffect, 4> active_assist_effects;
|
||||
std::shared_ptr<const CardIndex::CardEntry> active_assist_card_defs[4];
|
||||
bcarray<std::shared_ptr<const CardIndex::CardEntry>, 4> active_assist_card_defs;
|
||||
uint32_t num_active_assists;
|
||||
std::shared_ptr<HandAndEquipState> hand_and_equip_states[4];
|
||||
std::shared_ptr<parray<CardShortStatus, 0x10>> card_short_statuses[4];
|
||||
std::shared_ptr<DeckEntry> deck_entries[4];
|
||||
std::shared_ptr<parray<ActionChainWithConds, 9>> set_card_action_chains[4];
|
||||
std::shared_ptr<parray<ActionMetadata, 9>> set_card_action_metadatas[4];
|
||||
bcarray<std::shared_ptr<HandAndEquipState>, 4> hand_and_equip_states;
|
||||
bcarray<std::shared_ptr<parray<CardShortStatus, 0x10>>, 4> card_short_statuses;
|
||||
bcarray<std::shared_ptr<DeckEntry>, 4> deck_entries;
|
||||
bcarray<std::shared_ptr<parray<ActionChainWithConds, 9>>, 4> set_card_action_chains;
|
||||
bcarray<std::shared_ptr<parray<ActionMetadata, 9>>, 4> set_card_action_metadatas;
|
||||
};
|
||||
|
||||
} // namespace Episode3
|
||||
|
||||
@@ -96,9 +96,7 @@ private:
|
||||
|
||||
class BattleRecordPlayer {
|
||||
public:
|
||||
BattleRecordPlayer(
|
||||
std::shared_ptr<const BattleRecord> rec,
|
||||
std::shared_ptr<struct event_base> base);
|
||||
BattleRecordPlayer(std::shared_ptr<const BattleRecord> rec, std::shared_ptr<struct event_base> base);
|
||||
~BattleRecordPlayer() = default;
|
||||
|
||||
std::shared_ptr<const BattleRecord> get_record() const;
|
||||
|
||||
+12
-20
@@ -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<PlayerState> 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<Card> 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;
|
||||
|
||||
@@ -148,7 +148,7 @@ private:
|
||||
|
||||
public:
|
||||
std::shared_ptr<Card> sc_card;
|
||||
std::shared_ptr<Card> set_cards[8];
|
||||
bcarray<std::shared_ptr<Card>, 8> set_cards;
|
||||
uint8_t client_id;
|
||||
uint16_t num_mulligans_allowed;
|
||||
CardType sc_card_type;
|
||||
|
||||
@@ -198,11 +198,11 @@ private:
|
||||
std::weak_ptr<Server> w_server;
|
||||
|
||||
public:
|
||||
std::shared_ptr<HandAndEquipState> hand_and_equip_states[4];
|
||||
std::shared_ptr<parray<CardShortStatus, 0x10>> short_statuses[4];
|
||||
std::shared_ptr<DeckEntry> deck_entries[4];
|
||||
std::shared_ptr<parray<ActionChainWithConds, 9>> set_card_action_chains[4];
|
||||
std::shared_ptr<parray<ActionMetadata, 9>> set_card_action_metadatas[4];
|
||||
bcarray<std::shared_ptr<HandAndEquipState>, 4> hand_and_equip_states;
|
||||
bcarray<std::shared_ptr<parray<CardShortStatus, 0x10>>, 4> short_statuses;
|
||||
bcarray<std::shared_ptr<DeckEntry>, 4> deck_entries;
|
||||
bcarray<std::shared_ptr<parray<ActionChainWithConds, 9>>, 4> set_card_action_chains;
|
||||
bcarray<std::shared_ptr<parray<ActionMetadata, 9>>, 4> set_card_action_metadatas;
|
||||
std::shared_ptr<MapAndRulesState> map_and_rules;
|
||||
std::shared_ptr<StateFlags> state_flags;
|
||||
std::shared_ptr<AssistServer> assist_server;
|
||||
|
||||
+21
-28
@@ -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:<SYS>";
|
||||
}
|
||||
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:<SYS>";
|
||||
}
|
||||
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<const MapIndex::Map> map, uint8_t language, bool is_nte) {
|
||||
@@ -2498,8 +2494,7 @@ void Server::handle_CAx34_subtract_ally_atk_points(shared_ptr<Client>, 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;
|
||||
}
|
||||
|
||||
@@ -292,7 +292,7 @@ public:
|
||||
void clear();
|
||||
} __attribute__((packed));
|
||||
std::shared_ptr<MapAndRulesState> map_and_rules;
|
||||
std::shared_ptr<DeckEntry> deck_entries[4];
|
||||
bcarray<std::shared_ptr<DeckEntry>, 4> deck_entries;
|
||||
parray<PresenceEntry, 4> presence_entries;
|
||||
uint8_t num_clients_present;
|
||||
parray<NameEntry, 4> name_entries;
|
||||
@@ -311,7 +311,7 @@ public:
|
||||
RegistrationPhase registration_phase;
|
||||
ActionSubphase action_subphase;
|
||||
uint8_t current_team_turn2;
|
||||
ActionState pending_attacks[0x20];
|
||||
bcarray<ActionState, 0x20> pending_attacks;
|
||||
uint32_t num_pending_attacks;
|
||||
parray<uint8_t, 4> client_done_enqueuing_attacks;
|
||||
parray<uint8_t, 4> player_ready_to_end_phase;
|
||||
@@ -327,8 +327,8 @@ public:
|
||||
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];
|
||||
ActionState pending_attacks_with_cards[0x20];
|
||||
bcarray<std::shared_ptr<Card>, 0x20> attack_cards;
|
||||
bcarray<ActionState, 0x20> pending_attacks_with_cards;
|
||||
uint32_t unknown_a14;
|
||||
uint32_t unknown_a15;
|
||||
parray<uint32_t, 4> defense_list_ended_for_client;
|
||||
@@ -346,7 +346,7 @@ public:
|
||||
parray<parray<parray<uint8_t, 2>, 8>, 5> trap_tile_locs;
|
||||
parray<parray<uint8_t, 2>, 0x10> trap_tile_locs_nte;
|
||||
size_t num_trap_tiles_nte;
|
||||
ActionState pb_action_states[4];
|
||||
bcarray<ActionState, 4> pb_action_states;
|
||||
parray<uint8_t, 4> has_done_pb;
|
||||
parray<parray<uint8_t, 4>, 4> has_done_pb_with_client;
|
||||
mutable uint32_t num_6xB4x06_commands_sent;
|
||||
|
||||
+84
@@ -247,6 +247,90 @@ struct parray {
|
||||
}
|
||||
} __attribute__((packed));
|
||||
|
||||
template <typename ItemT, size_t Count>
|
||||
struct bcarray {
|
||||
ItemT items[Count];
|
||||
|
||||
bcarray(ItemT v) {
|
||||
this->clear(v);
|
||||
}
|
||||
bcarray(std::initializer_list<ItemT> 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 <typename ArgT = ItemT>
|
||||
requires(std::is_arithmetic_v<ArgT> || is_converted_endian_sc_v<ArgT>)
|
||||
bcarray() {
|
||||
this->clear(0);
|
||||
}
|
||||
template <typename ArgT = ItemT>
|
||||
requires std::is_pointer_v<ArgT>
|
||||
bcarray() {
|
||||
this->clear(nullptr);
|
||||
}
|
||||
template <typename ArgT = ItemT>
|
||||
requires(!std::is_arithmetic_v<ArgT> && !std::is_pointer_v<ArgT> && !is_converted_endian_sc_v<ArgT>)
|
||||
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 {
|
||||
|
||||
Reference in New Issue
Block a user