From a7817f9631a3c15e1a9257f6c6b3137c511cb20a Mon Sep 17 00:00:00 2001 From: novgorodschi catalin Date: Fri, 24 Jul 2026 18:16:53 +0300 Subject: [PATCH] Fix demolish #337 Fix demolish #337 --- .../Automation/AutomationBuildQueue.php | 29 +++---- .../Database/DatabaseVillageQueries.php | 76 +++++++++++++++++++ Templates/Build/15_1.tpl | 49 +++++++++++- install/data/constant_format.tpl | 74 +++++++++++------- 4 files changed, 181 insertions(+), 47 deletions(-) diff --git a/GameEngine/Automation/AutomationBuildQueue.php b/GameEngine/Automation/AutomationBuildQueue.php index b75f5b32..4d739b64 100644 --- a/GameEngine/Automation/AutomationBuildQueue.php +++ b/GameEngine/Automation/AutomationBuildQueue.php @@ -210,23 +210,14 @@ trait AutomationBuildQueue { $buildarray = $GLOBALS["bid".$type]; - if ($type == 10 || $type == 38) { - $database->query(" - UPDATE ".TB_PREFIX."vdata - SET - `maxstore` = IF(`maxstore` - ".$buildarray[$level]['attri']." <= ".STORAGE_BASE.", ".STORAGE_BASE.", `maxstore` - ".$buildarray[$level]['attri'].") - WHERE - wref=".(int) $vil['vref']); - } - - if ($type == 11 || $type == 39) { - $database->query(" - UPDATE ".TB_PREFIX."vdata - SET - `maxcrop` = IF(`maxcrop` - ".$buildarray[$level]['attri']." <= ".STORAGE_BASE.", ".STORAGE_BASE.", `maxcrop` - ".$buildarray[$level]['attri'].") - WHERE - wref=".(int) $vil['vref']); - } + // FIX: capacitatea de depozitare se RECALCULEAZA din cladirile + // ramase, dupa ce nivelul nou e scris mai jos. Scaderea de + // dinainte lua `attri` al nivelului, dar `attri` e capacitatea + // TOTALA la acel nivel (1200, 1700, 2300...), nu incrementul - + // deci taia prea mult. Ignora si STORAGE_MULTIPLIER. Efectul era + // ascuns de pragul STORAGE_BASE si "reparat" abia la urmatoarea + // rulare a lui updateStore(). + $needsStorageRecalc = in_array($type, [10, 11, 38, 39]); if ($level == 1) $clear = ",f".$vil['buildnumber']."t=0"; else $clear = ""; @@ -235,6 +226,10 @@ trait AutomationBuildQueue { $q = "UPDATE ".TB_PREFIX."fdata SET f".$vil['buildnumber']."=".$newLevel." ".$clear." WHERE vref=".(int)$vil['vref']; $database->query($q); + if ($needsStorageRecalc) { + $database->recalculateStorage($vil['vref']); + } + $pop = $this->getPop($type, $newLevel); $database->modifyPop($vil['vref'], $pop[0], 1); $this->procClimbers($database->getVillageField($vil['vref'], 'owner')); diff --git a/GameEngine/Database/DatabaseVillageQueries.php b/GameEngine/Database/DatabaseVillageQueries.php index 0d96cac6..c6327209 100644 --- a/GameEngine/Database/DatabaseVillageQueries.php +++ b/GameEngine/Database/DatabaseVillageQueries.php @@ -1675,6 +1675,82 @@ trait DatabaseVillageQueries { return $result; } + /** + * Recalculeaza capacitatea de depozitare a unui sat din cladirile lui. + * + * Aceeasi regula ca recalcularea periodica din Automation::updateStore(): + * se aduna `attri` * STORAGE_MULTIPLIER pentru fiecare depozit/hambar + * (normal si mare) din sloturile f19..f39, cu prag minim STORAGE_BASE. + * + * De ce recalculare, nu scadere incrementala: `attri` este capacitatea + * TOTALA la acel nivel (1200, 1700, 2300...), nu incrementul. Scaderea + * folosita la demolare lua toata valoarea nivelului si ignora si + * STORAGE_MULTIPLIER, deci taia prea mult - efect mascat de pragul minim. + * Recalcularea nu poate ramane in urma, indiferent ce s-a schimbat. + */ + function recalculateStorage($wid) { + $wid = (int) $wid; + + global $bid10, $bid11, $bid38, $bid39; + + $fdata = $this->getResourceLevel($wid, false); + + if (!$fdata) { + return false; + } + + $multiplier = defined('STORAGE_MULTIPLIER') ? STORAGE_MULTIPLIER : 1; + $base = defined('STORAGE_BASE') ? STORAGE_BASE : 0; + + $store = 0; + $crop = 0; + + $map = array( + 10 => array('store', $bid10), + 38 => array('store', $bid38), + 11 => array('crop', $bid11), + 39 => array('crop', $bid39), + ); + + for ($i = 19; $i < 40; $i++) { + $type = isset($fdata['f' . $i . 't']) ? (int) $fdata['f' . $i . 't'] : 0; + $level = isset($fdata['f' . $i]) ? (int) $fdata['f' . $i] : 0; + + if (!isset($map[$type]) || $level <= 0) { + continue; + } + + list($target, $data) = $map[$type]; + + if (!isset($data[$level]['attri'])) { + continue; + } + + $amount = $data[$level]['attri'] * $multiplier; + + if ($target === 'store') { + $store += $amount; + } else { + $crop += $amount; + } + } + + if ($store < $base) { $store = $base; } + if ($crop < $base) { $crop = $base; } + + $result = mysqli_query( + $this->dblink, + "UPDATE " . TB_PREFIX . "vdata + SET maxstore = " . (int) $store . ", maxcrop = " . (int) $crop . " + WHERE wref = " . $wid + ); + + // randul de sat s-a schimbat: urmatoarea citire trebuie sa vina din DB + unset(self::$villageFieldsCache[$wid . '0'], self::$villageFieldsCache[$wid . '3']); + + return $result; + } + function modifyPop($vid, $pop, $mode) { list($vid, $pop, $mode) = $this->escape_input((int) $vid, (int) $pop, $mode); diff --git a/Templates/Build/15_1.tpl b/Templates/Build/15_1.tpl index 4b259616..5706938a 100644 --- a/Templates/Build/15_1.tpl +++ b/Templates/Build/15_1.tpl @@ -56,11 +56,56 @@ if (!empty($_REQUEST['demolish']) && $_REQUEST['c'] == $session->mchecker) { if($currentLvl > 0){ // sterge orice demolare in curs $database->delDemolition($village->wid); + + // FIX 2: populatia nu era scazuta deloc la demolarea instant, deci + // satul ramanea cu locuitorii unei cladiri care nu mai exista. + // Cladirea dispare de la nivelul curent pana la 0, deci trebuie + // scazuta populatia TUTUROR nivelurilor, nu doar a ultimului + // (demolarea clasica scade cate un nivel pe rand - vezi + // Automation::demolitionComplete). + $demolishPop = 0; + $demolishData = $GLOBALS['bid'.$buildType] ?? null; + + if (is_array($demolishData)) { + for ($demolishLvl = 1; $demolishLvl <= $currentLvl; $demolishLvl++) { + if (isset($demolishData[$demolishLvl]['pop'])) { + $demolishPop += (int) $demolishData[$demolishLvl]['pop']; + } + } + } + // setare nivel 0 direct in DB $database->query("UPDATE ".TB_PREFIX."fdata SET `$field` = 0, `{$field}t` = 0 WHERE `vref` = ".$village->wid); - // scade gold - $database->modifyGold($session->uid, -10, 0); + + // Capacitatea de depozitare nu era ajustata deloc pe calea cu aur: + // demolarea instant a unui Depozit sau Hambar lasa satul cu + // capacitatea cladirii disparute. Recalculam din ce a ramas. + if (in_array((int) $buildType, [10, 11, 38, 39], true)) { + $database->recalculateStorage($village->wid); + } + + if ($demolishPop > 0) { + // modul 1 = scade (vezi Database::modifyPop) + $database->modifyPop($village->wid, $demolishPop, 1); + } + + // Punctele de cultura se recalculeaza din cladirile ramase: fara + // asta satul ar produce in continuare cultura pentru cladirea + // demolata. recountCP citeste starea proaspata din baza de date. + if (class_exists('Building')) { + Building::recountCP($database, $village->wid); + } + + // FIX 1: modul 0 al lui modifyGold SCADE deja (gold = gold - $amt), + // deci valoarea trebuie sa fie POZITIVA. Cu -10 iesea + // "gold - (-10)", adica jucatorul PRIMEA 10 aur in loc sa plateasca. + $database->modifyGold($session->uid, 10, 0); $session->gold -= 10; + + // soldul din sesiune se poate reciti la urmatoarea cerere din + // cache-ul de utilizator; il invalidam ca sa nu reapara vechea valoare + unset($_SESSION['cache_user_' . (isset($_SESSION['username']) ? $_SESSION['username'] : '')]); + $session->changeChecker(); header("Location: build.php?gid=15&ty=$type&demolished=1"); exit; diff --git a/install/data/constant_format.tpl b/install/data/constant_format.tpl index d637d063..6ea92c7a 100644 --- a/install/data/constant_format.tpl +++ b/install/data/constant_format.tpl @@ -25,29 +25,37 @@ define('AUTOMATION_LOCK_FILE_NAME', 'automation.lck'); ////////////////////////////////// // ***** CRON / AUTOMATION *****// ////////////////////////////////// -// Automation ruleaza din cron.php (cron job pe server), nu din paginile -// jucatorilor. Vezi comentariile din cron.php pentru instalarea cron job-ului. // -// CRON_LOOP_SECONDS = cat timp tine o invocare de cron.php. -// Multe hosturi nu permit cron mai des de 5 minute, iar Automation vrea sa -// ruleze la ~60s. De aceea o invocare ruleaza mai multe tick-uri la rand. -// 300 = potrivit pentru un cron "*/5 * * * *". Pune 0 daca hostul tau permite -// cron la fiecare minut (atunci o invocare = un singur tick). -// CRON_TICK_SECONDS = la cat timp se repeta un tick in interiorul invocarii. +// Automation runs from cron.php (a server cron job), not from player page +// requests. See the comments in cron.php for cron job installation instructions. +// +// CRON_LOOP_SECONDS = how long a single cron.php invocation runs. +// Many hosting providers do not allow cron jobs to run more frequently than +// every 5 minutes, while Automation is designed to run approximately every +// 60 seconds. For this reason, a single invocation executes multiple ticks +// in sequence. +// 300 = suitable for a "*/5 * * * *" cron schedule. +// Set to 0 if your hosting provider allows a cron job every minute +// (in that case, each invocation executes only a single tick). +// +// CRON_TICK_SECONDS = the interval, in seconds, between each tick within a +// single cron.php invocation. define('CRON_LOOP_SECONDS', %CRONLOOP%); define('CRON_TICK_SECONDS', %CRONTICK%); -// Cheie pentru apelarea cron.php prin HTTP (wget/curl sau un serviciu extern de -// cron). Rularea din linia de comanda (cron job cPanel) NU are nevoie de ea. -// Generata automat la instalare; pastrata la salvarile de configuratie din ACP. +// Key used to access cron.php via HTTP (wget/curl or an external cron service). +// Command-line execution (e.g. a cPanel cron job) does NOT require it. +// Automatically generated during installation and preserved when saving configuration settings from the ACP. define('CRON_KEY', '%CRONKEY%'); ////////////////////////////////// // ***** DATABASE CLEANUP *****// ////////////////////////////////// -// Tabelele care cresc nelimitat (rapoarte, chat, mesaje sterse) sunt curatate -// periodic de Automation. 0 = dezactivat pentru fiecare regula in parte. -// Rapoartele ARHIVATE de jucator nu se sterg niciodata. +// +// Tables that grow indefinitely (reports, chat, deleted messages) are cleaned +// up periodically by Automation. Set each rule to 0 to disable it individually. +// +// Reports archived by players are never deleted. define('CLEANUP_REPORTS_DAYS', %CLEANUPREPORTS%); define('CLEANUP_CHAT_DAYS', %CLEANUPCHAT%); define('CLEANUP_MESSAGES_DAYS', %CLEANUPMESSAGES%); @@ -55,26 +63,36 @@ define('CLEANUP_INTERVAL', 3600); define('CLEANUP_BATCH', 5000); ////////////////////////////////// -// ***** EROU *****// +// ***** HERO *****// ////////////////////////////////// -// Regenerarea de BAZA a vietii eroului, in HP pe zi, independenta de punctele -// puse in atributul de regenerare (ca in Travian T4). Fara ea, un erou cu 0 -// puncte in regenerare nu si-ar reface niciodata viata si ar muri inevitabil -// dupa destule aventuri. Se scaleaza cu viteza serverului, ca si regenerarea -// din atribute. 0 = dezactivata (comportamentul vechi). +// +// The hero's BASE health regeneration, in HP per day, independent of the +// points invested in the Regeneration attribute (as in Travian T4). +// Without this, a hero with 0 points in Regeneration would never recover +// health and would eventually die after enough adventures. +// +// It scales with the server speed, just like regeneration from attributes. +// Set to 0 to disable it (legacy behavior). define('HERO_BASE_REGEN', %HEROBASEREGEN%); -// Ratele casei de schimb din casa de licitatii: -// HERO_SILVER_PER_GOLD = cat argint primesti pentru 1 aur -// HERO_SILVER_TO_GOLD = cat argint costa 1 aur la schimbul invers -// Diferenta dintre ele este marja casei (ca in Travian: 1 aur -> 10 argint, -// dar 25 argint -> 1 aur). +// Auction House exchange rates: +// +// HERO_SILVER_PER_GOLD = how much silver you receive for 1 gold +// HERO_SILVER_TO_GOLD = how much silver it costs to buy 1 gold +// +// The difference between the two rates is the Auction House margin +// (just like in Travian: 1 gold → 10 silver, but 25 silver → 1 gold). define('HERO_SILVER_PER_GOLD', %HEROSILVERPERGOLD%); define('HERO_SILVER_TO_GOLD', %HEROSILVERTOGOLD%); -// Atributul de erou "Resources" (T4): cate resurse produce un punct pe ora. -// ALL = cand bonusul e raspandit egal pe toate patru (implicit 3 din fiecare) -// ONE = cand e concentrat pe o singura resursa (implicit 10) +// Hero "Resources" attribute (T4): how many resources each attribute point +// produces per hour. +// +// ALL = when the bonus is distributed equally across all four resources +// (default: 3 of each resource) +// +// ONE = when the bonus is concentrated on a single resource +// (default: 10) define('HERO_RES_PER_POINT_ALL', %HERORESALL%); define('HERO_RES_PER_POINT_ONE', %HERORESONE%);