diff --git a/GameEngine/HeroItems.php b/GameEngine/HeroItems.php index f087cc40..7c9d05e5 100644 --- a/GameEngine/HeroItems.php +++ b/GameEngine/HeroItems.php @@ -515,6 +515,95 @@ class HeroItems return self::$awayCache[$uid] = $reason; } + /** @var array cache per request: uid => detaliile deplasarii */ + private static $locationCache = array(); + + /** + * Acelasi motiv ca heroAwayReason(), plus DESTINATIA si TIMPUL RAMAS. + * + * Intoarce mereu un array: + * 'reason' => '' | 'nohero' | 'adventure' | 'attack' | 'reinforcement' + * 'target' => wref-ul catre care se indreapta (0 daca nu se stie) + * 'endtime' => timestamp-ul sosirii (0 = nu e in miscare, ex. intarire + * deja ajunsa, care sta pe loc pana e retrasa) + * 'sort' => sort_type-ul miscarii (3 = dus, 4 = intoarcere), 0 daca nu e cazul + * + * Costul: query-ul de detalii se face DOAR daca eroul chiar e plecat, deci + * cazul obisnuit (erou acasa) ramane exact cat era inainte - un query. + */ + public function heroLocation($uid) + { + $uid = (int) $uid; + + if (isset(self::$locationCache[$uid])) { + return self::$locationCache[$uid]; + } + + $info = array('reason' => $this->heroAwayReason($uid), 'target' => 0, 'endtime' => 0, 'sort' => 0); + + if ($info['reason'] === '' || $info['reason'] === 'nohero') { + return self::$locationCache[$uid] = $info; + } + + $p = TB_PREFIX; + $q = ''; + + if ($info['reason'] === 'adventure') { + + // LEFT JOIN, nu INNER: daca randul de miscare a fost deja procesat, + // vrem macar destinatia, nu sa pierdem tot randul. + $q = "SELECT a.wref AS target, IFNULL(m.endtime, 0) AS endtime, IFNULL(m.sort_type, 0) AS sort_type + FROM {$p}hero_adventure a + LEFT JOIN {$p}movement m ON m.moveid = a.moveid + WHERE a.uid = ? AND a.status = 1 + LIMIT 1"; + + } elseif ($info['reason'] === 'attack') { + + // La dus (sort_type 3) satul jucatorului e `from`, la intoarcere + // (4) e `to`; IF() alege coloana corecta pentru verificarea + // proprietarului. Destinatia afisata e mereu `to`. + $q = "SELECT m.`to` AS target, m.endtime, m.sort_type + FROM {$p}movement m + INNER JOIN {$p}attacks a ON a.id = m.ref + INNER JOIN {$p}vdata v ON v.wref = IF(m.sort_type = 4, m.`to`, m.`from`) + WHERE v.owner = ? AND m.proc = 0 AND m.sort_type IN (3, 4) AND a.t11 > 0 + ORDER BY m.endtime ASC + LIMIT 1"; + + } else { + + // Intarirea a ajuns deja: nu exista miscare, deci nici timp ramas. + $q = "SELECT e.vref AS target, 0 AS endtime, 0 AS sort_type + FROM {$p}enforcement e + INNER JOIN {$p}vdata v ON v.wref = e.`from` + WHERE v.owner = ? AND e.hero > 0 + LIMIT 1"; + } + + $stmt = $this->db->prepare($q); + + if (!$stmt) { + // instalarile vechi pot sa nu aiba toate tabelele - motivul ramane + // valid, doar detaliile lipsesc + return self::$locationCache[$uid] = $info; + } + + $stmt->bind_param('i', $uid); + $stmt->execute(); + $stmt->bind_result($target, $endtime, $sortType); + + if ($stmt->fetch()) { + $info['target'] = (int) $target; + $info['endtime'] = (int) $endtime; + $info['sort'] = (int) $sortType; + } + + $stmt->close(); + + return self::$locationCache[$uid] = $info; + } + public function equipItem($uid, $rowId) { global $database; diff --git a/GameEngine/Lang/en.php b/GameEngine/Lang/en.php index 46c54b26..b56aaa50 100755 --- a/GameEngine/Lang/en.php +++ b/GameEngine/Lang/en.php @@ -4366,3 +4366,12 @@ tz_def('ALLYBONUS_MSG_OVERMAX', 'This is the final level: you can donate at most ////////////////////////////////////////////////////////////////////////////////////////////////////// tz_def('ADM_PROTECTED_PLAYERS', 'Protected players'); tz_def('ADM_PROTECTED_PLAYERS_TIP', 'Comma-separated player names that cannot be attacked or raided by anyone. Reinforcements are still allowed. Leave empty to disable.'); + +////////////////////////////////////////////////////////////////////////////////////////////////////// +// COMPONENTA HERO DIN BARA DE SUS +////////////////////////////////////////////////////////////////////////////////////////////////////// +tz_def('HERO_HEADER_AT_HOME', 'Hero at home'); +tz_def('HERO_HEADER_DEAD', 'Hero is dead'); +tz_def('HERO_HEADER_TRAINING', 'Hero in training'); +tz_def('HERO_HEADER_NOHERO', 'No hero yet'); +tz_def('TZ_HEALTH', 'Health'); diff --git a/GameEngine/Lang/fr.php b/GameEngine/Lang/fr.php index c3e27470..f78331e0 100644 --- a/GameEngine/Lang/fr.php +++ b/GameEngine/Lang/fr.php @@ -4309,3 +4309,12 @@ tz_def('ALLYBONUS_MSG_OVERMAX', 'Ceci est le dernier niveau : vous pouvez donner ////////////////////////////////////////////////////////////////////////////////////////////////////// tz_def('ADM_PROTECTED_PLAYERS', 'Joueurs proteges'); tz_def('ADM_PROTECTED_PLAYERS_TIP', 'Noms de joueurs separes par des virgules qui ne peuvent etre ni attaques ni pilles. Les renforts restent autorises. Laisser vide pour desactiver.'); + +////////////////////////////////////////////////////////////////////////////////////////////////////// +// COMPONENTA HERO DIN BARA DE SUS +////////////////////////////////////////////////////////////////////////////////////////////////////// +tz_def('HERO_HEADER_AT_HOME', 'Le heros est chez lui'); +tz_def('HERO_HEADER_DEAD', 'Le heros est mort'); +tz_def('HERO_HEADER_TRAINING', 'Heros en formation'); +tz_def('HERO_HEADER_NOHERO', 'Pas encore de heros'); +tz_def('TZ_HEALTH', 'Sante'); diff --git a/GameEngine/Lang/ro.php b/GameEngine/Lang/ro.php index 35e264d7..8b86074b 100644 --- a/GameEngine/Lang/ro.php +++ b/GameEngine/Lang/ro.php @@ -4106,3 +4106,12 @@ tz_def('ALLYBONUS_MSG_OVERMAX', 'Acesta e ultimul nivel: poti dona cel mult %s r ////////////////////////////////////////////////////////////////////////////////////////////////////// tz_def('ADM_PROTECTED_PLAYERS', 'Jucatori protejati'); tz_def('ADM_PROTECTED_PLAYERS_TIP', 'Nume de jucatori separate prin virgula, care nu pot fi atacati sau jefuiti de nimeni. Intaririle raman permise. Lasa gol ca sa dezactivezi.'); + +////////////////////////////////////////////////////////////////////////////////////////////////////// +// COMPONENTA HERO DIN BARA DE SUS +////////////////////////////////////////////////////////////////////////////////////////////////////// +tz_def('HERO_HEADER_AT_HOME', 'Eroul este acasa'); +tz_def('HERO_HEADER_DEAD', 'Eroul este mort'); +tz_def('HERO_HEADER_TRAINING', 'Eroul este in antrenament'); +tz_def('HERO_HEADER_NOHERO', 'Inca nu ai erou'); +tz_def('TZ_HEALTH', 'Sanatate'); diff --git a/Templates/Build/37_auction.tpl b/Templates/Build/37_auction.tpl index f8e7b2c1..f4b464ec 100644 --- a/Templates/Build/37_auction.tpl +++ b/Templates/Build/37_auction.tpl @@ -135,7 +135,51 @@ $t4RateS2G = HeroItems::silverForOneGold();

- + 'roman.png', // Romani + 2 => 'teuton.png', // Teutoni + 3 => 'gaul.png', // Gali + 6 => 'huns.png', // Huni + 7 => 'egiptean.png', // Egipteni + 8 => 'spartan.png', // Spartani + 9 => 'vikings.png', // Vikingi + ]; + + $t4Tribe = 0; + + if (isset($session->tribe)) { + $t4Tribe = (int) $session->tribe; + } elseif (isset($session->userinfo['tribe'])) { + $t4Tribe = (int) $session->userinfo['tribe']; + } + + $t4MerchantFile = isset($t4MerchantByTribe[$t4Tribe]) + ? $t4MerchantByTribe[$t4Tribe] + : 'merchant.png'; + + // Daca fisierul tribului inca n-a fost urcat pe server, nu + // lasam un patrat gol - revenim la negustorul generic. + if (!@file_exists('img/hero/' . $t4MerchantFile)) { + $t4MerchantFile = 'merchant.png'; + } + ?> + diff --git a/Templates/header.tpl b/Templates/header.tpl index a950317c..11b622e8 100644 --- a/Templates/header.tpl +++ b/Templates/header.tpl @@ -170,7 +170,31 @@ if ($hour > 1759 || $hour < 500) { - + + + + + 1759 || $hour < 500) { display: inline-block; } - /* GOLD IN CERCUL VERDE */ + /* GOLD IN DREPTUNGHIUL ALBASTRU (RELOCARE_GOLD_LOCATIE_EROU.png) + Vechea pozitie era left:370px, adica exact cercul rosu - acolo sta + acum componenta Hero (#tzHeroBox), asa ca aurul s-a mutat la dreapta, + dupa butonul Plus si iconita day/night. */ #goldHeader { position: absolute; - left: 370px; /* << AICI ESTE CERCUL VERDE - muta 370-400 daca e nevoie */ + left: 630px; /* << DREPTUNGHIUL ALBASTRU - muta 620-680 daca e nevoie */ /* Centrare pe verticala in bara gri: ancoram la mijloc si compensam inaltimea proprie. Asa ramane centrat si acum, cand sunt doua randuri (aur + argint), nu impins spre partea de jos. */ diff --git a/Templates/hero_header.tpl b/Templates/hero_header.tpl new file mode 100644 index 00000000..b5a04fe8 --- /dev/null +++ b/Templates/hero_header.tpl @@ -0,0 +1,573 @@ + 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 ## +## ## +## Toate valorile sunt reale (nimic hardcodat). Inelul e SVG desenat din ## +## procentele efective, NU o imagine statica. ## +## ## +################################################################################# + +/** + * Gard 1: fara sesiune de jucator real nu afisam nimic. + * $isRestrictedUser vine din header.tpl (contul special cu id 1). + */ +if (!isset($session) || !is_object($session)) { + return; +} + +if (isset($isRestrictedUser) && $isRestrictedUser) { + return; +} + +if (!isset($database) || !is_object($database)) { + return; +} + +$tzHeroUid = (int) $session->uid; + +if ($tzHeroUid <= 0) { + return; +} + +/** + * Functiile T4 de erou (aventuri / licitatii / argint) sunt optionale. + * Cand steagul e stins, ramane doar cercul cu erou + casa, fiindca + * Adventures si Silver n-ar avea unde sa duca. + */ +$tzHeroT4 = defined('NEW_FUNCTIONS_HERO_T4') && NEW_FUNCTIONS_HERO_T4; + +/** + * --------------------------------------------------------------------------- + * 1. Randul eroului + * --------------------------------------------------------------------------- + * getHero($uid, 1) intoarce TOTI eroii, ordonati dupa lastupdate DESC. + * Alegem, ca in Units::Hero(), primul erou viu si care nu e in antrenament; + * daca nu exista, luam primul rand (cel mai recent folosit) - asa prindem + * si eroul mort, de care avem nevoie pentru starea DEAD. + */ +$tzHeroRow = false; +$tzHeroRows = $database->getHero($tzHeroUid, 1); + +if (is_array($tzHeroRows) && count($tzHeroRows)) { + + foreach ($tzHeroRows as $tzRow) { + + if ((int) $tzRow['dead'] !== 1 && (int) $tzRow['intraining'] !== 1) { + $tzHeroRow = $tzRow; + break; + } + } + + if (!$tzHeroRow) { + $tzHeroRow = $tzHeroRows[0]; + } +} + +$tzHeroExists = is_array($tzHeroRow); +$tzHeroDead = $tzHeroExists ? ((int) $tzHeroRow['dead'] === 1) : false; +$tzHeroTraining = $tzHeroExists ? ((int) $tzHeroRow['intraining'] === 1) : false; +$tzHeroName = $tzHeroExists ? (string) $tzHeroRow['name'] : ''; +$tzHeroLevel = $tzHeroExists ? (int) $tzHeroRow['level'] : 0; +$tzHeroUnit = $tzHeroExists ? (int) $tzHeroRow['unit'] : 0; +$tzHeroWref = $tzHeroExists ? (int) $tzHeroRow['wref'] : 0; + +/** + * health e float(12,9) in baza de date. Il rotunjim doar la afisare. + */ +$tzHeroHealth = $tzHeroExists ? (float) $tzHeroRow['health'] : 0; +$tzHeroHealth = max(0, min(100, $tzHeroHealth)); + +if ($tzHeroDead) { + $tzHeroHealth = 0; +} + +/** + * --------------------------------------------------------------------------- + * 2. Procentul de Experience catre nivelul urmator + * --------------------------------------------------------------------------- + * Aceeasi formula ca in Templates/Build/37_hero.tpl, ca sa nu existe doua + * adevaruri diferite in interfata. $hero_levels vine din + * GameEngine/Data/hero_full.php, incarcat de Session.php pe fiecare pagina. + */ +$tzHeroLevels = (isset($GLOBALS['hero_levels']) && is_array($GLOBALS['hero_levels']) && count($GLOBALS['hero_levels']) > 1) + ? $GLOBALS['hero_levels'] + : array(0 => 0, 1 => 100); + +$tzMaxLevel = max(array_keys($tzHeroLevels)) - 1; +$tzMaxExp = isset($tzHeroLevels[$tzMaxLevel]) ? (int) $tzHeroLevels[$tzMaxLevel] : 0; + +$tzCurExp = $tzHeroExists ? (int) $tzHeroRow['experience'] : 0; +$tzExpCur = isset($tzHeroLevels[$tzHeroLevel]) ? (int) $tzHeroLevels[$tzHeroLevel] : 0; +$tzExpNext = isset($tzHeroLevels[$tzHeroLevel + 1]) ? (int) $tzHeroLevels[$tzHeroLevel + 1] : $tzMaxExp; + +if ($tzHeroExists && $tzCurExp < $tzMaxExp && $tzExpNext > $tzExpCur && $tzHeroLevel < $tzMaxLevel) { + $tzHeroExpPct = ($tzCurExp - $tzExpCur) / ($tzExpNext - $tzExpCur) * 100; + $tzHeroExpPct = max(0, min(100, $tzHeroExpPct)); +} else { + $tzHeroExpPct = $tzHeroExists ? 100 : 0; +} + +/** + * --------------------------------------------------------------------------- + * 3. Unde se afla eroul acum + * --------------------------------------------------------------------------- + * Refolosim HeroItems::heroAwayReason(), aceeasi sursa de adevar ca pagina de + * echipare: un singur query cu subinterogari separate, care intoarce + * '' (acasa) | 'nohero' | 'adventure' | 'attack' | 'reinforcement'. + * - 'adventure' : hero_adventure cu status = 1 + * - 'attack' : movement sort_type 3 (dus) sau 4 (intors) cu attacks.t11 + * - 'reinforcement' : enforcement.hero pornit dintr-un sat al jucatorului + * Metoda are cache static pe uid, deci daca o mai cheama cineva pe aceeasi + * pagina nu se duce a doua oara la baza de date. + */ +$tzHeroAway = ''; +$tzHeroTarget = 0; +$tzHeroEndtime = 0; +$tzHeroSort = 0; + +if ($tzHeroExists && !$tzHeroDead && !$tzHeroTraining && class_exists('HeroItems')) { + + $tzAwayObject = new HeroItems(); + + if (method_exists($tzAwayObject, 'heroLocation')) { + + $tzLoc = $tzAwayObject->heroLocation($tzHeroUid); + $tzHeroAway = (string) $tzLoc['reason']; + $tzHeroTarget = (int) $tzLoc['target']; + $tzHeroEndtime = (int) $tzLoc['endtime']; + $tzHeroSort = (int) $tzLoc['sort']; + + } else { + + // rezerva, daca ajunge pe un server cu HeroItems.php vechi + $tzHeroAway = (string) $tzAwayObject->heroAwayReason($tzHeroUid); + } +} + +// 'nohero' nu ne intereseaza aici - stim deja ca eroul exista +if ($tzHeroAway === 'nohero') { + $tzHeroAway = ''; +} + +/** + * Coordonatele destinatiei si secundele ramase pana la sosire. + * La intoarcere (sort_type 4) destinatia e chiar satul jucatorului. + */ +$tzHeroTargetCoor = ''; + +if ($tzHeroTarget > 0) { + + $tzCoor = $database->getCoor($tzHeroTarget); + + if (is_array($tzCoor) && isset($tzCoor['x'], $tzCoor['y'])) { + $tzHeroTargetCoor = '(' . (int) $tzCoor['x'] . '|' . (int) $tzCoor['y'] . ')'; + } +} + +$tzHeroSecondsLeft = ($tzHeroEndtime > 0) ? max(0, $tzHeroEndtime - time()) : 0; + +/** + * Starea unica a componentei, din care ies si iconita, si tooltip-ul. + * Ordinea conteaza: mort > inexistent > in antrenament > plecat > acasa. + */ +if (!$tzHeroExists) { + $tzHeroState = 'nohero'; +} elseif ($tzHeroDead) { + $tzHeroState = 'dead'; +} elseif ($tzHeroTraining) { + $tzHeroState = 'training'; +} elseif ($tzHeroAway !== '') { + $tzHeroState = $tzHeroAway; +} else { + $tzHeroState = 'home'; +} + +/** + * --------------------------------------------------------------------------- + * 4. Satul eroului + * --------------------------------------------------------------------------- + */ +$tzHeroVillage = ''; + +if ($tzHeroWref > 0) { + $tzHeroVillage = (string) $database->getVillageField($tzHeroWref, 'name'); +} + +/** + * --------------------------------------------------------------------------- + * 5. Aventuri disponibile + * --------------------------------------------------------------------------- + * Un erou mort nu poate pleca in aventura, deci afisam 0 (cerinta 7), + * dar zona ramane clickabila. + */ +$tzHeroAdv = 0; + +if ($tzHeroT4 && !$tzHeroDead && class_exists('HeroAdventure')) { + + $tzAdvObject = new HeroAdventure(); + $tzAdvOffers = $tzAdvObject->getOffers($tzHeroUid); + $tzHeroAdv = is_array($tzAdvOffers) ? count($tzAdvOffers) : 0; +} + +/** + * --------------------------------------------------------------------------- + * 6. Argintul + * --------------------------------------------------------------------------- + * Refolosim exact acelasi cache ca blocul de aur din header.tpl + * ($GLOBALS['t4SilverValue']), ca sa nu iasa doua interogari pe pagina. + */ +$tzHeroSilver = 0; + +if ($tzHeroT4 && class_exists('HeroItems')) { + + if (!isset($GLOBALS['t4SilverValue'])) { + $tzSilverObject = new HeroItems(); + $GLOBALS['t4SilverValue'] = (int) $tzSilverObject->getSilver($tzHeroUid); + } + + $tzHeroSilver = (int) $GLOBALS['t4SilverValue']; +} + +/** + * --------------------------------------------------------------------------- + * 7. Link-urile catre Resedinta Eroului + * --------------------------------------------------------------------------- + * 37.tpl / 37_adventures.tpl / 37_auction.tpl nu sunt URL-uri: se ajunge + * la ele prin build.php pe campul unde e cladirea 37, cu parametrul t4tab. + * + * getTypeField() cauta DOAR in satul curent. Daca jucatorul se uita la un + * sat fara Resedinta Eroului, trimitem catre satul unde sta eroul, cu + * newdid + gid=37 (build.php pastreaza t4tab peste redirect - vezi patch-ul + * din build.php livrat impreuna cu acest fisier). + */ +$tzHeroField = 0; + +if (isset($building) && is_object($building) && method_exists($building, 'getTypeField')) { + $tzHeroField = (int) $building->getTypeField(37); +} + +if ($tzHeroField > 0) { + $tzHeroBase = 'build.php?id=' . $tzHeroField; +} elseif ($tzHeroWref > 0) { + $tzHeroBase = 'build.php?newdid=' . $tzHeroWref . '&gid=37'; +} else { + $tzHeroBase = 'build.php?gid=37'; +} + +$tzLinkHero = $tzHeroBase; +$tzLinkAdv = $tzHeroBase . '&t4tab=adventures'; +$tzLinkAuc = $tzHeroBase . '&t4tab=auction'; + +/** + * --------------------------------------------------------------------------- + * 8. Portretul eroului + * --------------------------------------------------------------------------- + * img/u2/uN.gif sunt portretele mari (150x120), existente pentru toate + * unitatile de erou, inclusiv triburile noi 6-9 (u51..u90). Daca lipseste + * fisierul, cadem pe iconita mica img/u/N.gif. + */ +$tzHeroPortrait = ''; + +if ($tzHeroUnit > 0) { + + $tzBig = GP_LOCATE . 'img/u2/u' . $tzHeroUnit . '.gif'; + $tzSmall = GP_LOCATE . 'img/u/' . $tzHeroUnit . '.gif'; + + if (@file_exists($tzBig)) { + $tzHeroPortrait = $tzBig; + } elseif (@file_exists($tzSmall)) { + $tzHeroPortrait = $tzSmall; + } +} + +/** + * --------------------------------------------------------------------------- + * 9. Geometria inelului + * --------------------------------------------------------------------------- + * Doua arce concentrice, in acelasi SVG: exterior = Health (rosu), + * interior = Experience (albastru). Lungimea vizibila se obtine cu + * stroke-dasharray, iar rotate(-90) porneste arcele de sus. + */ +$tzRingR1 = 26.5; // raza arcului de Health +$tzRingR2 = 21; // raza arcului de Experience +$tzRingC1 = 2 * M_PI * $tzRingR1; // circumferinte +$tzRingC2 = 2 * M_PI * $tzRingR2; + +$tzDashHealth = round($tzRingC1 * $tzHeroHealth / 100, 2); +$tzDashExp = round($tzRingC2 * $tzHeroExpPct / 100, 2); + +/** + * --------------------------------------------------------------------------- + * 10. Texte + * --------------------------------------------------------------------------- + * Tiparul defined()?: e cel folosit deja in 37_hero.tpl / 37_t4nav.tpl - + * componenta merge si pe servere care n-au inca noile constante de limba. + */ +$tzTxtAtHome = defined('HERO_HEADER_AT_HOME') ? HERO_HEADER_AT_HOME : 'Hero at home'; +$tzTxtDead = defined('HERO_HEADER_DEAD') ? HERO_HEADER_DEAD : 'Hero is dead'; +$tzTxtTraining = defined('HERO_HEADER_TRAINING') ? HERO_HEADER_TRAINING : 'Hero in training'; +$tzTxtNoHero = defined('HERO_HEADER_NOHERO') ? HERO_HEADER_NOHERO : 'No hero yet'; +$tzTxtAdventure = defined('HERO_HEADER_ADVENTURE') ? HERO_HEADER_ADVENTURE : 'Hero on adventure'; +$tzTxtAttack = defined('HERO_HEADER_ATTACK') ? HERO_HEADER_ATTACK : 'Hero is with the army'; +$tzTxtReinforce = defined('HERO_HEADER_REINFORCE') ? HERO_HEADER_REINFORCE : 'Hero is reinforcing'; +$tzTxtIn = defined('HERO_HEADER_IN') ? HERO_HEADER_IN : 'in'; +$tzTxtVillage = defined('VILLAGE') ? VILLAGE : 'Village'; +$tzTxtLevel = defined('LEVEL') ? LEVEL : 'Level'; +$tzTxtHealth = defined('TZ_HEALTH') ? TZ_HEALTH : 'Health'; +$tzTxtExperience = defined('EXPERIENCE') ? EXPERIENCE : 'Experience'; +$tzTxtSilver = defined('HERO_SILVER') ? HERO_SILVER : 'Silver'; +$tzTxtAdventures = defined('HERO_T4_TAB_ADVENTURES') ? HERO_T4_TAB_ADVENTURES : 'Adventures'; + +/** + * Numele afisate vin din baza de date, deci trec obligatoriu prin escape. + */ +$tzHeroNameSafe = htmlspecialchars($tzHeroName, ENT_QUOTES, 'UTF-8'); +$tzHeroVillageSafe = htmlspecialchars($tzHeroVillage, ENT_QUOTES, 'UTF-8'); + +?> + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + $tzTxtDead, + 'nohero' => $tzTxtNoHero, + 'training' => $tzTxtTraining, + 'adventure' => $tzTxtAdventure, + 'attack' => $tzTxtAttack, + 'reinforcement' => $tzTxtReinforce, + 'home' => $tzTxtAtHome, + ]; + ?> + + + + + + + → + + + + + 0) { ?> + + + + + + + + + + + + + + + + + + + + + + + + + ( ) + : % + : % + (/ XP) + + + + + + + + + + + + + + : + + + + + + + + + : + + + + + +
+ + 0) { ?> + + diff --git a/build.php b/build.php index b0e270b3..4e86c247 100644 --- a/build.php +++ b/build.php @@ -29,7 +29,35 @@ AccessLogger::logRequest(); if(isset($_GET['newdid'])){ $_SESSION['wid'] = $_GET['newdid']; - header("Location: " . $_SERVER['PHP_SELF'].(isset($_GET['id']) ? '?id='.$_GET['id'] : (isset($_GET['gid']) ? '?gid='.$_GET['gid'] : ''))); + + /** + * Redirectul pastra doar id/gid, deci un link de forma + * "build.php?newdid=X&gid=37&t4tab=adventures" (folosit de componenta + * Hero din bara de sus, cand eroul e in alt sat decat cel privit) + * ajungea pe tab-ul implicit al Resedintei Eroului, nu pe Aventuri. + * Pastram acum si t4tab (lista alba) si parametrul "land" al oazelor. + * + * Bonus: id/gid trec prin acelasi filtru ca mai jos inainte sa intre in + * antetul Location - inainte se concatena valoarea bruta din $_GET. + */ + $tzRedirect = ''; + + if (isset($_GET['id'])) { + $tzRedirect = '?id=' . preg_replace("/[^a-zA-Z0-9_-]/", "", $_GET['id']); + } else if (isset($_GET['gid'])) { + $tzRedirect = '?gid=' . preg_replace("/[^a-zA-Z0-9_-]/", "", $_GET['gid']); + } + + if ($tzRedirect !== '') { + + if (isset($_GET['t4tab']) && in_array($_GET['t4tab'], ['items', 'adventures', 'auction'], true)) { + $tzRedirect .= '&t4tab=' . $_GET['t4tab']; + } else if (isset($_GET['land'])) { + $tzRedirect .= '&land'; + } + } + + header("Location: " . $_SERVER['PHP_SELF'] . $tzRedirect); exit; } if(isset($_GET['id']) && ($_GET['id'] < 1 || $_GET['id'] > 40 && ($_GET['id'] == 99 && $village->natar == 0 || $_GET['id'] != 99))){ diff --git a/css/hero_header.css b/css/hero_header.css new file mode 100644 index 00000000..dd5507ef --- /dev/null +++ b/css/hero_header.css @@ -0,0 +1,273 @@ +/* + * ########################################################################### + * hero_header.css - componenta Hero din bara de sus (TravianZ) + * Proiect : TravianZ - https://github.com/Shadowss/TravianZ + * Copyright: TravianZ (c) 2010-2026. All rights reserved. + * ########################################################################### + * + * Elementele sunt piese UI separate (casa, inel, badge aventuri, argint), + * asamblate cu pozitionare absoluta in interiorul lui #tzHeroBox - NU o + * imagine mare unica. + * + * REGLAJ POZITIE: singurul lucru de atins cand vrei sa muti componenta e + * "left" din #tzHeroBox (coordonate relative la #mtop, care e position:relative). + */ + +/* ========================================================================= + Ordinea de desenare a barii de sus + ========================================================================= + #mtop are z-index:2 in graphic pack si creeaza un CONTEXT DE STIVUIRE, + deci z-index-ul tooltip-urilor nu poate depasi bara insasi. Randul de + resurse (div#res) e tot pe z-index 2/3 SI e inclus la finalul paginii + (dupa footer), asa ca la valoare egala castiga ordinea din DOM si trecea + peste tooltip-uri. + Ridicam bara la 4: bate #res, dar ramane mult sub popup-uri (50+), + harta (20+), chat (999) si ferestrele de ghid (9999). */ + +div#mtop { + z-index: 4; +} + +/* ========================================================================= + Cadrul componentei + ========================================================================= */ + +#tzHeroBox { + position: absolute; + left: 344px; /* << ZONA INCERCUITA CU ROSU. Muta 330-370 daca e nevoie */ + top: 50%; + margin-top: -36px; /* jumatate din inaltime = centrare pe verticala */ + width: 124px; + height: 72px; + z-index: 60; + font-size: 11px; + line-height: normal; +} + +#tzHeroBox a, +#tzHeroBox a:hover { + text-decoration: none; + border: 0; + outline: 0; +} + +.tzHeroSlot { + position: absolute; + display: block; +} + +/* ========================================================================= + Centru: inelul Health / Experience + portretul + ========================================================================= */ + +/* Diametrul inelului = 64px, cat iconitele de navigatie din stanga barii */ +.tzHeroCenter { + left: 30px; + top: 4px; + width: 64px; + height: 64px; +} + +.tzHeroRing { + display: block; + width: 64px; + height: 64px; +} + +.tzHeroRingBg { + fill: #f2f1ee; + stroke: #c6c4bf; + stroke-width: 1; +} + +.tzHeroTrack { + fill: none; + stroke: #dedcd7; + stroke-width: 4; +} + +/* ROSU = procentul de Health al eroului */ +.tzHeroArcHealth { + fill: none; + stroke: #c0392b; + stroke-width: 4; + stroke-linecap: butt; +} + +/* ALBASTRU = progresul Experience catre nivelul urmator */ +.tzHeroArcExp { + fill: none; + stroke: #2f6fb0; + stroke-width: 4; + stroke-linecap: butt; +} + +.tzHeroInner { + fill: #ffffff; + stroke: #d6d4cf; + stroke-width: 1; +} + +/* ATENTIE: portretul e copil al lui .tzHeroCenter, care e position:absolute, + deci coordonatele sunt relative la INEL (64x64), nu la #tzHeroBox. + Centrare = (64 - 32) / 2 pe ambele axe. */ +.tzHeroPortrait { + position: absolute; + left: 16px; + top: 16px; + width: 32px; + height: 32px; + object-fit: contain; +} + +.tzHeroPortraitEmpty { + fill: #b9b7b2; +} + +/* Eroul mort: portretul se decoloreaza, dar linkul ramane activ */ +#tzHeroBox.tzHeroDeadState .tzHeroPortrait { + filter: grayscale(100%); + opacity: .45; +} + +/* ========================================================================= + Stanga sus: casa (Hero at home) / craniu (Hero is dead) + ========================================================================= */ + +.tzHeroHome { + left: 10px; + top: 0; + width: 24px; + height: 24px; +} + +.tzHeroIco { + display: block; + width: 24px; + height: 24px; +} + +.tzHeroIcoBg { + fill: #f6f5f2; + stroke: #b8b6b1; + stroke-width: 1; +} + +.tzHeroRoof { fill: #b8452f; } +.tzHeroWall { fill: #f0e6cf; } +.tzHeroDoor { fill: #8a6a3f; } + +.tzHeroSkull { fill: #e9e7e2; stroke: #7d7b76; stroke-width: .8; } +.tzHeroSkullEye { fill: #3a3835; } + +/* Starile "plecat": aventura (cizma), atac (sabii), intarire (scut) */ +.tzHeroBoot { fill: #8a6a3f; stroke: #5f482a; stroke-width: .8; } +.tzHeroBootSole { fill: #4a3a24; } +.tzHeroBootCuff { fill: #b08a52; } + +.tzHeroBlade { fill: none; stroke: #9a9894; stroke-width: 2.2; stroke-linecap: round; } +.tzHeroHilt { fill: none; stroke: #8a6a3f; stroke-width: 2.2; stroke-linecap: round; } + +.tzHeroShield { fill: #c9d4e2; stroke: #5d7391; stroke-width: .9; } +.tzHeroShieldDark { fill: #9fb2c9; stroke: none; } + +/* Teancul de monede din iconita de argint */ +.tzHeroCoin { fill: #d3d2ce; stroke: #8f8d88; stroke-width: .8; } +.tzHeroCoinTop { fill: #efeeeb; stroke: none; } + +/* ========================================================================= + Dreapta sus: numarul de aventuri + ========================================================================= */ + +.tzHeroAdv { + left: 90px; + top: 0; + width: 23px; + height: 23px; + border-radius: 50%; + text-align: center; + border: 1px solid #8d8b86; + box-sizing: border-box; +} + +.tzHeroAdvOn { background: #5aa02c; border-color: #3f7a17; } +.tzHeroAdvOff { background: #e6e4df; border-color: #b3b1ac; } + +.tzHeroAdvNum { + display: block; + line-height: 21px; + font-size: 12px; + font-weight: bold; +} + +.tzHeroAdvOn .tzHeroAdvNum { color: #ffffff; } +.tzHeroAdvOff .tzHeroAdvNum { color: #6b6964; } + +/* ========================================================================= + Dreapta jos: argintul / casa de licitatii + ========================================================================= */ + +.tzHeroSilver { + left: 90px; + top: 45px; + width: 24px; + height: 24px; +} + +/* ========================================================================= + Tooltip-uri (numai la mouseover, fara JS) + ========================================================================= */ + +.tzHeroTip { + display: none; + position: absolute; + z-index: 500; + padding: 5px 9px; + background-color: #3f3d39; + background-image: none; + color: #ffffff; + border: 1px solid #23211f; + border-radius: 3px; + box-shadow: 0 2px 6px rgba(0, 0, 0, .45); + opacity: 1; + white-space: nowrap; + font-size: 11px; + font-weight: normal; + text-align: left; + line-height: 15px; +} + +.tzHeroSlot:hover .tzHeroTip { + display: block; +} + +.tzHeroTip b { + display: block; + color: #ffffff; + font-weight: bold; +} + +.tzHeroTip i { + display: block; + color: #d9d7d2; + font-style: normal; +} + +.tzHeroTip .tzHeroTipWarn { + color: #f0a49a; +} + +.tzHeroTip .tzHeroTipTime { + color: #ffffff; +} + +/* latime fixa pe cifre: ceasul nu mai tresare la fiecare secunda */ +.tzHeroTimer { + font-variant-numeric: tabular-nums; +} + +/* Pozitiile din imaginile de referinta */ +.tzHeroTipHome { left: 28px; top: 4px; } +.tzHeroTipCenter { left: 58px; top: 44px; } +.tzHeroTipAdv { left: 29px; top: 4px; } +.tzHeroTipSilver { left: 29px; top: 2px; } diff --git a/img/hero/egiptean.png b/img/hero/egiptean.png new file mode 100644 index 00000000..165428ff Binary files /dev/null and b/img/hero/egiptean.png differ diff --git a/img/hero/gaul.png b/img/hero/gaul.png new file mode 100644 index 00000000..d231f958 Binary files /dev/null and b/img/hero/gaul.png differ diff --git a/img/hero/huns.png b/img/hero/huns.png new file mode 100644 index 00000000..74a667bd Binary files /dev/null and b/img/hero/huns.png differ diff --git a/img/hero/roman.png b/img/hero/roman.png new file mode 100644 index 00000000..f7f815a4 Binary files /dev/null and b/img/hero/roman.png differ diff --git a/img/hero/spartan.png b/img/hero/spartan.png new file mode 100644 index 00000000..ceb3cfca Binary files /dev/null and b/img/hero/spartan.png differ diff --git a/img/hero/teuton.png b/img/hero/teuton.png new file mode 100644 index 00000000..d7761a84 Binary files /dev/null and b/img/hero/teuton.png differ diff --git a/img/hero/vikings.png b/img/hero/vikings.png new file mode 100644 index 00000000..0d8188cd Binary files /dev/null and b/img/hero/vikings.png differ