Add T4 Hero Resource and some fix

Add T4 Hero Resource and some fix
This commit is contained in:
novgorodschi catalin
2026-07-24 08:34:50 +03:00
parent 1e19f117ca
commit 2e53094b48
20 changed files with 641 additions and 43 deletions
+16 -1
View File
@@ -92,7 +92,22 @@ $editIcon = '<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke=
<tr><td><?php echo CONF_SERV_PEACESYST ?> <em class="tooltip">?<span class="classic"><?php echo CONF_SERV_PEACESYST_TOOLTIP ?></span></em></td><td><?php echo (["None", "Normal", "Christmas", "New Year", "Easter"])[PEACE]; ?></td></tr>
<tr><td><?php echo CONF_SERV_GRAPHICPACK ?> <em class="tooltip">?<span class="classic"><?php echo CONF_SERV_GRAPHICPACK_TOOLTIP ?></span></em></td><td><?php echo GP_ENABLE ? "<span class='badge green'>Enabled</span>" : "<span class='badge red'>Disabled</span>"; ?></td></tr>
<tr><td><?php echo CONF_SERV_ERRORREPORT ?> <em class="tooltip">?<span class="classic"><?php echo CONF_SERV_ERRORREPORT_TOOLTIP ?></span></em></td><td><b><?php echo (ERROR_REPORT=="error_reporting (0);")? "No": "Yes";?></b></td></tr>
<tr><td>Hero base regeneration <em class="tooltip">?<span class="classic">Hit points the hero recovers per day, independent of the regeneration attribute and of equipped items. 0 disables it.</span></em></td><td><b><?php echo defined('HERO_BASE_REGEN') ? (int) HERO_BASE_REGEN : 10; ?></b> HP / day</td></tr>
<tr>
<td>Hero base regeneration <em class="tooltip">?<span class="classic">Hit points the hero recovers per day, independent of the regeneration attribute and of equipped items. 0 disables it.</span></em></td>
<td><b><?php echo defined('HERO_BASE_REGEN') ? (int) HERO_BASE_REGEN : 10; ?></b> HP / day</td>
</tr>
<tr>
<td>Hero exchange rates <em class="tooltip">?<span class="classic">Rates of the exchange office in the auction house. The difference between the two directions is the house margin, so trading back and forth loses value instead of creating it.</span></em></td>
<td>1 gold &rarr; <b><?php echo defined('HERO_SILVER_PER_GOLD') ? (int) HERO_SILVER_PER_GOLD : 10; ?></b> silver
&nbsp;|&nbsp;
<b><?php echo defined('HERO_SILVER_TO_GOLD') ? (int) HERO_SILVER_TO_GOLD : 25; ?></b> silver &rarr; 1 gold</td>
</tr>
<tr>
<td>Hero resource production <em class="tooltip">?<span class="classic">Hourly resources produced by each point the hero invested in the Resources attribute, in the village where the hero is. Players choose freely between spreading it over all four resources or concentrating it on one.</span></em></td>
<td><b><?php echo defined('HERO_RES_PER_POINT_ALL') ? (int) HERO_RES_PER_POINT_ALL : 3; ?></b> of each
&nbsp;|&nbsp;
<b><?php echo defined('HERO_RES_PER_POINT_ONE') ? (int) HERO_RES_PER_POINT_ONE : 10; ?></b> of one type</td>
</tr>
</table>
</div>
+21
View File
@@ -349,6 +349,27 @@ function refresh(tz) {
value="<?php echo defined('HERO_BASE_REGEN') ? (int) HERO_BASE_REGEN : 10; ?>"> HP / day
</td>
</tr>
<tr>
<td class="b">Hero exchange rates <em class="tooltip">?<span class="classic">Exchange office in the auction house. Keep the second value higher than the first, otherwise players could trade back and forth to create gold out of nothing.</span></em></td>
<td>
1 gold &rarr;
<input type="number" name="hero_silver_per_gold" min="1" max="10000" style="width:80px"
value="<?php echo defined('HERO_SILVER_PER_GOLD') ? (int) HERO_SILVER_PER_GOLD : 10; ?>"> silver
&nbsp;|&nbsp;
<input type="number" name="hero_silver_to_gold" min="1" max="10000" style="width:80px"
value="<?php echo defined('HERO_SILVER_TO_GOLD') ? (int) HERO_SILVER_TO_GOLD : 25; ?>"> silver &rarr; 1 gold
</td>
</tr>
<tr>
<td class="b">Hero resource production <em class="tooltip">?<span class="classic">Hourly resources per point invested in the hero's Resources attribute. The first value applies when the player spreads the bonus over all four resources, the second when it is concentrated on a single one. Both scale with server speed.</span></em></td>
<td>
<input type="number" name="hero_res_all" min="0" max="10000" style="width:80px"
value="<?php echo defined('HERO_RES_PER_POINT_ALL') ? (int) HERO_RES_PER_POINT_ALL : 3; ?>"> of each
&nbsp;|&nbsp;
<input type="number" name="hero_res_one" min="0" max="10000" style="width:80px"
value="<?php echo defined('HERO_RES_PER_POINT_ONE') ? (int) HERO_RES_PER_POINT_ONE : 10; ?>"> of one type
</td>
</tr>
</tbody>
</table>
</div>
@@ -99,6 +99,10 @@ if (!function_exists('admin_config_template_path')) {
// regenerarea de baza a eroului: acelasi tratament, sa nu fie resetata
$cleanupDefaults['%HEROBASEREGEN%'] = array('HERO_BASE_REGEN', 10);
$cleanupDefaults['%HEROSILVERPERGOLD%'] = array('HERO_SILVER_PER_GOLD', 10);
$cleanupDefaults['%HEROSILVERTOGOLD%'] = array('HERO_SILVER_TO_GOLD', 25);
$cleanupDefaults['%HERORESALL%'] = array('HERO_RES_PER_POINT_ALL', 3);
$cleanupDefaults['%HERORESONE%'] = array('HERO_RES_PER_POINT_ONE', 10);
foreach ($overrides as $ovPlaceholder => $ovValue) {
if (strpos($text, $ovPlaceholder) !== false) {
+25 -1
View File
@@ -80,7 +80,31 @@ $heroBaseRegen = isset($_POST['hero_base_regen']) ? (int) $_POST['hero_base_rege
if ($heroBaseRegen < 0) { $heroBaseRegen = 0; }
if ($heroBaseRegen > 100) { $heroBaseRegen = 100; }
$text = admin_config_template_contents(array('%HEROBASEREGEN%' => $heroBaseRegen));
// Ratele casei de schimb aur <-> argint.
$silverPerGold = isset($_POST['hero_silver_per_gold']) ? (int) $_POST['hero_silver_per_gold'] : 10;
$silverToGold = isset($_POST['hero_silver_to_gold']) ? (int) $_POST['hero_silver_to_gold'] : 25;
if ($silverPerGold < 1) { $silverPerGold = 1; }
if ($silverPerGold > 10000) { $silverPerGold = 10000; }
if ($silverToGold < 1) { $silverToGold = 1; }
if ($silverToGold > 10000) { $silverToGold = 10000; }
// Productia de resurse a eroului (atributul "Resources").
$heroResAll = isset($_POST['hero_res_all']) ? (int) $_POST['hero_res_all'] : 3;
$heroResOne = isset($_POST['hero_res_one']) ? (int) $_POST['hero_res_one'] : 10;
if ($heroResAll < 0) { $heroResAll = 0; }
if ($heroResAll > 10000) { $heroResAll = 10000; }
if ($heroResOne < 0) { $heroResOne = 0; }
if ($heroResOne > 10000) { $heroResOne = 10000; }
$text = admin_config_template_contents(array(
'%HEROBASEREGEN%' => $heroBaseRegen,
'%HEROSILVERPERGOLD%' => $silverPerGold,
'%HEROSILVERTOGOLD%' => $silverToGold,
'%HERORESALL%' => $heroResAll,
'%HERORESONE%' => $heroResOne,
));
$text = preg_replace("'%ERRORREPORT%'", $_POST['error'], $text);
$text = preg_replace("'%ERROR%'", $_POST['error'], $text);
$text = preg_replace("'%SERVERNAME%'", $_POST['servername'], $text);
+2
View File
@@ -275,6 +275,8 @@ class MYSQLi_DB implements IDbConnection {
* @var array Cache of heroes.
*/
$heroCache = [],
// cache per request pentru eroul care produce resurse intr-un sat
$heroVillageCache = [],
/**
* @var array Cache of hero field values.
@@ -23,6 +23,33 @@ use App\Utils\Math;
trait DatabaseHeroQueries {
/**
* Eroul care produce resurse in satul dat (atributul T4 "Resources").
*
* Se ia eroul VIU, terminat de antrenat, al carui sat de resedinta (wref)
* este satul cerut. Intoarce null daca nu exista.
* Rezultatul e cache-uit per request, fiindcă productia se calculeaza des.
*/
function getHeroForVillage($wid, $use_cache = true) {
$wid = (int) $wid;
if ($use_cache && isset(self::$heroVillageCache[$wid])) {
return self::$heroVillageCache[$wid];
}
$q = "SELECT heroid, uid, wref, resources, res_type
FROM " . TB_PREFIX . "hero
WHERE wref = " . $wid . "
AND dead = 0
AND COALESCE(intraining, 0) = 0
LIMIT 1";
$result = mysqli_query($this->dblink, $q);
$row = $result ? mysqli_fetch_assoc($result) : null;
return self::$heroVillageCache[$wid] = ($row ?: null);
}
function getHero($uid=0, $all=0, $include_dead = false, $use_cache = true) {
list($uid,$all) = $this->escape_input((int) $uid,$all);
+166 -4
View File
@@ -264,6 +264,162 @@ class HeroItems
* - anything already in that slot is unequipped first (atomic enough for
* a per-user action; both statements touch only this user's rows)
*/
/* =========================================================================
* SCHIMB AUR <-> ARGINT (casa de licitatii)
* ===================================================================== */
const EXCHANGE_OK = 1;
const EXCHANGE_NO_HERO = 2;
const EXCHANGE_NOT_ENOUGH = 3;
const EXCHANGE_INVALID = 4;
const EXCHANGE_FAILED = 5;
/** Cat argint primesti pentru 1 aur (implicit 10, ca in Travian). */
public static function silverPerGold()
{
return defined('HERO_SILVER_PER_GOLD') ? max(1, (int) HERO_SILVER_PER_GOLD) : 10;
}
/** Cat argint costa 1 aur la schimbul invers (implicit 25 - diferenta e marja casei). */
public static function silverForOneGold()
{
return defined('HERO_SILVER_TO_GOLD') ? max(1, (int) HERO_SILVER_TO_GOLD) : 25;
}
/**
* Aur -> argint. $gold = cat aur dai.
*
* Ambele scrieri (scaderea aurului si adaugarea argintului) sunt intr-o
* TRANZACTIE: sunt tabele diferite (users si hero), iar fara tranzactie o
* eroare intre ele ar lasa jucatorul fara aur si fara argint. Scaderea are
* conditia "gold >= ?" chiar in UPDATE, deci doua cereri trimise simultan nu
* pot cheltui acelasi aur de doua ori.
*/
public function exchangeGoldToSilver($uid, $gold)
{
$uid = (int) $uid;
$gold = (int) $gold;
if ($gold <= 0 || $gold > 100000) {
return self::EXCHANGE_INVALID;
}
$silver = $gold * self::silverPerGold();
return $this->runExchange($uid, $gold, $silver, true);
}
/**
* Argint -> aur. $gold = cat aur vrei sa primesti.
*/
public function exchangeSilverToGold($uid, $gold)
{
$uid = (int) $uid;
$gold = (int) $gold;
if ($gold <= 0 || $gold > 100000) {
return self::EXCHANGE_INVALID;
}
$silver = $gold * self::silverForOneGold();
return $this->runExchange($uid, $gold, $silver, false);
}
/**
* Executa schimbul. $goldToSilver = true inseamna "dai aur, primesti argint".
*/
private function runExchange($uid, $gold, $silver, $goldToSilver)
{
// Fara erou nu exista unde tine argintul.
if ($this->heroRowId($uid) === 0) {
return self::EXCHANGE_NO_HERO;
}
$this->db->begin_transaction();
try {
if ($goldToSilver) {
$take = $this->db->prepare(
"UPDATE " . TB_PREFIX . "users SET gold = gold - ? WHERE id = ? AND gold >= ? LIMIT 1"
);
$take->bind_param('iii', $gold, $uid, $gold);
$take->execute();
$taken = $take->affected_rows;
$take->close();
if ($taken < 1) {
$this->db->rollback();
return self::EXCHANGE_NOT_ENOUGH;
}
$give = $this->db->prepare(
"UPDATE " . TB_PREFIX . "hero SET silver = silver + ? WHERE uid = ? LIMIT 1"
);
$give->bind_param('ii', $silver, $uid);
$give->execute();
$given = $give->affected_rows;
$give->close();
if ($given < 1) {
$this->db->rollback();
return self::EXCHANGE_FAILED;
}
} else {
$take = $this->db->prepare(
"UPDATE " . TB_PREFIX . "hero SET silver = silver - ? WHERE uid = ? AND silver >= ? LIMIT 1"
);
$take->bind_param('iii', $silver, $uid, $silver);
$take->execute();
$taken = $take->affected_rows;
$take->close();
if ($taken < 1) {
$this->db->rollback();
return self::EXCHANGE_NOT_ENOUGH;
}
$give = $this->db->prepare(
"UPDATE " . TB_PREFIX . "users SET gold = gold + ? WHERE id = ? LIMIT 1"
);
$give->bind_param('ii', $gold, $uid);
$give->execute();
$given = $give->affected_rows;
$give->close();
if ($given < 1) {
$this->db->rollback();
return self::EXCHANGE_FAILED;
}
}
$this->db->commit();
return self::EXCHANGE_OK;
} catch (Throwable $e) {
$this->db->rollback();
return self::EXCHANGE_FAILED;
}
}
/** Id-ul randului de erou al jucatorului, 0 daca nu exista. */
private function heroRowId($uid)
{
$uid = (int) $uid;
$stmt = $this->db->prepare(
"SELECT heroid FROM " . TB_PREFIX . "hero WHERE uid = ? LIMIT 1"
);
$stmt->bind_param('i', $uid);
$stmt->execute();
$stmt->bind_result($heroid);
$found = $stmt->fetch();
$stmt->close();
return $found ? (int) $heroid : 0;
}
/* =========================================================================
* DISPONIBILITATEA EROULUI PENTRU SCHIMBAREA ECHIPAMENTULUI
* ===================================================================== */
@@ -547,14 +703,20 @@ class HeroItems
if (!$hero) {
return self::USE_INVALID;
}
// Refund all spent points: 5 free points per level gained (same
// convention as Automation::calculateLevelUp). Attributes return to 0.
// FIX: un erou porneste cu 5 puncte la nivelul 0 (vezi INSERT-ul din
// 37_train.tpl), iar fiecare nivel mai da 5 (Automation::calculateLevelUp).
// Formula veche, "level * 5", uita punctele initiale: cartea returna cu 5
// mai putin decat avusese jucatorul, iar la nivelul 0 le pierdea pe toate
// si lasa eroul cu 0 puncte si toate atributele pe zero.
$level = (int) $hero['level'];
$points = $level * 5;
$points = 5 + ($level * 5);
// resources intra si el in reset (punctele se redistribuie doar cu cartea);
// res_type ramane neatins - alegerea resursei se schimba oricand, gratis.
$stmt = $this->db->prepare(
"UPDATE " . TB_PREFIX . "hero
SET points = ?, attack = 0, defence = 0, attackbonus = 0,
defencebonus = 0, regeneration = 0
defencebonus = 0, regeneration = 0, resources = 0
WHERE heroid = ? LIMIT 1"
);
$heroid = (int) $hero['heroid'];
+11
View File
@@ -2818,6 +2818,17 @@ tz_def('HERO_T4_TAB_ITEMS', 'Inventory');
tz_def('HERO_T4_TAB_ADVENTURES', 'Adventures');
tz_def('HERO_T4_TAB_AUCTION', 'Auctions');
tz_def('HERO_EXCHANGE', 'Exchange office');
tz_def('HERO_EXCHANGE_G2S', 'Gold to silver');
tz_def('HERO_EXCHANGE_S2G', 'Silver to gold');
tz_def('HERO_EXCHANGE_OK', 'Exchange completed.');
tz_def('HERO_EXCHANGE_NOTENOUGH', 'You do not have enough for this exchange.');
tz_def('HERO_EXCHANGE_FAIL', 'The exchange could not be completed.');
tz_def('HERO_EXCHANGE_HINT', 'The amount you type is the gold given or received; silver is calculated at the rate shown.');
tz_def('HERO_RES_PRODUCTION', 'Resources');
tz_def('HERO_RES_TYPE', 'Produced resource');
tz_def('HERO_RES_ALL', 'All resources');
tz_def('HERO_RES_TYPE_HINT', 'Can be changed at any time, free of charge.');
tz_def('HERO_SILVER', 'Silver');
tz_def('HERO_EXPERIENCE', 'Experience');
tz_def('RESOURCES', 'Resources');
+11
View File
@@ -2803,6 +2803,17 @@ tz_def('HERO_ITEM_USE_FAIL', 'Acest obiect nu poate fi folosit acum.');
tz_def('HERO_QUANTITY', 'Cantitate');
tz_def('HERO_RELEASE_ANIMALS', 'Elibereaza');
tz_def('HERO_RELEASE_CONFIRM', 'Eliberezi aceste animale? Vor disparea definitiv.');
tz_def('HERO_EXCHANGE', 'Casa de schimb');
tz_def('HERO_EXCHANGE_G2S', 'Aur in argint');
tz_def('HERO_EXCHANGE_S2G', 'Argint in aur');
tz_def('HERO_EXCHANGE_OK', 'Schimb efectuat.');
tz_def('HERO_EXCHANGE_NOTENOUGH', 'Nu ai suficient pentru acest schimb.');
tz_def('HERO_EXCHANGE_FAIL', 'Schimbul nu a putut fi efectuat.');
tz_def('HERO_EXCHANGE_HINT', 'Valoarea introdusa e aurul dat sau primit; argintul se calculeaza la rata afisata.');
tz_def('HERO_RES_PRODUCTION', 'Resurse');
tz_def('HERO_RES_TYPE', 'Resursa produsa');
tz_def('HERO_RES_ALL', 'Toate resursele');
tz_def('HERO_RES_TYPE_HINT', 'Se poate schimba oricand, gratuit.');
tz_def('HERO_SILVER', 'Argint');
tz_def('HERO_SLOT_1', 'Coif');
tz_def('HERO_SLOT_2', 'Armura');
+66
View File
@@ -43,6 +43,9 @@ class Village {
public $enforcetome = [];
public $enforcetoyou = [];
public $enforceoasis = [];
/** cache per sat pentru productia adusa de erou (null = neincarcat) */
private $heroProd = null;
public $currentcel = 0;
public $currentfestival = 0;
public $allcrop = 0;
@@ -306,11 +309,74 @@ class Village {
$amount += $amount / 100 * $bonusPct;
}
// Productia de resurse a eroului (atributul "Resources", ca in T4).
// Se adauga DUPA bonusurile de cladiri si oaze (alea se aplica doar campurilor)
// dar INAINTE de bonusul de 25% si de inmultirea cu SPEED, fiindca in T4 si
// bonusul de 25% si viteza serverului se aplica si productiei eroului.
$amount += $this->getHeroProdFor($type);
if ($this->sess->{$cfg['sessionBonus']} == 1) $amount *= 1.25;
return round($amount * SPEED);
}
/**
* Productia orara adusa de atributul "Resources" al eroului, pentru satul asta.
*
* Regula T4: fiecare punct produce 3 din FIECARE resursa (res_type = 0) sau 10
* dintr-un singur tip (res_type = 1..4 pentru lemn/lut/fier/cereale).
* Bonusul merge in satul in care se afla eroul (hero.wref), deci mutarea
* eroului muta si productia.
*
* Randul de erou se citeste O SINGURA DATA per instanta de sat.
*/
private function getHeroProdFor(string $type): float {
if ($this->heroProd === null) {
$this->heroProd = $this->loadHeroProd();
}
return $this->heroProd[$type] ?? 0.0;
}
/** Citeste eroul acestui sat si transforma punctele in productie per resursa. */
private function loadHeroProd(): array {
$empty = ['wood' => 0.0, 'clay' => 0.0, 'iron' => 0.0, 'crop' => 0.0];
if (!defined('NEW_FUNCTIONS_HERO_T4') || !NEW_FUNCTIONS_HERO_T4) {
return $empty;
}
$row = $this->db->getHeroForVillage($this->wid);
if (!$row) {
return $empty;
}
$points = (int) $row['resources'];
if ($points <= 0) {
return $empty;
}
$resType = (int) $row['res_type'];
$map = [1 => 'wood', 2 => 'clay', 3 => 'iron', 4 => 'crop'];
// 0 = raspandit egal: 3 din fiecare. Altfel: 10 dintr-un singur tip.
if ($resType === 0 || !isset($map[$resType])) {
$each = $points * (defined('HERO_RES_PER_POINT_ALL') ? (int) HERO_RES_PER_POINT_ALL : 3);
return ['wood' => $each, 'clay' => $each, 'iron' => $each, 'crop' => $each];
}
$single = $points * (defined('HERO_RES_PER_POINT_ONE') ? (int) HERO_RES_PER_POINT_ONE : 10);
$out = $empty;
$out[$map[$resType]] = $single;
return $out;
}
/**
* W1 #4: scans the f1..f38 fields ONLY once per load (instead of 4 passes)
* and buckets them by type.
+77
View File
@@ -23,6 +23,36 @@ $t4Auction = new HeroAuction();
$t4Msg = '';
if (isset($_POST['t4action'])) {
// --- SCHIMB AUR <-> ARGINT -------------------------------------------
// Validarea si atomicitatea sunt in HeroItems::exchange*(); aici doar
// afisam rezultatul si tinem sesiunea sincronizata cu noul sold de aur.
if (($_POST['t4action'] === 'g2s' || $_POST['t4action'] === 's2g') && isset($_POST['amount'])) {
$t4Items = new HeroItems();
$t4Amount = (int) $_POST['amount'];
$t4Ex = ($_POST['t4action'] === 'g2s')
? $t4Items->exchangeGoldToSilver($session->uid, $t4Amount)
: $t4Items->exchangeSilverToGold($session->uid, $t4Amount);
if ($t4Ex === HeroItems::EXCHANGE_OK) {
$t4Msg = defined('HERO_EXCHANGE_OK') ? HERO_EXCHANGE_OK : 'Exchange completed.';
// soldul de aur din sesiune trebuie reimprospatat, altfel pagina ar
// arata vechea valoare pana la expirarea cache-ului de utilizator
$t4NewGold = (int) $database->getUserField($session->uid, 'gold', 0);
$session->gold = $t4NewGold;
$_SESSION['gold'] = $t4NewGold;
unset($_SESSION['cache_user_' . (isset($_SESSION['username']) ? $_SESSION['username'] : '')]);
} elseif ($t4Ex === HeroItems::EXCHANGE_NOT_ENOUGH) {
$t4Msg = defined('HERO_EXCHANGE_NOTENOUGH') ? HERO_EXCHANGE_NOTENOUGH : 'You do not have enough for this exchange.';
} elseif ($t4Ex === HeroItems::EXCHANGE_NO_HERO) {
$t4Msg = defined('HERO_LOCKED_NOHERO') ? HERO_LOCKED_NOHERO : 'You have no hero yet.';
} else {
$t4Msg = defined('HERO_EXCHANGE_FAIL') ? HERO_EXCHANGE_FAIL : 'The exchange could not be completed.';
}
}
if ($_POST['t4action'] === 'bid' && isset($_POST['aucid'], $_POST['maxbid'])) {
$t4Result = $t4Auction->placeBid($session->uid, (int) $_POST['aucid'], (int) $_POST['maxbid']);
if ($t4Result === HeroAuction::BID_OK) {
@@ -62,6 +92,53 @@ foreach ($t4HeroItems->getInventory($session->uid) as $t4Row) {
<p class="message" style="font-weight:bold;"><?php echo $t4Msg; ?></p>
<?php } ?>
<?php
// Soldurile curente si ratele de schimb (configurabile din config.php).
$t4ExItems = isset($t4ExItems) ? $t4ExItems : new HeroItems();
$t4Silver = $t4ExItems->getSilver($session->uid);
$t4Gold = (int) $session->gold;
$t4RateG2S = HeroItems::silverPerGold();
$t4RateS2G = HeroItems::silverForOneGold();
?>
<table id="distribution" cellpadding="1" cellspacing="1">
<thead>
<tr><th colspan="2"><?php echo defined('HERO_EXCHANGE') ? HERO_EXCHANGE : 'Exchange office'; ?></th></tr>
</thead>
<tbody>
<tr>
<td style="width:290px;vertical-align:top;">
<p style="margin:0 0 6px 0;">
<b><?php echo HERO_SILVER; ?>:</b> <?php echo $t4Silver; ?>
&nbsp;&nbsp;
<b><?php echo defined('GOLD') ? GOLD : 'Gold'; ?>:</b> <?php echo $t4Gold; ?>
</p>
<form action="" method="POST" style="margin:0 0 5px 0;">
<input type="hidden" name="t4action" value="g2s">
<input type="number" name="amount" min="1" max="100000" value="1" style="width:70px">
<input type="submit" value="<?php echo defined('HERO_EXCHANGE_G2S') ? HERO_EXCHANGE_G2S : 'Gold to silver'; ?>">
<small>(1 : <?php echo $t4RateG2S; ?>)</small>
</form>
<form action="" method="POST" style="margin:0;">
<input type="hidden" name="t4action" value="s2g">
<input type="number" name="amount" min="1" max="100000" value="1" style="width:70px">
<input type="submit" value="<?php echo defined('HERO_EXCHANGE_S2G') ? HERO_EXCHANGE_S2G : 'Silver to gold'; ?>">
<small>(<?php echo $t4RateS2G; ?> : 1)</small>
</form>
<p style="margin:6px 0 0 0;color:#777;font-size:11px;">
<?php echo defined('HERO_EXCHANGE_HINT') ? HERO_EXCHANGE_HINT
: 'The amount you type is the gold given or received; silver is calculated at the rate shown.'; ?>
</p>
</td>
<td style="text-align:center;vertical-align:middle;">
<img src="img/hero/merchant.png" alt="" style="max-width:280px;">
</td>
</tr>
</tbody>
</table>
<table id="distribution" cellpadding="1" cellspacing="1">
<thead>
<tr><th colspan="5"><?php echo HERO_AUC_OPEN; ?></th></tr>
+123 -4
View File
@@ -40,6 +40,19 @@ $heroStatColumns = [
'reg' => 'regeneration',
];
// Atributul "Resources" apartine sistemului de erou T4: apare si poate primi
// puncte doar cand functiile T4 sunt pornite. Tot flag-ul asta decide si daca
// productia se aplica (vezi Village::loadHeroProd), deci cele doua nu pot ajunge
// in dezacord - altfel jucatorii ar investi in ceva care nu produce nimic.
// In plus, cu flag-ul stins interogarile de mai jos nu mai ating coloanele
// `resources` / `res_type`, deci pagina merge si pe un server care inca nu a
// rulat scriptul add-hero-resources.sql.
$t4HeroRes = defined('NEW_FUNCTIONS_HERO_T4') && NEW_FUNCTIONS_HERO_T4;
if ($t4HeroRes) {
$heroStatColumns['res'] = 'resources';
}
// Render the "(+)" link for a stat, or "(+)" uneditable
// if the hero has no more points or the stat is already at the top (100).
// Identical behavior to the original 5 if/else blocks.
@@ -113,6 +126,58 @@ $renderAddLink = function ($action) use ($hero_info, $id, $heroStatColumns) {
</td>
<td class="po" id="t4po_reg"><?php echo $hero_info['regeneration']; ?></td>
</tr>
<?php if ($t4HeroRes) { ?>
<tr>
<th><?php echo defined('HERO_RES_PRODUCTION') ? HERO_RES_PRODUCTION : 'Resources'; ?></th>
<td class="val">
<?php
// Cate resurse produce, dupa cum e setat: 3 din fiecare sau 10 dintr-una.
$t4ResPoints = (int) ($hero_info['resources'] ?? 0);
$t4ResType = (int) ($hero_info['res_type'] ?? 0);
$t4PerAll = defined('HERO_RES_PER_POINT_ALL') ? (int) HERO_RES_PER_POINT_ALL : 3;
$t4PerOne = defined('HERO_RES_PER_POINT_ONE') ? (int) HERO_RES_PER_POINT_ONE : 10;
$t4ResIcons = [1 => 'r1', 2 => 'r2', 3 => 'r3', 4 => 'r4'];
if ($t4ResType >= 1 && $t4ResType <= 4) {
echo '<img class="' . $t4ResIcons[$t4ResType] . '" src="img/x.gif" alt="" /> ';
echo (int) round($t4ResPoints * $t4PerOne * SPEED);
} else {
foreach ($t4ResIcons as $t4Ico) {
echo '<img class="' . $t4Ico . '" src="img/x.gif" alt="" /> '
. (int) round($t4ResPoints * $t4PerAll * SPEED) . ' ';
}
}
?>
/<?php echo defined('HOUR') ? HOUR : 'h'; ?></td>
<td class="xp"><img class="bar" src="img/x.gif" style="width:<?php echo ($t4ResPoints*2)+1; ?>px;" alt="" title="" /></td>
<td class="up"><span class="none">
<?php echo $renderAddLink('res'); ?>
</td>
<td class="po" id="t4po_res"><?php echo $t4ResPoints; ?></td>
</tr>
<tr>
<td colspan="5" class="empty"></td>
</tr>
<tr>
<td colspan="5">
<form action="" method="POST" style="margin:0;">
<?php echo defined('HERO_RES_TYPE') ? HERO_RES_TYPE : 'Produced resource'; ?>:
<select name="t4restype" onchange="this.form.submit();">
<option value="0" <?php if ($t4ResType === 0) echo 'selected'; ?>><?php echo defined('HERO_RES_ALL') ? HERO_RES_ALL : 'All resources'; ?> (<?php echo $t4PerAll; ?>)</option>
<option value="1" <?php if ($t4ResType === 1) echo 'selected'; ?>><?php echo LUMBER; ?> (<?php echo $t4PerOne; ?>)</option>
<option value="2" <?php if ($t4ResType === 2) echo 'selected'; ?>><?php echo CLAY; ?> (<?php echo $t4PerOne; ?>)</option>
<option value="3" <?php if ($t4ResType === 3) echo 'selected'; ?>><?php echo IRON; ?> (<?php echo $t4PerOne; ?>)</option>
<option value="4" <?php if ($t4ResType === 4) echo 'selected'; ?>><?php echo CROP; ?> (<?php echo $t4PerOne; ?>)</option>
</select>
<noscript><input type="submit" value="OK"></noscript>
<span style="color:#777;font-size:11px;margin-left:6px;">
<?php echo defined('HERO_RES_TYPE_HINT') ? HERO_RES_TYPE_HINT
: 'Can be changed at any time, free of charge.'; ?>
</span>
</form>
</td>
</tr>
<?php } ?>
<tr>
<td colspan="5" class="empty"></td>
</tr>
@@ -260,6 +325,58 @@ $renderAddLink = function ($action) use ($hero_info, $id, $heroStatColumns) {
// are, sau peste 100 la o statistica), conditiile nu se potrivesc, UPDATE-ul nu
// afecteaza niciun rand si nu se schimba nimic. Fiind o singura instructiune,
// nici doua cereri trimise simultan nu pot cheltui aceleasi puncte de doua ori.
// Schimbarea resursei favorizate. In T4 setarea asta e libera: nu costa puncte
// si nu are nevoie de Book of Wisdom, doar redistribuie acelasi bonus.
if ($t4HeroRes && isset($_POST['t4restype'])) {
$t4Type = (int) $_POST['t4restype'];
if ($t4Type >= 0 && $t4Type <= 4) {
// Interogarea se construieste din $heroStatColumns, deci acopera automat
// exact atributele active (cu sau fara "resources").
$t4Cols = array_values($heroStatColumns);
$t4Set = array();
$t4Guard = array();
foreach ($t4Cols as $t4Col) {
$t4Set[] = "`" . $t4Col . "` = `" . $t4Col . "` + ?";
$t4Guard[] = "`" . $t4Col . "` + ? <= 100";
}
$t4Stmt = $database->dblink->prepare(
"UPDATE " . TB_PREFIX . "hero SET " . implode(", ", $t4Set) . ",
`points` = `points` - ?
WHERE `heroid` = ?
AND `points` >= ?
AND " . implode("\n\t\t\t AND ", $t4Guard)
);
if ($t4Stmt) {
$t4HeroId = (int) $hero_info['heroid'];
// ordinea parametrilor: cresteri, punctele scazute, heroid, garda de
// puncte, apoi garzile de maxim 100 pentru fiecare atribut
$t4Values = array();
foreach ($t4Cols as $t4Col) { $t4Values[] = $t4Alloc[$t4Col]; }
$t4Values[] = $t4Total;
$t4Values[] = $t4HeroId;
$t4Values[] = $t4Total;
foreach ($t4Cols as $t4Col) { $t4Values[] = $t4Alloc[$t4Col]; }
$t4Stmt->bind_param(str_repeat('i', count($t4Values)), ...$t4Values);
$t4Stmt->execute();
$t4Stmt->close();
}
}
header("Location: build.php?id=" . $id);
exit;
}
if (isset($_POST['t4points'])) {
$t4Alloc = array();
@@ -284,6 +401,7 @@ if (isset($_POST['t4points'])) {
`attackbonus` = `attackbonus` + ?,
`defencebonus` = `defencebonus` + ?,
`regeneration` = `regeneration` + ?,
`resources` = `resources` + ?,
`points` = `points` - ?
WHERE `heroid` = ?
AND `points` >= ?
@@ -291,19 +409,20 @@ if (isset($_POST['t4points'])) {
AND `defence` + ? <= 100
AND `attackbonus` + ? <= 100
AND `defencebonus` + ? <= 100
AND `regeneration` + ? <= 100"
AND `regeneration` + ? <= 100
AND `resources` + ? <= 100"
);
if ($t4Stmt) {
$t4HeroId = (int) $hero_info['heroid'];
$t4Stmt->bind_param(
'iiiiiiiiiiiii',
'iiiiiiiiiiiiiii',
$t4Alloc['attack'], $t4Alloc['defence'], $t4Alloc['attackbonus'],
$t4Alloc['defencebonus'], $t4Alloc['regeneration'],
$t4Alloc['defencebonus'], $t4Alloc['regeneration'], $t4Alloc['resources'],
$t4Total, $t4HeroId, $t4Total,
$t4Alloc['attack'], $t4Alloc['defence'], $t4Alloc['attackbonus'],
$t4Alloc['defencebonus'], $t4Alloc['regeneration']
$t4Alloc['defencebonus'], $t4Alloc['regeneration'], $t4Alloc['resources']
);
$t4Stmt->execute();
+4 -4
View File
@@ -92,10 +92,10 @@ $diffLabel = $difficulty === 1
<tr>
<td><?php echo tz_hero_adv('RESOURCES', 'Resources'); ?></td>
<td style="text-align:right;">
<span class="res wood"><?php echo number_format($wood); ?></span>
<span class="res clay"><?php echo number_format($clay); ?></span>
<span class="res iron"><?php echo number_format($iron); ?></span>
<span class="res crop"><?php echo number_format($crop); ?></span>
<img class="r1" src="img/x.gif" alt="<?php echo LUMBER; ?>" title="<?php echo LUMBER; ?>"> <?php echo number_format($wood); ?>
<img class="r2" src="img/x.gif" alt="<?php echo CLAY; ?>" title="<?php echo CLAY; ?>"> <?php echo number_format($clay); ?>
<img class="r3" src="img/x.gif" alt="<?php echo IRON; ?>" title="<?php echo IRON; ?>"> <?php echo number_format($iron); ?>
<img class="r4" src="img/x.gif" alt="<?php echo CROP; ?>" title="<?php echo CROP; ?>"> <?php echo number_format($crop); ?>
</td>
</tr>
<?php } ?>
+44
View File
@@ -170,6 +170,30 @@ if ($hour > 1759 || $hour < 500) {
</div>
<!-- ===================== GOLD (MUTAT DIN RES.TPL - CERCUL VERDE) ===================== -->
<?php
/**
* Gold display - mutat din res.tpl
* Afisare intre Messages si Plus
*/
if (!$isRestrictedUser && isset($session->gold)) {
?>
<div id="goldHeader">
<?php
if ($session->gold <= 1) {
echo '<font color="#B3B3B3">
<img src="' . GP_LOCATE . 'img/a/gold_g.gif" alt="' . GOLD . '" title="' . GOLD . '"/>
' . $session->gold . ' ' . GOLD . '
</font>';
} else {
echo '<img src="' . GP_LOCATE . 'img/a/gold.gif" alt="' . GOLD . '" title="' . GOLD . '"/>
' . $session->gold . ' ' . GOLD;
}
?>
</div>
<?php } ?>
<!-- ===================== END GOLD ===================== -->
<?php
/**
* PLUS button
@@ -253,6 +277,26 @@ if ($hour > 1759 || $hour < 500) {
display: inline-block;
}
/* GOLD IN CERCUL VERDE */
#goldHeader {
position: absolute;
left: 380px; /* << AICI ESTE CERCUL VERDE - muta 370-400 daca e nevoie */
top: 18px; /* centrat pe bara gri */
width: auto;
min-width: 100px;
height: 22px;
line-height: 22px;
text-align: center;
font-size: 11px;
font-weight: bold;
z-index: 50;
}
#goldHeader img {
vertical-align: middle;
margin-right: 4px;
}
</style>
<!-- ===================== DAY/NIGHT ICON ===================== -->
-29
View File
@@ -112,35 +112,6 @@ if (!empty($village)) {
</tr>
</table>
<!-- ================= GOLD / STATUS ================= -->
<table cellpadding="1" cellspacing="1">
<tr>
<!-- spacing (kept as original layout) -->
<td>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</td>
<td>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</td>
<td>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</td>
<td>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</td>
<td></td>
<!-- Gold display -->
<td>
<?php
if ($session->gold <= 1) {
echo '<font color="#B3B3B3">
<img src="' . GP_LOCATE . 'img/a/gold_g.gif" alt="' . GOLD . '" title="' . GOLD . '"/>
' . $session->gold . ' ' . GOLD . '
</font>';
} else {
echo '<img src="' . GP_LOCATE . 'img/a/gold.gif" alt="' . GOLD . '" title="' . GOLD . '"/>
' . $session->gold . ' ' . GOLD;
}
?>
</td>
</tr>
</table>
</div>
</div>
Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

+14
View File
@@ -64,6 +64,20 @@ define('CLEANUP_BATCH', 5000);
// din atribute. 0 = dezactivata (comportamentul vechi).
define('HERO_BASE_REGEN', %HEROBASEREGEN%);
// Ratele casei de schimb din casa de licitatii:
// HERO_SILVER_PER_GOLD = cat argint primesti pentru 1 aur
// HERO_SILVER_TO_GOLD = cat argint costa 1 aur la schimbul invers
// Diferenta dintre ele este marja casei (ca in Travian: 1 aur -> 10 argint,
// dar 25 argint -> 1 aur).
define('HERO_SILVER_PER_GOLD', %HEROSILVERPERGOLD%);
define('HERO_SILVER_TO_GOLD', %HEROSILVERTOGOLD%);
// Atributul de erou "Resources" (T4): cate resurse produce un punct pe ora.
// ALL = cand bonusul e raspandit egal pe toate patru (implicit 3 din fiecare)
// ONE = cand e concentrat pe o singura resursa (implicit 10)
define('HERO_RES_PER_POINT_ALL', %HERORESALL%);
define('HERO_RES_PER_POINT_ONE', %HERORESONE%);
//////////////////////////////////
// ***** SERVER SETTINGS *****//
//////////////////////////////////
+24
View File
@@ -155,6 +155,30 @@ class Process {
if ($heroRegen > 100) { $heroRegen = 100; }
$findReplace["%HEROBASEREGEN%"] = $heroRegen;
// Ratele casei de schimb (aur <-> argint), din formularul de instalare.
$silverPerGold = isset($_POST['hero_silver_per_gold']) ? (int) $_POST['hero_silver_per_gold'] : 10;
$silverToGold = isset($_POST['hero_silver_to_gold']) ? (int) $_POST['hero_silver_to_gold'] : 25;
if ($silverPerGold < 1) { $silverPerGold = 1; }
if ($silverPerGold > 10000) { $silverPerGold = 10000; }
if ($silverToGold < 1) { $silverToGold = 1; }
if ($silverToGold > 10000) { $silverToGold = 10000; }
$findReplace["%HEROSILVERPERGOLD%"] = $silverPerGold;
$findReplace["%HEROSILVERTOGOLD%"] = $silverToGold;
// Atributul de erou "Resources": cate resurse da un punct pe ora.
$resAll = isset($_POST['hero_res_all']) ? (int) $_POST['hero_res_all'] : 3;
$resOne = isset($_POST['hero_res_one']) ? (int) $_POST['hero_res_one'] : 10;
if ($resAll < 0) { $resAll = 0; }
if ($resAll > 10000) { $resAll = 10000; }
if ($resOne < 0) { $resOne = 0; }
if ($resOne > 10000) { $resOne = 10000; }
$findReplace["%HERORESALL%"] = $resAll;
$findReplace["%HERORESONE%"] = $resOne;
$findReplace["%DOMAIN%"] = $_POST['domain'];
$findReplace["%HOMEPAGE%"] = $_POST['homepage'];
$findReplace["%SERVER%"] = $_POST['server'];
+4
View File
@@ -310,6 +310,10 @@ foreach($mechs as $k => $l){
<div><label>Delete chat messages after (days)</label><input class="input" name="cleanup_chat" id="cleanup_chat" value="7"></div>
<div><label>Delete messages erased by both sides (days)</label><input class="input" name="cleanup_messages" id="cleanup_messages" value="0"></div>
<div><label>Hero base regeneration (HP/day)</label><input class="input" name="hero_base_regen" id="hero_base_regen" value="10"></div>
<div><label>Silver received per 1 gold</label><input class="input" name="hero_silver_per_gold" id="hero_silver_per_gold" value="10"></div>
<div><label>Silver needed for 1 gold</label><input class="input" name="hero_silver_to_gold" id="hero_silver_to_gold" value="25"></div>
<div><label>Hero resources per point (all four)</label><input class="input" name="hero_res_all" id="hero_res_all" value="3"></div>
<div><label>Hero resources per point (single type)</label><input class="input" name="hero_res_one" id="hero_res_one" value="10"></div>
</div>
<div class="f10" style="margin-top:8px;opacity:.75;">
Automation runs from cron.php instead of players' page loads. One cron invocation keeps working for
+2
View File
@@ -1002,6 +1002,8 @@ CREATE TABLE IF NOT EXISTS `%PREFIX%hero` (
`attackbonus` tinyint(3) NULL,
`defencebonus` tinyint(3) NULL,
`regeneration` tinyint(3) NULL,
`resources` tinyint(3) NOT NULL DEFAULT 0,
`res_type` tinyint(1) NOT NULL DEFAULT 0,
`autoregen` int(2) NULL,
`lastupdate` int(11) NULL,
`trainingtime` int(11) NULL,