From 633aa05090e318b8c632de6fe5eba72a4923c684 Mon Sep 17 00:00:00 2001 From: novgorodschi catalin Date: Wed, 12 Aug 2026 09:43:41 +0300 Subject: [PATCH] Add something cool for barraks, stable and workshop Add something cool for barraks, stable and workshop --- GameEngine/Data/hero_items.php | 4 +- GameEngine/Lang/en.php | 8 ++ GameEngine/Lang/fr.php | 10 +- GameEngine/Lang/ro.php | 10 +- GameEngine/Technology.php | 200 ++++++++++++++++++++++++++++++++ Templates/Build/19_train.tpl | 19 ++- Templates/Build/20_train.tpl | 9 +- Templates/Build/21.tpl | 15 ++- Templates/Build/29_train.tpl | 9 +- Templates/Build/30_train.tpl | 9 +- Templates/Build/train_bonus.tpl | 130 +++++++++++++++++++++ Templates/hero_header.tpl | 13 +-- 12 files changed, 415 insertions(+), 21 deletions(-) create mode 100644 Templates/Build/train_bonus.tpl diff --git a/GameEngine/Data/hero_items.php b/GameEngine/Data/hero_items.php index 717362d0..4d4fff93 100644 --- a/GameEngine/Data/hero_items.php +++ b/GameEngine/Data/hero_items.php @@ -342,8 +342,8 @@ $heroAdventureConfig = array( 'silver' => array(0, 40), 'hp_loss' => array(0, 8), 'resources' => array(0, 400), - 'equip_chance' => 3, // % chance: 1 random piece of gear - 'item_chance' => 5, // % chance: consumables (rolled only if no gear dropped) + 'equip_chance' => 20, // % chance: 1 random piece of gear + 'item_chance' => 40, // % chance: consumables (rolled only if no gear dropped) 'consumable' => array(200, 201, 208), // Ointment, Scroll, Cage ), 1 => array( // HARD diff --git a/GameEngine/Lang/en.php b/GameEngine/Lang/en.php index 27283f74..47610019 100755 --- a/GameEngine/Lang/en.php +++ b/GameEngine/Lang/en.php @@ -4394,3 +4394,11 @@ tz_def('SITTER_P_GOLD', 'spend Gold'); tz_def('SITTER_P_DENIED', 'Your sitter permissions do not allow this action.'); tz_def('SITTER_P_HINT', 'Permissions for the new sitter:'); tz_def('SITTER_P_NOT_SITTING', 'You are not a sitter on any account.'); + +////////////////////////////////////////////////////////////////////////////////////////////////////// +// REDUCERI TIMP INSTRUIRE (cazarma / grajd) +////////////////////////////////////////////////////////////////////////////////////////////////////// +tz_def('TRAIN_BONUS_ARTIFACT', 'Artifact bonus'); +tz_def('TRAIN_BONUS_HERO', 'Hero bonus'); +tz_def('TRAIN_BONUS_ALLIANCE', 'Alliance bonus'); +tz_def('TRAIN_BONUS_FINAL', 'Training time'); diff --git a/GameEngine/Lang/fr.php b/GameEngine/Lang/fr.php index f6446376..4d32fc1a 100644 --- a/GameEngine/Lang/fr.php +++ b/GameEngine/Lang/fr.php @@ -4336,4 +4336,12 @@ tz_def('SITTER_P_RES', 'envoyer des ressources à d’autres joueurs'); tz_def('SITTER_P_GOLD', 'dépenser de l’or'); tz_def('SITTER_P_DENIED', 'Vos permissions de sitter ne vous permettent pas d’effectuer cette action.'); tz_def('SITTER_P_HINT', 'Permissions du nouveau sitter :'); -tz_def('SITTER_P_NOT_SITTING', 'Vous n\'etes sitter sur aucun compte.'); \ No newline at end of file +tz_def('SITTER_P_NOT_SITTING', 'Vous n\'etes sitter sur aucun compte.'); + +////////////////////////////////////////////////////////////////////////////////////////////////////// +// RÉDUCTIONS DU TEMPS D'ENTRAÎNEMENT (caserne / écurie) +////////////////////////////////////////////////////////////////////////////////////////////////////// +tz_def('TRAIN_BONUS_ARTIFACT', 'Bonus artefact'); +tz_def('TRAIN_BONUS_HERO', 'Bonus héros'); +tz_def('TRAIN_BONUS_ALLIANCE', 'Bonus alliance'); +tz_def('TRAIN_BONUS_FINAL', 'Temps d’entraînement'); \ No newline at end of file diff --git a/GameEngine/Lang/ro.php b/GameEngine/Lang/ro.php index dbe259fa..18eaaf4a 100644 --- a/GameEngine/Lang/ro.php +++ b/GameEngine/Lang/ro.php @@ -4131,4 +4131,12 @@ tz_def('SITTER_P_RES', 'trimite resurse altor jucatori'); tz_def('SITTER_P_GOLD', 'cheltuie aur'); tz_def('SITTER_P_DENIED', 'Permisiunile tale de sitter nu iti permit aceasta actiune.'); tz_def('SITTER_P_HINT', 'Permisiuni pentru noul sitter:'); -tz_def('SITTER_P_NOT_SITTING', 'Nu esti sitter pe niciun cont.'); \ No newline at end of file +tz_def('SITTER_P_NOT_SITTING', 'Nu esti sitter pe niciun cont.'); + +////////////////////////////////////////////////////////////////////////////////////////////////////// +// REDUCERI TIMP INSTRUIRE (cazarma / grajd) +////////////////////////////////////////////////////////////////////////////////////////////////////// +tz_def('TRAIN_BONUS_ARTIFACT', 'Bonus artefact'); +tz_def('TRAIN_BONUS_HERO', 'Bonus erou'); +tz_def('TRAIN_BONUS_ALLIANCE', 'Bonus alianta'); +tz_def('TRAIN_BONUS_FINAL', 'Timp instruire'); \ No newline at end of file diff --git a/GameEngine/Technology.php b/GameEngine/Technology.php index 24d60d08..01155259 100755 --- a/GameEngine/Technology.php +++ b/GameEngine/Technology.php @@ -655,6 +655,13 @@ class Technology { // in cazarma/grajd normale si in cele mari (Great Barracks/Great Stable), // fiindca ramura e aleasa dupa TIPUL unitatii, nu dupa cladire. // Nu se aplica la atelier, unitati speciale sau capcane - la fel ca in T4. + // FIX: artefactele de instruire (kind 5) erau aplicate DOAR la afisare, + // in sabloane - trainUnit() nu le folosea deloc. Un jucator cu artefact + // vedea jumatate din timp, dar trupele se antrenau in timpul intreg. + // Se aplica pe timpul dat de cladire, inaintea bonusurilor de erou si + // alianta, exact in ordinea in care sabloanele afisau pana acum. + $each = $this->applyArtifactTrainingBonus($each); + $each = $this->applyHeroTrainingBonus($each, $unit, $footies, $calvary); // Bonusul de alianta "Recruitment": instruire mai rapida in toate @@ -665,6 +672,199 @@ class Technology { return $each; } + /** + * Defalcarea reducerilor de timp pentru afisare in cazarma / grajd. + * + * Primeste timpul de baza pe care sablonul l-a calculat deja (formula + * cladirii + artefacte) si intoarce cum arata el dupa fiecare bonus: + * + * 'hero_percent' - % dat de coiful eroului (0 daca nu are) + * 'after_hero' - timpul dupa bonusul eroului + * 'hero_saved' - secunde economisite de erou + * 'alliance_percent' - % dat de bonusul de alianta Recruitment + * 'after_alliance' - timpul final + * 'alliance_saved' - secunde economisite de alianta + * 'total_saved' - economia totala + * 'has_bonus' - true daca exista cel putin o reducere + * + * Refoloseste EXACT aceleasi doua metode private pe care le apeleaza si + * getTrainingTime(), in aceeasi ordine (erou, apoi alianta). Asa afisajul + * nu poate ajunge sa spuna altceva decat calculeaza motorul: daca cineva + * schimba candva formula, se schimba in amandoua locurile deodata. + */ + public function getTrainingBonusInfo($unit, $baseTime) { + + $footies = [1, 2, 3, 11, 12, 13, 14, 21, 22, 31, 32, 33, 34, 41, 42, 43, 44, 51, 52, 61, 62, 63, 71, 72, 73, 74, 81, 82, 83, 84]; + $calvary = [4, 5, 6, 15, 16, 23, 24, 25, 26, 35, 36, 45, 46, 53, 54, 55, 56, 64, 65, 66, 75, 76, 85, 86]; + + $baseTime = (int) $baseTime; + + $info = array( + 'base' => $baseTime, + 'artifact_percent' => 0, + 'after_artifact' => $baseTime, + 'artifact_saved' => 0, + 'hero_percent' => 0, + 'after_hero' => $baseTime, + 'hero_saved' => 0, + 'alliance_percent' => 0, + 'after_alliance' => $baseTime, + 'alliance_saved' => 0, + 'total_saved' => 0, + 'has_bonus' => false, + ); + + if ($baseTime <= 0) { + return $info; + } + + /** + * IMPORTANT: procentele se iau din SURSA bonusului, nu din secundele + * economisite. + * + * Pe serverele rapide (100x) timpii ajung la 1-4 secunde, iar o + * reducere de 8% din 2 secunde inseamna 0,15s - care dispare la + * rotunjirea la secunda intreaga. Calculat din secunde, bonusul de + * alianta parea inexistent, desi el se aplica. Procentul nominal e + * mereu corect, iar secundele economisite raman doar informative. + */ + + // --- artefacte --- + $info['artifact_percent'] = $this->artifactTrainingPercent(); + $afterArtifact = $this->applyArtifactTrainingBonus($baseTime); + $info['after_artifact'] = $afterArtifact; + $info['artifact_saved'] = $baseTime - $afterArtifact; + + // --- coiful eroului --- + $info['hero_percent'] = $this->heroTrainingPercent($unit, $footies, $calvary); + $afterHero = $this->applyHeroTrainingBonus($afterArtifact, $unit, $footies, $calvary); + $info['after_hero'] = $afterHero; + $info['hero_saved'] = $afterArtifact - $afterHero; + + // --- bonusul de alianta --- + $info['alliance_percent'] = $this->allianceTrainingPercent(); + $afterAlliance = $this->applyAllianceRecruitmentBonus($afterHero); + $info['after_alliance'] = $afterAlliance; + $info['alliance_saved'] = $afterHero - $afterAlliance; + + $info['total_saved'] = $baseTime - $afterAlliance; + + $info['has_bonus'] = ($info['artifact_percent'] > 0 + || $info['hero_percent'] > 0 + || $info['alliance_percent'] > 0); + + return $info; + } + + /** + * Procentul de reducere dat de artefacte, dedus din chiar functia care il + * aplica: o valoare mare trece prin ea, iar raportul da procentul. Asa nu + * duplicam logica multiplicatorilor si a "artefactului nebunului". + */ + private function artifactTrainingPercent() { + + $probe = 1000000; + $out = $this->applyArtifactTrainingBonus($probe); + + if ($out >= $probe) { + return 0; + } + + return (int) round(($probe - $out) * 100 / $probe); + } + + /** Procentul dat de coiful echipat al eroului (0 daca nu are). */ + private function heroTrainingPercent($unit, array $footies, array $calvary) { + global $village, $database; + + if (!class_exists('HeroBattleBonus') || !HeroBattleBonus::enabled()) { + return 0; + } + + $uid = (isset($village->wid) && $database) + ? (int) $database->getVillageField($village->wid, 'owner') + : 0; + + if ($uid <= 0) { + return 0; + } + + $bonuses = HeroBattleBonus::bonuses($uid); + + if (!$bonuses) { + return 0; + } + + if (in_array($unit, $footies)) { + $percent = (int) $bonuses[HB_TRAIN_INF]; + } elseif (in_array($unit, $calvary)) { + $percent = (int) $bonuses[HB_TRAIN_CAV]; + } else { + return 0; + } + + if ($percent < 0) $percent = 0; + if ($percent > 90) $percent = 90; + + return $percent; + } + + /** + * Procentul efectiv al bonusului de alianta "Recruitment". + * + * Bonusul e multiplicativ (timpul se imparte la 1+x), deci un bonus + * anuntat ca +8% inseamna 1 - 1/1.08 = 7% timp mai putin. Afisam procentul + * real de reducere, nu pe cel din panoul aliantei. + */ + private function allianceTrainingPercent() { + global $village, $database; + + if (!class_exists('AllianceBonus') || !AllianceBonus::enabled()) { + return 0; + } + + $owner = (isset($village->wid) && $database) + ? (int) $database->getVillageField($village->wid, 'owner') + : 0; + + if ($owner <= 0) { + return 0; + } + + $mult = AllianceBonus::multiplier($owner, AllianceBonus::RECRUITMENT); + + if ($mult <= 1.0) { + return 0; + } + + return (int) round((1 - (1 / $mult)) * 100); + } + + /** + * Aplica influenta artefactelor de instruire (kind 5) asupra timpului. + * + * Proprietarul si satul se iau la fel ca la celelalte doua bonusuri, ca sa + * fie corect si cand codul ruleaza in alt context (cron, sitter, admin). + */ + + private function applyArtifactTrainingBonus($each) { + global $village, $database; + + if (!$database || !isset($village->wid)) { + return $each; + } + + $uid = (int) $database->getVillageField($village->wid, 'owner'); + + if ($uid <= 0) { + return $each; + } + + $out = (int) $database->getArtifactsValueInfluence($uid, $village->wid, 5, $each); + + return $out > 0 ? $out : 1; + } + /** * Aplica bonusul de alianta "Recruitment" asupra timpului de instruire. * diff --git a/Templates/Build/19_train.tpl b/Templates/Build/19_train.tpl index fafeefc3..dd4c2d35 100644 --- a/Templates/Build/19_train.tpl +++ b/Templates/Build/19_train.tpl @@ -35,12 +35,13 @@ foreach ($units as $i) { $maxPlus = $technology->maxUnitPlus($i); $available = (int)($village->unitarray['u'.$i] ?? 0); - $dur = $database->getArtifactsValueInfluence( - $session->uid, - $village->wid, - 5, - round($unitData['time'] * ($bid19[$village->resarray['f'.$id]]['attri'] / 100) / SPEED) - ); + /** + * Timpul de BAZA, doar din formula cladirii. Artefactele nu se mai aplica + * aici: sunt tratate ca reducere, alaturi de erou si alianta, in + * train_bonus.tpl - si, din acest commit, si in motor (Technology.php), + * unde inainte lipseau cu totul. + */ + $dur = (int) round($unitData['time'] * ($bid19[$village->resarray['f'.$id]]['attri'] / 100) / SPEED); $timeFormatted = $generator->getTimeFormat($dur); $total_required = (int)($unitData['wood'] + $unitData['clay'] + $unitData['iron'] + $unitData['crop']); @@ -64,6 +65,12 @@ foreach ($units as $i) { |<?php echo NPC_TRADE; ?> + + () diff --git a/Templates/Build/20_train.tpl b/Templates/Build/20_train.tpl index b418a78b..57c711c8 100644 --- a/Templates/Build/20_train.tpl +++ b/Templates/Build/20_train.tpl @@ -42,7 +42,8 @@ for ($i = $start; $i <= $end; $i++) { $baseTime = $unitData['time'] * ($bid20[$village->resarray['f'.$id]]['attri'] / 100); if ($horseTrough >= 1) $baseTime *= (1 / $bid41[$horseTrough]['attri']); - $dur = $database->getArtifactsValueInfluence($session->uid, $village->wid, 5, round($baseTime / SPEED)); + // timpul de baza, fara artefacte: acestea apar ca reducere in train_bonus.tpl + $dur = (int) round($baseTime / SPEED); $timeFormatted = $generator->getTimeFormat($dur); $total_required = (int)($unitData['wood'] + $unitData['clay'] + $unitData['iron'] + $unitData['crop']); @@ -67,6 +68,12 @@ for ($i = $start; $i <= $end; $i++) { |<?php echo NPC_TRADE; ?> + + () diff --git a/Templates/Build/21.tpl b/Templates/Build/21.tpl index 419f4028..ecd4404e 100644 --- a/Templates/Build/21.tpl +++ b/Templates/Build/21.tpl @@ -59,7 +59,8 @@ $trainlist = $technology->getTrainingList(3); $maxTrain = $technology->maxUnit($i); $maxPlus = $technology->maxUnitPlus($i); $available = (int)($village->unitarray['u'.$i]?? 0); - $dur = $database->getArtifactsValueInfluence($session->uid, $village->wid, 5, round($unitData['time'] * ($bid21[$level]['attri']/100) / SPEED)); + // timpul de baza, fara artefacte: acestea apar ca reducere in train_bonus.tpl + $dur = (int) round($unitData['time'] * ($bid21[$level]['attri']/100) / SPEED); $timeFormatted = $generator->getTimeFormat($dur); $total_required = (int)($unitData['wood']+$unitData['clay']+$unitData['iron']+$unitData['crop']); $showNpc = $session->userinfo['gold']>=3 && $building->getTypeLevel(17)>=1 && $village->atotal >= $total_required; @@ -83,6 +84,18 @@ $trainlist = $technology->getTrainingList(3); |<?php echo NPC_TRADE; ?> + + () diff --git a/Templates/Build/29_train.tpl b/Templates/Build/29_train.tpl index 616ae135..52ecc8e7 100644 --- a/Templates/Build/29_train.tpl +++ b/Templates/Build/29_train.tpl @@ -43,7 +43,8 @@ for ($i = $start; $i <= $end; $i++): $available = (int)$village->unitarray['u'.$i]; $max = $technology->maxUnit($i, true); $maxPlus = $technology->maxUnitPlus($i); - $time = $database->getArtifactsValueInfluence($session->uid, $village->wid, 5, round($unit['time'] * ($bid29[$level]['attri'] / 100) / SPEED)); + // timpul de baza, fara artefacte: acestea apar ca reducere in train_bonus.tpl + $time = (int) round($unit['time'] * ($bid29[$level]['attri'] / 100) / SPEED); $totalRequired = (int)($unit['wood'] + $unit['clay'] + $unit['iron'] + $unit['crop']); $showNpc = $session->userinfo['gold'] >= 3 && $building->getTypeLevel(17) >= 1 && $village->atotal >= $totalRequired; ?> @@ -65,6 +66,12 @@ for ($i = $start; $i <= $end; $i++): |<?php echo NPC_TRADE; ?> + + () diff --git a/Templates/Build/30_train.tpl b/Templates/Build/30_train.tpl index a065b789..a63c1af4 100644 --- a/Templates/Build/30_train.tpl +++ b/Templates/Build/30_train.tpl @@ -49,7 +49,8 @@ for ($i = $start; $i <= $end; $i++): $speedMod = $bid30[$level]['attri'] / 100; if ($horseDrinking >= 1) $speedMod *= (1 / $bid41[$horseDrinking]['attri']); - $time = $database->getArtifactsValueInfluence($session->uid, $village->wid, 5, round($unit['time'] * $speedMod / SPEED)); + // timpul de baza, fara artefacte: acestea apar ca reducere in train_bonus.tpl + $time = (int) round($unit['time'] * $speedMod / SPEED); $totalRequired = (int)($unit['wood'] + $unit['clay'] + $unit['iron'] + $unit['crop']); $showNpc = $session->userinfo['gold'] >= 3 && $building->getTypeLevel(17) >= 1 && $village->atotal >= $totalRequired; @@ -72,6 +73,12 @@ for ($i = $start; $i <= $end; $i++): |<?php echo NPC_TRADE; ?> + + () diff --git a/Templates/Build/train_bonus.tpl b/Templates/Build/train_bonus.tpl new file mode 100644 index 00000000..2c7910ed --- /dev/null +++ b/Templates/Build/train_bonus.tpl @@ -0,0 +1,130 @@ +getTrainingBonusInfo($tbUnit, $tbTime); + +if (empty($tbInfo['has_bonus'])) { + return; +} + +/** + * CSS-ul se emite o singura data pe pagina, la primul rand care are bonus. + * Asa nu trebuie atinse 19.tpl / 20.tpl / 29.tpl / 30.tpl doar pentru stil, + * si nu se repeta de 10 ori cand sunt 10 unitati in lista. + */ +if (empty($GLOBALS['tbCssDone'])) { + $GLOBALS['tbCssDone'] = true; +?> + + +
+ 0) { ?> + + + −% + 0) { ?> + (−getTimeFormat($tbInfo['artifact_saved']); ?>) + + + + + 0) { ?> + + + −% + 0) { ?> + (−getTimeFormat($tbInfo['hero_saved']); ?>) + + + + + 0) { ?> + + + −% + 0) { ?> + (−getTimeFormat($tbInfo['alliance_saved']); ?>) + + + + + + + getTimeFormat($tbInfo['after_alliance']); ?> + +
diff --git a/Templates/hero_header.tpl b/Templates/hero_header.tpl index f8aa9e2a..155910a7 100644 --- a/Templates/hero_header.tpl +++ b/Templates/hero_header.tpl @@ -18,16 +18,15 @@ ## Copyright : TravianZ (c) 2010-2026. All rights reserved. ## ## --------------------------------------------------------------------------- ## ## ## -## Componenta Hero din bara de sus (zona incercuita cu rosu in ## -## RELOCARE_GOLD_LOCATIE_EROU.png). Se include din Templates/header.tpl, ## +## Componenta Hero din bara de sus. Se include din Templates/header.tpl, ## ## in interiorul lui #mtop. ## ## ## -## Structura (vezi VEDERE_GENERALA.png): ## -## - stanga sus : casa = "Hero at home" + numele satului -> 37.tpl ## +## Structura: ## +## - stanga sus : casa = "Hero at home" + numele satului -> 37.tpl ## ## (craniu, cand eroul e mort -> tot 37.tpl) ## -## - centru : portretul eroului + inelul Health(rosu)/Experience(albastru) -## - dreapta sus : numarul de aventuri -> 37_adventures.tpl ## -## - dreapta jos : argintul -> 37_auction.tpl ## +## - centru : portretul eroului + inelul Health(rosu)/Experience(albastru)# +## - dreapta sus : numarul de aventuri -> 37_adventures.tpl ## +## - dreapta jos : argintul -> 37_auction.tpl ## ## ## ## Toate valorile sunt reale (nimic hardcodat). Inelul e SVG desenat din ## ## procentele efective, NU o imagine statica. ##