fix rounding in division expressions

This commit is contained in:
Martin Michelsen
2023-09-05 22:52:49 -07:00
parent 2b2d8dfb3d
commit f771643880
4 changed files with 20 additions and 5 deletions
+16 -2
View File
@@ -1537,6 +1537,8 @@ int32_t CardSpecial::evaluate_effect_expr(
const AttackEnvStats& ast, const AttackEnvStats& ast,
const char* expr, const char* expr,
DiceRoll& dice_roll) const { 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);
// Note: This implementation is not based on the original code because the // 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 // original code was hard to follow - it used a look-behind approach with lots
// of local variables instead of the look-ahead approach that this // of local variables instead of the look-ahead approach that this
@@ -1566,6 +1568,7 @@ int32_t CardSpecial::evaluate_effect_expr(
// Operators are evaluated left-to-right - there are no operator precedence // Operators are evaluated left-to-right - there are no operator precedence
// rules // rules
int32_t value = 0; int32_t value = 0;
this->debug_log("evaluate_effect_expr: value=%" PRId32 " (start)", value);
for (size_t token_index = 0; token_index < tokens.size(); token_index++) { for (size_t token_index = 0; token_index < tokens.size(); token_index++) {
auto token_type = tokens[token_index].first; auto token_type = tokens[token_index].first;
int32_t token_value = tokens[token_index].second; int32_t token_value = tokens[token_index].second;
@@ -1574,6 +1577,7 @@ int32_t CardSpecial::evaluate_effect_expr(
} }
if (token_type == ExpressionTokenType::NUMBER) { if (token_type == ExpressionTokenType::NUMBER) {
value = token_value; value = token_value;
this->debug_log("evaluate_effect_expr: value=%" PRId32 " (token_type=NUMBER, token_value=%" PRId32 ")", value, token_value);
} else { } else {
if (token_index >= tokens.size() - 1) { if (token_index >= tokens.size() - 1) {
throw runtime_error("no token on right side of binary operator"); throw runtime_error("no token on right side of binary operator");
@@ -1586,19 +1590,24 @@ int32_t CardSpecial::evaluate_effect_expr(
} }
switch (token_type) { switch (token_type) {
case ExpressionTokenType::ROUND_DIVIDE: case ExpressionTokenType::ROUND_DIVIDE:
value = lround(value / right_value); 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);
break; break;
case ExpressionTokenType::SUBTRACT: case ExpressionTokenType::SUBTRACT:
value -= right_value; value -= right_value;
this->debug_log("evaluate_effect_expr: value=%" PRId32 " (token_type=SUBTRACT, right_token_value=%" PRId32 ")", value, right_value);
break; break;
case ExpressionTokenType::ADD: case ExpressionTokenType::ADD:
value += right_value; value += right_value;
this->debug_log("evaluate_effect_expr: value=%" PRId32 " (token_type=ADD, right_token_value=%" PRId32 ")", value, right_value);
break; break;
case ExpressionTokenType::MULTIPLY: case ExpressionTokenType::MULTIPLY:
value *= right_value; value *= right_value;
this->debug_log("evaluate_effect_expr: value=%" PRId32 " (token_type=MULTIPLY, right_token_value=%" PRId32 ")", value, right_value);
break; break;
case ExpressionTokenType::FLOOR_DIVIDE: case ExpressionTokenType::FLOOR_DIVIDE:
value = floor(value / right_value); value = floor(value / right_value);
this->debug_log("evaluate_effect_expr: value=%" PRId32 " (token_type=FLOOR_DIVIDE, right_token_value=%" PRId32 ")", value, right_value);
break; break;
default: default:
throw logic_error("invalid binary operator"); throw logic_error("invalid binary operator");
@@ -1606,6 +1615,7 @@ int32_t CardSpecial::evaluate_effect_expr(
} }
} }
this->debug_log("evaluate_effect_expr: value=%" PRId32 " (result)", value);
return value; return value;
} }
@@ -1615,8 +1625,12 @@ bool CardSpecial::execute_effect(
int16_t expr_value, int16_t expr_value,
int16_t unknown_p5, int16_t unknown_p5,
ConditionType cond_type, ConditionType cond_type,
uint unknown_p7, uint32_t unknown_p7,
uint16_t attacker_card_ref) { uint16_t attacker_card_ref) {
{
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);
}
int16_t clamped_expr_value = clamp<int16_t>(expr_value, -99, 99); int16_t clamped_expr_value = clamp<int16_t>(expr_value, -99, 99);
int16_t clamped_unknown_p5 = clamp<int16_t>(unknown_p5, -99, 99); int16_t clamped_unknown_p5 = clamp<int16_t>(unknown_p5, -99, 99);
+1 -1
View File
@@ -196,7 +196,7 @@ public:
int16_t expr_value, int16_t expr_value,
int16_t unknown_p5, int16_t unknown_p5,
ConditionType cond_type, ConditionType cond_type,
uint unknown_p7, uint32_t unknown_p7,
uint16_t attacker_card_ref); uint16_t attacker_card_ref);
const Condition* find_condition_with_parameters( const Condition* find_condition_with_parameters(
std::shared_ptr<const Card> card, std::shared_ptr<const Card> card,
+1 -1
View File
@@ -35,7 +35,7 @@ ServerBase::ServerBase(
card_index(card_index), card_index(card_index),
map_index(map_index), map_index(map_index),
behavior_flags(behavior_flags), behavior_flags(behavior_flags),
log(lobby->log.prefix + "[Ep3::Server] "), log(lobby->log.prefix + "[Ep3::Server] ", lobby->log.min_level),
random_crypt(random_crypt), random_crypt(random_crypt),
is_tournament(!!map_if_tournament), is_tournament(!!map_if_tournament),
last_chosen_map(map_if_tournament) {} last_chosen_map(map_if_tournament) {}
+2 -1
View File
@@ -196,7 +196,8 @@
// License manager messages describe the creation of new license files. // License manager messages describe the creation of new license files.
"LicenseManager": "INFO", "LicenseManager": "INFO",
// Lobby messages describe creation and deletion of lobbies and games, as // Lobby messages describe creation and deletion of lobbies and games, as
// well as item tracking events within games. // well as item tracking events within games. On Episode 3, debug messages
// during battles go to this stream as well; use "DEBUG" here to see them.
"Lobbies": "INFO", "Lobbies": "INFO",
// Patch file index messages describe finding and preloading the patch files // Patch file index messages describe finding and preloading the patch files
// available for download to BB and PC clients. // available for download to BB and PC clients.