fix(combat): keep the hero casualty when rams force a battle recalculation [#372] (#373)

When rams change the wall level, applyRamDamage() replays the whole battle
through calculateBattle(). That helper WRITES to the hero table, so the replay
applied the hero damage a second time: applyHeroBattleDamage() only looks up
heroes with dead = 0, so the hero who had just died on the first pass was no
longer found, the call returned null and casualties_attacker[11] was never set.

Consequences, all visible in the screenshots of the issue: the report showed the
hero alive and "gained XP" instead of "died", modifyAttack3() never decremented
t11, and returnunitsComplete() added the hero back to units.hero - a hero dead in
the hero table but still displayed in dorf1 and in the rally point. Defender
heroes were also charged their health damage twice.

calculateBattle() now takes an optional $previousHeroOutcome: when the caller
hands over the first pass result, the hero damage is not applied again and the
first verdict (attacker / defender / reinforcement heroes) is carried over.

Also:
- drop the temporary [TravianZ][EROU] error_log() debug traces;
- 37_revive.tpl: only render a revive row for a hero that is actually dead
  (the revive action itself was already gated on dead = 1).

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
Co-authored-by: Catalin Novgorodschi <cata7007@gmail.com>
This commit is contained in:
Ferywir
2026-08-09 19:20:37 +02:00
committed by GitHub
parent 770fa9fd6b
commit 91a980fa3d
3 changed files with 26 additions and 7 deletions
+12 -4
View File
@@ -484,6 +484,13 @@ class Battle {
Function to process Calculate Battle
(Phase 2: orchestrator — fiecare sectiune
a devenit un helper privat, mai jos)
$previousHeroOutcome: result of an earlier
pass over the SAME battle (rams changed the
wall level, so it is replayed). When set,
the hero damage is not applied a second
time — the first verdict is reused instead
(issue #372).
*****************************************/
function calculateBattle(
@@ -498,8 +505,9 @@ class Battle {
$AttackerID, $DefenderID,
$AttackerWref, $DefenderWref,
$conqureby,
$defReinforcements = null) {
$defReinforcements = null,
$previousHeroOutcome = null) {
global $database, $unitsbytype;
/******************************************************************
@@ -742,7 +750,7 @@ class Battle {
/******************************************************************
* HERO DAMAGE (DEFENDER)
******************************************************************/
if (!empty($units['Def_unit']['hero']) && !empty($defenderhero['heroid'])) {
if (!$heroDamageAlreadyApplied && !empty($units['Def_unit']['hero']) && !empty($defenderhero['heroid'])) {
$dead = $this->applyHeroBattleDamage($defenderhero['heroid'], $result[2]);
@@ -754,7 +762,7 @@ class Battle {
/******************************************************************
* HERO DAMAGE (DEFENDER + REINFORCEMENTS)
******************************************************************/
if (!empty($DefendersAll)) {
if (!$heroDamageAlreadyApplied && !empty($DefendersAll)) {
$battleHeroesCache = [];
$villageOwnerCache = [];