Files
TravianZ/Templates/Build/37_revive.tpl
T
Ferywir 91a980fa3d 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>
2026-08-09 20:20:37 +03:00

233 lines
9.6 KiB
Smarty
Raw Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<?php
#################################################################################
## -= YOU MAY NOT REMOVE OR CHANGE THIS NOTICE =- ##
## --------------------------------------------------------------------------- ##
## Filename : HEROSMANSION REVIVE PAGE ##
## Type : BUILDING TEMPLATE ##
## --------------------------------------------------------------------------- ##
## Refactored by : Shadow ##
## Redesign by : Shadow ##
## --------------------------------------------------------------------------- ##
## Contact : cata7007@gmail.com ##
## Project : TravianZ ##
## Test Server : https://travianz.org ##
## GitHub : https://github.com/Shadowss/TravianZ ##
## --------------------------------------------------------------------------- ##
## License : TravianZ Project ##
## Copyright : TravianZ (c) 2010-2026. All rights reserved. ##
## --------------------------------------------------------------------------- ##
#################################################################################
?>
<table cellpadding="1" cellspacing="1" class="build_details">
<thead>
<tr>
<th colspan="2"><?php echo REVIVE; ?> <?php echo U0; ?></th>
</tr>
</thead>
<?php
// Explicit lookup instead of dynamic variables ${'h'.$unit.'_full'}.
// The variables h1_full, h2_full, ... h26_full are defined elsewhere
// (hero_full.php / build.php's global context), exactly as they were
// accessed dynamically in the original - here we just put them in a single array,
// without changing where the values come from.
$heroFullData = [
// Romans
1 => $h1_full ?? [],
2 => $h2_full ?? [],
3 => $h3_full ?? [],
5 => $h5_full ?? [],
6 => $h6_full ?? [],
// Teutons
11 => $h11_full ?? [],
12 => $h12_full ?? [],
13 => $h13_full ?? [],
15 => $h15_full ?? [],
16 => $h16_full ?? [],
// Gauls
21 => $h21_full ?? [],
22 => $h22_full ?? [],
24 => $h24_full ?? [],
25 => $h25_full ?? [],
26 => $h26_full ?? [],
// Huns
51 => $h51_full ?? [],
53 => $h53_full ?? [],
54 => $h54_full ?? [],
55 => $h55_full ?? [],
56 => $h56_full ?? [],
// Egyptians
61 => $h61_full ?? [],
62 => $h62_full ?? [],
63 => $h63_full ?? [],
65 => $h65_full ?? [],
66 => $h66_full ?? [],
// Spartans
71 => $h71_full ?? [],
72 => $h72_full ?? [],
73 => $h73_full ?? [],
75 => $h75_full ?? [],
76 => $h76_full ?? [],
// Vikings
81 => $h81_full ?? [],
83 => $h83_full ?? [],
84 => $h84_full ?? [],
85 => $h85_full ?? [],
86 => $h86_full ?? [],
];
// The "can be resurrected" line was duplicated identically in the original: one version
// for the base unit of the tribe (without research check) and one for
// the rest of the units (with research check) - but the generated HTML was byte-for-byte
// the same. Extracted here once, called from both branches below.
$renderReviveRow = function ($hero_datarow, $name, $wood, $clay, $iron, $crop, $training_time, $id) use ($session, $building, $village) {
$total_required = (int) ($wood + $clay + $iron + $crop);
$html = "<tr>";
$html .= "<td class=\"desc\">";
$html .= "<div class=\"tit\">";
$html .= "<img class=\"unit u" . $hero_datarow['unit'] . "\" src=\"img/x.gif\" alt=\"" . $name . "\" title=\"" . $name . "\" />";
$html .= $name . " (Level " . $hero_datarow['level'] . ")";
$html .= "</div>";
$html .= "<div class=\"details\">";
$html .= "<img class=\"r1\" src=\"img/x.gif\" alt=\"" . TZ_WOOD . "\" title=\"" . LUMBER . "\" />" . $wood . "|";
$html .= "<img class=\"r2\" src=\"img/x.gif\" alt=\"" . CLAY . "\" title=\"" . CLAY . "\" />" . $clay . "|";
$html .= "<img class=\"r3\" src=\"img/x.gif\" alt=\"" . IRON . "\" title=\"" . IRON . "\" />" . $iron . "|";
$html .= "<img class=\"r4\" src=\"img/x.gif\" alt=\"" . CROP . "\" title=\"" . CROP . "\" />" . $crop . "|";
$html .= "<img class=\"r5\" src=\"img/x.gif\" alt=\"Crop consumption\" title=\"" . CROP_COM . "\" />6|";
$html .= "<img class=\"clock\" src=\"img/x.gif\" alt=\"" . DURATION . "\" title=\"" . DURATION . "\" />";
$html .= $training_time;
//-- If available resources combined are not enough, remove NPC button
if ($session->userinfo['gold'] >= 3 && $building->getTypeLevel(17) >= 1 && $village->atotal >= $total_required) {
$html .= "|<a href=\"build.php?gid=17&t=3&r1=" . $wood . "&r2=" . $clay . "&r3=" . $iron . "&r4=" . $crop . "\" title=\"NPC trade\"><img class=\"npc\" src=\"img/x.gif\" alt=\"NPC trade\" title=\"NPC trade\" /></a>";
}
$html .= "</div>";
$html .= "</td>";
$html .= "<td class=\"val\" width=\"20%\" style=\"text-align: center\">";
if ($village->awood < $wood || $village->aclay < $clay || $village->airon < $iron || $village->acrop < $crop) {
$html .= "<span class=\"none\">" . NOT . "" . ENOUGH_RESOURCES . "</span>";
} else {
$html .= "<a href=\"build.php?id=" . $id . "&amp;revive=1&amp;hid=" . $hero_datarow['heroid'] . "\">" . REVIVE . "</a>";
}
$html .= "</td>";
$html .= "</tr>";
return $html;
};
// check if there is a hero in revive already
$reviving = $training = false;
foreach ($heroes as $hero_datarow) {
if ($hero_datarow['inrevive']) {
$reviving = true;
}
if ($hero_datarow['intraining']) {
$training = true;
}
$name = $technology->getUnitName($hero_datarow['unit']);
// Collapsed the two branches (level <= 60 / level > 60) that differed
// only by the key used in the lookup (current level vs. ceiling 60) -
// same result, without duplicating the 5 calculation lines.
$levelKey = ($hero_datarow['level'] <= 60) ? $hero_datarow['level'] : 60;
$heroLevelData = $heroFullData[$hero_datarow['unit']][$levelKey];
$wood = $heroLevelData['wood'];
$clay = $heroLevelData['clay'];
$iron = $heroLevelData['iron'];
$crop = $heroLevelData['crop'];
$timeToTrain = $database->getArtifactsValueInfluence($session->uid, $village->wid, 5, $heroLevelData['time'] / SPEED);
$training_time = $generator->getTimeFormat($timeToTrain);
$training_time2 = time() + $timeToTrain;
if ($hero_datarow['inrevive'] == 1) {
$timeleft = $generator->getTimeFormat($hero_datarow['trainingtime'] - time());
?>
<table id="distribution" cellpadding="1" cellspacing="1">
<thead>
<tr>
<?php echo "<tr class='next'><th>".HERO_READY." <span id=timer".++$session->timer.">".$timeleft."</span></th></tr>"; ?>
</tr>
</thead>
<tr>
<?php
// NOTE (pre-existing bug, kept unchanged): $name1 comes from
// the parent scope (37.tpl), where at this point in the flow it is
// 'unknown' - NOT the real name of this $hero_datarow. Same
// behavior as in the original file.
echo "<tr>
<td class=\"desc\">
<div class=\"tit\">
<img class=\"unit u".$hero_datarow['unit']."\" src=\"img/x.gif\" alt=\"".$name."\" title=\"".$name."\" />
$name ($name1)
</div>"
?>
</tr>
</table>
<?php
} elseif (!$reviving && $hero_datarow['dead'] == 1) {
/**
* Only a DEAD hero gets a revive row: $heroes holds every hero row of
* the player, so without this guard a hero who is merely in training
* was offered for revival as well (the action below is already gated
* on dead == 1, so the button did nothing).
*
* BUG REPARAT: invierea cerea ca unitatea EROULUI sa fie cercetata in
* satul CURENT.
*
* Eroul e insa antrenat o singura data, in satul lui de origine, si se
* poate muta oriunde. Daca murea intr-un sat care nu avea cercetata
* acea unitate, butonul de inviere pur si simplu nu aparea - eroul
* ramanea mort pentru totdeauna, desi satul avea Conacul.
*
* Cercetarea conteaza la ANTRENAREA unui erou nou, nu la invierea unuia
* existent: acela a fost deja platit si antrenat. Singura conditie e
* Conacul din satul unde se afla acum.
*/
echo $renderReviveRow($hero_datarow, $name, $wood, $clay, $iron, $crop, $training_time, $id);
}
if (isset($_GET['revive']) && $_GET['revive'] == 1 && isset($_GET['hid']) && $_GET['hid'] == $hero_datarow['heroid'] && $hero_datarow['inrevive'] == 0 && $hero_datarow['intraining'] == 0 && $hero_datarow['dead'] == 1) {
mysqli_query($database->dblink, "UPDATE " . TB_PREFIX . "hero SET `inrevive` = '1', `trainingtime` = '" . (int) $training_time2 . "', `wref` = '" . (int) $village->wid . "' WHERE `heroid` = " . (int) $_GET['hid'] . " AND `uid` = '" . (int) $session->uid . "'");
$database->modifyResource($village->wid, $wood, $clay, $iron, $crop, 0);
header("Location: build.php?id=" . $id . "");
exit;
}
}
?>
</table><br />
<?php
// NOTE: plain include() (not include_once), just like in the original. It
// is important to keep it that way - if 37_train.tpl has already been included from
// 37.tpl via an include_once earlier in the same request, PHP
// tracks the file as "already included" globally (regardless of what kind of
// include it was first brought in), so a subsequent include_once in
// 37.tpl will not re-run it. Changing to include_once here wouldn't be
// wrong per se, but I preferred not to change this detail at all.
if (!$reviving && !$training) {
include("37_train.tpl");
}
?>