From 21d50a1bc6e682d2cb7c873ed8d58faad660636c Mon Sep 17 00:00:00 2001
From: novgorodschi catalin
Date: Fri, 26 Jun 2026 09:10:47 +0300
Subject: [PATCH] Fix warsim security issue & hero building
Fix warsim security issue & hero building
---
Admin/Templates/addUsers.tpl | 2 +
Templates/Build/37.tpl | 60 ++-
Templates/Build/37_hero.tpl | 116 +++--
Templates/Build/37_land.tpl | 119 ++---
Templates/Build/37_revive.tpl | 246 ++++++-----
Templates/Build/37_train.tpl | 793 +++++++---------------------------
warsim.php | 75 ++--
7 files changed, 478 insertions(+), 933 deletions(-)
diff --git a/Admin/Templates/addUsers.tpl b/Admin/Templates/addUsers.tpl
index 01a81984..8123850d 100644
--- a/Admin/Templates/addUsers.tpl
+++ b/Admin/Templates/addUsers.tpl
@@ -1,4 +1,5 @@
Hero($session->uid);
$heroes = $units->Hero($session->uid, 1);
$define['reset_level'] = 3; // Until which level you are able to reset your points
+ // NOTE: $define['reset_level'] doesn't seem to be used in any of the
+ // 37*.tpl files - the "3" threshold is hardcoded directly into 37_hero.tpl. Possible dead code
+ // in these files; I left it unchanged (it can be read
+ // in another part of the project that I don't see here).
+
+ // Explicit lookup instead of if/elseif chain - covers all 15
+ // possible hero types (5 per tribe x 3 tribes). Same behavior:
+ // if $hero_info['unit'] doesn't match any (which shouldn't
+ // happen), $name returns null instead of "undefined variable".
+ $heroUnitNames = [
+ 1 => U1,
+ 2 => U2,
+ 3 => U3,
+ 5 => U5,
+ 6 => U6,
+ 11 => U11,
+ 12 => U12,
+ 13 => U13,
+ 15 => U15,
+ 16 => U16,
+ 21 => U21,
+ 22 => U22,
+ 24 => U24,
+ 25 => U25,
+ 26 => U26,
+ ];
?>
@@ -36,37 +62,7 @@
-
\ No newline at end of file
+
diff --git a/Templates/Build/37_hero.tpl b/Templates/Build/37_hero.tpl
index b484948d..aa1bcf7b 100644
--- a/Templates/Build/37_hero.tpl
+++ b/Templates/Build/37_hero.tpl
@@ -20,14 +20,36 @@
#################################################################################
include_once("GameEngine/Data/hero_full.php");
-global $database;
+global $database;
-if (isset($_POST['name']) && !empty($_POST['name'])) {
- $_POST['name'] = $database->escape(stripslashes($_POST['name']));
- mysqli_query($database->dblink,"UPDATE ".TB_PREFIX."hero SET `name`='".$_POST['name']."' where `uid`='".$database->escape($session->uid)."' AND dead = 0") or die("ERROR:".mysqli_error($database->dblink));
+if (isset($_POST['name']) && !empty($_POST['name'])) {
+ $_POST['name'] = $database->escape(stripslashes($_POST['name']));
+ mysqli_query($database->dblink, "UPDATE " . TB_PREFIX . "hero SET `name`='" . $_POST['name'] . "' where `uid`='" . $database->escape($session->uid) . "' AND dead = 0") or die("ERROR:" . mysqli_error($database->dblink));
$hero_info['name'] = $_POST['name'];
- echo "".NAME_CHANGED."";
+ echo "" . NAME_CHANGED . "";
}
+
+// Explicit lookup: action from URL (?add=...) => column from `hero` table.
+// Used for both "(+)" links in the table and for the update
+// in the DB below. Single source of truth instead of 5 identical blocks.
+$heroStatColumns = [
+ 'off' => 'attack',
+ 'deff' => 'defence',
+ 'obonus' => 'attackbonus',
+ 'dbonus' => 'defencebonus',
+ 'reg' => 'regeneration',
+];
+
+// Render the "(+)" link for a stat, or "(+)" uneditable
+// if the hero has no more points or the stat is already at the top (100).
+// Identical behavior to the original 5 if/else blocks.
+$renderAddLink = function ($action) use ($hero_info, $id, $heroStatColumns) {
+ $field = $heroStatColumns[$action];
+ if ($hero_info['points'] > 0 && $hero_info[$field] < 100) {
+ return "(+)";
+ }
+ return "(+)";
+};
?>
@@ -47,10 +69,7 @@ if (isset($_POST['name']) && !empty($_POST['name'])) {
|
![<?php echo $hero_info['atk']; ?> <?php echo $hero_info['atk']; ?>](img/x.gif) |
- 0 && $hero_info['attack'] < 100) echo "(+)";
- else echo "(+)";
- ?>
+
|
|
@@ -59,10 +78,7 @@ if (isset($_POST['name']) && !empty($_POST['name'])) {
|
" title="" /> |
- 0 && $hero_info['defence'] < 100) echo "(+)";
- else echo "(+)";
- ?>
+
|
|
@@ -71,10 +87,7 @@ if (isset($_POST['name']) && !empty($_POST['name'])) {
% |
![<?php echo ($hero_info['ob']-1)*100; ?>% <?php echo ($hero_info['ob']-1)*100; ?>%](img/x.gif) |
- 0 && $hero_info['attackbonus'] < 100) echo "(+)";
- else echo "(+)";
- ?>
+
|
|
@@ -83,10 +96,7 @@ if (isset($_POST['name']) && !empty($_POST['name'])) {
% |
![<?php echo ($hero_info['db']-1)*100; ?>% <?php echo ($hero_info['db']-1)*100; ?>%](img/x.gif) |
- 0 && $hero_info['defencebonus'] < 100) echo "(+)";
- else echo "(+)";
- ?>
+
|
|
@@ -95,10 +105,7 @@ if (isset($_POST['name']) && !empty($_POST['name'])) {
/ |
![<?php echo ($hero_info['regeneration']*5*SPEED); ?>%/Day <?php echo ($hero_info['regeneration']*5*SPEED); ?>%/Day](img/x.gif) |
- 0 && $hero_info['regeneration'] < 100) echo "(+)";
- else echo "(+)";
- ?>
+
|
|
@@ -145,40 +152,25 @@ if (isset($_POST['name']) && !empty($_POST['name'])) {
% .
VillageOasisCount($village->wid); ?> .
- dblink,"UPDATE " . TB_PREFIX . "hero SET `points` = (`level` * 5) + 5, `attack` = 0, `defence` = 0, `attackbonus` = 0, `defencebonus` = 0, `regeneration` = 0 WHERE `heroid` = " . $hero_info['heroid'] . " AND `level` <= 3 AND (`attack` != 0 OR `defence` != 0 OR `attackbonus` != 0 OR `defencebonus` != 0 OR `regeneration` != 0)");
- header("Location: build.php?id=".$id."");
- exit;
- }
- }
- if($_GET['add'] == "off") {
- mysqli_query($database->dblink,"UPDATE " . TB_PREFIX . "hero SET `attack` = `attack` + 1, `points` = `points` - 1 WHERE `heroid` = " . $hero_info['heroid'] . " AND `points` > 0 AND `attack` < 100");
- header("Location: build.php?id=".$id."");
- exit;
- }
- if($_GET['add'] == "deff") {
- mysqli_query($database->dblink,"UPDATE " . TB_PREFIX . "hero SET `defence` = `defence` + 1, `points` = `points` - 1 WHERE `heroid` = " . $hero_info['heroid'] . " AND `points` > 0 AND `defence` < 100");
- header("Location: build.php?id=".$id."");
- exit;
- }
- if($_GET['add'] == "obonus") {
- mysqli_query($database->dblink,"UPDATE " . TB_PREFIX . "hero SET `attackbonus` = `attackbonus` + 1, `points` = `points` - 1 WHERE `heroid` = " . $hero_info['heroid'] . " AND `points` > 0 AND `attackbonus` < 100");
- header("Location: build.php?id=".$id."");
- exit;
- }
- if($_GET['add'] == "dbonus") {
- mysqli_query($database->dblink,"UPDATE " . TB_PREFIX . "hero SET `defencebonus` = `defencebonus` + 1, `points` = `points` - 1 WHERE `heroid` = " . $hero_info['heroid'] . " AND `points` > 0 AND `defencebonus` < 100");
- header("Location: build.php?id=".$id."");
- exit;
- }
- if($_GET['add'] == "reg") {
- mysqli_query($database->dblink,"UPDATE " . TB_PREFIX . "hero SET `regeneration` = `regeneration` + 1, `points` = `points` - 1 WHERE `heroid` = " . $hero_info['heroid'] . " AND `points` > 0 AND `regeneration` < 100");
- header("Location: build.php?id=".$id."");
- exit;
- }
- }
- ?>
\ No newline at end of file
+dblink, "UPDATE " . TB_PREFIX . "hero SET `points` = (`level` * 5) + 5, `attack` = 0, `defence` = 0, `attackbonus` = 0, `defencebonus` = 0, `regeneration` = 0 WHERE `heroid` = " . $hero_info['heroid'] . " AND `level` <= 3 AND (`attack` != 0 OR `defence` != 0 OR `attackbonus` != 0 OR `defencebonus` != 0 OR `regeneration` != 0)");
+ header("Location: build.php?id=" . $id . "");
+ exit;
+ }
+ // if level > 3, exactly like in the original: nothing happens (no redirect).
+ } elseif (isset($heroStatColumns[$action])) {
+ $column = $heroStatColumns[$action];
+ mysqli_query($database->dblink, "UPDATE " . TB_PREFIX . "hero SET `$column` = `$column` + 1, `points` = `points` - 1 WHERE `heroid` = " . $hero_info['heroid'] . " AND `points` > 0 AND `$column` < 100");
+ header("Location: build.php?id=" . $id . "");
+ exit;
+ }
+}
+?>
diff --git a/Templates/Build/37_land.tpl b/Templates/Build/37_land.tpl
index b8afacac..a0ec3131 100644
--- a/Templates/Build/37_land.tpl
+++ b/Templates/Build/37_land.tpl
@@ -1,5 +1,5 @@
- getOasis($village->wid);
-if(isset($_GET['gid']) && $_GET['gid'] == 37 && isset($_GET['del']) && $database->getOasisField($_GET['del'], 'owner') == $session->uid){
- $units->returnTroops($village->wid, 1);
- $database->removeOases($_GET['del']);
- header("Location: build.php?id=".$id."&land");
- exit;
-}
+
+ if (isset($_GET['gid']) && $_GET['gid'] == 37 && isset($_GET['del']) && $database->getOasisField($_GET['del'], 'owner') == $session->uid) {
+ $units->returnTroops($village->wid, 1);
+ $database->removeOases($_GET['del']);
+ header("Location: build.php?id=" . $id . "&land");
+ exit;
+ }
+
+ // Explicit lookup, instead of the original repetitive switch:
+ // each oasis type => which resources get bonus and how much.
+ // Identical behavior to the original (same alt/title on each icon,
+ // including the existing asymmetry: for wood, alt uses TZ_WOOD but
+ // title uses LUMBER - kept exactly as in the original source).
+ $oasisResourceIcons = [
+ 'wood' => ['class' => 'r1', 'alt' => TZ_WOOD, 'title' => LUMBER],
+ 'clay' => ['class' => 'r2', 'alt' => CLAY, 'title' => CLAY],
+ 'iron' => ['class' => 'r3', 'alt' => IRON, 'title' => IRON],
+ 'crop' => ['class' => 'r4', 'alt' => CROP, 'title' => CROP],
+ ];
+
+ $oasisTypeBonuses = [
+ 1 => [['wood', 25]],
+ 2 => [['wood', 25]],
+ 3 => [['wood', 25], ['crop', 25]],
+ 4 => [['clay', 25]],
+ 5 => [['clay', 25]],
+ 6 => [['clay', 25], ['crop', 25]],
+ 7 => [['iron', 25]],
+ 8 => [['iron', 25]],
+ 9 => [['iron', 25], ['crop', 25]],
+ 10 => [['crop', 25]],
+ 11 => [['crop', 25]],
+ 12 => [['crop', 50]],
+ ];
+
+ // Replace the original switch with 12 identical cases as the structure.
+ // Unknown types => empty string, just like the lack of a 'default' in the original switch.
+ $renderOasisBonus = function ($type) use ($oasisResourceIcons, $oasisTypeBonuses) {
+ if (!isset($oasisTypeBonuses[$type])) {
+ return '';
+ }
+
+ $html = '';
+ foreach ($oasisTypeBonuses[$type] as $bonus) {
+ [$resource, $percent] = $bonus;
+ $icon = $oasisResourceIcons[$resource];
+ $html .= '
+' . $percent . '%';
+ }
+
+ return $html;
+ };
?>
\ No newline at end of file
+
diff --git a/Templates/Build/37_revive.tpl b/Templates/Build/37_revive.tpl
index 8414f5a7..d6fe6103 100644
--- a/Templates/Build/37_revive.tpl
+++ b/Templates/Build/37_revive.tpl
@@ -31,36 +31,102 @@
getUnitName($hero_datarow['unit']);
-
- if($hero_datarow['level'] <= 60){
- $wood = (${'h'.$hero_datarow['unit'].'_full'}[$hero_datarow['level']]['wood']);
- $clay = (${'h'.$hero_datarow['unit'].'_full'}[$hero_datarow['level']]['clay']);
- $iron = (${'h'.$hero_datarow['unit'].'_full'}[$hero_datarow['level']]['iron']);
- $crop = (${'h'.$hero_datarow['unit'].'_full'}[$hero_datarow['level']]['crop']);
- $timeToTrain = $database->getArtifactsValueInfluence($session->uid, $village->wid, 5, (${'h'.$hero_datarow['unit'].'_full'}[$hero_datarow['level']]['time']) / SPEED);
- $training_time = $generator->getTimeFormat($timeToTrain);
- $training_time2 = time() + $timeToTrain;
- }else{
- $wood = (${'h'.$hero_datarow['unit'].'_full'}[60]['wood']);
- $clay = (${'h'.$hero_datarow['unit'].'_full'}[60]['clay']);
- $iron = (${'h'.$hero_datarow['unit'].'_full'}[60]['iron']);
- $crop = (${'h'.$hero_datarow['unit'].'_full'}[60]['crop']);
- $timeToTrain = $database->getArtifactsValueInfluence($session->uid, $village->wid, 5, (${'h'.$hero_datarow['unit'].'_full'}[60]['time']) / SPEED);
- $training_time = $generator->getTimeFormat($timeToTrain);
- $training_time2 = time() + $timeToTrain;
- }
-
- if($hero_datarow['inrevive'] == 1) {
- $timeleft = $generator->getTimeFormat($hero_datarow['trainingtime'] - time());
- ?>
+// 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 = [
+ 1 => $h1_full ?? [],
+ 2 => $h2_full ?? [],
+ 3 => $h3_full ?? [],
+ 5 => $h5_full ?? [],
+ 6 => $h6_full ?? [],
+ 11 => $h11_full ?? [],
+ 12 => $h12_full ?? [],
+ 13 => $h13_full ?? [],
+ 15 => $h15_full ?? [],
+ 16 => $h16_full ?? [],
+ 21 => $h21_full ?? [],
+ 22 => $h22_full ?? [],
+ 24 => $h24_full ?? [],
+ 25 => $h25_full ?? [],
+ 26 => $h26_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 = "";
+ $html .= "";
+ $html .= "";
+ $html .= "  ";
+ $html .= $name . " (Level " . $hero_datarow['level'] . ")";
+ $html .= " ";
+ $html .= "";
+ $html .= "  " . $wood . "|";
+ $html .= "  " . $clay . "|";
+ $html .= "  " . $iron . "|";
+ $html .= "  " . $crop . "|";
+ $html .= "  6|";
+ $html .= "  ";
+ $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 .= "|  ";
+ }
+
+ $html .= " ";
+ $html .= " | ";
+
+ $html .= "";
+ if ($village->awood < $wood || $village->aclay < $clay || $village->airon < $iron || $village->acrop < $crop) {
+ $html .= "" . NOT . "" . ENOUGH_RESOURCES . "";
+ } else {
+ $html .= "" . REVIVE . "";
+ }
+ $html .= " | ";
+ $html .= "
";
+
+ 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());
+ ?>
@@ -70,6 +136,10 @@
|
@@ -80,95 +150,39 @@
|
-
-
-
-
- 
-
-
-
-  |
-  |
-  |
-  |
-  6|
- 
-
- userinfo['gold'] >= 3 && $building->getTypeLevel(17) >= 1 && $village->atotal >= $total_required) {
- echo "|  ";
- }
- ?>
-
- |
+ checkIfResearched($village->wid, 't' . $hero_datarow['unit']) != 0) {
+ echo $renderReviveRow($hero_datarow, $name, $wood, $clay, $iron, $crop, $training_time, $id);
+ }
+ }
+ }
-
- awood < $wood || $village->aclay < $clay || $village->airon < $iron || $village->acrop < $crop) {
- echo "".NOT."".ENOUGH_RESOURCES."";
- }else {
- echo "".REVIVE."";
- }
-
- ?> |
-
-
-
-
- checkIfResearched($village->wid, 't'.$hero_datarow['unit']) != 0){ ?>
-
-
-
- 
-
-
-
-  |
-  |
-  |
-  |
-  6|
- 
-
- userinfo['gold'] >= 3 && $building->getTypeLevel(17) >= 1 && $village->atotal >= $total_required) {
- echo "|  ";
- }
- ?>
-
- |
-
-
- awood < $wood || $village->aclay < $clay || $village->airon < $iron || $village->acrop < $crop) {
- echo "".NOT."".ENOUGH_RESOURCES."";
- }else {
- echo "".REVIVE."";
- }
-
- ?>
- |
-
- 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;
- }
- }
+ 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;
+ }
+}
?>
-
\ No newline at end of file
+
diff --git a/Templates/Build/37_train.tpl b/Templates/Build/37_train.tpl
index 5730c134..ac2fc4ba 100644
--- a/Templates/Build/37_train.tpl
+++ b/Templates/Build/37_train.tpl
@@ -19,658 +19,181 @@
## --------------------------------------------------------------------------- ##
#################################################################################
+// ============================================================================
+// REFACTOR - NOTE IMPORTANTE
+// ============================================================================
+// Two pre-existing bugs were found during the audit and are EXACTLY REPRODUCED
+// (not corrected), according to the rule of not changing logic:
+// 1) U3 (Imperian): in the original unfactored, the row did not close
+// - it was written as a string without "$output.=" in front,
+// so it was evaluated and thrown, with no effect. Replicated via the flag
+// 'skip_closing_tags' below.
+// 2) U13: the call $generator->getTimeFormat(...) for the training duration
+// was executed, but the result was never concatenated to $output -
+// the duration did not appear on that row at all. Replicated via the flag
+// 'skip_duration' below (the call is made identically, only the result
+// is no longer displayed).
+// If at some point you want to FIX these 2 bugs (not just keep them
+//), just delete the two entries in $bugOverrides below.
+// ============================================================================
+
//check if there is unit needed in the village
-$result = mysqli_query($database->dblink,"SELECT * FROM ".TB_PREFIX."units WHERE `vref` = ".(int) $village->wid."");
+$result = mysqli_query($database->dblink, "SELECT * FROM " . TB_PREFIX . "units WHERE `vref` = " . (int) $village->wid . "");
$units_array = mysqli_fetch_array($result);
-$count_hero = mysqli_fetch_array(mysqli_query($database->dblink,"SELECT Count(*) as Total FROM " . TB_PREFIX . "hero WHERE `uid` = " . $database->escape($session->uid) . ""), MYSQLI_ASSOC);
+$count_hero = mysqli_fetch_array(mysqli_query($database->dblink, "SELECT Count(*) as Total FROM " . TB_PREFIX . "hero WHERE `uid` = " . $database->escape($session->uid) . ""), MYSQLI_ASSOC);
$count_hero = $count_hero['Total'];
+// Explicit lookup instead of dynamic variables ${'u'.$unitID}. Variables
+// u1, u2, u3, u5, u6, u11... are defined elsewhere (just like in
+// the original that accessed them dynamically) - here we just put them in a single
+// array, without changing where the values come from. The "?? []" fallback is just
+// defensive (avoid notices), the original didn't have one and assumed that
+// the variables always exist.
+$unitData = [
+ 1 => $u1 ?? [],
+ 2 => $u2 ?? [],
+ 3 => $u3 ?? [],
+ 5 => $u5 ?? [],
+ 6 => $u6 ?? [],
+ 11 => $u11 ?? [],
+ 12 => $u12 ?? [],
+ 13 => $u13 ?? [],
+ 15 => $u15 ?? [],
+ 16 => $u16 ?? [],
+ 21 => $u21 ?? [],
+ 22 => $u22 ?? [],
+ 24 => $u24 ?? [],
+ 25 => $u25 ?? [],
+ 26 => $u26 ?? [],
+];
+
+// The single source of truth for "which units belong to each tribe", used
+// both when displaying the rows and when validating ?train=ID below (in
+// the original it was duplicated: once implicitly through the 3 if(tribe==X) blocks,
+// once explicitly in the switch in the validationArray).
+// The first ID in each list (1, 11, 21) is the base unit of the tribe -
+// it is always displayed, without research check, exactly as in the original.
+$tribeUnits = [
+ 1 => [1, 2, 3, 5, 6],
+ 2 => [11, 12, 13, 15, 16],
+ 3 => [21, 22, 24, 25, 26],
+];
+
+// The 2 pre-existing bugs, explicitly identified on the unit (see note above).
+$bugOverrides = [
+ 3 => ['skip_closing_tags' => true],
+ 13 => ['skip_duration' => true],
+];
+
+// Render a row from the hero training table for a unit.
+// Replace the 15 nearly identical blocks in the unfactored original.
+$renderTrainRow = function ($unitID, $unitData, $unitName, $units_array, $bugOptions = []) use ($database, $session, $village, $building, $generator, $id) {
+ $skipDuration = $bugOptions['skip_duration'] ?? false;
+ $skipClosingTags = $bugOptions['skip_closing_tags'] ?? false;
+
+ $data = $unitData[$unitID];
+
+ $row = "";
+ $row .= "";
+ $row .= "";
+ $row .= "  ";
+ $row .= $unitName;
+ $row .= " ";
+ $row .= "";
+ $row .= "  " . $data['wood'] . "|";
+ $row .= "  " . $data['clay'] . "|";
+ $row .= "  " . $data['iron'] . "|";
+ $row .= "  " . $data['crop'] . "|";
+ $row .= "  6|";
+ $row .= "  ";
+
+ // The call is always made (just like in the original, including for U13);
+ // only the display of the result is omitted for the pre-existing bug of U13.
+ $durationText = $generator->getTimeFormat($database->getArtifactsValueInfluence($session->uid, $village->wid, 5, $data['time'] / SPEED) * 3);
+ if (!$skipDuration) {
+ $row .= $durationText;
+ }
+
+ //-- If available resources combined are not enough, remove NPC button
+ $total_required = (int) ($data['wood'] + $data['clay'] + $data['iron'] + $data['crop']);
+ if ($session->userinfo['gold'] >= 3 && $building->getTypeLevel(17) >= 1 && $village->atotal >= $total_required) {
+ $row .= "|  ";
+ }
+
+ $row .= " ";
+ $row .= " | ";
+ $row .= "";
+
+ if ($village->awood < $data['wood'] || $village->aclay < $data['clay'] || $village->airon < $data['iron'] || $village->acrop < $data['crop']) {
+ $row .= "" . NOT . "" . ENOUGH_RESOURCES . "";
+ } elseif ($units_array['u' . $unitID] == 0) {
+ $row .= "" . NOT_UNITS . "";
+ } else {
+ $row .= "" . TRAIN . "";
+ }
+
+ // Pre-existing U3 bug: closing tags are no longer added.
+ if (!$skipClosingTags) {
+ $row .= " |
";
+ }
+
+ return $row;
+};
+
if ($count_hero < 3) {
-$output="
+ $output = "
- | ".TRAIN_HERO." |
+ " . TRAIN_HERO . " |
";
-if($session->tribe == 1) {
- $output.="
-
-
- 
- ".U1."
-
-
-  ".$u1['wood']."|
-  ".$u1['clay']."|
-  ".$u1['iron']."|
-  ".$u1['crop']."|
-  6|
-  ";
- $output .= $generator->getTimeFormat($database->getArtifactsValueInfluence($session->uid, $village->wid, 5,$u1['time'] / SPEED)*3);
-
- //-- If available resources combined are not enough, remove NPC button
- $total_required = (int)($u1['wood'] + $u1['clay'] + $u1['iron'] + $u1['crop']);
- if($session->userinfo['gold'] >= 3 && $building->getTypeLevel(17) >= 1 && $village->atotal >= $total_required) {
- $output .= "|  ";
- }
- $output.="
- |
-
- ";
-
-
- if($village->awood < $u1['wood'] || $village->aclay < $u1['clay'] || $village->airon < $u1['iron'] || $village->acrop < $u1['crop'])
- $output.="".NOT."".ENOUGH_RESOURCES."";
- elseif( $units_array['u1'] == 0)
- $output.="".NOT_UNITS."";
- else $output.="".TRAIN."";
-
-
- $output.=" |
-
";
-
-
-
- if($database->checkIfResearched($village->wid, 't2') != 0){
- $output.="
-
-
- 
- ".U2."
-
-
-  ".$u2['wood']."|
-  ".$u2['clay']."|
-  ".$u2['iron']."|
-  ".$u2['crop']."|
-  6|
-  ";
- $output.=$generator->getTimeFormat($database->getArtifactsValueInfluence($session->uid, $village->wid, 5, $u2['time'] / SPEED) * 3);
-
- //-- If available resources combined are not enough, remove NPC button
- $total_required = (int)($u2['wood'] + $u2['clay'] + $u2['iron'] + $u2['crop']);
- if($session->userinfo['gold'] >= 3 && $building->getTypeLevel(17) >= 1 && $village->atotal >= $total_required) {
- $output .= "|  ";
- }
-
- $output.="
- |
-
- ";
-
- if($village->awood < $u2['wood'] OR $village->aclay < $u2['clay'] OR $village->airon < $u2['iron'] OR $village->acrop < $u2['crop'])
- $output.="".NOT."".ENOUGH_RESOURCES."";
- elseif( $units_array['u2'] == 0)
- $output.="".NOT_UNITS."";
- else
- $output.="".TRAIN."";
-
- $output.=" |
-
";
- }
-
- if($database->checkIfResearched($village->wid, 't3') != 0){
-
- $output.="
-
-
- 
- ".U3."
-
-
-  ".$u3['wood']."|
-  ".$u3['clay']."|
-  ".$u3['iron']."|
-  ".$u3['crop']."|
-  6|
-  ";
-
- $output.= $generator->getTimeFormat($database->getArtifactsValueInfluence($session->uid, $village->wid, 5, $u3['time'] / SPEED) * 3);
-
- //-- If available resources combined are not enough, remove NPC button
- $total_required = (int)($u3['wood'] + $u3['clay'] + $u3['iron'] + $u3['crop']);
- if($session->userinfo['gold'] >= 3 && $building->getTypeLevel(17) >= 1 && $village->atotal >= $total_required) {
- $output .= "|  ";
- }
-
- $output.= "
- |
-
- ";
-
- if($village->awood < $u3['wood'] OR $village->aclay < $u3['clay'] OR $village->airon < $u3['iron'] OR $village->acrop < $u3['crop']) {
- $output.="".NOT."".ENOUGH_RESOURCES."";
- }else if( $units_array['u3'] == 0){
- $output.="".NOT_UNITS."";
- }else {
- $output.="".TRAIN."";
- }
- " |
-
" ;
- }
-
- if($database->checkIfResearched($village->wid, 't5') != 0){
- $output.= "
-
-
- 
- ".U5."
-
-
-  ".$u5['wood']."|
-  ".$u5['clay']."|
-  ".$u5['iron']."|
-  ".$u5['crop']."|
-  6|
-  ".
- $generator->getTimeFormat($database->getArtifactsValueInfluence($session->uid, $village->wid, 5, $u5['time'] / SPEED) * 3);
-
- //-- If available resources combined are not enough, remove NPC button
- $total_required = (int)($u5['wood'] + $u5['clay'] + $u5['iron'] + $u5['crop']);
- if($session->userinfo['gold'] >= 3 && $building->getTypeLevel(17) >= 1 && $village->atotal >= $total_required) {
- $output .= "|  ";
- }
-
- $output .= "
-
- |
-
- ";
-
- if($village->awood < $u5['wood'] OR $village->aclay < $u5['clay'] OR $village->airon < $u5['iron'] OR $village->acrop < $u5['crop']) {
- $output.= "".NOT."".ENOUGH_RESOURCES."";
- }else if( $units_array['u5'] == 0){
- $output.= "".NOT_UNITS."";
- }else {
- $output.= "".TRAIN."";
- }
- $output.=" |
-
";
- }
-
- if($database->checkIfResearched($village->wid, 't6') != 0){
- $output.="
-
-
- 
- ".U6."
-
-
-  ".$u6['wood']."|
-  ".$u6['clay']."|
-  ".$u6['iron']."|
-  ".$u6['crop']."|
-  6|
-  ".
- $generator->getTimeFormat($database->getArtifactsValueInfluence($session->uid, $village->wid, 5, $u6['time'] / SPEED) * 3);
-
- //-- If available resources combined are not enough, remove NPC button
- $total_required = (int)($u6['wood'] + $u6['clay'] + $u6['iron'] + $u6['crop']);
- if($session->userinfo['gold'] >= 3 && $building->getTypeLevel(17) >= 1 && $village->atotal >= $total_required) {
- $output .= "|  ";
- }
-
- $output .= "
-
- |
-
- ";
-
- if($village->awood < $u6['wood'] OR $village->aclay < $u6['clay'] OR $village->airon < $u6['iron'] OR $village->acrop < $u6['crop']) {
- $output.= "".NOT."".ENOUGH_RESOURCES."";
- }else if( $units_array['u6'] == 0){
- $output.= "".NOT_UNITS."";
- }else {
- $output.= "".TRAIN."";
- }
-
- $output.=" |
-
";
- }
-}
-
-if($session->tribe == 2) {
-
-$output.="
-
-
- 
- ".U11."
-
-
-  ".$u11['wood']."|
-  ".$u11['clay']."|
-  ".$u11['iron']."|
-  ".$u11['crop']."|
-  6|
-  ".
- $generator->getTimeFormat($database->getArtifactsValueInfluence($session->uid, $village->wid, 5, $u11['time'] / SPEED) * 3);
-
- //-- If available resources combined are not enough, remove NPC button
- $total_required = (int)($u11['wood'] + $u11['clay'] + $u11['iron'] + $u11['crop']);
- if($session->userinfo['gold'] >= 3 && $building->getTypeLevel(17) >= 1 && $village->atotal >= $total_required) {
- $output .= "|  ";
- }
-
- $output .= "
-
- |
-
- ";
-
- if($village->awood < $u11['wood'] OR $village->aclay < $u11['clay'] OR $village->airon < $u11['iron'] OR $village->acrop < $u11['crop']) {
- $output.= "".NOT."".ENOUGH_RESOURCES."";
- }else if( $units_array['u11'] == 0){
- $output.= "".NOT_UNITS."";
- }else {
- $output.= "".TRAIN."";
- }
- $output.=" |
-
";
-
-
- if($database->checkIfResearched($village->wid, 't12') != 0){
- $output.="
-
-
- 
- ".U12."
-
-
-  ".$u12['wood']."|
-  ".$u12['clay']."|
-  ".$u12['iron']."|
-  ".$u12['crop']."|
-  6|
-  ".
- $generator->getTimeFormat($database->getArtifactsValueInfluence($session->uid, $village->wid, 5, $u12['time'] / SPEED) * 3);
-
- //-- If available resources combined are not enough, remove NPC button
- $total_required = (int)($u12['wood'] + $u12['clay'] + $u12['iron'] + $u12['crop']);
- if($session->userinfo['gold'] >= 3 && $building->getTypeLevel(17) >= 1 && $village->atotal >= $total_required) {
- $output .= "|  ";
- }
-
- $output .= "
-
- |
-
- ";
-
- if($village->awood < $u12['wood'] OR $village->aclay < $u12['clay'] OR $village->airon < $u12['iron'] OR $village->acrop < $u12['crop']) {
- $output.= "".NOT."".ENOUGH_RESOURCES."";
- }else if( $units_array['u12'] == 0){
- $output.= "".NOT_UNITS."";
- }else {
- $output.= "".TRAIN."";
- }
- $output.=" |
-
";
- }
-
-
- if($database->checkIfResearched($village->wid, 't13') != 0){
- $output.="
-
-
- 
- ".U13."
-
-
-  ".$u13['wood']."|
-  ".$u13['clay']."|
-  ".$u13['iron']."|
-  ".$u13['crop']."|
-  6|
-  ";
-
- $generator->getTimeFormat($database->getArtifactsValueInfluence($session->uid, $village->wid, 5, $u13['time'] / SPEED) * 3);
-
- //-- If available resources combined are not enough, remove NPC button
- $total_required = (int)($u13['wood'] + $u13['clay'] + $u13['iron'] + $u13['crop']);
- if($session->userinfo['gold'] >= 3 && $building->getTypeLevel(17) >= 1 && $village->atotal >= $total_required) {
- $output .= "|  ";
- }
-
- $output .= "
-
- |
-
- ";
-
- if($village->awood < $u13['wood'] OR $village->aclay < $u13['clay'] OR $village->airon < $u13['iron'] OR $village->acrop < $u13['crop']) {
- $output.= "".NOT."".ENOUGH_RESOURCES."";
- }else if( $units_array['u13'] == 0){
- $output.= "".NOT_UNITS."";
- }else {
- $output.= "".TRAIN."";
- }
- $output.=" |
-
";
- }
-
- if($database->checkIfResearched($village->wid, 't15') != 0){
- $output.="
-
-
- 
- ".U15."
-
-
-  ".$u15['wood']."|
-  ".$u15['clay']."|
-  ".$u15['iron']."|
-  ".$u15['crop']."|
-  6|
-  ".
- $generator->getTimeFormat($database->getArtifactsValueInfluence($session->uid, $village->wid, 5, $u15['time'] / SPEED) * 3);
-
- //-- If available resources combined are not enough, remove NPC button
- $total_required = (int)($u15['wood'] + $u15['clay'] + $u15['iron'] + $u15['crop']);
- if($session->userinfo['gold'] >= 3 && $building->getTypeLevel(17) >= 1 && $village->atotal >= $total_required) {
- $output .= "|  ";
- }
-
- $output .= "
-
- |
-
- ";
-
- if($village->awood < $u15['wood'] OR $village->aclay < $u15['clay'] OR $village->airon < $u15['iron'] OR $village->acrop < $u15['crop']) {
- $output.= "".NOT."".ENOUGH_RESOURCES."";
- }else if( $units_array['u15'] == 0){
- $output.= "".NOT_UNITS."";
- }else {
- $output.= "".TRAIN."";
- }
- $output.=" |
-
";
- }
-
-
- if($database->checkIfResearched($village->wid, 't16') != 0){
- $output.="
-
-
- 
- ".U16."
-
-
-  ".$u16['wood']."|
-  ".$u16['clay']."|
-  ".$u16['iron']."|
-  ".$u16['crop']."|
-  6|
-  ".
- $generator->getTimeFormat($database->getArtifactsValueInfluence($session->uid, $village->wid, 5, $u16['time'] / SPEED) * 3);
-
- //-- If available resources combined are not enough, remove NPC button
- $total_required = (int)($u16['wood'] + $u16['clay'] + $u16['iron'] + $u16['crop']);
- if($session->userinfo['gold'] >= 3 && $building->getTypeLevel(17) >= 1 && $village->atotal >= $total_required) {
- $output .= "|  ";
- }
-
- $output .= "
-
- |
-
- ";
-
- if($village->awood < $u16['wood'] OR $village->aclay < $u16['clay'] OR $village->airon < $u16['iron'] OR $village->acrop < $u16['crop']) {
- $output.= "".NOT."".ENOUGH_RESOURCES."";
- }else if( $units_array['u16'] == 0){
- $output.= "".NOT_UNITS."";
- }else {
- $output.= "".TRAIN."";
- }
- $output.=" |
-
";
- }
-}
-
-
-if($session->tribe == 3) {
-
-$output.="
-
-
- 
- ".U21."
-
-
-  ".$u21['wood']."|
-  ".$u21['clay']."|
-  ".$u21['iron']."|
-  ".$u21['crop']."|
-  6|
-  ".
- $generator->getTimeFormat($database->getArtifactsValueInfluence($session->uid, $village->wid, 5, $u21['time'] / SPEED) * 3);
-
- //-- If available resources combined are not enough, remove NPC button
- $total_required = (int)($u21['wood'] + $u21['clay'] + $u21['iron'] + $u21['crop']);
- if($session->userinfo['gold'] >= 3 && $building->getTypeLevel(17) >= 1 && $village->atotal >= $total_required) {
- $output .= "|  ";
- }
-
- $output .= "
-
- |
-
- ";
-
- if($village->awood < $u21['wood'] OR $village->aclay < $u21['clay'] OR $village->airon < $u21['iron'] OR $village->acrop < $u21['crop']) {
- $output.= "".NOT."".ENOUGH_RESOURCES."";
- }else if( $units_array['u21'] == 0){
- $output.= "".NOT_UNITS."";
- }else {
- $output.= "".TRAIN."";
- }
- $output.=" |
-
";
-
-
- if($database->checkIfResearched($village->wid, 't22') != 0){
- $output.="
-
-
- 
- ".U22."
-
-
-  ".$u22['wood']."|
-  ".$u22['clay']."|
-  ".$u22['iron']."|
-  ".$u22['crop']."|
-  6|
-  ".
- $generator->getTimeFormat($database->getArtifactsValueInfluence($session->uid, $village->wid, 5, $u22['time'] / SPEED) * 3);
-
- //-- If available resources combined are not enough, remove NPC button
- $total_required = (int)($u22['wood'] + $u22['clay'] + $u22['iron'] + $u22['crop']);
- if($session->userinfo['gold'] >= 3 && $building->getTypeLevel(17) >= 1 && $village->atotal >= $total_required) {
- $output .= "|  ";
- }
-
- $output .= "
-
- |
-
- ";
-
- if($village->awood < $u22['wood'] OR $village->aclay < $u22['clay'] OR $village->airon < $u22['iron'] OR $village->acrop < $u22['crop']) {
- $output.= "".NOT."".ENOUGH_RESOURCES."";
- }else if( $units_array['u22'] == 0){
- $output.= "".NOT_UNITS."";
- }else {
- $output.= "".TRAIN."";
- }
- $output.=" |
-
";
- }
-
-
- if($database->checkIfResearched($village->wid, 't24') != 0){
- $output.="
-
-
- 
- ".U24."
-
-
-  ".$u24['wood']."|
-  ".$u24['clay']."|
-  ".$u24['iron']."|
-  ".$u24['crop']."|
-  6|
-  ".
- $generator->getTimeFormat($database->getArtifactsValueInfluence($session->uid, $village->wid, 5, $u24['time'] / SPEED) * 3);
-
- //-- If available resources combined are not enough, remove NPC button
- $total_required = (int)($u24['wood'] + $u24['clay'] + $u24['iron'] + $u24['crop']);
- if($session->userinfo['gold'] >= 3 && $building->getTypeLevel(17) >= 1 && $village->atotal >= $total_required) {
- $output .= "|  ";
- }
-
- $output .= "
-
- |
-
- ";
-
- if($village->awood < $u24['wood'] OR $village->aclay < $u24['clay'] OR $village->airon < $u24['iron'] OR $village->acrop < $u24['crop']) {
- $output.= "".NOT."".ENOUGH_RESOURCES."";
- }else if( $units_array['u24'] == 0){
- $output.= "".NOT_UNITS."";
- }else {
- $output.= "".TRAIN."";
- }
- $output.=" |
-
";
- }
-
- if($database->checkIfResearched($village->wid, 't25') != 0){
- $output.="
-
-
- 
- ".U25."
-
-
-  ".$u25['wood']."|
-  ".$u25['clay']."|
-  ".$u25['iron']."|
-  ".$u25['crop']."|
-  6|
-  ".
- $generator->getTimeFormat($database->getArtifactsValueInfluence($session->uid, $village->wid, 5, $u25['time'] / SPEED) * 3);
-
- //-- If available resources combined are not enough, remove NPC button
- $total_required = (int)($u25['wood'] + $u25['clay'] + $u25['iron'] + $u25['crop']);
- if($session->userinfo['gold'] >= 3 && $building->getTypeLevel(17) >= 1 && $village->atotal >= $total_required) {
- $output .= "|  ";
- }
-
- $output .= "
-
- |
-
- ";
-
- if($village->awood < $u25['wood'] OR $village->aclay < $u25['clay'] OR $village->airon < $u25['iron'] OR $village->acrop < $u25['crop']) {
- $output.= "".NOT."".ENOUGH_RESOURCES."";
- }else if( $units_array['u25'] == 0){
- $output.= "".NOT_UNITS."";
- }else {
- $output.= "".TRAIN."";
- }
- $output.=" |
-
";
- }
-
-
- if($database->checkIfResearched($village->wid, 't26') != 0){
- $output.="
-
-
- 
- ".U26."
-
-
-  ".$u26['wood']."|
-  ".$u26['clay']."|
-  ".$u26['iron']."|
-  ".$u26['crop']."|
-  6|
-  ".
- $generator->getTimeFormat($database->getArtifactsValueInfluence($session->uid, $village->wid, 5, $u26['time'] / SPEED) * 3);
-
- //-- If available resources combined are not enough, remove NPC button
- $total_required = (int)($u26['wood'] + $u26['clay'] + $u26['iron'] + $u26['crop']);
- if($session->userinfo['gold'] >= 3 && $building->getTypeLevel(17) >= 1 && $village->atotal >= $total_required) {
- $output .= "|  ";
- }
-
- $output .= "
-
- |
-
- ";
-
- if($village->awood < $u26['wood'] OR $village->aclay < $u26['clay'] OR $village->airon < $u26['iron'] OR $village->acrop < $u26['crop']) {
- $output.= "".NOT."".ENOUGH_RESOURCES."";
- }else if( $units_array['u26'] == 0){
- $output.= "".NOT_UNITS."";
- }else {
- $output.= "".TRAIN."";
- }
- $output.=" |
-
";
- }
-}
-
-
-
- //HERO TRAINING
- if (isset($_GET['train'])) {
- $validationArray = [];
- switch ($session->tribe) {
- case 1: $validationArray = [1, 2, 3, 5, 6];
- break;
-
- case 2: $validationArray = [11, 12, 13, 15, 16];
- break;
-
- case 3: $validationArray = [21, 22, 24, 25, 26];
- break;
- }
-
- // check for a valid unit value
- if (in_array($_GET['train'], $validationArray)) {
- if($count_hero < 3){
- $unitID = $_GET['train'];
- mysqli_query($database->dblink,"INSERT INTO ".TB_PREFIX."hero (`uid`, `wref`, `regeneration`, `unit`, `name`, `level`, `points`, `experience`, `dead`, `health`, `attack`, `defence`, `attackbonus`, `defencebonus`, `trainingtime`, `autoregen`, `intraining`) VALUES (".$database->escape($session->uid).", " . (int) $village->wid . ", 0, ".$unitID.", '".$database->escape($session->username)."', 0, 5, 0, 0, 100, 0, 0, 0, 0, ".round((time() + (${'u'.$unitID}['time'] / SPEED)*3)).", 50, 1)");
- mysqli_query($database->dblink,"UPDATE " . TB_PREFIX . "units SET `u$unitID` = `u$unitID` - 1 WHERE `vref` = " . (int) $village->wid);
- mysqli_query($database->dblink,"
+ if (isset($tribeUnits[$session->tribe])) {
+ foreach ($tribeUnits[$session->tribe] as $index => $unitID) {
+ $isBaseUnit = ($index === 0); // u1 / u11 / u21: mereu afisat, fara research check
+ $unitName = constant('U' . $unitID);
+ $bugOptions = $bugOverrides[$unitID] ?? [];
+
+ if ($isBaseUnit || $database->checkIfResearched($village->wid, 't' . $unitID) != 0) {
+ $output .= $renderTrainRow($unitID, $unitData, $unitName, $units_array, $bugOptions);
+ }
+ }
+ }
+
+ //HERO TRAINING
+ if (isset($_GET['train'])) {
+ $validationArray = $tribeUnits[$session->tribe] ?? [];
+
+ // check for a valid unit value
+ if (in_array($_GET['train'], $validationArray)) {
+ if ($count_hero < 3) {
+ $unitID = $_GET['train'];
+ mysqli_query($database->dblink, "INSERT INTO " . TB_PREFIX . "hero (`uid`, `wref`, `regeneration`, `unit`, `name`, `level`, `points`, `experience`, `dead`, `health`, `attack`, `defence`, `attackbonus`, `defencebonus`, `trainingtime`, `autoregen`, `intraining`) VALUES (" . $database->escape($session->uid) . ", " . (int) $village->wid . ", 0, " . $unitID . ", '" . $database->escape($session->username) . "', 0, 5, 0, 0, 100, 0, 0, 0, 0, " . round((time() + ($unitData[$unitID]['time'] / SPEED) * 3)) . ", 50, 1)");
+ mysqli_query($database->dblink, "UPDATE " . TB_PREFIX . "units SET `u$unitID` = `u$unitID` - 1 WHERE `vref` = " . (int) $village->wid);
+ mysqli_query($database->dblink, "
UPDATE " . TB_PREFIX . "vdata
SET
- `wood` = `wood` - ".(int) ${'u'.$unitID}['wood'].",
- `clay` = `clay` - ".(int) ${'u'.$unitID}['clay'].",
- `iron` = `iron` - ".(int) ${'u'.$unitID}['iron'].",
- `crop` = `crop` - ".(int) ${'u'.$unitID}['crop']."
+ `wood` = `wood` - " . (int) $unitData[$unitID]['wood'] . ",
+ `clay` = `clay` - " . (int) $unitData[$unitID]['clay'] . ",
+ `iron` = `iron` - " . (int) $unitData[$unitID]['iron'] . ",
+ `crop` = `crop` - " . (int) $unitData[$unitID]['crop'] . "
WHERE
`wref` = " . (int) $village->wid);
- }
- header("Location: build.php?id=".$id."");
- exit;
- }
- }
+ }
+ header("Location: build.php?id=" . $id . "");
+ exit;
+ }
+ }
- echo $output;
+ echo $output;
}
+// NOTE (pre-existing behavior, kept unchanged): if $count_hero >= 3,
+// $output is no longer created and no longer echoed - but the
below
+// is outside this if and is displayed unconditionally. In that case the file
+// generates an "orphan"
, without a corresponding . This was also the case in
+// the original file.
?>
-
\ No newline at end of file
+
diff --git a/warsim.php b/warsim.php
index 8ea38839..a677c45a 100644
--- a/warsim.php
+++ b/warsim.php
@@ -5,14 +5,21 @@ $start_timer = $generator->pageLoadTimeStart();
#################################################################################
## -= YOU MAY NOT REMOVE OR CHANGE THIS NOTICE =- ##
## --------------------------------------------------------------------------- ##
-## Project: TravianZ ##
-## Filename warsim.php ##
-## Developed by: Dzoki ##
-## License: TravianZ Project ##
-## Copyright: TravianZ (c) 2010-2026. All rights reserved. ##
-## URLs: http://travian.shadowss.ro ##
-## Source code: https://github.com/Shadowss/TravianZ ##
-## ##
+## Filename : warsim.php ##
+## Type : Attack Simulator File ##
+## --------------------------------------------------------------------------- ##
+## Developed by : Dzoki (Original) ##
+## Refactored by : Shadow ##
+## Redesign by : Shadow ##
+## --------------------------------------------------------------------------- ##
+## Contact : cata7007@gmail.com ##
+## Project : TravianZ ##
+## URLs: : https://travianz.org ##
+## GitHub : https://github.com/Shadowss/TravianZ ##
+## --------------------------------------------------------------------------- ##
+## License : TravianZ Project ##
+## Copyright : TravianZ (c) 2010-2026. All rights reserved. ##
+## --------------------------------------------------------------------------- ##
#################################################################################
use App\Utils\AccessLogger;
@@ -70,37 +77,37 @@ $battle->procSim($_POST);
if(isset($_POST['result'])) {
$target = isset($_POST['target'])? $_POST['target'] : array();
$tribe = isset($_POST['mytribe'])? $_POST['mytribe'] : $session->tribe;
- include("Templates/Simulator/res_a".$tribe.".tpl");
+ include("Templates/Simulator/res_a".(int)$tribe.".tpl");
foreach($target as $tar) {
- include("Templates/Simulator/res_d".$tar.".tpl");
+ include("Templates/Simulator/res_d".(int)$tar.".tpl");
}
echo "Type of attack: ";
echo $form->getValue('ktyp') == 0 ? "Normal" : "Raid";
echo "
";
echo "";
- if (isset($_POST['result'][7]) && isset($_POST['result'][8])){
- if ($form->getValue('ktyp') == 1) {
- echo "Hint: The ram does not work during a raid.
";
- }elseif ($_POST['result'][7] == 0){
- echo "Damage done by ram: from level ".$form->getValue('walllevel')." to level 0
";
- }elseif ($_POST['result'][7] == $_POST['result'][8]){
- echo "Damage done by ram: from level ".$form->getValue('walllevel')." to level ".$form->getValue('walllevel')."
";
- }else{
- echo "Damage done by ram: from level ".$form->getValue('walllevel')." to level ".$_POST['result'][7]."";
- }
- }
+ if (isset($_POST['result'][7]) && isset($_POST['result'][8])){
+ if ($form->getValue('ktyp') == 1) {
+ echo "Hint: The ram does not work during a raid.
";
+ }elseif ($_POST['result'][7] == 0){
+ echo "Damage done by ram: from level ".$form->getValue('walllevel')." to level 0";
+ }elseif ($_POST['result'][7] == $_POST['result'][8]){
+ echo "Damage done by ram: from level ".$form->getValue('walllevel')." to level ".$form->getValue('walllevel')."";
+ }else{
+ echo "Damage done by ram: from level ".$form->getValue('walllevel')." to level ".(int)$_POST['result'][7]."";
+ }
+ }
- if (isset($_POST['result'][3]) && isset($_POST['result'][4])){
- if ($form->getValue('ktyp') == 1) {
- echo "Hint: The catapult does not shoot during a raid.";
- }elseif ($_POST['result'][3] == 0){
- echo "Damage done by catapult: from level ".$form->getValue('kata')." to level 0";
- }elseif ($_POST['result'][3] == $_POST['result'][4]){
- echo "Damage done by catapult: from level ".$form->getValue('kata')." to level ".$form->getValue('kata')."";
- }else{
- echo "Damage done by catapult: from level ".$form->getValue('kata')." to level ".$_POST['result'][3]."";
- }
- }
+ if (isset($_POST['result'][3]) && isset($_POST['result'][4])){
+ if ($form->getValue('ktyp') == 1) {
+ echo "Hint: The catapult does not shoot during a raid.";
+ }elseif ($_POST['result'][3] == 0){
+ echo "Damage done by catapult: from level ".$form->getValue('kata')." to level 0";
+ }elseif ($_POST['result'][3] == $_POST['result'][4]){
+ echo "Damage done by catapult: from level ".$form->getValue('kata')." to level ".$form->getValue('kata')."";
+ }else{
+ echo "Damage done by catapult: from level ".$form->getValue('kata')." to level ".(int)$_POST['result'][3]."";
+ }
+ }
}
if (!empty($_GET['target'])) {
@@ -122,7 +129,7 @@ if (!empty($_GET['target'])) {
$target = isset($_POST['target'])? $_POST['target'] : (!empty($_GET['target']) ? array((int) $_GET['target']) : array());
$tribe = isset($_POST['mytribe'])? $_POST['mytribe'] : $session->tribe;
if(count($target) > 0) {
- include("Templates/Simulator/att_".preg_replace("/[^a-zA-Z0-9_-]/","",$tribe).".tpl");
+ include("Templates/Simulator/att_".(int)$tribe.".tpl");
echo "
@@ -133,7 +140,7 @@ if(count($target) > 0) {
";
foreach($target as $tar) {
- include("Templates/Simulator/def_".$tar.".tpl");
+ include("Templates/Simulator/def_".(int)$tar.".tpl");
}
include("Templates/Simulator/def_end.tpl");
echo "";