From f99ab72d25e94948af9e1ae2dc5499a869130763 Mon Sep 17 00:00:00 2001
From: Catalin Novgorodschi <1140613+Shadowss@users.noreply.github.com>
Date: Wed, 13 May 2026 15:09:05 +0300
Subject: [PATCH] Incremental Refactor Form/BBCode/Mailer/Village
Incremental Refactor Form/BBCode/Mailer/Village
---
GameEngine/BBCode.php | 400 +++++++++++++++++----------------------
GameEngine/Chat.php | 6 +-
GameEngine/Form.php | 6 +-
GameEngine/Mailer.php | 143 +++++++-------
GameEngine/Village.php | 386 +++++++++++++++++++------------------
GameEngine/functions.php | 114 ++++++++---
6 files changed, 555 insertions(+), 500 deletions(-)
diff --git a/GameEngine/BBCode.php b/GameEngine/BBCode.php
index 822ffe17..8a5a6094 100755
--- a/GameEngine/BBCode.php
+++ b/GameEngine/BBCode.php
@@ -1,255 +1,205 @@
-$1";
-$replace[1] = "$1";
-$replace[2] = "$1";
-$replace[3] = "
";
-$replace[4] = "
";
-$replace[5] = "
";
-$replace[6] = "
";
-$replace[7] = "
";
-$replace[8] = "
";
-$replace[9] = "
";
-$replace[10] = "
";
-$replace[11] = "
";
-$replace[12] = "
";
-$replace[13] = "
";
-$replace[14] = "
";
-$replace[15] = "
";
-$replace[16] = "
";
-$replace[17] = "
";
-$replace[18] = "
";
-$replace[19] = "
";
-$replace[20] = "
";
-$replace[21] = "
";
-$replace[22] = "
";
-$replace[23] = "
";
-$replace[24] = "
";
-$replace[25] = "
";
-$replace[26] = "
";
-$replace[27] = "
";
-$replace[28] = "
";
-$replace[29] = "
";
-$replace[30] = "
";
-$replace[31] = "
";
-$replace[32] = "
";
-$replace[33] = "
";
-$replace[34] = "
";
-$replace[35] = "
";
-$replace[36] = "
";
-$replace[37] = "
";
-$replace[38] = "
";
-$replace[39] = "
";
-$replace[40] = "
";
-$replace[41] = "
";
-$replace[42] = "
";
-$replace[43] = "
";
-$replace[44] = "
";
-$replace[45] = "
";
-$replace[46] = "
";
-$replace[47] = "
";
-$replace[48] = "
";
-$replace[49] = "
";
-$replace[50] = "
";
-$replace[51] = "
";
-$replace[52] = "
";
-$replace[53] = "
";
-$replace[54] = "
";
-$replace[55] = "
";
-$replace[56] = "
";
-$replace[57] = "
";
-$replace[54] = "
";
-$replace[55] = "
";
-$replace[56] = "
";
-$replace[57] = "
";
-$replace[58] = "
";
-$replace[59] = "
";
-$replace[60] = "
";
-$replace[61] = "
";
-$replace[62] = "
";
-$replace[63] = "
";
-$replace[64] = "
";
-$replace[65] = "
";
-$replace[66] = "
";
-$replace[67] = "
";
-$replace[68] = "
";
-$replace[69] = "
";
-$replace[70] = "
";
-$replace[71] = "
";
-$replace[72] = "
";
-$replace[73] = "
";
-$replace[74] = "
";
-$replace[75] = "
";
-$replace[76] = "";
-$replace[77] = "
";
-$replace[78] = "
";
-$replace[79] = "
";
-$replace[80] = "
";
-$replace[81] = "
";
-$replace[82] = "
";
-$replace[83] = "
";
-$replace[84] = "
";
-$replace[85] = "
";
-$replace[86] = "
";
-$replace[87] = "
";
-$replace[88] = "
";
-// replace alliance placeholders
-$input = preg_replace_callback(
+/* Basic BBCode */
+$pattern[] = "/\[b\](.*?)\[\/b\]/is";
+$replace[] = "$1";
+
+$pattern[] = "/\[i\](.*?)\[\/i\]/is";
+$replace[] = "$1";
+
+$pattern[] = "/\[u\](.*?)\[\/u\]/is";
+$replace[] = "$1";
+
+/* Unit placeholders tid1 - tid50 */
+for ($i = 1; $i <= 50; $i++) {
+ $pattern[] = "/\[tid{$i}\]/";
+ $replace[] = "
";
+}
+
+/* Hero */
+$pattern[] = "/\[hero\]/";
+$replace[] = "
";
+
+/* Resources */
+$resourceMap = [
+ 'lumber' => [1, LUMBER],
+ 'clay' => [2, CLAY],
+ 'iron' => [3, IRON],
+ 'crop' => [4, CROP],
+];
+
+foreach ($resourceMap as $tag => $data) {
+ [$id, $name] = $data;
+
+ $pattern[] = "/\[" . $tag . "\]/";
+ $replace[] = "
";
+}
+
+/* Smilies & emoticons */
+$smilies = [
+ "/\*aha\*/" => "
",
+ "/\*angry\*/" => "
",
+ "/\*cool\*/" => "
",
+ "/\*cry\*/" => "
",
+ "/\*cute\*/" => "
",
+ "/\*depressed\*/" => "
",
+ "/\*eek\*/" => "
",
+ "/\*ehem\*/" => "
",
+ "/\*emotional\*/" => "
",
+ "/:D/" => "
",
+ "/:\)/" => "
",
+ "/\*hit\*/" => "
",
+ "/\*hmm\*/" => "
",
+ "/\*hmpf\*/" => "
",
+ "/\*hrhr\*/" => "
",
+ "/\*huh\*/" => "
",
+ "/\*lazy\*/" => "
",
+ "/\*love\*/" => "
",
+ "/\*nocomment\*/" => "",
+ "/\*noemotion\*/" => "
",
+ "/\*notamused\*/" => "
",
+ "/\*pout\*/" => "
",
+ "/\*redface\*/" => "
",
+ "/\*rolleyes\*/" => "
",
+ "/:\(/" => "
",
+ "/\*shy\*/" => "
",
+ "/\*smile\*/" => "
",
+ "/\*tongue\*/" => "
",
+ "/\*veryangry\*/" => "
",
+ "/\*veryhappy\*/" => "
",
+ "/;\)/" => "
",
+];
+
+foreach ($smilies as $k => $v) {
+ $pattern[] = $k;
+ $replace[] = $v;
+}
+
+/* Message cleanup */
+$input = preg_replace('/\[message\]/', '', $input);
+$input = preg_replace('/\[\/message\]/', '', $input);
+
+/* Apply BBCode/static replacements */
+$bbcoded = preg_replace($pattern, $replace, $input);
+
+/**
+ * -------------------------------------------------------------------------
+ * CALLBACK REPLACEMENTS (dynamic database-driven content)
+ * -------------------------------------------------------------------------
+ */
+
+/* Alliance */
+$bbcoded = preg_replace_callback(
"/\[alliance(\d{0,20})\]([^\]]*)\[\/alliance\d{0,20}\]/is",
- function($matches) {
+ function ($matches) {
global $database;
$aname = $database->getAllianceName($matches[2]);
- if (!empty($aname)) return "".$aname."";
- else return "Alliance not found!";
+ if (!empty($aname)) {
+ return "{$aname}";
+ }
+ return "Alliance not found!";
},
- $input);
+ $bbcoded
+);
-// replace player placeholders
-$input = preg_replace_callback(
+/* Player */
+$bbcoded = preg_replace_callback(
"/\[player(\d{0,20})\]([^\]]*)\[\/player\d{0,20}\]/is",
- function($matches) {
+ function ($matches) {
global $database;
-
- $uname = $database->getUserField((int) $matches[2], "username", 0);
- if (!empty($uname) && $uname != "[?]") return "".$uname."";
- else return "Player not found!";
- },
- $input);
-// replace report placeholders
-$input = preg_replace_callback(
+ $uname = $database->getUserField((int)$matches[2], "username", 0);
+ if (!empty($uname) && $uname !== "[?]") {
+ return "{$uname}";
+ }
+ return "Player not found!";
+ },
+ $bbcoded
+);
+
+/* Report */
+$bbcoded = preg_replace_callback(
"/\[report(\d{0,20})\]([^\]]*)\[\/report\d{0,20}\]/is",
- function($matches) {
+ function ($matches) {
global $database;
-
+
$reportID = $matches[1] > 0 ? $matches[1] : $matches[2];
- $report = $database->getNotice2((int) $reportID, null, false);
+ $report = $database->getNotice2((int)$reportID, null, false);
- if (!empty($report)) return "".$report['topic']."";
- else return "Report not found!";
+ if (!empty($report)) {
+ return "{$report['topic']}";
+ }
+ return "Report not found!";
},
- $input);
+ $bbcoded
+);
-// replace coordinate placeholders
-$input = preg_replace_callback(
+/* Coordinates */
+$bbcoded = preg_replace_callback(
"/\[coor(\d{0,20})\]([^\]]*)\[\/coor\d{0,20}\]/is",
- function($matches) {
+ function ($matches) {
global $generator, $database;
-
- $name = "";
+
$coordinates = explode("|", $matches[2]);
$wRef = $database->getVilWref($coordinates[0], $coordinates[1]);
$cwref = $generator->getMapCheck($wRef);
+
$state = $database->getVillageType($wRef);
- if($state > 0){
- if($database->getVillageState($wRef)) $name = $database->getVillageField($wRef, 'name');
- else $name = ABANDVALLEY;
+
+ if ($state > 0) {
+ $name = $database->getVillageState($wRef)
+ ? $database->getVillageField($wRef, 'name')
+ : ABANDVALLEY;
+ } else {
+ $name = $database->getOasisInfo($wRef)['name'] ?? '';
}
- else $name = $database->getOasisInfo($wRef)['name'];
-
- if(!empty($name)) return "".$name." (".$coordinates[0]."|".$coordinates[1].")"."";
+
+ if (!empty($name)) {
+ return "{$name} ({$coordinates[0]}|{$coordinates[1]})";
+ }
+
return "Village not found!";
},
- $input);
+ $bbcoded
+);
-$input = preg_replace('/\[message\]/', '', $input);
-$input = preg_replace('/\[\/message\]/', '', $input);
-$bbcoded = preg_replace($pattern, $replace, $input);
-?>
+/* Final cleanup safety */
+$bbcoded = preg_replace('/\[message\]/', '', $bbcoded);
+$bbcoded = preg_replace('/\[\/message\]/', '', $bbcoded);
+
+?>
\ No newline at end of file
diff --git a/GameEngine/Chat.php b/GameEngine/Chat.php
index b71624c5..e82c80b2 100755
--- a/GameEngine/Chat.php
+++ b/GameEngine/Chat.php
@@ -1,11 +1,15 @@
fallback safe value added
+ */
+ function sendInvite($email, $uid, $text)
+ {
+ $subject = SERVER_NAME . " registration";
- $subject = "".SERVER_NAME." registeration";
+ // FIX: prevent undefined variable notice
+ $username = "User";
- $message = "Hello ".$username."
+ $message =
+ "Hello " . $username . "\n\n" .
+ "Try the new " . SERVER_NAME . "!\n\n\n" .
+ "Link: " . SERVER . "anmelden.php?id=ref" . $uid . "\n\n" .
+ $text . "\n\n\n" .
+ "Greetings,\n" .
+ "Travian";
-Try the new ".SERVER_NAME."!
+ $headers = "From: " . ADMIN_EMAIL . "\r\n";
-
-Link: ".SERVER."anmelden.php?id=ref".$uid."
-
-".$text."
-
-
-Greetings,
-Travian";
-
- $headers = "From: ".ADMIN_EMAIL."\n";
-
- mail($email, $subject, $message, $headers);
+ @mail($email, $subject, $message, $headers);
}
- function sendPassword($email,$uid,$username,$npw,$cpw) {
-
+ /**
+ * -------------------------------------------------------------------------
+ * SEND PASSWORD RESET EMAIL
+ * -------------------------------------------------------------------------
+ */
+ function sendPassword($email, $uid, $username, $npw, $cpw)
+ {
$subject = "Password forgotten";
- $message = "Hello ".$username."
+ $host = isset($_SERVER['HTTP_HOST']) ? $_SERVER['HTTP_HOST'] : 'localhost';
-You have requested a new password for Travian.
+ $message =
+ "Hello " . $username . "\n\n" .
+ "You have requested a new password for Travian.\n\n" .
+ "----------------------------\n" .
+ "Name: " . $username . "\n" .
+ "Password: " . $npw . "\n" .
+ "----------------------------\n\n" .
+ "Please click this link to activate your new password. The old password then becomes invalid:\n\n" .
+ "http://" . $host . "/password.php?cpw=" . $cpw . "&npw=" . $uid . "\n\n" .
+ "If you want to change your new password, you can enter a new one in your profile\n" .
+ "on tab \"account\".\n\n" .
+ "In case you did not request a new password you may ignore this email.\n\n" .
+ "Travian";
-----------------------------
-Name: ".$username."
-Password: ".$npw."
-----------------------------
+ $headers = "From: " . ADMIN_EMAIL . "\r\n";
-Please click this link to activate your new password. The old password then
-becomes invalid:
-
-http://${_SERVER['HTTP_HOST']}/password.php?cpw=$cpw&npw=$uid
-
-If you want to change your new password, you can enter a new one in your profile
-on tab \"account\".
-
-In case you did not request a new password you may ignore this email.
-
-Travian
-";
-
- $headers = "From: ".ADMIN_EMAIL."\n";
-
- mail($email, $subject, $message, $headers);
+ @mail($email, $subject, $message, $headers);
}
+}
+
+/**
+ * -------------------------------------------------------------------------
+ * GLOBAL INSTANCE (legacy compatibility)
+ * -------------------------------------------------------------------------
+ */
+$mailer = new Mailer();
-};
-$mailer = new Mailer;
?>
\ No newline at end of file
diff --git a/GameEngine/Village.php b/GameEngine/Village.php
index be4b6059..6e4f132d 100755
--- a/GameEngine/Village.php
+++ b/GameEngine/Village.php
@@ -3,9 +3,15 @@
#################################################################################
## -= YOU MAY NOT REMOVE OR CHANGE THIS NOTICE =- ##
## --------------------------------------------------------------------------- ##
+## Project: TravianZ ##
+## Version: 13.05.2026 ##
## Filename Village.php ##
+## Developed by: Dzoki ##
+## Refactor by: Shadow ##
## License: TravianZ Project ##
-## Copyright: TravianZ (c) 2010-2025. All rights reserved. ##
+## Copyright: TravianZ (c) 2010-2026. All rights reserved. ##
+## URLs: https://travianz.org ##
+## https://github.com/Shadowss/TravianZ ##
## ##
#################################################################################
@@ -23,41 +29,55 @@ class Village {
public $wid, $vname, $capital, $natar, $master;
public $resarray = [];
public $unitarray, $techarray, $unitall, $researching, $abarray = [];
+
private $infoarray = [];
private $production = [];
private $oasisowned, $ocounter = [];
- function __construct() {
- global $session, $database;
-
- if(isset($_SESSION['wid'])) $this->wid = $_SESSION['wid'];
- else $this->wid = $session->villages[0];
+ // single-load guards
+ private static $loadedWid = null;
+ private static $cacheCleared = false;
- $this->preloadVillagesData();
+ function __construct() {
+ global $session, $database;
- //add new line code
- //check exist village if from village destroy to avoid error msg.
- if(!$database->checkVilExist($this->wid)){
- $this->wid=$database->getVillageID($session->uid);
- $_SESSION['wid'] = $this->wid;
- }
+ // set village id
+ if (isset($_SESSION['wid'])) $this->wid = $_SESSION['wid'];
+ else $this->wid = $session->villages[0];
+
+ // preload caches (safe warmup)
+ $this->preloadVillagesData();
+
+ // validate existence
+ if (!$database->checkVilExist($this->wid)) {
+ $this->wid = $database->getVillageID($session->uid);
+ $_SESSION['wid'] = $this->wid;
+ }
+
+ // prevent double init in same request
+ if (self::$loadedWid === $this->wid) {
+ return;
+ }
+ self::$loadedWid = $this->wid;
+
+ $this->LoadTown();
+
+ $database->cacheResourceLevels($this->wid);
- $this->LoadTown();
- $database->cacheResourceLevels($this->wid);
$this->calculateProduction();
$this->processProduction();
$this->ActionControl();
}
+ /**
+ * preload user + world cache
+ */
private function preloadVillagesData() {
- global $database, $session;
+ global $database, $session;
- // preload villages for this user account
- $database->getProfileVillages($session->uid, 5);
-
- // preload villages world data records
- $database->cacheVillageByWorldIDs($session->uid);
- }
+ $database->getProfileVillages($session->uid, 5);
+ $database->cacheVillageByWorldIDs($session->uid);
+ }
public function getProd($type) {
return $this->production[$type];
@@ -65,29 +85,46 @@ class Village {
public function getAllUnits($vid) {
global $database, $technology;
- return $technology->getUnits($database->getUnit($vid),$database->getEnforceVillage($vid,0));
+
+ return $technology->getUnits(
+ $database->getUnit($vid),
+ $database->getEnforceVillage($vid, 0)
+ );
}
+ /**
+ * LOAD VILLAGE DATA (single source of truth)
+ */
private function LoadTown($second_run = false) {
global $database, $session, $logging, $technology;
-
+
+ // prevent duplicate reload in same request
+ if (self::$loadedWid === $this->wid && !$second_run && !empty($this->infoarray)) {
+ return;
+ }
+
$this->infoarray = $database->getVillage($this->wid);
- if($this->infoarray['owner'] != $session->uid && !$session->isAdmin) {
+
+ if ($this->infoarray['owner'] != $session->uid && !$session->isAdmin) {
unset($_SESSION['wid']);
- $logging->addIllegal($session->uid,$this->wid,1);
+ $logging->addIllegal($session->uid, $this->wid, 1);
+
$this->wid = $session->villages[0];
$this->infoarray = $database->getVillage($this->wid);
}
+
$this->resarray = $database->getResourceLevel($this->wid);
$this->coor = $database->getCoor($this->wid);
$this->type = $database->getVillageType($this->wid);
$this->oasisowned = $database->getOasis($this->wid);
$this->ocounter = $this->sortOasis();
+
$this->unitarray = $database->getUnit($this->wid);
- $this->enforcetome = $database->getEnforceVillage($this->wid,0);
- $this->enforcetoyou = $database->getEnforceVillage($this->wid,1);
- $this->enforceoasis = $database->getOasisEnforce($this->wid,0);
- $this->unitall = $technology->getAllUnits($this->wid);
+ $this->enforcetome = $database->getEnforceVillage($this->wid, 0);
+ $this->enforcetoyou = $database->getEnforceVillage($this->wid, 1);
+ $this->enforceoasis = $database->getOasisEnforce($this->wid, 0);
+
+ $this->unitall = $technology->getAllUnits($this->wid);
$this->techarray = $database->getTech($this->wid);
$this->abarray = $database->getABTech($this->wid);
$this->researching = $database->getResearching($this->wid, !$second_run);
@@ -97,199 +134,194 @@ class Village {
$this->currentcel = $this->infoarray['celebration'];
$this->wid = $this->infoarray['wref'];
$this->vname = $this->infoarray['name'];
+
$this->awood = $this->infoarray['wood'];
$this->aclay = $this->infoarray['clay'];
$this->airon = $this->infoarray['iron'];
$this->acrop = $this->infoarray['crop'];
+
$this->atotal = (int)($this->awood + $this->aclay + $this->airon + $this->acrop);
+
$this->pop = $this->infoarray['pop'];
$this->maxstore = $this->infoarray['maxstore'];
$this->maxcrop = $this->infoarray['maxcrop'];
+
$this->allcrop = $this->getCropProd();
$this->loyalty = $this->infoarray['loyalty'];
+
$this->master = count($database->getMasterJobs($this->wid));
-
- //If resources overflow the warehouse/granary limit, set them at the maximum value
- $resourceUpdates = [];
- if($this->awood > $this->maxstore)
- {
- $this->awood = $this->maxstore;
- $resourceUpdates['wood'] = $this->maxstore;
- }
-
- if($this->aclay > $this->maxstore)
- {
- $this->aclay = $this->maxstore;
- $resourceUpdates['clay'] = $this->maxstore;
- }
-
- if($this->airon > $this->maxstore)
- {
- $this->airon = $this->maxstore;
- $resourceUpdates['iron'] = $this->maxstore;
- }
-
- if($this->acrop > $this->maxcrop)
- {
- $this->acrop = $this->maxcrop;
- $resourceUpdates['crop'] = $this->maxcrop;
- }
- if (count($resourceUpdates)) {
- $database->updateResource($this->wid, array_keys($resourceUpdates), array_values($resourceUpdates));
+ // overflow fix
+ $updates = [];
- // reload cache if we've updated resources and the like
- if ($second_run) {
- // update DB cache
- call_user_func(get_class($database).'::clearVillageCache');
- $this->preloadVillagesData();
- }
- }
- else if ($second_run) $this->preloadVillagesData();
+ if ($this->awood > $this->maxstore) { $this->awood = $this->maxstore; $updates['wood'] = $this->maxstore; }
+ if ($this->aclay > $this->maxstore) { $this->aclay = $this->maxstore; $updates['clay'] = $this->maxstore; }
+ if ($this->airon > $this->maxstore) { $this->airon = $this->maxstore; $updates['iron'] = $this->maxstore; }
+ if ($this->acrop > $this->maxcrop) { $this->acrop = $this->maxcrop; $updates['crop'] = $this->maxcrop; }
+
+ if (count($updates)) {
+ $database->updateResource($this->wid, array_keys($updates), array_values($updates));
+ }
}
+ /**
+ * PRODUCTION CALC
+ */
private function calculateProduction() {
- global $technology, $database, $session;
+ global $technology, $database;
+
+ if (!self::$cacheCleared) {
+ $db = get_class($database);
+ $db::clearVillageCache();
+ self::$cacheCleared = true;
+ }
- // clear cache, since we're updating village data
- call_user_func(get_class($database).'::clearVillageCache');
$upkeep = $technology->getUpkeep($this->unitall, 0, $this->wid);
+
$this->production['wood'] = $this->getWoodProd();
$this->production['clay'] = $this->getClayProd();
$this->production['iron'] = $this->getIronProd();
- $this->production['crop'] = $this->getCropProd() - (!$this->natar ? $this->pop : round($this->pop / 2)) - $upkeep;
+
+ $this->production['crop'] =
+ $this->getCropProd()
+ - (!$this->natar ? $this->pop : round($this->pop / 2))
+ - $upkeep;
}
+ /**
+ * APPLY PRODUCTION (NO MORE LOADTOWN RELOAD)
+ */
private function processProduction() {
global $database;
-
+
$timepast = time() - $this->infoarray['lastupdate'];
+
$nwood = min(($this->production['wood'] / 3600) * $timepast, $this->maxstore);
$nclay = min(($this->production['clay'] / 3600) * $timepast, $this->maxstore);
$niron = min(($this->production['iron'] / 3600) * $timepast, $this->maxstore);
$ncrop = min(($this->production['crop'] / 3600) * $timepast, $this->maxcrop);
- call_user_func(get_class($database).'::clearVillageCache');
+
+ if (!self::$cacheCleared) {
+ $db = get_class($database);
+ $db::clearVillageCache();
+ self::$cacheCleared = true;
+ }
$database->modifyResource($this->wid, $nwood, $nclay, $niron, $ncrop, 1);
$database->updateVillage($this->wid);
- $this->LoadTown(true);
+
+ // lightweight sync ONLY (no DB reload)
+ $this->infoarray['lastupdate'] = time();
+
+ $this->awood = min($this->awood + $nwood, $this->maxstore);
+ $this->aclay = min($this->aclay + $nclay, $this->maxstore);
+ $this->airon = min($this->airon + $niron, $this->maxstore);
+ $this->acrop = min($this->acrop + $ncrop, $this->maxcrop);
}
-
+
private function getWoodProd() {
+
global $bid1, $bid5, $session;
-
$wood = $sawmill = 0;
- $woodholder = [];
- for($i = 1; $i <= 38; $i++) {
- if($this->resarray['f'.$i.'t'] == 1) array_push($woodholder,'f'.$i);
- if($this->resarray['f'.$i.'t'] == 5) $sawmill = $this->resarray['f'.$i];
+ $holder = [];
+ for ($i = 1; $i <= 38; $i++) {
+ if ($this->resarray['f'.$i.'t'] == 1) $holder[] = 'f'.$i;
+ if ($this->resarray['f'.$i.'t'] == 5) $sawmill = $this->resarray['f'.$i];
}
-
- for($i = 0; $i <= count($woodholder) - 1; $i++) $wood += $bid1[$this->resarray[$woodholder[$i]]]['prod'];
- $wood = $wood + $wood * 0.25 * $this->ocounter[0];
-
- if($sawmill >= 1) $wood += $wood / 100 * $bid5[$sawmill]['attri'];
- if($session->bonus1 == 1) $wood *= 1.25;
-
+ $cnt = count($holder);
+ for ($i = 0; $i < $cnt; $i++) {
+ $wood += $bid1[$this->resarray[$holder[$i]]]['prod'];
+ }
+ $wood += $wood * 0.25 * $this->ocounter[0];
+ if ($sawmill >= 1) {
+ $wood += $wood / 100 * $bid5[$sawmill]['attri'];
+ }
+ if ($session->bonus1 == 1) $wood *= 1.25;
return round($wood * SPEED);
}
private function getClayProd() {
+
global $bid2, $bid6, $session;
-
$clay = $brick = 0;
- $clayholder = [];
- for($i = 1; $i <= 38; $i++) {
- if($this->resarray['f'.$i.'t'] == 2) array_push($clayholder,'f'.$i);
- if($this->resarray['f'.$i.'t'] == 6) $brick = $this->resarray['f'.$i];
+ $holder = [];
+ for ($i = 1; $i <= 38; $i++) {
+ if ($this->resarray['f'.$i.'t'] == 2) $holder[] = 'f'.$i;
+ if ($this->resarray['f'.$i.'t'] == 6) $brick = $this->resarray['f'.$i];
}
-
- for($i = 0; $i <= count($clayholder) - 1; $i++) $clay+= $bid2[$this->resarray[$clayholder[$i]]]['prod'];
- $clay = $clay + $clay * 0.25 * $this->ocounter[1];
-
- if($brick >= 1) $clay += $clay / 100 * $bid6[$brick]['attri'];
- if($session->bonus2 == 1) $clay *= 1.25;
-
+ $cnt = count($holder);
+ for ($i = 0; $i < $cnt; $i++) {
+ $clay += $bid2[$this->resarray[$holder[$i]]]['prod'];
+ }
+ $clay += $clay * 0.25 * $this->ocounter[1];
+ if ($brick >= 1) {
+ $clay += $clay / 100 * $bid6[$brick]['attri'];
+ }
+ if ($session->bonus2 == 1) $clay *= 1.25;
return round($clay * SPEED);
}
private function getIronProd() {
+
global $bid3, $bid7, $session;
-
$iron = $foundry = 0;
- $ironholder = [];
- for($i = 1; $i <= 38; $i++) {
- if($this->resarray['f'.$i.'t'] == 3) array_push($ironholder,'f'.$i);
- if($this->resarray['f'.$i.'t'] == 7) $foundry = $this->resarray['f'.$i];
+ $holder = [];
+ for ($i = 1; $i <= 38; $i++) {
+ if ($this->resarray['f'.$i.'t'] == 3) $holder[] = 'f'.$i;
+ if ($this->resarray['f'.$i.'t'] == 7) $foundry = $this->resarray['f'.$i];
}
-
- for($i = 0;$i <= count($ironholder) - 1; $i++) $iron+= $bid3[$this->resarray[$ironholder[$i]]]['prod'];
- $iron = $iron + $iron * 0.25 * $this->ocounter[2];
-
- if($foundry >= 1) $iron += $iron / 100 * $bid7[$foundry]['attri'];
- if($session->bonus3 == 1) $iron *= 1.25;
-
+ $cnt = count($holder);
+ for ($i = 0; $i < $cnt; $i++) {
+ $iron += $bid3[$this->resarray[$holder[$i]]]['prod'];
+ }
+ $iron += $iron * 0.25 * $this->ocounter[2];
+ if ($foundry >= 1) {
+ $iron += $iron / 100 * $bid7[$foundry]['attri'];
+ }
+ if ($session->bonus3 == 1) $iron *= 1.25;
return round($iron * SPEED);
}
private function getCropProd() {
+
global $bid4, $bid8, $bid9, $session;
-
$crop = $grainmill = $bakery = 0;
- $cropholder = [];
- for($i = 1; $i <= 38; $i++) {
- if($this->resarray['f'.$i.'t'] == 4) array_push($cropholder,'f'.$i);
- if($this->resarray['f'.$i.'t'] == 8) $grainmill = $this->resarray['f'.$i];
- if($this->resarray['f'.$i.'t'] == 9) $bakery = $this->resarray['f'.$i];
+ $holder = [];
+ for ($i = 1; $i <= 38; $i++) {
+ if ($this->resarray['f'.$i.'t'] == 4) $holder[] = 'f'.$i;
+ if ($this->resarray['f'.$i.'t'] == 8) $grainmill = $this->resarray['f'.$i];
+ if ($this->resarray['f'.$i.'t'] == 9) $bakery = $this->resarray['f'.$i];
}
-
- for ($i = 0; $i <= count($cropholder) - 1; $i++) $crop += $bid4[$this->resarray[$cropholder[$i]]]['prod'];
- $bonus = 0.25 * $this->ocounter[3];
- $crop = $crop + $crop * 0.25 * $this->ocounter[3];
-
- if($grainmill >= 1 || $bakery >= 1) {
- $crop += $crop / 100 * ((isset($bid8[$grainmill]['attri']) ? $bid8[$grainmill]['attri'] : 0) + (isset($bid9[$bakery]['attri']) ? $bid9[$bakery]['attri'] : 0));
+ $cnt = count($holder);
+ for ($i = 0; $i < $cnt; $i++) {
+ $crop += $bid4[$this->resarray[$holder[$i]]]['prod'];
}
- if($session->bonus4 == 1) $crop *= 1.25;
-
+ $crop += $crop * 0.25 * $this->ocounter[3];
+ if ($grainmill >= 1 || $bakery >= 1) {
+ $crop += $crop / 100 * (
+ (isset($bid8[$grainmill]['attri']) ? $bid8[$grainmill]['attri'] : 0) +
+ (isset($bid9[$bakery]['attri']) ? $bid9[$bakery]['attri'] : 0)
+ );
+ }
+ if ($session->bonus4 == 1) $crop *= 1.25;
return round($crop * SPEED);
}
+ /**
+ * OASIS
+ */
private function sortOasis() {
- $crop = $clay = $wood = $iron = 0;
- if(!empty($this->oasisowned)){
- foreach($this->oasisowned as $oasis){
- switch($oasis['type']){
- case 1:
- case 2:
- $wood++;
- break;
- case 3:
- $wood++;
- $crop++;
- break;
- case 4:
- case 5:
- $clay++;
- break;
- case 6:
- $clay++;
- $crop++;
- break;
- case 7:
- case 8:
- $iron++;
- break;
- case 9:
- $iron++;
- $crop++;
- break;
- case 10:
- case 11:
- $crop++;
- break;
- case 12:
- $crop += 2;
- break;
+ $wood = $clay = $iron = $crop = 0;
+ if (!empty($this->oasisowned)) {
+ foreach ($this->oasisowned as $oasis) {
+ switch ($oasis['type']) {
+ case 1: case 2: $wood++; break;
+ case 3: $wood++; $crop++; break;
+ case 4: case 5: $clay++; break;
+ case 6: $clay++; $crop++; break;
+ case 7: case 8: $iron++; break;
+ case 9: $iron++; $crop++; break;
+ case 10: case 11: $crop++; break;
+ case 12: $crop += 2; break;
}
}
}
@@ -297,38 +329,26 @@ class Village {
}
private function ActionControl() {
+
global $session;
-
- if(SERVER_WEB_ROOT) $page = $_SERVER['SCRIPT_NAME'];
- else
- {
- $explode = explode("/",$_SERVER['SCRIPT_NAME']);
- $i = count($explode)-1;
- $page = $explode[$i];
+ $page = $_SERVER['SCRIPT_NAME'];
+ if (!SERVER_WEB_ROOT) {
+ $page = basename($_SERVER['SCRIPT_NAME']);
}
-
- if($page == "build.php" && $session->uid != $this->infoarray['owner']) {
+ if ($page == "build.php" && $session->uid != $this->infoarray['owner']) {
unset($_SESSION['wid']);
header("Location: dorf1.php");
exit;
}
}
-
-};
+}
$village = new Village;
$building = new Building;
-// if automation is not currently running, run it for this user,
-// so if they are waiting for some automation to take place
-// (units, resources, buildings...), the script will calculate that
-// before showing the page
-// ... this is a quick fix for automation being called async by AJAX
-// and users seeing old values on their page even though new values
-// already exist after the initial AJAX call
-if ( !file_exists( AUTOMATION_LOCK_FILE_NAME ) ) {
- define( 'AUTOMATION_MANUAL_RUN', true );
- // this file is auto-removed by the Automation.php script
- file_put_contents( AUTOMATION_LOCK_FILE_NAME, '' );
+// automation
+if (!file_exists(AUTOMATION_LOCK_FILE_NAME)) {
+ define('AUTOMATION_MANUAL_RUN', true);
+ file_put_contents(AUTOMATION_LOCK_FILE_NAME, '');
include_once("Automation.php");
}
-?>
+?>
\ No newline at end of file
diff --git a/GameEngine/functions.php b/GameEngine/functions.php
index 8be84b48..afca01a8 100755
--- a/GameEngine/functions.php
+++ b/GameEngine/functions.php
@@ -1,37 +1,103 @@
$repl)
- {
- $text = str_replace($sub, $repl, $text);
+ // Cache key (file + modification time)
+ $cacheKey = $filepath . '|' . filemtime($filepath);
+
+ // Return cached version if exists
+ if (isset($cache[$cacheKey])) {
+ $text = $cache[$cacheKey];
+ } else {
+ $text = file_get_contents($filepath);
+ if ($text === false) {
+ return false;
+ }
+
+ // Store raw template in cache
+ $cache[$cacheKey] = $text;
}
- ob_start();
- eval("?>".$text);
- $text = ob_get_contents();
- ob_end_clean();
- return $text;
-}
+ // Merge subs (local overrides global)
+ $subs = array_merge($globalSubs, $subs);
+ // Replace placeholders
+ if (!empty($subs)) {
+ foreach ($subs as $sub => $repl) {
+ $text = str_replace($sub, $repl, $text);
+ }
+ }
+
+ /**
+ * SECURITY CHANGE:
+ * Removed eval() completely.
+ * Old system allowed PHP injection via templates.
+ *
+ * Now only plain text substitution is supported.
+ */
+
+ // Output buffering kept for compatibility with legacy usage
+ ob_start();
+ echo $text;
+ return ob_get_clean();
+}
?>
\ No newline at end of file