fix all-players range gathering bug

This commit is contained in:
Martin Michelsen
2023-09-08 22:29:15 -07:00
parent 9dcdece1f9
commit 9c3f764cd9
7 changed files with 182 additions and 127 deletions
+74 -44
View File
@@ -14,7 +14,8 @@ static uint16_t ref_for_card(shared_ptr<const Card> card) {
}
}
static string refs_str_for_cards_vector(const vector<shared_ptr<const Card>>& cards) {
template <typename T>
static string refs_str_for_cards_vector(const vector<shared_ptr<T>>& cards) {
string ret;
for (const auto& card : cards) {
if (!ret.empty()) {
@@ -108,14 +109,6 @@ shared_ptr<const Server> CardSpecial::server() const {
return s;
}
ATTR_PRINTF(2, 3)
void CardSpecial::debug_log(const char* fmt, ...) const {
va_list va;
va_start(va, fmt);
this->server()->base()->log.debug_v(fmt, va);
va_end(va);
}
void CardSpecial::adjust_attack_damage_due_to_conditions(
shared_ptr<const Card> target_card, int16_t* inout_damage, uint16_t attacker_card_ref) {
shared_ptr<const Card> attacker_card = this->server()->card_for_set_card_ref(attacker_card_ref);
@@ -279,8 +272,6 @@ bool CardSpecial::apply_defense_condition(
if ((when == 2) && (defender_cond->type == ConditionType::GUOM) && (flags & 4)) {
CardShortStatus stat = defender_card->get_short_status();
if (stat.card_flags & 4) {
this->debug_log("(when=2) @%04hX clearing GUOM from @%04hX",
attacker_card_ref, ref_for_card(defender_card));
G_ApplyConditionEffect_GC_Ep3_6xB4x06 cmd;
cmd.effect.flags = 0x04;
cmd.effect.attacker_card_ref = this->send_6xB4x06_if_card_ref_invalid(attacker_card_ref, 0x0E);
@@ -300,7 +291,6 @@ bool CardSpecial::apply_defense_condition(
(defender_cond->type == ConditionType::ACID)) {
int16_t hp = defender_card->get_current_hp();
if (hp > 0) {
this->debug_log("(when=2) @%04hX has ACID; removing 1 HP", defender_cond->card_ref.load());
this->send_6xB4x06_for_stat_delta(
defender_card, defender_cond->card_ref, 0x20, -1, 0, 1);
defender_card->set_current_hp(hp - 1);
@@ -1537,7 +1527,8 @@ int32_t CardSpecial::evaluate_effect_expr(
const AttackEnvStats& ast,
const char* expr,
DiceRoll& dice_roll) const {
this->debug_log("evaluate_effect_expr(ast, expr=\"%s\", dice_roll=(client_id=%02hhX, a2=%02hhX, value=%02hhX, value_used_in_expr=%s, a5=%04hX))", expr, dice_roll.client_id, dice_roll.unknown_a2, dice_roll.value, dice_roll.value_used_in_expr ? "true" : "false", dice_roll.unknown_a5);
auto log = this->server()->base()->log.sub("evaluate_effect_expr: ");
log.debug("ast, expr=\"%s\", dice_roll=(client_id=%02hhX, a2=%02hhX, value=%02hhX, value_used_in_expr=%s, a5=%04hX)", expr, dice_roll.client_id, dice_roll.unknown_a2, dice_roll.value, dice_roll.value_used_in_expr ? "true" : "false", dice_roll.unknown_a5);
// Note: This implementation is not based on the original code because the
// original code was hard to follow - it used a look-behind approach with lots
@@ -1568,7 +1559,7 @@ int32_t CardSpecial::evaluate_effect_expr(
// Operators are evaluated left-to-right - there are no operator precedence
// rules
int32_t value = 0;
this->debug_log("evaluate_effect_expr: value=%" PRId32 " (start)", value);
log.debug("value=%" PRId32 " (start)", value);
for (size_t token_index = 0; token_index < tokens.size(); token_index++) {
auto token_type = tokens[token_index].first;
int32_t token_value = tokens[token_index].second;
@@ -1577,7 +1568,7 @@ int32_t CardSpecial::evaluate_effect_expr(
}
if (token_type == ExpressionTokenType::NUMBER) {
value = token_value;
this->debug_log("evaluate_effect_expr: value=%" PRId32 " (token_type=NUMBER, token_value=%" PRId32 ")", value, token_value);
log.debug("value=%" PRId32 " (token_type=NUMBER, token_value=%" PRId32 ")", value, token_value);
} else {
if (token_index >= tokens.size() - 1) {
throw runtime_error("no token on right side of binary operator");
@@ -1591,23 +1582,23 @@ int32_t CardSpecial::evaluate_effect_expr(
switch (token_type) {
case ExpressionTokenType::ROUND_DIVIDE:
value = lround(static_cast<double>(value) / right_value);
this->debug_log("evaluate_effect_expr: value=%" PRId32 " (token_type=ROUND_DIVIDE, right_token_value=%" PRId32 ")", value, right_value);
log.debug("value=%" PRId32 " (token_type=ROUND_DIVIDE, right_token_value=%" PRId32 ")", value, right_value);
break;
case ExpressionTokenType::SUBTRACT:
value -= right_value;
this->debug_log("evaluate_effect_expr: value=%" PRId32 " (token_type=SUBTRACT, right_token_value=%" PRId32 ")", value, right_value);
log.debug("value=%" PRId32 " (token_type=SUBTRACT, right_token_value=%" PRId32 ")", value, right_value);
break;
case ExpressionTokenType::ADD:
value += right_value;
this->debug_log("evaluate_effect_expr: value=%" PRId32 " (token_type=ADD, right_token_value=%" PRId32 ")", value, right_value);
log.debug("value=%" PRId32 " (token_type=ADD, right_token_value=%" PRId32 ")", value, right_value);
break;
case ExpressionTokenType::MULTIPLY:
value *= right_value;
this->debug_log("evaluate_effect_expr: value=%" PRId32 " (token_type=MULTIPLY, right_token_value=%" PRId32 ")", value, right_value);
log.debug("value=%" PRId32 " (token_type=MULTIPLY, right_token_value=%" PRId32 ")", value, right_value);
break;
case ExpressionTokenType::FLOOR_DIVIDE:
value = floor(value / right_value);
this->debug_log("evaluate_effect_expr: value=%" PRId32 " (token_type=FLOOR_DIVIDE, right_token_value=%" PRId32 ")", value, right_value);
log.debug("value=%" PRId32 " (token_type=FLOOR_DIVIDE, right_token_value=%" PRId32 ")", value, right_value);
break;
default:
throw logic_error("invalid binary operator");
@@ -1615,7 +1606,7 @@ int32_t CardSpecial::evaluate_effect_expr(
}
}
this->debug_log("evaluate_effect_expr: value=%" PRId32 " (result)", value);
log.debug("value=%" PRId32 " (result)", value);
return value;
}
@@ -1627,9 +1618,10 @@ bool CardSpecial::execute_effect(
ConditionType cond_type,
uint32_t unknown_p7,
uint16_t attacker_card_ref) {
auto log = this->server()->base()->log.sub("execute_effect: ");
{
string cond_str = cond.str();
this->debug_log("execute_effect(cond=%s, card=%04hX, expr_value=%hd, unknown_p5=%hd, cond_type=%s, unknown_p7=%" PRIu32 ", attacker_card_ref=%04hX)", cond_str.c_str(), ref_for_card(card), expr_value, unknown_p5, name_for_condition_type(cond_type), unknown_p7, attacker_card_ref);
log.debug("cond=%s, card=%04hX, expr_value=%hd, unknown_p5=%hd, cond_type=%s, unknown_p7=%" PRIu32 ", attacker_card_ref=%04hX", cond_str.c_str(), ref_for_card(card), expr_value, unknown_p5, name_for_condition_type(cond_type), unknown_p7, attacker_card_ref);
}
int16_t clamped_expr_value = clamp<int16_t>(expr_value, -99, 99);
int16_t clamped_unknown_p5 = clamp<int16_t>(unknown_p5, -99, 99);
@@ -2504,7 +2496,8 @@ vector<shared_ptr<const Card>> CardSpecial::get_targeted_cards_for_condition(
const ActionState& as,
int16_t p_target_type,
bool apply_usability_filters) const {
this->debug_log("get_targeted_cards_for_condition(card_ref=%04hX, def_effect_index=%02hhX, setter_card_ref=%04hX, as, p_target_type=%hd, apply_usability_filters=%s)", card_ref, def_effect_index, setter_card_ref, p_target_type, apply_usability_filters ? "true" : "false");
auto log = this->server()->base()->log.sub("get_targeted_cards_for_condition: ");
log.debug("card_ref=%04hX, def_effect_index=%02hhX, setter_card_ref=%04hX, as, p_target_type=%hd, apply_usability_filters=%s", card_ref, def_effect_index, setter_card_ref, p_target_type, apply_usability_filters ? "true" : "false");
vector<shared_ptr<const Card>> ret;
@@ -2513,12 +2506,12 @@ vector<shared_ptr<const Card>> CardSpecial::get_targeted_cards_for_condition(
if (!card1) {
card1 = this->server()->card_for_set_card_ref(setter_card_ref);
}
this->debug_log("get_targeted_cards_for_condition: card1=%04hX", ref_for_card(card1));
log.debug("card1=%04hX", ref_for_card(card1));
auto card2 = this->server()->card_for_set_card_ref((as.attacker_card_ref == 0xFFFF)
? as.original_attacker_card_ref
: as.attacker_card_ref);
this->debug_log("get_targeted_cards_for_condition: card2=%04hX", ref_for_card(card2));
log.debug("card2=%04hX", ref_for_card(card2));
Location card1_loc;
if (!card1) {
@@ -2529,13 +2522,13 @@ vector<shared_ptr<const Card>> CardSpecial::get_targeted_cards_for_condition(
this->get_card1_loc_with_card2_opposite_direction(&card1_loc, card1, card2);
string card1_loc_str = card1_loc.str();
this->debug_log("get_targeted_cards_for_condition: card1_loc=%s", card1_loc_str.c_str());
log.debug("card1_loc=%s", card1_loc_str.c_str());
}
AttackMedium attack_medium = card2
? card2->action_chain.chain.attack_medium
: AttackMedium::UNKNOWN;
this->debug_log("get_targeted_cards_for_condition: attack_medium=%s", name_for_attack_medium(attack_medium));
log.debug("attack_medium=%s", name_for_attack_medium(attack_medium));
auto add_card_refs = [&](const vector<uint16_t>& result_card_refs) -> void {
for (uint16_t result_card_ref : result_card_refs) {
@@ -2551,10 +2544,10 @@ vector<shared_ptr<const Card>> CardSpecial::get_targeted_cards_for_condition(
case 5: {
auto result_card = this->server()->card_for_set_card_ref(setter_card_ref);
if (result_card) {
this->debug_log("get_targeted_cards_for_condition: (p01/p05) result_card=%04hX", ref_for_card(result_card));
log.debug("(p01/p05) result_card=%04hX", ref_for_card(result_card));
ret.emplace_back(result_card);
} else {
this->debug_log("get_targeted_cards_for_condition: (p01/p05) result_card=null");
log.debug("(p01/p05) result_card=null");
}
break;
}
@@ -2649,10 +2642,10 @@ vector<shared_ptr<const Card>> CardSpecial::get_targeted_cards_for_condition(
case 16: {
ret = this->find_cards_in_hp_range(8, 1000);
string range_refs_str = refs_str_for_cards_vector(ret);
this->debug_log("get_targeted_cards_for_condition: (p16) candidate cards = [%s]", range_refs_str.c_str());
log.debug("(p16) candidate cards = [%s]", range_refs_str.c_str());
ret = this->filter_cards_by_range(ret, card1, card1_loc, card2);
range_refs_str = refs_str_for_cards_vector(ret);
this->debug_log("get_targeted_cards_for_condition: (p16) filtered cards = [%s]", range_refs_str.c_str());
log.debug("(p16) filtered cards = [%s]", range_refs_str.c_str());
break;
}
case 17: {
@@ -2703,26 +2696,39 @@ vector<shared_ptr<const Card>> CardSpecial::get_targeted_cards_for_condition(
}
}
break;
case 23:
case 23: {
auto log23 = log.sub("(p23) ");
if (card1) {
auto def = this->server()->definition_for_card_ref(card_ref);
auto ps = card1->player_state();
if (def && ps) {
// TODO: Again with the Gifoie hardcoding...
uint16_t range_card_id = this->get_card_id_with_effective_range(card1, 0x00D9, card2);
log23.debug("effective range card ID is %04hX", range_card_id);
parray<uint8_t, 9 * 9> range;
compute_effective_range(range, this->server()->base()->card_index, range_card_id, card1_loc, this->server()->base()->map_and_rules1);
compute_effective_range(range, this->server()->base()->card_index, range_card_id, card1_loc, this->server()->base()->map_and_rules1, &log23);
auto result_card_refs = ps->get_all_cards_within_range(range, card1_loc, 0xFF);
log23.debug("%zu result card refs", result_card_refs.size());
for (uint16_t result_card_ref : result_card_refs) {
auto result_log = log23.subf("(result ref %04hX) ", result_card_ref);
auto result_card = this->server()->card_for_set_card_ref(result_card_ref);
if (result_card &&
(result_card->get_definition()->def.type != CardType::ITEM)) {
if (!result_card) {
result_log.debug("result card not found");
} else if (result_card->get_definition()->def.type == CardType::ITEM) {
result_log.debug("result card is item");
} else {
result_log.debug("result card found and is not item");
ret.emplace_back(result_card);
}
}
} else {
log23.debug("def or ps is missing");
}
} else {
log23.debug("card1 is missing");
}
break;
}
case 24:
ret = this->find_cards_by_condition_inc_exc(ConditionType::PARALYZE);
break;
@@ -3058,9 +3064,9 @@ vector<shared_ptr<const Card>> CardSpecial::get_targeted_cards_for_condition(
if (this->server()->ruler_server->check_usability_or_apply_condition_for_card_refs(
card_ref, setter_card_ref, c->get_card_ref(), def_effect_index, attack_medium)) {
filtered_ret.emplace_back(c);
this->debug_log("get_targeted_cards_for_condition: usability filter: kept card %04hX", ref_for_card(c));
log.debug("usability filter: kept card %04hX", ref_for_card(c));
} else {
this->debug_log("get_targeted_cards_for_condition: usability filter: removed card %04hX", ref_for_card(c));
log.debug("usability filter: removed card %04hX", ref_for_card(c));
}
}
return filtered_ret;
@@ -3524,9 +3530,17 @@ void CardSpecial::unknown_8024C2B0(
uint16_t sc_card_ref,
bool apply_defense_condition_to_all_cards,
uint16_t apply_defense_condition_to_card_ref) {
auto debug_log = this->server()->base()->log.sub("unknown_8024C2B0: ");
{
string as_str = as.str();
debug_log.debug("when=%02" PRIX32 ", set_card_ref=%04hX, as=%s, sc_card_ref=%04hX, apply_defense_condition_to_all_cards=%s, apply_defense_condition_to_card_ref=%04hX",
when, set_card_ref, as_str.c_str(), sc_card_ref, apply_defense_condition_to_all_cards ? "true" : "false", apply_defense_condition_to_card_ref);
}
set_card_ref = this->send_6xB4x06_if_card_ref_invalid(set_card_ref, 1);
auto ce = this->server()->definition_for_card_ref(set_card_ref);
if (!ce) {
debug_log.debug("ce missing");
return;
}
@@ -3567,27 +3581,30 @@ void CardSpecial::unknown_8024C2B0(
dice_roll.unknown_a2 = 3;
dice_roll.value_used_in_expr = false;
debug_log.debug("inputs: dice_roll=%02hhX, random_percent=%hhu, unknown_v1=%s", dice_roll.value, random_percent, unknown_v1 ? "true" : "false");
for (size_t def_effect_index = 0; (def_effect_index < 3) && !unknown_v1 && (ce->def.effects[def_effect_index].type != ConditionType::NONE); def_effect_index++) {
auto effect_log = debug_log.sub(string_printf("(effect:%zu) ", def_effect_index));
const auto& card_effect = ce->def.effects[def_effect_index];
string card_effect_str = card_effect.str();
effect_log.debug("effect: %s", card_effect_str.c_str());
if (card_effect.when != when) {
effect_log.debug("does not apply (effect.when=%02hhX, when=%02" PRIX32 ")", card_effect.when, when);
continue;
}
{
string as_s = as.str();
string eff_s = card_effect.str();
this->debug_log("(when=%" PRIu32 ") set=@%04hX sc=@%04hX as=%s att=@%04hX eff=%s",
when, set_card_ref, sc_card_ref, as_s.c_str(), as_attacker_card_ref, eff_s.c_str());
}
int16_t arg3_value = atoi(&card_effect.arg3[1]);
effect_log.debug("arg3_value=%hd", arg3_value);
auto targeted_cards = this->get_targeted_cards_for_condition(
set_card_ref, def_effect_index, sc_card_ref, as, arg3_value, 1);
string refs_str = refs_str_for_cards_vector(targeted_cards);
effect_log.debug("targeted_cards=[%s]", refs_str.c_str());
bool all_targets_matched = false;
if (!targeted_cards.empty() &&
((card_effect.type == ConditionType::UNKNOWN_64) ||
(card_effect.type == ConditionType::MISC_DEFENSE_BONUSES) ||
(card_effect.type == ConditionType::MOSTLY_HALFGUARDS))) {
effect_log.debug("special targeting applies");
size_t count = 0;
for (size_t z = 0; z < targeted_cards.size(); z++) {
dice_roll.value_used_in_expr = false;
@@ -3614,18 +3631,24 @@ void CardSpecial::unknown_8024C2B0(
} else {
targeted_cards.clear();
}
} else {
effect_log.debug("special targeting does not apply");
}
for (size_t z = 0; z < targeted_cards.size(); z++) {
auto target_log = effect_log.sub(string_printf("(target:%04hX) ", targeted_cards[z]->get_card_ref()));
dice_roll.value_used_in_expr = false;
string arg2_str = card_effect.arg2;
target_log.debug("arg2_str = %s", arg2_str.c_str());
if (all_targets_matched ||
this->evaluate_effect_arg2_condition(
as, targeted_cards[z], arg2_str.c_str(), dice_roll, set_card_ref, sc_card_ref, random_percent, when)) {
target_log.debug("arg2 condition passed");
auto env_stats = this->compute_attack_env_stats(
as, targeted_cards[z], dice_roll, set_card_ref, sc_card_ref);
string expr_str = card_effect.expr;
int16_t value = this->evaluate_effect_expr(env_stats, expr_str.c_str(), dice_roll);
target_log.debug("expr = %s, value = %hd", expr_str.c_str(), value);
uint32_t unknown_v1 = 0;
auto target_card = this->compute_replaced_target_based_on_conditions(
@@ -3641,12 +3664,16 @@ void CardSpecial::unknown_8024C2B0(
sc_card_ref);
if (!target_card) {
target_card = targeted_cards[z];
target_log.debug("target card (not replaced) = %04hX", target_card->get_card_ref());
} else {
target_log.debug("target card (replaced) = %04hX", target_card->get_card_ref());
}
ssize_t applied_cond_index = -1;
if ((unknown_v1 == 0) && !this->should_cancel_condition_due_to_anti_abnormality(card_effect, target_card, dice_cmd.effect.target_card_ref, sc_card_ref)) {
applied_cond_index = target_card->apply_abnormal_condition(
card_effect, def_effect_index, dice_cmd.effect.target_card_ref, sc_card_ref, value, dice_roll.value, random_percent);
target_log.debug("applied abnormal condition");
// This debug_print call is in the original code.
// this->debug_print(when, 4, &env_stats, "!set_abnormal..", target_card, card_effect.type);
}
@@ -3668,8 +3695,11 @@ void CardSpecial::unknown_8024C2B0(
(apply_defense_condition_to_all_cards || (apply_defense_condition_to_card_ref == targeted_cards[z]->get_card_ref()))) {
this->apply_defense_condition(
when, &target_card->action_chain.conditions[applied_cond_index], applied_cond_index, as, target_card, 4, 1);
target_log.debug("applied defense condition");
}
target_card->send_6xB4x4E_4C_4D_if_needed(0);
} else {
target_log.debug("arg2 condition failed");
}
if (dice_roll.value_used_in_expr) {
any_expr_used_dice_roll = true;
-2
View File
@@ -95,8 +95,6 @@ public:
std::shared_ptr<Server> server();
std::shared_ptr<const Server> server() const;
void debug_log(const char* fmt, ...) const ATTR_PRINTF(2, 3);
void adjust_attack_damage_due_to_conditions(
std::shared_ptr<const Card> target_card, int16_t* inout_damage, uint16_t attacker_card_ref);
void adjust_dice_boost_if_team_has_condition_52(
+6 -2
View File
@@ -751,13 +751,17 @@ vector<uint16_t> PlayerState::get_all_cards_within_range(
const parray<uint8_t, 9 * 9>& range,
const Location& loc,
uint8_t target_team_id) const {
auto log = this->server()->base()->log.sub("get_all_cards_within_range: ");
string loc_str = loc.str();
log.debug("loc=%s, target_team_id=%02hhX", loc_str.c_str(), target_team_id);
vector<uint16_t> ret;
for (size_t client_id = 0; client_id < 4; client_id++) {
auto other_ps = this->server()->player_states[client_id];
if (other_ps &&
((target_team_id == 0xFF) || (target_team_id == other_ps->get_team_id()))) {
ret = get_card_refs_within_range(
range, loc, *other_ps->card_short_statuses);
auto card_refs = get_card_refs_within_range(range, loc, *other_ps->card_short_statuses, &log);
ret.insert(ret.end(), card_refs.begin(), card_refs.end());
}
}
return ret;
+42 -6
View File
@@ -759,38 +759,74 @@ const char* PlayerBattleStats::name_for_rank(uint8_t rank) {
return RANK_NAMES[rank];
}
bool is_card_within_range(
static bool is_card_within_range(
const parray<uint8_t, 9 * 9>& range,
const Location& anchor_loc,
const CardShortStatus& ss) {
const CardShortStatus& ss,
PrefixedLogger* log) {
if (ss.card_ref == 0xFFFF) {
if (log) {
log->debug("is_card_within_range: (false) ss.card_ref missing");
}
return false;
}
if (range[0] == 2) {
if (log) {
log->debug("is_card_within_range: (true) range is entire field");
}
return true;
}
if ((ss.loc.x < anchor_loc.x - 4) || (ss.loc.x > anchor_loc.x + 4)) {
if (log) {
log->debug("is_card_within_range: (false) outside x range (ss.loc.x=%hhu, anchor_loc.x=%hhu)", ss.loc.x, anchor_loc.x);
}
return false;
}
if ((ss.loc.y < anchor_loc.y - 4) || (ss.loc.y > anchor_loc.y + 4)) {
if (log) {
log->debug("is_card_within_range: (false) outside y range (ss.loc.y=%hhu, anchor_loc.y=%hhu)", ss.loc.y, anchor_loc.y);
}
return false;
}
return (range[(ss.loc.x - anchor_loc.x) + ((ss.loc.y - anchor_loc.y) + 4) * 9 + 4] != 0);
uint8_t y_index = (ss.loc.y - anchor_loc.y) + 4;
uint8_t x_index = (ss.loc.x - anchor_loc.x) + 4;
bool ret = (range[y_index * 9 + x_index] != 0);
if (log) {
log->debug("is_card_within_range: (%s) (ss.loc=(%hhu,%hhu), anchor_loc=(%hhu,%hhu), indexes=(%hhu,%hhu))",
ret ? "true" : "false", ss.loc.x, ss.loc.y, anchor_loc.x, anchor_loc.y, x_index, y_index);
}
return ret;
}
vector<uint16_t> get_card_refs_within_range(
const parray<uint8_t, 9 * 9>& range,
const Location& loc,
const parray<CardShortStatus, 0x10>& short_statuses) {
const parray<CardShortStatus, 0x10>& short_statuses,
PrefixedLogger* log) {
vector<uint16_t> ret;
if (is_card_within_range(range, loc, short_statuses[0])) {
if (is_card_within_range(range, loc, short_statuses[0], log)) {
if (log) {
log->debug("get_card_refs_within_range: sc card %04hX within range", short_statuses[0].card_ref.load());
}
ret.emplace_back(short_statuses[0].card_ref);
} else {
if (log) {
log->debug("get_card_refs_within_range: sc card %04hX not within range", short_statuses[0].card_ref.load());
}
}
for (size_t card_index = 7; card_index < 15; card_index++) {
const auto& ss = short_statuses[card_index];
if (is_card_within_range(range, loc, ss)) {
if (is_card_within_range(range, loc, ss, log)) {
if (log) {
log->debug("get_card_refs_within_range: card %04hX within range", ss.card_ref.load());
}
ret.emplace_back(ss.card_ref);
} else {
if (log) {
log->debug("get_card_refs_within_range: card %04hX not within range", ss.card_ref.load());
}
}
}
return ret;
+2 -1
View File
@@ -270,6 +270,7 @@ struct PlayerBattleStats {
std::vector<uint16_t> get_card_refs_within_range(
const parray<uint8_t, 9 * 9>& range,
const Location& loc,
const parray<CardShortStatus, 0x10>& short_statuses);
const parray<CardShortStatus, 0x10>& short_statuses,
PrefixedLogger* log = nullptr);
} // namespace Episode3
+56 -71
View File
@@ -11,7 +11,14 @@ void compute_effective_range(
shared_ptr<const CardIndex> card_index,
uint16_t card_id,
const Location& loc,
shared_ptr<const MapAndRulesState> map_and_rules) {
shared_ptr<const MapAndRulesState> map_and_rules,
PrefixedLogger* log) {
if (log && log->should_log(LogLevel::DEBUG)) {
string loc_str = loc.str();
log->debug("compute_effective_range: card_id=%04hX, loc=%s", card_id, loc_str.c_str());
log->debug("compute_effective_range: map_and_rules->map:");
map_and_rules->map.print(stderr);
}
ret.clear(0);
parray<uint32_t, 6> range_def;
@@ -29,10 +36,16 @@ void compute_effective_range(
range_def[z] = ce->def.range[z];
}
}
if (log) {
log->debug("compute_effective_range: range_def: %05" PRIX32 " %05" PRIX32 " %05" PRIX32 " %05" PRIX32 " %05" PRIX32 " %05" PRIX32, range_def[0], range_def[1], range_def[2], range_def[3], range_def[4], range_def[5]);
}
if (range_def[0] == 0x000FFFFF) {
// Entire field
ret.clear(2);
if (log) {
log->debug("compute_effective_range: entire field (2)");
}
return;
}
@@ -46,82 +59,54 @@ void compute_effective_range(
row >>= 4;
}
}
if (log) {
for (size_t y = 0; y < 9; y++) {
log->debug("compute_effective_range: decoded_range: %hhX %hhX %hhX %hhX %hhX %hhX %hhX %hhX %hhX",
decoded_range[y * 9 + 0], decoded_range[y * 9 + 1], decoded_range[y * 9 + 2], decoded_range[y * 9 + 3], decoded_range[y * 9 + 4], decoded_range[y * 9 + 5], decoded_range[y * 9 + 6], decoded_range[y * 9 + 7], decoded_range[y * 9 + 8]);
}
}
switch (loc.direction) {
case Direction::LEFT:
for (int16_t y = 0; y < 9; y++) {
int16_t map_y = loc.y + y - 4;
if (!map_and_rules || ((map_y >= 0) && (map_y < map_and_rules->map.height))) {
for (int16_t x = 0; x < 9; x++) {
int16_t map_x = loc.x + x - 4;
if (!map_and_rules || ((map_x >= 0) && (map_x < map_and_rules->map.width))) {
ret[y * 9 + x] = decoded_range[(8 - x) * 9 + y];
} else {
for (int16_t y = 0; y < 9; y++) {
int16_t map_y = y + loc.y - 4;
if (!map_and_rules || ((map_y >= 0) && (map_y < map_and_rules->map.height))) {
for (int16_t x = 0; x < 9; x++) {
int16_t map_x = x + loc.x - 4;
if (!map_and_rules || ((map_x >= 0) && (map_x < map_and_rules->map.width))) {
int16_t up_x, up_y;
switch (loc.direction) {
case Direction::LEFT:
up_x = y;
up_y = 9 - x - 1;
break;
}
case Direction::RIGHT:
up_x = 9 - y - 1;
up_y = x;
break;
case Direction::UP:
up_x = x;
up_y = y;
break;
case Direction::DOWN:
up_x = 9 - x - 1;
up_y = 9 - y - 1;
break;
default:
throw logic_error("invalid direction");
}
ret[y * 9 + x] = decoded_range[up_y * 9 + up_x];
if (log) {
log->debug("compute_effective_range: x=%hd y=%hd up_x=%hd up_y=%hd v=%hhX", x, y, up_x, up_y, ret[y * 9 + x]);
}
} else {
break;
}
}
break;
}
}
case Direction::RIGHT:
for (int16_t y = 0; y < 9; y++) {
int16_t map_y = loc.y + y - 4;
if (!map_and_rules || ((map_y >= 0) && (map_y < map_and_rules->map.height))) {
for (int16_t x = 0; x < 9; x++) {
int16_t map_x = loc.x + x - 4;
if (!map_and_rules || ((map_x >= 0) && (map_x < map_and_rules->map.width))) {
ret[y * 9 + x] = decoded_range[((x * 9) - y) + 8];
} else {
break;
}
}
} else {
break;
}
}
break;
case Direction::UP:
for (int16_t y = 0; y < 9; y++) {
int16_t map_y = loc.y + y - 4;
if (!map_and_rules || ((map_y >= 0) && (map_y < map_and_rules->map.height))) {
for (int16_t x = 0; x < 9; x++) {
int16_t map_x = loc.x + x - 4;
if (!map_and_rules || ((map_x >= 0) && (map_x < map_and_rules->map.width))) {
ret[y * 9 + x] = decoded_range[y * 9 + x];
} else {
break;
}
}
} else {
break;
}
}
break;
case Direction::DOWN:
for (int16_t y = 0; y < 9; y++) {
int16_t map_y = loc.y + y - 4;
if (!map_and_rules || ((map_y >= 0) && (map_y < map_and_rules->map.height))) {
for (int16_t x = 0; x < 9; x++) {
int16_t map_y = loc.x + x - 4;
if (!map_and_rules || ((map_y >= 0) && (map_y < map_and_rules->map.width))) {
ret[y * 9 + x] = decoded_range[((8 - y) * 9 - x) + 8];
} else {
break;
}
}
} else {
break;
}
}
break;
default:
break;
if (log) {
for (size_t y = 0; y < 9; y++) {
log->debug("compute_effective_range: ret: %hhX %hhX %hhX %hhX %hhX %hhX %hhX %hhX %hhX",
ret[y * 9 + 0], ret[y * 9 + 1], ret[y * 9 + 2], ret[y * 9 + 3], ret[y * 9 + 4], ret[y * 9 + 5], ret[y * 9 + 6], ret[y * 9 + 7], ret[y * 9 + 8]);
}
}
}
+2 -1
View File
@@ -18,7 +18,8 @@ void compute_effective_range(
std::shared_ptr<const CardIndex> card_index,
uint16_t card_id,
const Location& loc,
std::shared_ptr<const MapAndRulesState> map_and_rules);
std::shared_ptr<const MapAndRulesState> map_and_rules,
PrefixedLogger* log = nullptr);
bool card_linkage_is_valid(
std::shared_ptr<const CardIndex::CardEntry> right_def,