diff --git a/Admin/Templates/config.tpl b/Admin/Templates/config.tpl index 67fa8290..0e0ed1f5 100644 --- a/Admin/Templates/config.tpl +++ b/Admin/Templates/config.tpl @@ -92,12 +92,12 @@ $editIcon = ' ? ?Enabled" : "Disabled"; ?> ? - - Server graphic pack ?The graphic pack every player sees by default, read from the gpack/ folder. + + ? - Player graphic packs ?When enabled, players can point their profile at their own graphic pack (Profile → Graphics). When disabled, everyone sees the server pack. + ? @@ -266,6 +266,7 @@ $cronKeyMasked = ($cronKey === '') ?Enabled" : "Disabled"; ?> ?Enabled" : "Disabled"; ?> ? + ?Enabled" : "Disabled"; ?> diff --git a/Admin/Templates/editNewFunctions.tpl b/Admin/Templates/editNewFunctions.tpl index 988913e4..e0eafb10 100644 --- a/Admin/Templates/editNewFunctions.tpl +++ b/Admin/Templates/editNewFunctions.tpl @@ -244,6 +244,15 @@ if($_SESSION['access'] < 9) die(ACCESS_DENIED_ADMIN); + + Alliance bonuses (T4) + + + + ?
diff --git a/GameEngine/Admin/Mods/editNewFunctions.php b/GameEngine/Admin/Mods/editNewFunctions.php index ab72279e..dd101980 100644 --- a/GameEngine/Admin/Mods/editNewFunctions.php +++ b/GameEngine/Admin/Mods/editNewFunctions.php @@ -112,6 +112,7 @@ $fh = fopen($myFile, 'w') or die("


Can't open file: GameEngine\con tz_config_set($text, '%HOMEPAGE%', HOMEPAGE); tz_config_set($text, '%SERVER%', SERVER); tz_config_set($text, '%NEW_FUNCTIONS_OASIS%', $_POST['new_functions_oasis'] ?? ''); + tz_config_set($text, '%ALLIANCEBONUSES%', $_POST['alliance_bonuses'] ?? 'false'); tz_config_set($text, '%NEW_FUNCTIONS_ALLIANCE_INVITATION%', $_POST['new_functions_alliance_invitation'] ?? ''); tz_config_set($text, '%NEW_FUNCTIONS_EMBASSY_MECHANICS%', $_POST['new_functions_embassy_mechanics'] ?? ''); tz_config_set($text, '%NEW_FUNCTIONS_FORUM_POST_MESSAGE%', $_POST['new_functions_forum_post_message'] ?? ''); diff --git a/GameEngine/Alliance.php b/GameEngine/Alliance.php index fc6d4ac0..7b1bfb8b 100755 --- a/GameEngine/Alliance.php +++ b/GameEngine/Alliance.php @@ -352,6 +352,12 @@ class Alliance { // Acceptăm invitația $database->removeInvitation($inviteID); $database->updateUserField($invite['uid'], "alliance", $invite['alliance'], 1); + // Bonusurile de alianta devin disponibile treptat pentru + // membrii noi, deci retinem cand a intrat. Fara asta, + // cineva ar putea sari dintr-o alianta in alta doar ca sa + // culeaga bonusuri de nivel mare. + $database->updateUserField($invite['uid'], "alliance_joined", time(), 1); + $database->createAlliPermissions($invite['uid'], $invite['alliance'], '', 0, 0, 0, 0, 0, 0, 0, 0); // Invalidate the 30s session user-cache (see Session::PopulateVar) so the // new alliance membership shows up immediately, without a re-login. @@ -410,6 +416,12 @@ class Alliance { } $database->updateUserField($session->uid, "alliance", $aid, 1); + // Bonusurile de alianta devin disponibile treptat pentru + // membrii noi, deci retinem cand a intrat. Fara asta, + // cineva ar putea sari dintr-o alianta in alta doar ca sa + // culeaga bonusuri de nivel mare. + $database->updateUserField($session->uid, "alliance_joined", time(), 1); + $database->procAllyPop($aid); $database->createAlliPermissions($session->uid, $aid, 'Alliance founder', '1', '1', '1', '1', '1', '1', '1', '1'); // Invalidate the 30s session user-cache (see Session::PopulateVar) so the diff --git a/GameEngine/AllianceBonus.php b/GameEngine/AllianceBonus.php new file mode 100644 index 00000000..4f46cdcb --- /dev/null +++ b/GameEngine/AllianceBonus.php @@ -0,0 +1,638 @@ +db = $database->dblink; + } + + /** + * Functiile sunt pornite? Verificam si flagul, si existenta tabelei, ca sa + * nu cada jocul pe un server care nu a rulat inca migrarea SQL. + */ + public static function enabled() + { + static $ok = null; + + if ($ok !== null) { + return $ok; + } + + if (!defined('NEW_FUNCTIONS_ALLIANCE_BONUSES') || !NEW_FUNCTIONS_ALLIANCE_BONUSES) { + return $ok = false; + } + + global $database; + $res = @mysqli_query($database->dblink, + "SHOW TABLES LIKE '" . TB_PREFIX . "alliance_bonus'"); + + return $ok = ($res && mysqli_num_rows($res) > 0); + } + + /** Lista tipurilor, cu cheia de limba si iconita. */ + public static function types() + { + return array( + self::RECRUITMENT => array('key' => 'recruitment', 'lang' => 'ALLYBONUS_RECRUITMENT'), + self::PHILOSOPHY => array('key' => 'philosophy', 'lang' => 'ALLYBONUS_PHILOSOPHY'), + self::METALLURGY => array('key' => 'metallurgy', 'lang' => 'ALLYBONUS_METALLURGY'), + self::COMMERCE => array('key' => 'commerce', 'lang' => 'ALLYBONUS_COMMERCE'), + ); + } + + /* ------------------------------------------------------------------ */ + /* Tabele de valori (din config, cu rezerva pe valorile din T4) */ + /* ------------------------------------------------------------------ */ + + private static function listFromConst($name, $fallback) + { + $raw = defined($name) ? (string) constant($name) : $fallback; + $out = array(); + + foreach (explode(',', $raw) as $v) { + $v = trim($v); + + if ($v !== '' && is_numeric($v)) { + $out[] = (float) $v; + } + } + + return $out ? $out : array_map('floatval', explode(',', $fallback)); + } + + /** Resurse necesare pentru a trece de la $level la $level+1. */ + public static function costFor($level) + { + $costs = self::listFromConst('ALLIANCE_BONUS_COSTS', + '1200000,5600000,17100000,51200000,153600000'); + + return isset($costs[$level]) ? (float) $costs[$level] : 0.0; + } + + /** Durata upgrade-ului, in secunde, scalata cu viteza serverului. */ + public static function upgradeSeconds($level) + { + $hours = self::listFromConst('ALLIANCE_BONUS_HOURS', '24,48,72,96,120'); + $h = isset($hours[$level]) ? (float) $hours[$level] : 24.0; + $speed = (defined('SPEED') && SPEED > 0) ? (float) SPEED : 1.0; + + return (int) max(60, round($h * 3600 / $speed)); + } + + /** + * Plafonul zilnic de donatie al unui jucator, dupa cel mai mare nivel + * deblocat in alianta. Se scaleaza cu viteza serverului, ca in T4. + */ + public static function dailyLimit($highestLevel) + { + $limits = self::listFromConst('ALLIANCE_BONUS_DAILY', + '300000,300000,400000,550000,750000,1000000'); + + $idx = max(0, min(count($limits) - 1, (int) $highestLevel)); + $val = (float) $limits[$idx]; + $speed = (defined('SPEED') && SPEED > 0) ? (float) SPEED : 1.0; + + return (float) round($val * $speed); + } + + /** Procentul acordat de un nivel, pentru un tip de bonus. */ + public static function percentFor($btype, $level) + { + $level = max(0, min(self::MAX_LEVEL, (int) $level)); + + if ($level === 0) { + return 0.0; + } + + $small = defined('ALLIANCE_BONUS_PCT_SMALL') ? (float) ALLIANCE_BONUS_PCT_SMALL : 2.0; + $large = defined('ALLIANCE_BONUS_PCT_LARGE') ? (float) ALLIANCE_BONUS_PCT_LARGE : 4.0; + + // Recruitment si Philosophy cresc cu 2% pe nivel, Metallurgy si + // Commerce cu 4% pe nivel (vezi tabelul din T4). + $step = in_array((int) $btype, array(self::METALLURGY, self::COMMERCE), true) + ? $large : $small; + + return $level * $step; + } + + /* ------------------------------------------------------------------ */ + /* Citire */ + /* ------------------------------------------------------------------ */ + + /** + * Starea completa a bonusurilor unei aliante: nivel, progres, upgrade activ. + * Randurile lipsa se completeaza cu nivel 0, deci apelantul primeste mereu + * toate cele patru tipuri. + */ + public function getState($aid) + { + $aid = (int) $aid; + $out = array(); + + foreach (array_keys(self::types()) as $btype) { + $out[$btype] = array( + 'btype' => $btype, + 'level' => 0, + 'pool' => 0.0, + 'upgrade_end' => 0, + ); + } + + if ($aid <= 0 || !self::enabled()) { + return $out; + } + + $res = mysqli_query($this->db, + "SELECT btype, level, pool, upgrade_end FROM " . TB_PREFIX . "alliance_bonus + WHERE aid = " . $aid); + + while ($res && ($row = mysqli_fetch_assoc($res))) { + $b = (int) $row['btype']; + + if (isset($out[$b])) { + $out[$b] = array( + 'btype' => $b, + 'level' => (int) $row['level'], + 'pool' => (float) $row['pool'], + 'upgrade_end' => (int) $row['upgrade_end'], + ); + } + } + + return $out; + } + + /** + * Nivelurile efective ale unei aliante, ca array btype => nivel. + * Cache-uit pe cerere: se citeste des (lupte, instruire, productie). + */ + public function getLevels($aid) + { + $aid = (int) $aid; + + if (isset(self::$levelCache[$aid])) { + return self::$levelCache[$aid]; + } + + $levels = array(); + + foreach (array_keys(self::types()) as $btype) { + $levels[$btype] = 0; + } + + if ($aid > 0 && self::enabled()) { + $res = mysqli_query($this->db, + "SELECT btype, level FROM " . TB_PREFIX . "alliance_bonus WHERE aid = " . $aid); + + while ($res && ($row = mysqli_fetch_assoc($res))) { + $b = (int) $row['btype']; + + if (isset($levels[$b])) { + $levels[$b] = (int) $row['level']; + } + } + } + + return self::$levelCache[$aid] = $levels; + } + + /** Cel mai mare nivel deblocat in alianta (pentru plafonul de donatie). */ + public function highestLevel($aid) + { + $levels = $this->getLevels($aid); + + return $levels ? max($levels) : 0; + } + + /** + * Nivelul de care beneficiaza EFECTIV un jucator. + * + * Membrii noi capata acces treptat: nivelul 1 imediat, nivelul 2 dupa 24h, + * nivelul 3 dupa 48h si asa mai departe (scalat cu viteza serverului). + * Asa nu se poate sari dintr-o alianta in alta doar ca sa culegi bonusuri. + */ + public function effectiveLevel($uid, $btype) + { + if (!self::enabled()) { + return 0; + } + + $uid = (int) $uid; + $res = mysqli_query($this->db, + "SELECT alliance, alliance_joined FROM " . TB_PREFIX . "users WHERE id = " . $uid . " LIMIT 1"); + $row = $res ? mysqli_fetch_assoc($res) : null; + + if (!$row || (int) $row['alliance'] <= 0) { + return 0; + } + + $levels = $this->getLevels((int) $row['alliance']); + $level = isset($levels[(int) $btype]) ? (int) $levels[(int) $btype] : 0; + + if ($level <= 1) { + return $level; // nivelul 1 e disponibil imediat + } + + $joined = (int) $row['alliance_joined']; + + // 0 sau 1 inseamna membru dinainte de aceasta functie: primeste tot + if ($joined <= 1) { + return $level; + } + + $speed = (defined('SPEED') && SPEED > 0) ? (float) SPEED : 1.0; + $elapsed = time() - $joined; + + // nivelul N devine disponibil dupa (N-1) * 24h de la intrare + $allowed = 1 + (int) floor($elapsed / max(60, (86400 / $speed))); + + return max(0, min($level, $allowed)); + } + + /* ------------------------------------------------------------------ */ + /* Donatii */ + /* ------------------------------------------------------------------ */ + + /** Cat a donat un jucator azi. */ + public function donatedToday($uid) + { + if (!self::enabled()) { + return 0.0; + } + + $uid = (int) $uid; + $day = (int) floor(time() / 86400); + + $res = mysqli_query($this->db, + "SELECT amount FROM " . TB_PREFIX . "alliance_donation + WHERE uid = " . $uid . " AND day = " . $day . " LIMIT 1"); + $row = $res ? mysqli_fetch_assoc($res) : null; + + return $row ? (float) $row['amount'] : 0.0; + } + + /** + * Doneaza resurse catre un bonus. + * + * $amounts - array cu patru valori: lemn, lut, fier, cereale + * $triple - daca jucatorul plateste aur ca donatia sa conteze intreit + * + * Tipul resursei nu conteaza, doar totalul; resursele se scad din satul + * activ. Intoarce una dintre constantele DONATE_*. + */ + public function donate($uid, $wref, $btype, array $amounts, $triple = false) + { + global $database, $session; + + if (!self::enabled()) { + return self::DONATE_DISABLED; + } + + $uid = (int) $uid; + $wref = (int) $wref; + $btype = (int) $btype; + + if (!isset(self::types()[$btype])) { + return self::DONATE_INVALID; + } + + // sumele trebuie sa fie intregi pozitivi + $clean = array(); + $total = 0.0; + + foreach (array_slice($amounts, 0, 4) as $a) { + $a = (float) $a; + + if ($a < 0 || !is_finite($a)) { + return self::DONATE_INVALID; + } + + $a = floor($a); + $clean[] = $a; + $total += $a; + } + + while (count($clean) < 4) { + $clean[] = 0.0; + } + + if ($total <= 0) { + return self::DONATE_INVALID; + } + + // alianta jucatorului + $res = mysqli_query($this->db, + "SELECT alliance FROM " . TB_PREFIX . "users WHERE id = " . $uid . " LIMIT 1"); + $row = $res ? mysqli_fetch_assoc($res) : null; + $aid = $row ? (int) $row['alliance'] : 0; + + if ($aid <= 0) { + return self::DONATE_NO_ALLIANCE; + } + + // bonusul nu trebuie sa fie in curs de upgrade + $state = $this->getState($aid); + + if ($state[$btype]['upgrade_end'] > time()) { + return self::DONATE_UPGRADING; + } + + if ($state[$btype]['level'] >= self::MAX_LEVEL) { + return self::DONATE_INVALID; + } + + // valoarea contorizata (triplata sau nu) si plafonul zilnic + $counted = $triple ? $total * 3 : $total; + $limit = self::dailyLimit($this->highestLevel($aid)); + $already = $this->donatedToday($uid); + + if ($already + $counted > $limit) { + return self::DONATE_LIMIT; + } + + // aurul pentru triplare + if ($triple) { + $cost = defined('ALLIANCE_BONUS_TRIPLE_GOLD') ? (int) ALLIANCE_BONUS_TRIPLE_GOLD : 3; + + if ((int) $session->gold < $cost) { + return self::DONATE_NO_GOLD; + } + } + + // Resursele trebuie sa existe in sat. + // FIX: getResource() nu exista in clasa de baza de date; randul satului + // (cu wood/clay/iron/crop) se citeste cu getVillage(), fara cache, ca sa + // vedem valorile de dupa ultima productie, nu unele vechi de cateva zeci + // de secunde. + $vres = $database->getVillage($wref, 0, false); + + if (!$vres) { + return self::DONATE_RESOURCES; + } + + $fields = array('wood', 'clay', 'iron', 'crop'); + + foreach ($fields as $i => $f) { + if ((float) $vres[$f] < $clean[$i]) { + return self::DONATE_RESOURCES; + } + } + + /* ---- de aici incolo modificam starea; totul intr-o tranzactie ---- */ + mysqli_query($this->db, "START TRANSACTION"); + + // ATENTIE LA SEMN: modifyResource cu modul 0 SCADE deja + // ("wood = wood - $wood"). Trimiterea de valori negative ar fi + // ADAUGAT resurse - aceeasi capcana ca la aurul de la demolare. + $ok = $database->modifyResource($wref, $clean[0], $clean[1], $clean[2], $clean[3], 0); + + if (!$ok) { + mysqli_query($this->db, "ROLLBACK"); + return self::DONATE_RESOURCES; + } + + // randul de bonus poate lipsi: il cream la prima donatie + mysqli_query($this->db, + "INSERT INTO " . TB_PREFIX . "alliance_bonus (aid, btype, level, pool, upgrade_end) + VALUES (" . $aid . ", " . $btype . ", 0, 0, 0) + ON DUPLICATE KEY UPDATE aid = aid"); + + // adaugam in fond DOAR daca bonusul tot nu e in upgrade (protejeaza + // impotriva a doua donatii simultane care ar sari peste verificare) + $res = mysqli_query($this->db, + "UPDATE " . TB_PREFIX . "alliance_bonus + SET pool = pool + " . $counted . " + WHERE aid = " . $aid . " AND btype = " . $btype . " + AND upgrade_end <= " . time() . " AND level < " . self::MAX_LEVEL . " LIMIT 1"); + + if (!$res || mysqli_affected_rows($this->db) === 0) { + mysqli_query($this->db, "ROLLBACK"); + return self::DONATE_UPGRADING; + } + + $day = (int) floor(time() / 86400); + mysqli_query($this->db, + "INSERT INTO " . TB_PREFIX . "alliance_donation (uid, day, amount) + VALUES (" . $uid . ", " . $day . ", " . $counted . ") + ON DUPLICATE KEY UPDATE amount = amount + " . $counted); + + mysqli_query($this->db, + "INSERT INTO " . TB_PREFIX . "alliance_donation_log (aid, uid, btype, amount, time) + VALUES (" . $aid . ", " . $uid . ", " . $btype . ", " . $counted . ", " . time() . ")"); + + if ($triple) { + $cost = defined('ALLIANCE_BONUS_TRIPLE_GOLD') ? (int) ALLIANCE_BONUS_TRIPLE_GOLD : 3; + $database->modifyGold($uid, $cost, 0); + $session->gold -= $cost; + } + + mysqli_query($this->db, "COMMIT"); + + // daca fondul a atins pragul, pornim upgrade-ul + $this->startUpgradeIfReady($aid, $btype); + + unset(self::$levelCache[$aid]); + + return self::DONATE_OK; + } + + /** + * Porneste numaratoarea daca fondul acopera costul nivelului urmator. + * Costul se scade din fond, ca surplusul sa se reporteze la nivelul urmator. + */ + public function startUpgradeIfReady($aid, $btype) + { + $aid = (int) $aid; + $btype = (int) $btype; + + $res = mysqli_query($this->db, + "SELECT level, pool, upgrade_end FROM " . TB_PREFIX . "alliance_bonus + WHERE aid = " . $aid . " AND btype = " . $btype . " LIMIT 1"); + $row = $res ? mysqli_fetch_assoc($res) : null; + + if (!$row || (int) $row['upgrade_end'] > time() || (int) $row['level'] >= self::MAX_LEVEL) { + return false; + } + + $level = (int) $row['level']; + $cost = self::costFor($level); + + if ($cost <= 0 || (float) $row['pool'] < $cost) { + return false; + } + + $end = time() + self::upgradeSeconds($level); + + mysqli_query($this->db, + "UPDATE " . TB_PREFIX . "alliance_bonus + SET pool = pool - " . $cost . ", upgrade_end = " . $end . " + WHERE aid = " . $aid . " AND btype = " . $btype . " + AND upgrade_end <= " . time() . " LIMIT 1"); + + return true; + } + + /** + * Finalizeaza upgrade-urile expirate. Se apeleaza din Automation. + * Dupa crestere, verificam din nou fondul: daca surplusul acopera si + * nivelul urmator, upgrade-ul continua fara alta donatie. + */ + public function processUpgrades() + { + if (!self::enabled()) { + return 0; + } + + $now = time(); + $done = 0; + + $res = mysqli_query($this->db, + "SELECT aid, btype FROM " . TB_PREFIX . "alliance_bonus + WHERE upgrade_end > 0 AND upgrade_end <= " . $now); + + $rows = array(); + + while ($res && ($row = mysqli_fetch_assoc($res))) { + $rows[] = array((int) $row['aid'], (int) $row['btype']); + } + + foreach ($rows as $r) { + list($aid, $btype) = $r; + + $ok = mysqli_query($this->db, + "UPDATE " . TB_PREFIX . "alliance_bonus + SET level = level + 1, upgrade_end = 0 + WHERE aid = " . $aid . " AND btype = " . $btype . " + AND upgrade_end > 0 AND upgrade_end <= " . $now . " + AND level < " . self::MAX_LEVEL . " LIMIT 1"); + + if ($ok && mysqli_affected_rows($this->db) > 0) { + $done++; + unset(self::$levelCache[$aid]); + $this->startUpgradeIfReady($aid, $btype); + } + } + + return $done; + } + + /** Contributia fiecarui membru, pentru afisare. */ + public function contributions($aid, $limit = 30) + { + if (!self::enabled()) { + return array(); + } + + $aid = (int) $aid; + $limit = max(1, min(100, (int) $limit)); + $out = array(); + + $res = mysqli_query($this->db, + "SELECT d.uid, u.username, SUM(d.amount) AS total + FROM " . TB_PREFIX . "alliance_donation_log d + LEFT JOIN " . TB_PREFIX . "users u ON u.id = d.uid + WHERE d.aid = " . $aid . " + GROUP BY d.uid, u.username + ORDER BY total DESC + LIMIT " . $limit); + + while ($res && ($row = mysqli_fetch_assoc($res))) { + $out[] = array( + 'uid' => (int) $row['uid'], + 'username' => (string) $row['username'], + 'total' => (float) $row['total'], + ); + } + + return $out; + } + + /* ------------------------------------------------------------------ */ + /* Ajutor pentru hook-urile din joc */ + /* ------------------------------------------------------------------ */ + + /** + * Multiplicatorul unui bonus pentru un jucator, ca numar (1.0 = fara bonus). + * Folosit de Technology, Battle, Market si Building. + * + * Rezultatul e cache-uit pe cerere: se cere de multe ori intr-o singura + * pagina (fiecare unitate din lista de instruire, fiecare val din lupta). + */ + public static function multiplier($uid, $btype) + { + static $cache = array(); + + $uid = (int) $uid; + $btype = (int) $btype; + $key = $uid . ':' . $btype; + + if (isset($cache[$key])) { + return $cache[$key]; + } + + if (!self::enabled() || $uid <= 0) { + return $cache[$key] = 1.0; + } + + $engine = new self(); + $level = $engine->effectiveLevel($uid, $btype); + $pct = self::percentFor($btype, $level); + + return $cache[$key] = 1.0 + ($pct / 100.0); + } +} diff --git a/GameEngine/Automation.php b/GameEngine/Automation.php index 63442fbe..8a301032 100644 --- a/GameEngine/Automation.php +++ b/GameEngine/Automation.php @@ -52,6 +52,7 @@ include_once("Data/hero_full.php"); include_once("Data/cp.php"); include_once("Units.php"); include_once("Battle.php"); +include_once("AllianceBonus.php"); include_once("Technology.php"); include_once("Ranking.php"); include_once("Generator.php"); @@ -149,6 +150,12 @@ class Automation { $this->updateGeneralAttack(); $this->checkInvitedPlayes(); $this->updateStore(); + + // Finalizeaza upgrade-urile de bonus de alianta ajunse la termen. + if (class_exists('AllianceBonus') && AllianceBonus::enabled()) { + $allianceBonus = new AllianceBonus(); + $allianceBonus->processUpgrades(); + } $this->CheckBan(); $this->regenerateOasisTroops(); $this->medals(); diff --git a/GameEngine/Battle.php b/GameEngine/Battle.php index af1b25cd..b9bcf69c 100644 --- a/GameEngine/Battle.php +++ b/GameEngine/Battle.php @@ -1097,6 +1097,33 @@ class Battle { } } + // Bonusul de alianta "Metallurgy": forta trupelor creste peste + // upgrade-urile de fierarie, care sunt deja aplicate mai sus pe fiecare + // unitate. Se inmulteste cu ele, nu se aduna - la fel ca in T4. + // + // Se aplica pe toate cele patru totaluri, ca sa acopere si atacul, si + // apararea: aceeasi functie calculeaza ambele parti, in functie de rolul + // jucatorului in lupta. + if (class_exists('AllianceBonus') && AllianceBonus::enabled()) { + $metalOwner = 0; + + if (isset($Attacker) && (int) $Attacker > 0) { + global $database; + $metalOwner = (int) $database->getVillageField((int) $Attacker, 'owner'); + } + + if ($metalOwner > 0) { + $metalMult = AllianceBonus::multiplier($metalOwner, AllianceBonus::METALLURGY); + + if ($metalMult > 1.0) { + $ap *= $metalMult; + $cap *= $metalMult; + $dp *= $metalMult; + $cdp *= $metalMult; + } + } + } + return [ 'ap' => $ap, 'cap' => $cap, diff --git a/GameEngine/Building.php b/GameEngine/Building.php index c754e124..507fceb1 100755 --- a/GameEngine/Building.php +++ b/GameEngine/Building.php @@ -1644,6 +1644,18 @@ class Building { $cpTot += self::buildingCP($building, $lvl); } + // Bonusul de alianta "Philosophy": mai multe puncte de cultura. + // Se aplica peste CP-ul dat de cladiri (si, prin acesta, peste coifurile + // eroului, care se adauga separat). Serbarile din primarie NU sunt + // afectate - ele nu trec pe aici, se acorda direct la finalizare. + if (class_exists('AllianceBonus') && AllianceBonus::enabled()) { + $cpOwner = (int) $database->getVillageField($vid, 'owner'); + + if ($cpOwner > 0) { + $cpTot = (int) round($cpTot * AllianceBonus::multiplier($cpOwner, AllianceBonus::PHILOSOPHY)); + } + } + mysqli_query( $database->dblink, " diff --git a/GameEngine/Database/DatabaseMovementQueries.php b/GameEngine/Database/DatabaseMovementQueries.php index ec57271d..0ef4149b 100644 --- a/GameEngine/Database/DatabaseMovementQueries.php +++ b/GameEngine/Database/DatabaseMovementQueries.php @@ -189,44 +189,59 @@ trait DatabaseMovementQueries { } function addMovement($type, $from, $to, $ref, $time, $endtime, $send = 1, $wood = 0, $clay = 0, $iron = 0, $crop = 0, $ref2 = 0) { - // always prepare for multiple inserts at once - if (!is_array($type)) { - $type = [$type]; - $from = [$from]; - $to = [$to]; - $ref = [$ref]; - $time = [$time]; - $endtime = [$endtime]; - $send = [$send]; - $wood = [$wood]; - $clay = [$clay]; - $iron = [$iron]; - $crop = [$crop]; - $ref2 = [$ref2]; + // Caz 1: apel simplu, un singur movement + if (!is_array($type)) { + $type = [$type]; + $from = [$from]; + $to = [$to]; + $ref = [$ref]; + $time = [$time]; + $endtime = [$endtime]; + $send = [$send]; + $wood = [$wood]; + $clay = [$clay]; + $iron = [$iron]; + $crop = [$crop]; + $ref2 = [$ref2]; + } else { + // Caz 2: apel multiplu - $type e array, dar restul pot fi int + // le transformam si pe ele in array de aceeasi lungime + $count = count($type); + if (!is_array($from)) $from = array_fill(0, $count, $from); + if (!is_array($to)) $to = array_fill(0, $count, $to); + if (!is_array($ref)) $ref = array_fill(0, $count, $ref); + if (!is_array($time)) $time = array_fill(0, $count, $time); + if (!is_array($endtime)) $endtime = array_fill(0, $count, $endtime); + if (!is_array($send)) $send = array_fill(0, $count, $send); + if (!is_array($wood)) $wood = array_fill(0, $count, $wood); + if (!is_array($clay)) $clay = array_fill(0, $count, $clay); + if (!is_array($iron)) $iron = array_fill(0, $count, $iron); + if (!is_array($crop)) $crop = array_fill(0, $count, $crop); + if (!is_array($ref2)) $ref2 = array_fill(0, $count, $ref2); + } + + $counter = 0; + $pairs = []; + + foreach ($type as $index => $typeValue) { + // ?? 0 ca safety, sa nu mai dea niciodata warning + $pairs[] = '(0, '.(int) $typeValue.', '.(int) ($from[$index] ?? 0).', '.(int) ($to[$index] ?? 0).', '.(int) ($ref[$index] ?? 0).', '.(int) ($ref2[$index] ?? 0).', '.(int) ($time[$index] ?? 0).', '.(int) ($endtime[$index] ?? 0).', 0, '.(int) ($send[$index] ?? 1).', '.(int) ($wood[$index] ?? 0).', '.(int) ($clay[$index] ?? 0).', '.(int) ($iron[$index] ?? 0).', '.(int) ($crop[$index] ?? 0).')'; + + if ($counter++ > 25) { + $q = "INSERT INTO " . TB_PREFIX . "movement (moveid, sort_type, `from`, `to`, ref, ref2, starttime, endtime, proc, send, wood, clay, iron, crop) VALUES ".implode(', ', $pairs); + mysqli_query($this->dblink,$q); + $pairs = []; + $counter = 0; } + } - $counter = 0; - $pairs = []; - - foreach ($type as $index => $typeValue) { - $pairs[] = '(0, '.(int) $typeValue.', '.(int) $from[$index].', '.(int) $to[$index].', '.(int) $ref[$index].', '.(int) $ref2[$index].', '.(int) $time[$index].', '.(int) $endtime[$index].', 0, '.(int) $send[$index].', '.(int) $wood[$index].', '.(int) $clay[$index].', '.(int) $iron[$index].', '.(int) $crop[$index].')'; - - if ($counter++ > 25) { - $q = "INSERT INTO " . TB_PREFIX . "movement (moveid, sort_type, `from`, `to`, ref, ref2, starttime, endtime, proc, send, wood, clay, iron, crop) VALUES ".implode(', ', $pairs); - mysqli_query($this->dblink,$q); - - $pairs = []; - $counter = 0; - } - } - - if ($counter > 0) { - $q = "INSERT INTO " . TB_PREFIX . "movement (moveid, sort_type, `from`, `to`, ref, ref2, starttime, endtime, proc, send, wood, clay, iron, crop) VALUES " . implode( ', ', $pairs ); - return mysqli_query( $this->dblink, $q ); - } else { - return true; - } - } + if ($counter > 0) { + $q = "INSERT INTO " . TB_PREFIX . "movement (moveid, sort_type, `from`, `to`, ref, ref2, starttime, endtime, proc, send, wood, clay, iron, crop) VALUES " . implode( ', ', $pairs ); + return mysqli_query( $this->dblink, $q ); + } else { + return true; + } +} function addAttack($vid, $t1, $t2, $t3, $t4, $t5, $t6, $t7, $t8, $t9, $t10, $t11, $type, $ctar1, $ctar2, $spy,$b1=0,$b2=0,$b3=0,$b4=0,$b5=0,$b6=0,$b7=0,$b8=0) { if (!is_array($vid)) { diff --git a/GameEngine/Lang/en.php b/GameEngine/Lang/en.php index 2abfe746..db1bfbd7 100755 --- a/GameEngine/Lang/en.php +++ b/GameEngine/Lang/en.php @@ -4200,3 +4200,40 @@ tz_def('ADM_THE_7_DAY_BALANCE_FILLS_IN_AS_MERCHANT_DELIV', 'The 7-day balance fi tz_def('ADM_EDIT_THE_REWARD_EACH_QUEST_GRANTS_WOOD_CLAY', 'Edit the reward each quest grants (wood / clay / iron / crop / gold / Plus days) and the requirement level (e.g. main-building level for building quests). Values are seeded from the shipped defaults, so nothing changes until you edit. The two quest variants have different quests and rewards — pick the one your server uses (players on'); tz_def('ADM_IN_THE_QUEST_TEMPLATES_QUESTS_MARKED', 'in the quest templates. Quests marked'); tz_def('ADM_KEEP_THEIR_ORIGINAL_HARDCODED_LOGIC_CONDITIO', 'keep their original hardcoded logic (conditional rewards, atomic milestone claims, special mechanics) and are not affected by edits here. The reward numbers shown inside each quest\'s on-screen text are separate template strings — edits here change what is actually granted; update the quest language strings if you want the preview to match.'); + +////////////////////////////////////////////////////////////////////////////////////////////////////// +// BONUSURI DE ALIANTA (port T4) +////////////////////////////////////////////////////////////////////////////////////////////////////// +tz_def('ALLYBONUS_TAB', 'Bonuses'); +tz_def('ALLYBONUS_RECRUITMENT', 'Recruitment'); +tz_def('ALLYBONUS_PHILOSOPHY', 'Philosophy'); +tz_def('ALLYBONUS_METALLURGY', 'Metallurgy'); +tz_def('ALLYBONUS_COMMERCE', 'Commerce'); +tz_def('ALLYBONUS_LEVEL', 'Level'); +tz_def('ALLYBONUS_NEXT', 'next'); +tz_def('ALLYBONUS_MAXED', 'Fully unlocked'); +tz_def('ALLYBONUS_UNLOCKING', 'Unlocking level'); +tz_def('ALLYBONUS_DONATE', 'Donate'); +tz_def('ALLYBONUS_TRIPLE', 'Triple this donation'); +tz_def('ALLYBONUS_DAILY_LEFT', 'Your donation allowance left today'); +tz_def('ALLYBONUS_CONTRIBUTORS', 'Contributions'); +tz_def('ALLYBONUS_MEMBER', 'Member'); +tz_def('ALLYBONUS_TOTAL', 'Donated'); +tz_def('ALLYBONUS_MSG_OK', 'Resources donated.'); +tz_def('ALLYBONUS_MSG_UPGRADING', 'This bonus is currently being unlocked; donations are paused.'); +tz_def('ALLYBONUS_MSG_LIMIT', 'That would exceed your daily donation limit.'); +tz_def('ALLYBONUS_MSG_RESOURCES', 'Not enough resources in this village.'); +tz_def('ALLYBONUS_MSG_NOGOLD', 'Not enough gold to triple this donation.'); +tz_def('ALLYBONUS_MSG_NOALLY', 'You are not in an alliance.'); +tz_def('ALLYBONUS_MSG_INVALID', 'Invalid donation.'); +tz_def('ALLYBONUS_HINT', 'The resource type does not matter, only the total amount. While a level is unlocking, that bonus cannot receive donations.'); + +////////////////////////////////////////////////////////////////////////////////////////////////////// +// PANOU DE ADMINISTRARE - pachet grafic si bonusuri de alianta +////////////////////////////////////////////////////////////////////////////////////////////////////// +tz_def('ADM_SERVER_GRAPHIC_PACK', 'Server graphic pack'); +tz_def('ADM_SERVER_GRAPHIC_PACK_TIP', 'The graphic pack every player sees by default, read from the gpack/ folder.'); +tz_def('ADM_PLAYER_GRAPHIC_PACKS', 'Player graphic packs'); +tz_def('ADM_PLAYER_GRAPHIC_PACKS_TIP', 'When enabled, players can point their profile at their own graphic pack (Profile → Graphics). When disabled, everyone sees the server pack.'); +tz_def('ADM_ALLIANCE_BONUSES', 'Alliance bonuses'); +tz_def('ADM_ALLIANCE_BONUSES_TIP', 'T4 alliance bonuses: members donate resources to unlock Recruitment, Philosophy, Metallurgy and Commerce.'); diff --git a/GameEngine/Lang/fr.php b/GameEngine/Lang/fr.php index a673714f..bbfe6454 100644 --- a/GameEngine/Lang/fr.php +++ b/GameEngine/Lang/fr.php @@ -4143,3 +4143,40 @@ tz_def('ADM_THE_7_DAY_BALANCE_FILLS_IN_AS_MERCHANT_DELIV', 'Le bilan sur 7 jours tz_def('ADM_EDIT_THE_REWARD_EACH_QUEST_GRANTS_WOOD_CLAY', 'Modifiez la récompense de chaque quête (bois / argile / fer / céréales / or / jours de Plus) et le niveau requis (p. ex. niveau du bâtiment principal pour les quêtes de construction). Les valeurs proviennent des réglages livrés par défaut, rien ne change tant que vous ne modifiez pas. Les deux variantes de quêtes ont des quêtes et des récompenses différentes — choisissez celle qu\'utilise votre serveur (les joueurs en'); tz_def('ADM_IN_THE_QUEST_TEMPLATES_QUESTS_MARKED', 'dans les modèles de quêtes. Les quêtes marquées'); tz_def('ADM_KEEP_THEIR_ORIGINAL_HARDCODED_LOGIC_CONDITIO', 'conservent leur logique d\'origine codée en dur (récompenses conditionnelles, réclamations d\'étapes atomiques, mécaniques spéciales) et ne sont pas affectées par ces modifications. Les montants affichés dans le texte de chaque quête sont des chaînes de modèle distinctes — les modifications ici changent ce qui est réellement accordé ; mettez à jour les chaînes de langue si vous voulez que l\'aperçu corresponde.'); + +////////////////////////////////////////////////////////////////////////////////////////////////////// +// BONUSURI DE ALIANTA (port T4) +////////////////////////////////////////////////////////////////////////////////////////////////////// +tz_def('ALLYBONUS_TAB', 'Bonus'); +tz_def('ALLYBONUS_RECRUITMENT', 'Recrutement'); +tz_def('ALLYBONUS_PHILOSOPHY', 'Philosophie'); +tz_def('ALLYBONUS_METALLURGY', 'Métallurgie'); +tz_def('ALLYBONUS_COMMERCE', 'Commerce'); +tz_def('ALLYBONUS_LEVEL', 'Niveau'); +tz_def('ALLYBONUS_NEXT', 'suivant'); +tz_def('ALLYBONUS_MAXED', 'Entièrement débloqué'); +tz_def('ALLYBONUS_UNLOCKING', 'Déblocage du niveau'); +tz_def('ALLYBONUS_DONATE', 'Faire un don'); +tz_def('ALLYBONUS_TRIPLE', 'Tripler ce don'); +tz_def('ALLYBONUS_DAILY_LEFT', 'Votre quota de don restant aujourd\'hui'); +tz_def('ALLYBONUS_CONTRIBUTORS', 'Contributions'); +tz_def('ALLYBONUS_MEMBER', 'Membre'); +tz_def('ALLYBONUS_TOTAL', 'Donné'); +tz_def('ALLYBONUS_MSG_OK', 'Ressources données.'); +tz_def('ALLYBONUS_MSG_UPGRADING', 'Ce bonus est en cours de déblocage ; les dons sont suspendus.'); +tz_def('ALLYBONUS_MSG_LIMIT', 'Cela dépasserait votre limite de don quotidienne.'); +tz_def('ALLYBONUS_MSG_RESOURCES', 'Pas assez de ressources dans ce village.'); +tz_def('ALLYBONUS_MSG_NOGOLD', 'Pas assez d\'or pour tripler ce don.'); +tz_def('ALLYBONUS_MSG_NOALLY', 'Vous n\'êtes pas dans une alliance.'); +tz_def('ALLYBONUS_MSG_INVALID', 'Don invalide.'); +tz_def('ALLYBONUS_HINT', 'Le type de ressource n\'a pas d\'importance, seul le total compte. Pendant le déblocage d\'un niveau, ce bonus n\'accepte plus de dons.'); + +////////////////////////////////////////////////////////////////////////////////////////////////////// +// PANOU DE ADMINISTRARE - pachet grafic si bonusuri de alianta +////////////////////////////////////////////////////////////////////////////////////////////////////// +tz_def('ADM_SERVER_GRAPHIC_PACK', 'Pack graphique du serveur'); +tz_def('ADM_SERVER_GRAPHIC_PACK_TIP', 'Le pack graphique que voient tous les joueurs par défaut, lu depuis le dossier gpack/.'); +tz_def('ADM_PLAYER_GRAPHIC_PACKS', 'Packs graphiques des joueurs'); +tz_def('ADM_PLAYER_GRAPHIC_PACKS_TIP', 'Si activé, les joueurs peuvent choisir leur propre pack graphique depuis leur profil (Profil → Graphismes). Si désactivé, tout le monde voit le pack du serveur.'); +tz_def('ADM_ALLIANCE_BONUSES', 'Bonus d\'alliance'); +tz_def('ADM_ALLIANCE_BONUSES_TIP', 'Bonus d\'alliance T4 : les membres donnent des ressources pour débloquer Recrutement, Philosophie, Métallurgie et Commerce.'); diff --git a/GameEngine/Lang/ro.php b/GameEngine/Lang/ro.php index b3508976..75dfabe9 100644 --- a/GameEngine/Lang/ro.php +++ b/GameEngine/Lang/ro.php @@ -3940,3 +3940,40 @@ tz_def('ADM_THE_7_DAY_BALANCE_FILLS_IN_AS_MERCHANT_DELIV', 'Bilantul pe 7 zile s tz_def('ADM_EDIT_THE_REWARD_EACH_QUEST_GRANTS_WOOD_CLAY', 'Editeaza recompensa acordata de fiecare misiune (lemn / lut / fier / cereale / aur / zile de Plus) si nivelul necesar (de ex. nivelul cladirii principale pentru misiunile de constructie). Valorile pornesc de la cele implicite livrate, deci nu se schimba nimic pana nu editezi. Cele doua variante de misiuni au misiuni si recompense diferite — alege-o pe cea folosita de serverul tau (jucatorii pe'); tz_def('ADM_IN_THE_QUEST_TEMPLATES_QUESTS_MARKED', 'in sabloanele de misiuni. Misiunile marcate'); tz_def('ADM_KEEP_THEIR_ORIGINAL_HARDCODED_LOGIC_CONDITIO', 'isi pastreaza logica originala scrisa in cod (recompense conditionate, revendicari atomice de etape, mecanici speciale) si nu sunt afectate de modificarile de aici. Sumele afisate in textul fiecarei misiuni sunt siruri separate de sablon — modificarile de aici schimba ce se acorda efectiv; actualizeaza sirurile de limba daca vrei ca previzualizarea sa corespunda.'); + +////////////////////////////////////////////////////////////////////////////////////////////////////// +// BONUSURI DE ALIANTA (port T4) +////////////////////////////////////////////////////////////////////////////////////////////////////// +tz_def('ALLYBONUS_TAB', 'Bonusuri'); +tz_def('ALLYBONUS_RECRUITMENT', 'Recrutare'); +tz_def('ALLYBONUS_PHILOSOPHY', 'Filosofie'); +tz_def('ALLYBONUS_METALLURGY', 'Metalurgie'); +tz_def('ALLYBONUS_COMMERCE', 'Comert'); +tz_def('ALLYBONUS_LEVEL', 'Nivel'); +tz_def('ALLYBONUS_NEXT', 'urmator'); +tz_def('ALLYBONUS_MAXED', 'Deblocat complet'); +tz_def('ALLYBONUS_UNLOCKING', 'Se deblocheaza nivelul'); +tz_def('ALLYBONUS_DONATE', 'Doneaza'); +tz_def('ALLYBONUS_TRIPLE', 'Tripleaza aceasta donatie'); +tz_def('ALLYBONUS_DAILY_LEFT', 'Cat mai poti dona azi'); +tz_def('ALLYBONUS_CONTRIBUTORS', 'Contributii'); +tz_def('ALLYBONUS_MEMBER', 'Membru'); +tz_def('ALLYBONUS_TOTAL', 'Donat'); +tz_def('ALLYBONUS_MSG_OK', 'Resurse donate.'); +tz_def('ALLYBONUS_MSG_UPGRADING', 'Acest bonus se deblocheaza acum; donatiile sunt oprite.'); +tz_def('ALLYBONUS_MSG_LIMIT', 'Ai depasi plafonul zilnic de donatie.'); +tz_def('ALLYBONUS_MSG_RESOURCES', 'Nu ai destule resurse in acest sat.'); +tz_def('ALLYBONUS_MSG_NOGOLD', 'Nu ai destul aur ca sa triplezi donatia.'); +tz_def('ALLYBONUS_MSG_NOALLY', 'Nu esti intr-o alianta.'); +tz_def('ALLYBONUS_MSG_INVALID', 'Donatie invalida.'); +tz_def('ALLYBONUS_HINT', 'Tipul resursei nu conteaza, ci doar totalul. Cat timp un nivel se deblocheaza, bonusul acela nu mai primeste donatii.'); + +////////////////////////////////////////////////////////////////////////////////////////////////////// +// PANOU DE ADMINISTRARE - pachet grafic si bonusuri de alianta +////////////////////////////////////////////////////////////////////////////////////////////////////// +tz_def('ADM_SERVER_GRAPHIC_PACK', 'Pachetul grafic al serverului'); +tz_def('ADM_SERVER_GRAPHIC_PACK_TIP', 'Pachetul grafic pe care il vad implicit toti jucatorii, citit din folderul gpack/.'); +tz_def('ADM_PLAYER_GRAPHIC_PACKS', 'Pachete grafice ale jucatorilor'); +tz_def('ADM_PLAYER_GRAPHIC_PACKS_TIP', 'Daca e activat, jucatorii isi pot alege propriul pachet grafic din profil (Profil → Grafica). Daca e dezactivat, toata lumea vede pachetul serverului.'); +tz_def('ADM_ALLIANCE_BONUSES', 'Bonusuri de alianta'); +tz_def('ADM_ALLIANCE_BONUSES_TIP', 'Bonusuri de alianta T4: membrii doneaza resurse ca sa deblocheze Recrutare, Filosofie, Metalurgie si Comert.'); diff --git a/GameEngine/Market.php b/GameEngine/Market.php index 59114952..0e7795ef 100755 --- a/GameEngine/Market.php +++ b/GameEngine/Market.php @@ -181,6 +181,14 @@ class Market if ($building->getTypeLevel(28) != 0) { $this->maxcarry *= $bid28[$building->getTypeLevel(28)]['attri'] / 100; } + + // Bonusul de alianta "Commerce". Se inmulteste cu biroul comercial, ca + // in T4: 750 de baza x 2.2 (Commerce 4) x 5 (birou 20) = 8250. + if (class_exists('AllianceBonus') && AllianceBonus::enabled()) { + $this->maxcarry *= AllianceBonus::multiplier((int) $session->uid, AllianceBonus::COMMERCE); + } + + $this->maxcarry = floor($this->maxcarry); } /** diff --git a/GameEngine/Technology.php b/GameEngine/Technology.php index 13c55279..660434cb 100755 --- a/GameEngine/Technology.php +++ b/GameEngine/Technology.php @@ -645,7 +645,12 @@ class Technology { // fiindca ramura e aleasa dupa TIPUL unitatii, nu dupa cladire. // Nu se aplica la atelier, unitati speciale sau capcane - la fel ca in T4. $each = $this->applyHeroTrainingBonus($each, $unit, $footies, $calvary); - + + // Bonusul de alianta "Recruitment": instruire mai rapida in toate + // cladirile de trupe. Se inmulteste cu bonusul eroului, ca in T4 (coiful + // mercenarului si bonusul de alianta se cumuleaza multiplicativ). + $each = $this->applyAllianceRecruitmentBonus($each); + return $each; } @@ -657,6 +662,38 @@ class Technology { * jucatorului. HeroBattleBonus::bonuses() are deja gard de feature flag si * cache per request, si intoarce null cand sistemul T4 e oprit. */ + /** + * Aplica bonusul de alianta "Recruitment" asupra timpului de instruire. + * + * Proprietarul se ia din satul in care se instruieste, nu din sesiune, ca sa + * fie corect si cand codul ruleaza in alt context (cron, sitter). + */ + private function applyAllianceRecruitmentBonus($each) { + global $village, $database; + + if (!class_exists('AllianceBonus') || !AllianceBonus::enabled()) { + return $each; + } + + // acelasi mod de a afla proprietarul ca la bonusul de erou de mai jos + $owner = (isset($village->wid) && $database) + ? (int) $database->getVillageField($village->wid, 'owner') + : 0; + + if ($owner <= 0) { + return $each; + } + + $mult = AllianceBonus::multiplier($owner, AllianceBonus::RECRUITMENT); + + if ($mult <= 1.0) { + return $each; + } + + // bonusul de X% inseamna productie mai rapida, deci timp impartit + return max(1, (int) round($each / $mult)); + } + private function applyHeroTrainingBonus($each, $unit, array $footies, array $calvary) { global $village, $database; diff --git a/Templates/Alliance/alli_menu.tpl b/Templates/Alliance/alli_menu.tpl index a134564e..f8e932ab 100644 --- a/Templates/Alliance/alli_menu.tpl +++ b/Templates/Alliance/alli_menu.tpl @@ -51,6 +51,13 @@ if ($session->alliance == $aid && $session->alliance > 0) { News + + | + > + + + + sit == 0) { diff --git a/Templates/Alliance/bonuses.tpl b/Templates/Alliance/bonuses.tpl new file mode 100644 index 00000000..f61cd23f --- /dev/null +++ b/Templates/Alliance/bonuses.tpl @@ -0,0 +1,202 @@ +donate($session->uid, $village->wid, $abType, $abAmounts, $abTriple); + + switch ($abResult) { + case AllianceBonus::DONATE_OK: + $abMessage = defined('ALLYBONUS_MSG_OK') ? ALLYBONUS_MSG_OK : 'Resources donated.'; + break; + case AllianceBonus::DONATE_UPGRADING: + $abMessage = defined('ALLYBONUS_MSG_UPGRADING') ? ALLYBONUS_MSG_UPGRADING + : 'This bonus is currently being unlocked; donations are paused.'; + $abError = true; + break; + case AllianceBonus::DONATE_LIMIT: + $abMessage = defined('ALLYBONUS_MSG_LIMIT') ? ALLYBONUS_MSG_LIMIT + : 'That would exceed your daily donation limit.'; + $abError = true; + break; + case AllianceBonus::DONATE_RESOURCES: + $abMessage = defined('ALLYBONUS_MSG_RESOURCES') ? ALLYBONUS_MSG_RESOURCES + : 'Not enough resources in this village.'; + $abError = true; + break; + case AllianceBonus::DONATE_NO_GOLD: + $abMessage = defined('ALLYBONUS_MSG_NOGOLD') ? ALLYBONUS_MSG_NOGOLD + : 'Not enough gold to triple this donation.'; + $abError = true; + break; + case AllianceBonus::DONATE_NO_ALLIANCE: + $abMessage = defined('ALLYBONUS_MSG_NOALLY') ? ALLYBONUS_MSG_NOALLY + : 'You are not in an alliance.'; + $abError = true; + break; + default: + $abMessage = defined('ALLYBONUS_MSG_INVALID') ? ALLYBONUS_MSG_INVALID + : 'Invalid donation.'; + $abError = true; + } +} + +/* ------------------------------------------------------------------ stare */ +$abAid = (int) $session->alliance; +$abState = $abEngine->getState($abAid); +$abHighest = $abEngine->highestLevel($abAid); +$abLimit = AllianceBonus::dailyLimit($abHighest); +$abUsed = $abEngine->donatedToday($session->uid); +$abLeft = max(0, $abLimit - $abUsed); +$abTypes = AllianceBonus::types(); +$abGpack = defined('GP_LOCATE') ? GP_LOCATE : 'gpack/travian_default/'; +?> + + + +
+ + +
+ + +

+ : + + / +

+ +
+ $abInfo) { + $abRow = $abState[$abT]; + $abLevel = (int) $abRow['level']; + $abNext = $abLevel + 1; + $abCost = AllianceBonus::costFor($abLevel); + $abPool = (float) $abRow['pool']; + $abBusy = $abRow['upgrade_end'] > time(); + $abPct = ($abCost > 0) ? max(0, min(100, $abPool / $abCost * 100)) : 100; + $abName = defined($abInfo['lang']) ? constant($abInfo['lang']) : ucfirst($abInfo['key']); +?> +
+
+ <?php echo $abName; ?> + +
+ + + / +  +% + +
+
+ + = AllianceBonus::MAX_LEVEL) { ?> +
+ +
+
+ + – + getTimeFormat($abRow['upgrade_end'] - time()); ?> +
+ +
+
+ / +  (: + +%) +
+ +
+ + + +
+ +
+
+ +
+ +
+ +
+ +
+ +
+ +contributions($abAid, 20); + + if ($abTop) { +?> +

+ + + + + + + + + + + +
+ + +
diff --git a/allianz.php b/allianz.php index 09aaaba6..d2abd882 100644 --- a/allianz.php +++ b/allianz.php @@ -220,6 +220,15 @@ $userPermissions = $database->getAlliPermissions($session->uid, $session->allian case 6: include("Templates/Alliance/chat.tpl"); break; + case 7: + // Bonusuri de alianta (port T4). Cu functia oprita tabul nu apare + // in meniu, dar cineva ar putea ajunge aici direct pe URL. + if (defined('NEW_FUNCTIONS_ALLIANCE_BONUSES') && NEW_FUNCTIONS_ALLIANCE_BONUSES) { + include("Templates/Alliance/bonuses.tpl"); + } else { + include("Templates/Alliance/overview.tpl"); + } + break; case 1: default: include("Templates/Alliance/overview.tpl"); diff --git a/gpack/travian_default/img/ally/bonusCommerce.png b/gpack/travian_default/img/ally/bonusCommerce.png new file mode 100644 index 00000000..5bd7f40d Binary files /dev/null and b/gpack/travian_default/img/ally/bonusCommerce.png differ diff --git a/gpack/travian_default/img/ally/bonusMetallurgy.png b/gpack/travian_default/img/ally/bonusMetallurgy.png new file mode 100644 index 00000000..c24620ff Binary files /dev/null and b/gpack/travian_default/img/ally/bonusMetallurgy.png differ diff --git a/gpack/travian_default/img/ally/bonusPhilosophy.png b/gpack/travian_default/img/ally/bonusPhilosophy.png new file mode 100644 index 00000000..d3fb96df Binary files /dev/null and b/gpack/travian_default/img/ally/bonusPhilosophy.png differ diff --git a/gpack/travian_default/img/ally/bonusRecruitment.png b/gpack/travian_default/img/ally/bonusRecruitment.png new file mode 100644 index 00000000..1865ae12 Binary files /dev/null and b/gpack/travian_default/img/ally/bonusRecruitment.png differ diff --git a/gpack/travian_default/img/ally/commerce-glow.png b/gpack/travian_default/img/ally/commerce-glow.png new file mode 100644 index 00000000..208d3519 Binary files /dev/null and b/gpack/travian_default/img/ally/commerce-glow.png differ diff --git a/gpack/travian_default/img/ally/commerce-stage-1.png b/gpack/travian_default/img/ally/commerce-stage-1.png new file mode 100644 index 00000000..93b7bc01 Binary files /dev/null and b/gpack/travian_default/img/ally/commerce-stage-1.png differ diff --git a/gpack/travian_default/img/ally/commerce-stage-2.png b/gpack/travian_default/img/ally/commerce-stage-2.png new file mode 100644 index 00000000..a688bbc2 Binary files /dev/null and b/gpack/travian_default/img/ally/commerce-stage-2.png differ diff --git a/gpack/travian_default/img/ally/metallurgy-glow.png b/gpack/travian_default/img/ally/metallurgy-glow.png new file mode 100644 index 00000000..9dd1e0ec Binary files /dev/null and b/gpack/travian_default/img/ally/metallurgy-glow.png differ diff --git a/gpack/travian_default/img/ally/metallurgy-stage-1.png b/gpack/travian_default/img/ally/metallurgy-stage-1.png new file mode 100644 index 00000000..462a3688 Binary files /dev/null and b/gpack/travian_default/img/ally/metallurgy-stage-1.png differ diff --git a/gpack/travian_default/img/ally/metallurgy-stage-2.png b/gpack/travian_default/img/ally/metallurgy-stage-2.png new file mode 100644 index 00000000..f6aa7f34 Binary files /dev/null and b/gpack/travian_default/img/ally/metallurgy-stage-2.png differ diff --git a/gpack/travian_default/img/ally/noAllianceBackground.png b/gpack/travian_default/img/ally/noAllianceBackground.png new file mode 100644 index 00000000..a4746e39 Binary files /dev/null and b/gpack/travian_default/img/ally/noAllianceBackground.png differ diff --git a/gpack/travian_default/img/ally/philosophy-glow.png b/gpack/travian_default/img/ally/philosophy-glow.png new file mode 100644 index 00000000..78470758 Binary files /dev/null and b/gpack/travian_default/img/ally/philosophy-glow.png differ diff --git a/gpack/travian_default/img/ally/philosophy-stage-1.png b/gpack/travian_default/img/ally/philosophy-stage-1.png new file mode 100644 index 00000000..6495bb1b Binary files /dev/null and b/gpack/travian_default/img/ally/philosophy-stage-1.png differ diff --git a/gpack/travian_default/img/ally/philosophy-stage-2.png b/gpack/travian_default/img/ally/philosophy-stage-2.png new file mode 100644 index 00000000..48bb2edd Binary files /dev/null and b/gpack/travian_default/img/ally/philosophy-stage-2.png differ diff --git a/gpack/travian_default/img/ally/recruitment-glow.png b/gpack/travian_default/img/ally/recruitment-glow.png new file mode 100644 index 00000000..20ba2cb8 Binary files /dev/null and b/gpack/travian_default/img/ally/recruitment-glow.png differ diff --git a/gpack/travian_default/img/ally/recruitment-stage-1.png b/gpack/travian_default/img/ally/recruitment-stage-1.png new file mode 100644 index 00000000..2ddec463 Binary files /dev/null and b/gpack/travian_default/img/ally/recruitment-stage-1.png differ diff --git a/gpack/travian_default/img/ally/recruitment-stage-2.png b/gpack/travian_default/img/ally/recruitment-stage-2.png new file mode 100644 index 00000000..639c9af1 Binary files /dev/null and b/gpack/travian_default/img/ally/recruitment-stage-2.png differ diff --git a/gpack/travian_t4/img/ally/bonusCommerce.png b/gpack/travian_t4/img/ally/bonusCommerce.png new file mode 100644 index 00000000..5bd7f40d Binary files /dev/null and b/gpack/travian_t4/img/ally/bonusCommerce.png differ diff --git a/gpack/travian_t4/img/ally/bonusMetallurgy.png b/gpack/travian_t4/img/ally/bonusMetallurgy.png new file mode 100644 index 00000000..c24620ff Binary files /dev/null and b/gpack/travian_t4/img/ally/bonusMetallurgy.png differ diff --git a/gpack/travian_t4/img/ally/bonusPhilosophy.png b/gpack/travian_t4/img/ally/bonusPhilosophy.png new file mode 100644 index 00000000..d3fb96df Binary files /dev/null and b/gpack/travian_t4/img/ally/bonusPhilosophy.png differ diff --git a/gpack/travian_t4/img/ally/bonusRecruitment.png b/gpack/travian_t4/img/ally/bonusRecruitment.png new file mode 100644 index 00000000..1865ae12 Binary files /dev/null and b/gpack/travian_t4/img/ally/bonusRecruitment.png differ diff --git a/gpack/travian_t4/img/ally/commerce-glow.png b/gpack/travian_t4/img/ally/commerce-glow.png new file mode 100644 index 00000000..208d3519 Binary files /dev/null and b/gpack/travian_t4/img/ally/commerce-glow.png differ diff --git a/gpack/travian_t4/img/ally/commerce-stage-1.png b/gpack/travian_t4/img/ally/commerce-stage-1.png new file mode 100644 index 00000000..93b7bc01 Binary files /dev/null and b/gpack/travian_t4/img/ally/commerce-stage-1.png differ diff --git a/gpack/travian_t4/img/ally/commerce-stage-2.png b/gpack/travian_t4/img/ally/commerce-stage-2.png new file mode 100644 index 00000000..a688bbc2 Binary files /dev/null and b/gpack/travian_t4/img/ally/commerce-stage-2.png differ diff --git a/gpack/travian_t4/img/ally/metallurgy-glow.png b/gpack/travian_t4/img/ally/metallurgy-glow.png new file mode 100644 index 00000000..9dd1e0ec Binary files /dev/null and b/gpack/travian_t4/img/ally/metallurgy-glow.png differ diff --git a/gpack/travian_t4/img/ally/metallurgy-stage-1.png b/gpack/travian_t4/img/ally/metallurgy-stage-1.png new file mode 100644 index 00000000..462a3688 Binary files /dev/null and b/gpack/travian_t4/img/ally/metallurgy-stage-1.png differ diff --git a/gpack/travian_t4/img/ally/metallurgy-stage-2.png b/gpack/travian_t4/img/ally/metallurgy-stage-2.png new file mode 100644 index 00000000..f6aa7f34 Binary files /dev/null and b/gpack/travian_t4/img/ally/metallurgy-stage-2.png differ diff --git a/gpack/travian_t4/img/ally/noAllianceBackground.png b/gpack/travian_t4/img/ally/noAllianceBackground.png new file mode 100644 index 00000000..a4746e39 Binary files /dev/null and b/gpack/travian_t4/img/ally/noAllianceBackground.png differ diff --git a/gpack/travian_t4/img/ally/philosophy-glow.png b/gpack/travian_t4/img/ally/philosophy-glow.png new file mode 100644 index 00000000..78470758 Binary files /dev/null and b/gpack/travian_t4/img/ally/philosophy-glow.png differ diff --git a/gpack/travian_t4/img/ally/philosophy-stage-1.png b/gpack/travian_t4/img/ally/philosophy-stage-1.png new file mode 100644 index 00000000..6495bb1b Binary files /dev/null and b/gpack/travian_t4/img/ally/philosophy-stage-1.png differ diff --git a/gpack/travian_t4/img/ally/philosophy-stage-2.png b/gpack/travian_t4/img/ally/philosophy-stage-2.png new file mode 100644 index 00000000..48bb2edd Binary files /dev/null and b/gpack/travian_t4/img/ally/philosophy-stage-2.png differ diff --git a/gpack/travian_t4/img/ally/recruitment-glow.png b/gpack/travian_t4/img/ally/recruitment-glow.png new file mode 100644 index 00000000..20ba2cb8 Binary files /dev/null and b/gpack/travian_t4/img/ally/recruitment-glow.png differ diff --git a/gpack/travian_t4/img/ally/recruitment-stage-1.png b/gpack/travian_t4/img/ally/recruitment-stage-1.png new file mode 100644 index 00000000..2ddec463 Binary files /dev/null and b/gpack/travian_t4/img/ally/recruitment-stage-1.png differ diff --git a/gpack/travian_t4/img/ally/recruitment-stage-2.png b/gpack/travian_t4/img/ally/recruitment-stage-2.png new file mode 100644 index 00000000..639c9af1 Binary files /dev/null and b/gpack/travian_t4/img/ally/recruitment-stage-2.png differ diff --git a/img/admin/admin.css b/img/admin/admin.css index c2d0a874..26e89478 100644 --- a/img/admin/admin.css +++ b/img/admin/admin.css @@ -18,96 +18,112 @@ body { /* Fix */ .online1, .online2, .online3, .online4, .online5 {width:12px; height:12px;} -/* Oberer Layer mit Menue ohne Werbung */ +/* Top layer with menu without ads */ #ltop1 {position:relative; width:100%; min-width:980px; height:100px; z-index:2; background-image:url(../un/l/mp.gif); background-repeat:repeat-x; left:0px; top:0px;} -/* Oberer Layer mit Menue mit Werbung */ +/* Top layer with menu with ads */ #ltop2 {position:relative; padding-left: 25%; width:100%; min-width:980px; height:100px; z-index:2; background-image:url(../un/l/mw.gif); background-repeat:repeat-x; left:0px; top:0px;} -/* - VERALTET - Oberer Layer mit Mindestbreite fuer IE6 */ -/*#ltop3 {width:777px;} */ - -/* - VERALTET - Oberer Layer mit Mindestbreite fuer IE6 bei Skyscraper */ +/* - DEPRECATED - Top layer with minimum width for IE6 with Skyscraper */ #ltop4 {width:911px;} -/* Den gesamten mittleren Teil umschliessendes Div */ -#lmidall {background-image: none; float: none; height: auto; margin: 0 auto; width: 980px;} +/* Div enclosing the entire middle section */ +#lmidall {background-image: none; float: none; height: auto; margin: 0 auto; width: 1350px;} -/* Den gesamten mittleren Teil umschliessendes Div */ +/* Div enclosing the entire middle section */ #lmidlc {position:relative; min-width:682px; float:left;} -/* Div mit linkem Menue */ +/* Div with left menu */ #lleft {position:relative; width:230px; height:450px; z-index:3; float:left; left:0px; top:-7px;} -/* Mittlerer Layer */ +/* Middle layer */ #lmid1 {position:relative; width:552px; float:left; border:0px;} -/* Hilfslayer ohne float wegen Netscape Bug (InGame) */ +/* Helper layer without float due to Netscape bug (InGame) */ #lmid2 {padding-top:38px; min-height:380px;} -/* Hilfslayer ohne float wegen Netscape Bug (OutGame) */ +/* Helper layer without float due to Netscape bug (OutGame) */ #lmid3 {padding-top:0px; top:-7px; min-height:440px;} -#lmid2,#lmid3 {position:relative; width:500px; background-image:url(../un/a/rand.gif); background-repeat:repeat-y; padding-bottom:10px; padding-left:26px; padding-right:26px;} +#lmid2, +#lmid3 { + position: relative; + width: 1000px; + padding-bottom: 10px; + padding-left: 26px; + padding-right: 26px; -/* Msgboxen */ + background-image: + url(../un/a/rand_left.gif), + url(../un/a/rand_right.gif); + + background-repeat: + repeat-y, + repeat-y; + + background-position: + left top, + right top; +} + +/* Message boxes */ #lmid3 .nb {position:absolute; width:200px; z-index:5; left:580px; top:63px; background-color:#fff;} -/* Rechter Layer fuer Doerferliste und Direktlinks ohne Skyscraper */ +/* Right layer for village list and direct links without Skyscraper */ #lright1 {position:relative; width:200px; padding-left:18px; z-index:5; float:left;} -/* Rechter Layer fuer Doerferliste und Direktlinks mit Skyscraper */ +/* Right layer for village list and direct links with Skyscraper */ #lright2 {position:relative; width:200px; padding-left:158px; z-index:5; float:left;} -/* Unteres Div fuer Footer background-color:#0FF; */ +/* Lower div for footer background-color:#0FF; */ #lbottom {position:relative; width:100%; height:25px; z-index:1; clear:both;} -/* Zusaetliches unteres Div (OutGame) */ +/* Additional lower div (OutGame) */ #lfooter1 {background-image:url(../un/a/btm.gif); background-repeat:repeat-x; width:100%; clear:both;} -/* Div innerhalb von lfooter1 (OutGame) */ +/* Div inside lfooter1 (OutGame) */ #lfooter2 {padding-top:15px; font-size:8pt; color:#666; text-align:center; width:800px;} -/* Div Layer fuer die Lageranzeige */ +/* Div layer for the storage display */ #lres, #lres0, #lres1, #lres2 {position:absolute; width:612px; height:20px; text-align:center; z-index:2;} -#lres0 {left:100px; top:100px;} /* mit Skyscraprer oder ohne Ad */ -#lres1 {left:100px; top:142px;} /* mit Fullsize Ad */ -#lres2 {left:100px; top:172px;} /* mit Bigsize Ad */ +#lres0 {left:100px; top:100px;} /* with Skyscraper or without ad */ +#lres1 {left:100px; top:142px;} /* with Fullsize ad */ +#lres2 {left:100px; top:172px;} /* with Bigsize ad */ -/* Div Layer fuer die Zeitanzeige */ +/* Div layer for the time display */ #ltime {position:absolute; width:220px; height:15px; z-index:3; left:5px; top:0px; color:#FFF; font-size:10px;} -/* Div fuer Truppenbewegungen*/ +/* Div for troop movements */ #ltbw0, #ltbw1 {position:relative; width:230px; z-index:5; padding-top:5px; padding-bottom:5px; left:49px; top:0px; float:left;} #ltbw1 {height:47px;} -/* Div fuer die Anzeige der Rohstoffproduktion */ +/* Div for displaying resource production */ #lrpr {position:relative; width:230px; padding-top:5px; padding-bottom:10px; left:49px; top:0px; float:left;} -/* Div fuer die Anzeige der Truppen im Dorf */ +/* Div for displaying troops in the village */ #ltrm {position:relative; width:230px; padding-top:10px; padding-bottom:0px; left:49px; top:0px; float:left;} -/* Div fuer die Anzeige der Bauauftraege */ +/* Div for displaying construction orders */ #lbau1 {position:relative; width:500px; top:0px; clear:both;} #lbau2 {position:relative; width:500px; z-index:20;} -/* Platzhalter fuer Float und Ersatz fuer min-height im IE6 */ +/* Placeholder for float and replacement for min-height in IE6 */ #lplz1 {position:relative; width:250px; height:310px; float:left;} #lplz2, #lplz3 {position:relative; height:400px; width:500px;} -/* Textmenue: Punkt1 | Punkt2 | Punkt3 */ +/* Text menu: Item1 | Item2 | Item3 */ .txt_menue {font-size:10pt;} -/* Alle Bilder per Default ohne Rahmen */ +/* All images by default without border */ img {border:0px;} -/* Groesse der Bilder: Rohstoffe, Dauer, Truppen */ +/* Size of images: Resources, duration, troops */ img.res, img.clock {width:18px; height:12px;} img.unit, tr.unit td img {width:16px; height:16px;} img.logo {width:116px; height:60px;} -/* Liste mit den Direktlinks */ +/* List with direct links */ ul.dl {margin-left:0px; margin-top:0px; padding-left:20px; padding-top:3px;} li.dl {margin-top:2px;} @@ -116,7 +132,7 @@ li.dl {margin-top:2px;} .center {text-align: center;} .nbr {white-space:nowrap;} -/* Navigation InGame */ +/* InGame navigation */ #n1, #n2, #n3, #n4, #n5 {width:70px; height:100px; background-repeat:no-repeat;} #n1:hover,#n2:hover,#n3:hover,#n4:hover {background-position:bottom;} #n1 {background-image:url(../un/l/n1.gif);} @@ -124,10 +140,10 @@ li.dl {margin-top:2px;} #n3 {background-image:url(../un/l/n3.gif);} #n4 {background-image:url(../un/l/n4.gif);} -/* - VERALTET - Abstand der oberen Navigation von Links */ +/* - DEPRECATED - Distance of top navigation from left */ /* #navileft {margin-left:231px;} */ -/* Schriftgroessen */ +/* Font sizes */ .f16 {font-size:16pt;} .f135 {font-size:13.5pt;} .f10 {font-size:10pt;} @@ -137,10 +153,10 @@ li.dl {margin-top:2px;} .f7 {font-size:7pt;} .f6 {font-size:6pt;} -/* e Schriftfarbe fuer Fehlermeldung Login/Anmeldung */ +/* e Text color for error message Login/Registration */ .e {color:#FF8000;} -/* Schriftfarbe fuer Inaktive Links */ +/* Text color for inactive links */ .c {color:#C0C0C0;} .c0 {color:#000000;} .c1 {color:#71D000;} @@ -150,10 +166,10 @@ li.dl {margin-top:2px;} .c5 {color:#FF0000;} .c6 {color:#B500A3;} -/* Dicke Schrift */ +/* Bold font */ .b {font-weight:bold} -/* Duenne Schrift */ +/* Normal font weight */ .t {font-weight:normal;} /* Links */ @@ -168,38 +184,38 @@ h1, h2, h3, span, form, img, li {margin:0; padding:0;} h1 {font-size:18pt;} h2 {font-size:13.5pt;} -/* Hintergrundbild fuer kleine Karte */ +/* Background image for small map */ .mbg {background-image:url(../un/m/map.jpg); z-index:1;} -/* Positionsangabe fur Hintergrundbild und zwei transparente Ebenen darueber (Felder,ImgMap) */ +/* Position specification for background image and two transparent layers above it (fields, ImgMap) */ .mbg,.mdiv {position:absolute; width:540px; height:450px; left:5px; top:10px;} -/* Div Layer fuer die Mouse Over Infobox (kleine Karte) */ +/* Div layer for the mouse-over infobox (small map) */ .map_infobox {position:absolute; width:170px; height:80px; z-index:50; left:360px; top:48px;} -/* Div Layer fuer die Mouse Over Infobox (grosse Karte) */ +/* Div layer for the mouse-over infobox (large map) */ .map_infobox_xxl {position:absolute; width:170px; height:80px; z-index:500; right:20px; top:20px;} -/* ausgegraute leere Tabelle */ +/* Grayed-out empty table */ .map_infobox_grey {background-color:#F0F0F0; width:100%;} table.map_infobox_grey tr {background-color: #FFF;} -/* Link zur grossen Karte */ +/* Link to large map */ .map_link_to_xxlmap {position:absolute; width:33px; height:25px; z-index:650; left:26px; top:88px;} -/* Formular zur Direkteingabe von Koordinaten (kleine Karte) */ +/* Form for direct coordinate input (small map) */ .map_insert_xy {position:absolute; width:180px; height:80px; z-index:50; left:20px; top:365px;} -/* Formular zur Direkteingabe von Koordinaten (grosse Karte) */ +/* Form for direct coordinate input (large map) */ .map_insert_xy_xxl {position:absolute; width:180px; height:80px; z-index:500; left:10px; top:465px;} -/* Koordinatenanzeige auf kleiner Karte links oben */ +/* Coordinate display on small map top left */ .map_show_xy {position:absolute; width:200px; height:80px; z-index:50; left:26px; top:38px;} -/* Koordinatenanzeige auf grosser Karte links oben */ +/* Coordinate display on large map top left */ .map_show_xy_xxl {position:absolute; width:200px; height:80px; z-index:500; left:10px; top:10px;} -/* Koordinaten xy der kleinen Karte */ +/* Coordinates xy of the small map */ .mx1,.mx2,.mx3,.mx4,.mx5,.mx6,.mx7,.my1,.my2,.my3,.my4,.my5,.my6,.my7 {position:absolute; z-index:30; width:35px; height:12px; font-size:7pt; text-align:center;} .mx1{left:14px; top:255px;} @@ -218,7 +234,7 @@ table.map_infobox_grey tr {background-color: #FFF;} .my2{left:194px; top:110px;} .my1{left:230px; top:90px;} -/* Felder kleine Karte */ +/* Fields small map */ .mt1{position:absolute; z-index:1; left:229px; top:57px;} .mt2{position:absolute; z-index:2; left:266px; top:77px;} .mt3{position:absolute; z-index:3; left:303px; top:97px;} @@ -275,17 +291,17 @@ table.map_infobox_grey tr {background-color: #FFF;} .mt48{position:absolute; z-index:12; left:198px; top:277px;} .mt49{position:absolute; z-index:13; left:235px; top:297px;} -/* Div Layer fur die Details auf der rechten Seite */ +/* Div layer for details on the right side */ .map_details_right {position:absolute; width:230px; height:110px; z-index:3; left:325px; top:100px;} -/* Div Layer fur die Details auf der rechten Seite */ +/* Div layer for details on the right side */ .map_details_actions {position:absolute; width:500px; height:40px; z-index:5; left:30px; top:360px;} -/* Div Layer fur die Details auf der rechten Seite */ +/* Div layer for details on the right side */ .map_details_troops {position:absolute; width:220px; height:220px; z-index:3; left:325px; top:220px;} -/* Dorfname fuer dorf1.php und dorf2.php */ +/* Village name for dorf1.php and dorf2.php */ .dname {position:absolute; width:500px; height:40px; z-index:4; left:26px; top:38px;} -/* Rohstofffelder Hintergrund */ +/* Resource fields background */ #f1,#f2,#f3,#f4,#f5,#f6,#f7,#f8,#f9,#f10 {position:absolute; width:300px; height:264px; left:15px; top:75px; background-repeat:no-repeat; z-index:1;} #f1 {background-image:url(../un/g/f1.jpg);} #f2 {background-image:url(../un/g/f2.jpg);} @@ -299,7 +315,7 @@ table.map_infobox_grey tr {background-color: #FFF;} #f10 {background-image:url(../un/g/f10.jpg);} #resfeld {position:absolute; width:300px; height:264px; left:15px; top:75px; z-index:3;} -/* Rohstofffelder Stufe */ +/* Resource fields level */ .rf1,.rf2,.rf3,.rf4,.rf5,.rf6,.rf7,.rf8,.rf9,.rf10,.rf11,.rf12,.rf13,.rf14,.rf15,.rf16,.rf17,.rf18 {position:absolute; z-index:2;} .rf1 {left: 93px; top:27px;} .rf2 {left: 156px; top:26px;} @@ -320,16 +336,16 @@ table.map_infobox_grey tr {background-color: #FFF;} .rf17 {left: 132px; top:223px;} .rf18 {left: 182px; top:227px;} -/* Div Layer fuer Dorfhintergrund */ +/* Div layer for village background */ .d2_x {position:absolute; width:540px; height:448px; z-index:1; left:5px; top:30px;} .d2_0 {background-image:url(../un/g/bg0.jpg);} -.d2_1 {background-image:url(../un/g/bg1.jpg);} /* Palisade (Gallier) */ -.d2_11 {background-image:url(../un/g/bg11.jpg);} /* Stadtmauer (Roemer) */ -.d2_12 {background-image:url(../un/g/bg12.jpg);} /* Erdwall (Germanen) */ +.d2_1 {background-image:url(../un/g/bg1.jpg);} /* Palisade (Gauls) */ +.d2_11 {background-image:url(../un/g/bg11.jpg);} /* City wall (Romans) */ +.d2_12 {background-image:url(../un/g/bg12.jpg);} /* Earth wall (Teutons) */ .d2_2 {background-image:url(../un/g/bg2.jpg);} .d2_3 {background-image:url(../un/g/bg3.jpg);} -/* Position der Gebaeude im Dorfzentrum */ +/* Position of buildings in the village center */ .d1{position:absolute; z-index:6; left:121px; top:82px;} .d2{position:absolute; z-index:9; left:204px; top:57px;} .d3{position:absolute; z-index:8; left:264px; top:47px;} @@ -355,7 +371,7 @@ table.map_infobox_grey tr {background-color: #FFF;} .d20{position:absolute; z-index:25; left:266px; top:306px;} .dx1 {position:absolute; z-index:5; left:318px; top:232px;} -/* ImgMap fuer Gebauedelinks */ +/* ImgMap for building links */ .dmap {position:absolute; width:422px; height:339px; z-index:30; left:68px; top:70px;} #ce {position:absolute; z-index:80;} @@ -364,7 +380,7 @@ table.map_infobox_grey tr {background-color: #FFF;} .popup4 {position:absolute; width:30px; height:30px; z-index:81; border: 0px solid #000000; left: 600px; top: 115px} .m_navi {position:absolute; width:116px; height:18px; z-index:82; left: 145px; top: 420px} -/* Login und Anmeldeformular */ +/* Login and registration form */ .p1 {border-style:dashed; border-width:1px; border-color:#C0C0C0; padding:6px;} .p2 {border-style:dashed; border-width:1px; border-color:#C0C0C0; padding:3px;} label { @@ -384,39 +400,39 @@ textarea {border:#71D000 solid; border-width: 1px;} input.f80 { width:80px;} input.f30 { width:30px;} -input.std {font-weight:bold; font-size:8pt; height:14pt;} /* Berichte, Nachrichten verschieben */ +input.std {font-weight:bold; font-size:8pt; height:14pt;} /* Move reports, messages */ -/* Rahmenfarbe der Tabelle */ +/* Border color of the table */ .tbg {background-color: #C0C0C0; width:100%; text-align:center; font-size:10pt;} -/* Zellenfarbe der Tabelle */ +/* Cell color of the table */ table.tbg tr {background-color: #FFFFFF;} -/* Hintergrundbild für Tabellenkopf */ +/* Background image for table header */ .rbg {background-color: #FFFFFF; font-weight:bold; background-image: url(../un/a/c2.gif);} -/* Tabellenzeile Grau */ +/* Table row gray */ table.tbg tr.cbg1 td, td.cbg1 {background-color:#F5F5F5} table.tbg td.cbg2 {background-color:#71D000} -/* Abstand links, in Tabellenzeile */ +/* Padding left, in table row */ table.tbg tr.s7 td, td.s7 {padding-left:7px; text-align:left} table.tbg tr.r7 td, td.r7 {padding-right:7px; text-align:right} -/* Abstand links und rechts in Tabellenzeile */ +/* Padding left and right in table row */ .slr3 { padding-left:3px; padding-right:3px; text-align:center} -/* Rahmen für Treffer in der Statistik */ +/* Border for hits in statistics */ table.tbg td.ou {border-top:1px solid #71D000; border-bottom:1px solid #71D000; background-color:#F0FFF0; } table.tbg td.li {border-left:1px solid #71D000 } table.tbg td.re {border-right:1px solid #71D000} -/* Dorfliste */ +/* Village list */ .dtbl {width:73px; font-size:11px;} .dlist1, .dlist3 {width:35px;} .dlist2 {width:3px; font-size:10px;} -/* Allianz Forum */ +/* Alliance forum */ .forumline {background-color: #000000; border: 1px #c0c0c0 solid;} .forum_h1 { font-weight: bold; font-size: 11px ; letter-spacing: 1px; color : #000000} @@ -482,17 +498,17 @@ td.row2 {background-color:#FEFEFE; } display: none; } -/* Laenderflaggen */ +/* Country flags */ .dflags1 {position:relative; float:right; text-align:center; font-size:6pt; color:#FFF; padding-left:1px; padding-right:1px; padding-top:1px;} .dflags2 {padding-top:1px;} img.flags {border:solid 1px #000000; width:21px; height:13px; -opacity:0.4; /* W3C-konform */ --moz-opacity:0.4; /* Mozilla und Derivate */ +opacity:0.4; /* W3C-compliant */ +-moz-opacity:0.4; /* Mozilla and derivatives */ FILTER:progid:DXImageTransform.Microsoft.Alpha(opacity=40); /*IE*/ } -/* importiertes Allianzprofil */ +/* Imported alliance profile */ table#profile {border-collapse:collapse; line-height:16px; width:100%;} table#profile td, table#profile th {vertical-align:middle; padding:2px 7px; border:1px solid silver; font-size:13px; color:black;} table#profile thead th, table#profile tfoot th {background-image:url(../un/a/c2.gif); background-repeat:repeat; text-align:center; font-weight:bold;} diff --git a/img/un/a/rand_left.gif b/img/un/a/rand_left.gif new file mode 100644 index 00000000..13534e9f Binary files /dev/null and b/img/un/a/rand_left.gif differ diff --git a/img/un/a/rand_right.gif b/img/un/a/rand_right.gif new file mode 100644 index 00000000..8a50a488 Binary files /dev/null and b/img/un/a/rand_right.gif differ diff --git a/install/data/constant_format.tpl b/install/data/constant_format.tpl index efd248a3..fb22e09a 100644 --- a/install/data/constant_format.tpl +++ b/install/data/constant_format.tpl @@ -143,6 +143,31 @@ define("SPEED", "%SPEED%"); // Defines world size. NOTICE: DO NOT EDIT!! define("WORLD_MAX", "%MAX%"); +// ***** Alliance Bonuses (T4 Port) +// Members donate resources, allowing the alliance to unlock four bonuses, each +// with five levels. The costs, durations, and limits below are based on +// Travian T4; upgrade times and donation limits are scaled by the server speed. +define("NEW_FUNCTIONS_ALLIANCE_BONUSES", %ALLIANCEBONUSES%); + +// Total resources required for each level (cumulative for that level). +define("ALLIANCE_BONUS_COSTS", "1200000,5600000,17100000,51200000,153600000"); + +// Upgrade duration in HOURS for each level (divided by the server speed). +define("ALLIANCE_BONUS_HOURS", "24,48,72,96,120"); + +// Daily donation limit per player, based on the highest bonus level unlocked +// by the alliance (index 0 = no bonuses unlocked). +define("ALLIANCE_BONUS_DAILY", "300000,300000,400000,550000,750000,1000000"); + +// Percentage granted by each level. Two sets: "small" bonuses (2% per level: +// Recruitment, Philosophy) and "large" bonuses (4% per level: Metallurgy, +// Commerce), exactly as in T4. +define("ALLIANCE_BONUS_PCT_SMALL", 2); +define("ALLIANCE_BONUS_PCT_LARGE", 4); + +// Gold cost to triple a donation. +define("ALLIANCE_BONUS_TRIPLE_GOLD", 3); + // ***** Graphic Pack // // SERVER_GP is the pack every player sees by default (chosen at install or in diff --git a/install/process.php b/install/process.php index a3431814..c40442e6 100644 --- a/install/process.php +++ b/install/process.php @@ -81,6 +81,9 @@ class Process { $findReplace["%MAX%"] = $_POST['wmax']; // Comutatorul de pachete grafice proprii. Linia era comentata, deci %GP% // ramanea neinlocuit in config.php si constanta nu se definea deloc. + // Bonusuri de alianta (port T4) + $findReplace["%ALLIANCEBONUSES%"] = (isset($_POST['alliance_bonuses']) && $_POST['alliance_bonuses'] === 'true') ? 'true' : 'false'; + $findReplace["%GP%"] = (isset($_POST['gpack']) && $_POST['gpack'] === 'true') ? 'true' : 'false'; $findReplace["%SSERVER%"] = $_POST['sserver']; $findReplace["%SPORT%"] = $_POST['sport']; diff --git a/install/templates/config.tpl b/install/templates/config.tpl index 0ac5bf4a..e59c40b7 100644 --- a/install/templates/config.tpl +++ b/install/templates/config.tpl @@ -312,6 +312,10 @@ foreach($mechs as $k => $l){
+