mirror of
https://github.com/Shadowss/TravianZ.git
synced 2026-08-09 12:51:01 +00:00
Add Plus Statistics
Add Plus Statistics
This commit is contained in:
@@ -110,7 +110,7 @@ $editIcon = '<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke=
|
||||
</tr>
|
||||
<tr>
|
||||
<td><?php echo ADM_HERO_RESOURCE_PRODUCTION; ?><em class="tooltip">?<span class="classic"><?php echo ADM_HOURLY_RESOURCES_PRODUCED_BY_EACH_POINT_THE; ?></span></em></td>
|
||||
<td><b><?php echo defined('HERO_RES_PER_POINT_ALL') ? (int) HERO_RES_PER_POINT_ALL : 3; ?></b><?php echo ADM_OF_EACH; ?><b><?php echo defined('HERO_RES_PER_POINT_ONE') ? (int) HERO_RES_PER_POINT_ONE : 10; ?></b><?php echo ADM_OF_ONE_TYPE; ?></td>
|
||||
<td><b><?php echo defined('HERO_RES_PER_POINT_ALL') ? (int) HERO_RES_PER_POINT_ALL : 3; ?> </b><?php echo ADM_OF_EACH; ?><b><?php echo defined('HERO_RES_PER_POINT_ONE') ? (int) HERO_RES_PER_POINT_ONE : 10; ?></b> <?php echo ADM_OF_ONE_TYPE; ?></td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
@@ -267,6 +267,16 @@ $cronKeyMasked = ($cronKey === '')
|
||||
<tr><td><?php echo ADM_REGISTRATION_BONUS_GOLD; ?><em class="tooltip">?<span class="classic"><?php echo ADM_GIVE_EVERY_NEWLY_REGISTERED_PLAYER_A_ONE_TIM; ?></span></em></td><td><?php echo (defined('NEW_FUNCTION_REGISTRATION_GOLD') && NEW_FUNCTION_REGISTRATION_GOLD) ? "<span class='badge green'>Enabled</span>" : "<span class='badge red'>Disabled</span>"; ?></td></tr>
|
||||
<tr><td><?php echo ADM_REGISTRATION_BONUS_GOLD_AMOUNT; ?><em class="tooltip">?<span class="classic"><?php echo ADM_HOW_MUCH_GOLD_EACH_NEW_PLAYER_RECEIVES_WHEN; ?></span></em></td><td><?php echo (defined('NEW_FUNCTION_REGISTRATION_GOLD_VALUE') ? (int) NEW_FUNCTION_REGISTRATION_GOLD_VALUE : 200); ?></td></tr>
|
||||
<tr><td><?php echo ADM_ALLIANCE_BONUSES; ?> <em class="tooltip">?<span class="classic"><?php echo ADM_ALLIANCE_BONUSES_TIP; ?></span></em></td><td><?php echo (defined('NEW_FUNCTIONS_ALLIANCE_BONUSES') && NEW_FUNCTIONS_ALLIANCE_BONUSES) ? "<span class='badge green'>Enabled</span>" : "<span class='badge red'>Disabled</span>"; ?></td></tr>
|
||||
<tr><td><?php echo ADM_PLUS_STATISTICS; ?> <em class="tooltip">?<span class="classic"><?php echo ADM_PLUS_STATISTICS_TIP; ?></span></em></td><td><?php
|
||||
if (defined('NEW_FUNCTIONS_PLUS_STATISTICS') && NEW_FUNCTIONS_PLUS_STATISTICS) {
|
||||
$psKeep = defined('PLUS_STATS_KEEP_DAYS') ? (int) PLUS_STATS_KEEP_DAYS : 0;
|
||||
echo "<span class='badge green'>Enabled</span> <span style='color:#666'>("
|
||||
. (defined('PLUS_STATS_INTERVAL_HOURS') ? PLUS_STATS_INTERVAL_HOURS : 6) . "h, "
|
||||
. ($psKeep > 0 ? $psKeep . "d" : "∞") . ")</span>";
|
||||
} else {
|
||||
echo "<span class='badge red'>Disabled</span>";
|
||||
}
|
||||
?></td></tr>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -255,6 +255,31 @@ if($_SESSION['access'] < 9) die(ACCESS_DENIED_ADMIN);
|
||||
</select>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="b"><?php echo ADM_PLUS_STATISTICS; ?><em class="tooltip">?<span class="classic"><?php echo ADM_PLUS_STATISTICS_TIP; ?></span></em>
|
||||
<?php if (!defined('NEW_FUNCTIONS_PLUS_STATISTICS')): ?><br><span style="color:#c0392b;font-size:11px;font-weight:normal;text-transform:none;"><?php echo ADM_NOT_PRESENT_IN_CONFIG_PHP_YET_SAVING_THIS_FO; ?></span><?php endif; ?>
|
||||
</td>
|
||||
<td>
|
||||
<select name="plus_statistics">
|
||||
<option value="true" <?php if (defined('NEW_FUNCTIONS_PLUS_STATISTICS') && NEW_FUNCTIONS_PLUS_STATISTICS) echo "selected"; ?>>True</option>
|
||||
<option value="false" <?php if (!defined('NEW_FUNCTIONS_PLUS_STATISTICS') || !NEW_FUNCTIONS_PLUS_STATISTICS) echo "selected"; ?>>False</option>
|
||||
</select>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="b"><?php echo ADM_PLUS_STATISTICS_INTERVAL; ?><em class="tooltip">?<span class="classic"><?php echo ADM_PLUS_STATISTICS_INTERVAL_TIP; ?></span></em></td>
|
||||
<td>
|
||||
<input type="text" name="plus_stats_hours" size="6"
|
||||
value="<?php echo defined('PLUS_STATS_INTERVAL_HOURS') ? PLUS_STATS_INTERVAL_HOURS : 6; ?>">
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="b"><?php echo ADM_PLUS_STATISTICS_KEEP; ?><em class="tooltip">?<span class="classic"><?php echo ADM_PLUS_STATISTICS_KEEP_TIP; ?></span></em></td>
|
||||
<td>
|
||||
<input type="text" name="plus_stats_keep" size="6"
|
||||
value="<?php echo defined('PLUS_STATS_KEEP_DAYS') ? PLUS_STATS_KEEP_DAYS : 0; ?>">
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="b"><?php echo ADM_NEW_TRIBE_HUNS; ?><em class="tooltip">?<span class="classic"><?php echo ADM_ENABLE_DISABLE_TRIBE_HUNS; ?></span></em>
|
||||
<?php if (!defined('NEW_FUNCTION_TRIBE_HUNS')): ?><br><span style="color:#c0392b;font-size:11px;font-weight:normal;text-transform:none;"><?php echo ADM_NOT_PRESENT_IN_CONFIG_PHP_YET_SAVING_THIS_FO; ?></span><?php endif; ?>
|
||||
|
||||
@@ -113,6 +113,16 @@ $fh = fopen($myFile, 'w') or die("<br/><br/><br/>Can't open file: GameEngine\con
|
||||
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, '%PLUSSTATS%', $_POST['plus_statistics'] ?? 'false');
|
||||
|
||||
// intervalul si retentia: valori numerice, cu limite rezonabile
|
||||
$psHours = isset($_POST['plus_stats_hours']) ? (float) $_POST['plus_stats_hours'] : 6;
|
||||
if ($psHours < 0.25 || $psHours > 168) { $psHours = 6; }
|
||||
tz_config_set($text, '%PLUSSTATSHOURS%', $psHours);
|
||||
|
||||
$psKeep = isset($_POST['plus_stats_keep']) ? (int) $_POST['plus_stats_keep'] : 0;
|
||||
if ($psKeep < 0 || $psKeep > 3650) { $psKeep = 0; }
|
||||
tz_config_set($text, '%PLUSSTATSKEEP%', $psKeep);
|
||||
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'] ?? '');
|
||||
|
||||
@@ -74,6 +74,7 @@ include_once __DIR__ . '/Automation/AutomationStarvation.php';
|
||||
include_once __DIR__ . '/Automation/AutomationNatarsWW.php';
|
||||
include_once __DIR__ . '/Automation/AutomationMedals.php';
|
||||
include_once __DIR__ . '/Automation/AutomationCleanup.php';
|
||||
include_once __DIR__ . '/Automation/AutomationPlayerStatistics.php';
|
||||
|
||||
class Automation {
|
||||
// === Faza S2: metodele clasei, grupate pe domenii ===
|
||||
@@ -92,6 +93,7 @@ class Automation {
|
||||
|
||||
|
||||
use AutomationCleanup;
|
||||
use AutomationPlayerStatistics;
|
||||
/**
|
||||
* @var object The artifacts class, used to create Natars, artifacts and obtaining info about them
|
||||
*/
|
||||
@@ -135,7 +137,8 @@ class Automation {
|
||||
"spawnWWVillages", "spawnWWBuildingPlans", "activateArtifacts",
|
||||
"heroAdventureComplete",
|
||||
// P3: curatenie periodica (are interval propriu, nu ruleaza la fiecare tick)
|
||||
"cleanupOldData"];
|
||||
"cleanupOldData",
|
||||
"recordPlayerStatistics"];
|
||||
|
||||
foreach($methodsArrays as $method){
|
||||
$file = fopen($autoprefix."GameEngine/Prevention/".$method.".txt", "w");
|
||||
|
||||
@@ -0,0 +1,226 @@
|
||||
<?php
|
||||
|
||||
#################################################################################
|
||||
## AutomationPlayerStatistics ##
|
||||
## --------------------------------------------------------------------------- ##
|
||||
## Periodically takes a snapshot of every player's rank, population, and army. ##
|
||||
## These snapshots are used to draw the graphs on the Plus statistics page. ##
|
||||
## ##
|
||||
## Guarded by NEW_FUNCTIONS_PLUS_STATISTICS. When enabled, snapshots are taken ##
|
||||
## for ALL players; however, the statistics tab is only visible to players ##
|
||||
## with an active Plus account. ##
|
||||
## ##
|
||||
## Data is recorded for ALL players, not only Plus users; otherwise, a player ##
|
||||
## who purchases Plus would open the page and see an empty graph at the exact ##
|
||||
## moment they activated it. ##
|
||||
#################################################################################
|
||||
|
||||
trait AutomationPlayerStatistics
|
||||
{
|
||||
/**
|
||||
* Inregistreaza un instantaneu, daca a trecut destul de la ultimul.
|
||||
*
|
||||
* Intervalul e controlat de PLUS_STATS_INTERVAL_HOURS. Verificarea se face
|
||||
* pe baza celui mai recent rand din tabela, nu pe un fisier marker: daca
|
||||
* tabela e goala (prima rulare) sau cron-ul a stat oprit, instantaneul se
|
||||
* ia imediat.
|
||||
*/
|
||||
private function recordPlayerStatistics()
|
||||
{
|
||||
global $database;
|
||||
|
||||
if (!defined('NEW_FUNCTIONS_PLUS_STATISTICS') || !NEW_FUNCTIONS_PLUS_STATISTICS) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$table = TB_PREFIX . 'player_statistics_history';
|
||||
|
||||
// Pe un server care nu a rulat migrarea, tabela lipseste. Iesim linistit,
|
||||
// in loc sa aruncam o eroare la fiecare tick de cron.
|
||||
$check = @mysqli_query($database->dblink, "SHOW TABLES LIKE '" . $table . "'");
|
||||
|
||||
if (!$check || mysqli_num_rows($check) === 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$hours = defined('PLUS_STATS_INTERVAL_HOURS') ? (float) PLUS_STATS_INTERVAL_HOURS : 6.0;
|
||||
$interval = (int) max(600, round($hours * 3600));
|
||||
$now = time();
|
||||
|
||||
$res = mysqli_query($database->dblink,
|
||||
"SELECT MAX(recorded_at) AS last FROM " . $table);
|
||||
$row = $res ? mysqli_fetch_assoc($res) : null;
|
||||
$last = $row ? (int) $row['last'] : 0;
|
||||
|
||||
if ($last > 0 && ($now - $last) < $interval) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$this->writePlayerStatisticsSnapshot($now);
|
||||
$this->trimPlayerStatistics($now);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Scrie efectiv instantaneul.
|
||||
*
|
||||
* Populatia, satele si punctele vin dintr-o singura interogare. Trupele se
|
||||
* numara separat, fiindca hrana consumata are nevoie de datele de unitate
|
||||
* din PHP (fiecare unitate are alt consum).
|
||||
*/
|
||||
private function writePlayerStatisticsSnapshot($now)
|
||||
{
|
||||
global $database;
|
||||
|
||||
$table = TB_PREFIX . 'player_statistics_history';
|
||||
|
||||
// rang, populatie, sate si puncte de lupta, per jucator
|
||||
$q = "SELECT
|
||||
u.id AS uid,
|
||||
u.oldrank AS rank,
|
||||
COALESCE(SUM(v.pop), 0) AS population,
|
||||
COUNT(CASE WHEN v.type != 99 THEN v.wref END) AS villages,
|
||||
u.apall AS attack_points,
|
||||
u.dpall AS defence_points
|
||||
FROM " . TB_PREFIX . "users u
|
||||
LEFT JOIN " . TB_PREFIX . "vdata v ON v.owner = u.id
|
||||
WHERE u.id > 5 AND u.access > 0
|
||||
GROUP BY u.id";
|
||||
|
||||
$res = mysqli_query($database->dblink, $q);
|
||||
|
||||
if (!$res) {
|
||||
return;
|
||||
}
|
||||
|
||||
$players = array();
|
||||
|
||||
while ($row = mysqli_fetch_assoc($res)) {
|
||||
$players[(int) $row['uid']] = array(
|
||||
'rank' => (int) $row['rank'],
|
||||
'population' => (int) $row['population'],
|
||||
'villages' => (int) $row['villages'],
|
||||
'attack_points' => (int) $row['attack_points'],
|
||||
'defence_points' => (int) $row['defence_points'],
|
||||
'troop_count' => 0,
|
||||
'troop_upkeep' => 0,
|
||||
);
|
||||
}
|
||||
|
||||
if (!$players) {
|
||||
return;
|
||||
}
|
||||
|
||||
$this->addTroopTotals($players);
|
||||
|
||||
// scriem in loturi, ca sa nu facem o interogare per jucator
|
||||
$values = array();
|
||||
|
||||
foreach ($players as $uid => $p) {
|
||||
$values[] = '(' . (int) $uid . ',' . (int) $now . ','
|
||||
. $p['rank'] . ',' . $p['population'] . ',' . $p['villages'] . ','
|
||||
. $p['troop_count'] . ',' . $p['troop_upkeep'] . ','
|
||||
. $p['attack_points'] . ',' . $p['defence_points'] . ')';
|
||||
}
|
||||
|
||||
foreach (array_chunk($values, 200) as $chunk) {
|
||||
mysqli_query($database->dblink,
|
||||
"INSERT IGNORE INTO " . $table . "
|
||||
(uid, recorded_at, `rank`, population, villages,
|
||||
troop_count, troop_upkeep, attack_points, defence_points)
|
||||
VALUES " . implode(',', $chunk));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Aduna trupele fiecarui jucator si hrana pe care o consuma.
|
||||
*
|
||||
* Se numara trupele din satele proprii SI intaririle trimise altora
|
||||
* (enforcement.`from` pastreaza satul de origine, deci ele raman ale
|
||||
* trimitatorului). Trupele straine stationate la tine NU se numara: nu sunt
|
||||
* armata ta.
|
||||
*
|
||||
* Numarul brut de unitati e inselator - 1000 de falange nu inseamna cat 1000
|
||||
* de calareti de elita - de aceea inregistram si hrana consumata, care e
|
||||
* cantarul propriu al jocului si pondereaza automat unitatile dupa putere.
|
||||
*/
|
||||
private function addTroopTotals(array &$players)
|
||||
{
|
||||
global $database;
|
||||
|
||||
// consumul fiecarei unitati, din datele de joc
|
||||
$upkeep = array();
|
||||
|
||||
for ($i = 1; $i <= 90; $i++) {
|
||||
$name = 'u' . $i;
|
||||
|
||||
if (isset($GLOBALS[$name]) && isset($GLOBALS[$name]['pop'])) {
|
||||
$upkeep[$i] = (int) $GLOBALS[$name]['pop'];
|
||||
}
|
||||
}
|
||||
|
||||
if (!$upkeep) {
|
||||
return;
|
||||
}
|
||||
|
||||
// suma pe coloane, pentru trupele din satele proprii
|
||||
$sumCount = array();
|
||||
$sumUpkeep = array();
|
||||
|
||||
foreach ($upkeep as $i => $cost) {
|
||||
$sumCount[] = 'SUM(t.u' . $i . ')';
|
||||
$sumUpkeep[] = 'SUM(t.u' . $i . ') * ' . $cost;
|
||||
}
|
||||
|
||||
$sources = array(
|
||||
// trupele din satele proprii
|
||||
"SELECT v.owner AS uid,
|
||||
" . implode(' + ', $sumCount) . " AS cnt,
|
||||
" . implode(' + ', $sumUpkeep) . " AS upk
|
||||
FROM " . TB_PREFIX . "units t
|
||||
JOIN " . TB_PREFIX . "vdata v ON v.wref = t.vref
|
||||
GROUP BY v.owner",
|
||||
|
||||
// intaririle trimise altora: raman ale satului de origine
|
||||
"SELECT v.owner AS uid,
|
||||
" . implode(' + ', $sumCount) . " AS cnt,
|
||||
" . implode(' + ', $sumUpkeep) . " AS upk
|
||||
FROM " . TB_PREFIX . "enforcement t
|
||||
JOIN " . TB_PREFIX . "vdata v ON v.wref = t.`from`
|
||||
GROUP BY v.owner",
|
||||
);
|
||||
|
||||
foreach ($sources as $q) {
|
||||
$res = @mysqli_query($database->dblink, $q);
|
||||
|
||||
while ($res && ($row = mysqli_fetch_assoc($res))) {
|
||||
$uid = (int) $row['uid'];
|
||||
|
||||
if (!isset($players[$uid])) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$players[$uid]['troop_count'] += (int) $row['cnt'];
|
||||
$players[$uid]['troop_upkeep'] += (int) $row['upk'];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** Sterge instantaneele mai vechi decat retentia configurata. */
|
||||
private function trimPlayerStatistics($now)
|
||||
{
|
||||
global $database;
|
||||
|
||||
$days = defined('PLUS_STATS_KEEP_DAYS') ? (int) PLUS_STATS_KEEP_DAYS : 0;
|
||||
|
||||
if ($days <= 0) {
|
||||
return; // 0 = pastram tot
|
||||
}
|
||||
|
||||
mysqli_query($database->dblink,
|
||||
"DELETE FROM " . TB_PREFIX . "player_statistics_history
|
||||
WHERE recorded_at < " . (int) ($now - $days * 86400) . "
|
||||
LIMIT 5000");
|
||||
}
|
||||
}
|
||||
@@ -1990,6 +1990,11 @@ tz_def('TZ_ARRIVED', 'Arrived:');
|
||||
tz_def('TZ_ASSIGN_TO_POSITION', 'Assign to position');
|
||||
tz_def('TZ_AS_SOON_AS_A_PLAYER_YOU_INVITED_FO', 'As soon as a player you invited founds his');
|
||||
tz_def('TZ_ATTACKS', 'Attacks');
|
||||
tz_def('TZ_OVERVIEW', 'Overview');
|
||||
tz_def('TZ_FORUM', 'Forum');
|
||||
tz_def('TZ_CHAT', 'Chat');
|
||||
tz_def('TZ_NEWS', 'News');
|
||||
tz_def('TZ_OPTIONS', 'Options');
|
||||
tz_def('TZ_BOLD', 'bold');
|
||||
tz_def('TZ_BUILDING', 'Building');
|
||||
tz_def('TZ_CATAPULT_TARGET', 'catapult target');
|
||||
@@ -4245,3 +4250,29 @@ tz_def('ALLYBONUS_RECRUITMENT_DESC', 'Speeds up troop training in every troop-pr
|
||||
tz_def('ALLYBONUS_PHILOSOPHY_DESC', 'Increases culture point production from buildings and hero helmets. Town hall celebrations are not affected.');
|
||||
tz_def('ALLYBONUS_METALLURGY_DESC', 'Increases the offensive and defensive strength of your troops, on top of your smithy upgrades.');
|
||||
tz_def('ALLYBONUS_COMMERCE_DESC', 'Increases how much each merchant can carry. Multiplies with the trade office.');
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// STATISTICI GRAFICE (Travian Plus)
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
tz_def('PLUSSTATS_TITLE', 'Graphical statistics');
|
||||
tz_def('PLUSSTATS_INTRO', 'The development of your account over time.');
|
||||
tz_def('PLUSSTATS_RANK', 'Ranking');
|
||||
tz_def('PLUSSTATS_POP', 'Population');
|
||||
tz_def('PLUSSTATS_ARMY', 'Army strength (crop upkeep per hour)');
|
||||
tz_def('PLUSSTATS_VILLAGES', 'Villages');
|
||||
tz_def('PLUSSTATS_TROOPS', 'Troops');
|
||||
tz_def('PLUSSTATS_UPKEEP', 'Crop upkeep per hour');
|
||||
tz_def('PLUSSTATS_METRIC', 'Metric');
|
||||
tz_def('PLUSSTATS_NOW', 'Now');
|
||||
tz_def('PLUSSTATS_CHANGE', 'Change');
|
||||
tz_def('PLUSSTATS_NODATA', 'Not enough data yet');
|
||||
tz_def('PLUSSTATS_WAIT', 'Your account is being recorded. The graphs appear once at least two snapshots exist.');
|
||||
tz_def('PLUSSTATS_NEEDPLUS', 'Graphical statistics are a Travian Plus feature. Activate Plus to see the development of your account.');
|
||||
tz_def('PLUSSTATS_DISABLED', 'Graphical statistics are not enabled on this server.');
|
||||
tz_def('PLUSSTATS_FOOT', 'Army strength is measured by crop upkeep, which is the game\'s own weighting: it counts a strong unit for more than a weak one. Troops reinforcing other players still count as yours.');
|
||||
tz_def('ADM_PLUS_STATISTICS', 'Plus graphical statistics');
|
||||
tz_def('ADM_PLUS_STATISTICS_TIP', 'Records rank, population, villages and army for every player, so Plus players can see how their account developed. The tab is only visible with an active Plus account.');
|
||||
tz_def('ADM_PLUS_STATISTICS_INTERVAL', 'Statistics snapshot interval (hours)');
|
||||
tz_def('ADM_PLUS_STATISTICS_INTERVAL_TIP', 'How often a snapshot is taken. On a fast server a day is a lot of play, so a few hours gives a readable curve.');
|
||||
tz_def('ADM_PLUS_STATISTICS_KEEP', 'Statistics history kept (days)');
|
||||
tz_def('ADM_PLUS_STATISTICS_KEEP_TIP', '0 keeps everything, so players see the full history of their account since recording began.');
|
||||
|
||||
@@ -1996,6 +1996,11 @@ tz_def('TZ_ARRIVED', 'Arrivé :');
|
||||
tz_def('TZ_ASSIGN_TO_POSITION', 'Assigner à un poste');
|
||||
tz_def('TZ_AS_SOON_AS_A_PLAYER_YOU_INVITED_FO', 'Dès qu\'un joueur que vous avez invité fonde son');
|
||||
tz_def('TZ_ATTACKS', 'Attaques');
|
||||
tz_def('TZ_OVERVIEW', 'Vue d\'ensemble');
|
||||
tz_def('TZ_FORUM', 'Forum');
|
||||
tz_def('TZ_CHAT', 'Chat');
|
||||
tz_def('TZ_NEWS', 'Actualités');
|
||||
tz_def('TZ_OPTIONS', 'Options');
|
||||
tz_def('TZ_BOLD', 'gras');
|
||||
tz_def('TZ_BUILDING', 'Bâtiment');
|
||||
tz_def('TZ_CATAPULT_TARGET', 'cible de la catapulte');
|
||||
@@ -4188,3 +4193,29 @@ tz_def('ALLYBONUS_RECRUITMENT_DESC', 'Accélère l\'entraînement des troupes da
|
||||
tz_def('ALLYBONUS_PHILOSOPHY_DESC', 'Augmente la production de points de culture des bâtiments et des casques du héros. Les fêtes de l\'hôtel de ville ne sont pas affectées.');
|
||||
tz_def('ALLYBONUS_METALLURGY_DESC', 'Augmente la force d\'attaque et de défense de vos troupes, en plus des améliorations de la forge.');
|
||||
tz_def('ALLYBONUS_COMMERCE_DESC', 'Augmente la capacité de charge de chaque marchand. Se multiplie avec le bureau de commerce.');
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// STATISTICI GRAFICE (Travian Plus)
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
tz_def('PLUSSTATS_TITLE', 'Statistiques graphiques');
|
||||
tz_def('PLUSSTATS_INTRO', 'L\'évolution de votre compte au fil du temps.');
|
||||
tz_def('PLUSSTATS_RANK', 'Classement');
|
||||
tz_def('PLUSSTATS_POP', 'Population');
|
||||
tz_def('PLUSSTATS_ARMY', 'Puissance de l\'armée (consommation de céréales par heure)');
|
||||
tz_def('PLUSSTATS_VILLAGES', 'Villages');
|
||||
tz_def('PLUSSTATS_TROOPS', 'Troupes');
|
||||
tz_def('PLUSSTATS_UPKEEP', 'Consommation de céréales par heure');
|
||||
tz_def('PLUSSTATS_METRIC', 'Indicateur');
|
||||
tz_def('PLUSSTATS_NOW', 'Maintenant');
|
||||
tz_def('PLUSSTATS_CHANGE', 'Évolution');
|
||||
tz_def('PLUSSTATS_NODATA', 'Pas encore assez de données');
|
||||
tz_def('PLUSSTATS_WAIT', 'Votre compte est en cours d\'enregistrement. Les graphiques apparaîtront dès qu\'il y aura au moins deux relevés.');
|
||||
tz_def('PLUSSTATS_NEEDPLUS', 'Les statistiques graphiques sont une fonction Travian Plus. Activez Plus pour voir l\'évolution de votre compte.');
|
||||
tz_def('PLUSSTATS_DISABLED', 'Les statistiques graphiques ne sont pas activées sur ce serveur.');
|
||||
tz_def('PLUSSTATS_FOOT', 'La puissance de l\'armée se mesure à la consommation de céréales, la pondération propre au jeu : une unité forte compte plus qu\'une faible. Les troupes en renfort chez d\'autres joueurs restent les vôtres.');
|
||||
tz_def('ADM_PLUS_STATISTICS', 'Statistiques graphiques Plus');
|
||||
tz_def('ADM_PLUS_STATISTICS_TIP', 'Enregistre le classement, la population, les villages et l\'armée de chaque joueur, afin que les joueurs Plus puissent voir l\'évolution de leur compte. L\'onglet n\'est visible qu\'avec un compte Plus actif.');
|
||||
tz_def('ADM_PLUS_STATISTICS_INTERVAL', 'Intervalle des relevés (heures)');
|
||||
tz_def('ADM_PLUS_STATISTICS_INTERVAL_TIP', 'Fréquence des relevés. Sur un serveur rapide, une journée représente beaucoup de jeu ; quelques heures donnent une courbe lisible.');
|
||||
tz_def('ADM_PLUS_STATISTICS_KEEP', 'Historique conservé (jours)');
|
||||
tz_def('ADM_PLUS_STATISTICS_KEEP_TIP', '0 conserve tout, afin que les joueurs voient l\'historique complet de leur compte depuis le début de l\'enregistrement.');
|
||||
|
||||
@@ -1957,6 +1957,11 @@ tz_def('TZ_ARRIVED', 'Sosit:');
|
||||
tz_def('TZ_ASSIGN_TO_POSITION', 'Atribuie la poziție');
|
||||
tz_def('TZ_AS_SOON_AS_A_PLAYER_YOU_INVITED_FO', 'De îndată ce un jucător invitat de tine își întemeiază');
|
||||
tz_def('TZ_ATTACKS', 'Atacuri');
|
||||
tz_def('TZ_OVERVIEW', 'Prezentare');
|
||||
tz_def('TZ_FORUM', 'Forum');
|
||||
tz_def('TZ_CHAT', 'Chat');
|
||||
tz_def('TZ_NEWS', 'Noutăți');
|
||||
tz_def('TZ_OPTIONS', 'Opțiuni');
|
||||
tz_def('TZ_BOLD', 'îngroșat');
|
||||
tz_def('TZ_BUILDING', 'Clădire');
|
||||
tz_def('TZ_CATAPULT_TARGET', 'ținta catapultei');
|
||||
@@ -3985,3 +3990,29 @@ tz_def('ALLYBONUS_RECRUITMENT_DESC', 'Grabeste instruirea trupelor in toate clad
|
||||
tz_def('ALLYBONUS_PHILOSOPHY_DESC', 'Creste productia de puncte de cultura de la cladiri si de la coifurile eroului. Serbarile din primarie nu sunt afectate.');
|
||||
tz_def('ALLYBONUS_METALLURGY_DESC', 'Creste forta de atac si de aparare a trupelor, peste imbunatatirile din fierarie.');
|
||||
tz_def('ALLYBONUS_COMMERCE_DESC', 'Creste cat poate cara fiecare negustor. Se inmulteste cu biroul comercial.');
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// STATISTICI GRAFICE (Travian Plus)
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
tz_def('PLUSSTATS_TITLE', 'Statistici grafice');
|
||||
tz_def('PLUSSTATS_INTRO', 'Evolutia contului tau in timp.');
|
||||
tz_def('PLUSSTATS_RANK', 'Clasament');
|
||||
tz_def('PLUSSTATS_POP', 'Populatie');
|
||||
tz_def('PLUSSTATS_ARMY', 'Puterea armatei (cereale consumate pe ora)');
|
||||
tz_def('PLUSSTATS_VILLAGES', 'Sate');
|
||||
tz_def('PLUSSTATS_TROOPS', 'Trupe');
|
||||
tz_def('PLUSSTATS_UPKEEP', 'Cereale consumate pe ora');
|
||||
tz_def('PLUSSTATS_METRIC', 'Indicator');
|
||||
tz_def('PLUSSTATS_NOW', 'Acum');
|
||||
tz_def('PLUSSTATS_CHANGE', 'Evolutie');
|
||||
tz_def('PLUSSTATS_NODATA', 'Inca nu sunt destule date');
|
||||
tz_def('PLUSSTATS_WAIT', 'Contul tau se inregistreaza. Graficele apar dupa ce exista cel putin doua masuratori.');
|
||||
tz_def('PLUSSTATS_NEEDPLUS', 'Statisticile grafice sunt o functie Travian Plus. Activeaza Plus ca sa vezi evolutia contului.');
|
||||
tz_def('PLUSSTATS_DISABLED', 'Statisticile grafice nu sunt activate pe acest server.');
|
||||
tz_def('PLUSSTATS_FOOT', 'Puterea armatei se masoara prin cerealele consumate, cantarul propriu al jocului: o unitate puternica valoreaza mai mult decat una slaba. Trupele trimise ca intarire la alti jucatori raman ale tale.');
|
||||
tz_def('ADM_PLUS_STATISTICS', 'Statistici grafice Plus');
|
||||
tz_def('ADM_PLUS_STATISTICS_TIP', 'Inregistreaza rangul, populatia, satele si armata fiecarui jucator, ca jucatorii cu Plus sa vada cum a evoluat contul. Tabul se vede doar cu Plus activ.');
|
||||
tz_def('ADM_PLUS_STATISTICS_INTERVAL', 'Intervalul intre masuratori (ore)');
|
||||
tz_def('ADM_PLUS_STATISTICS_INTERVAL_TIP', 'Cat de des se ia o masuratoare. Pe un server rapid o zi inseamna mult joc, asa ca cateva ore dau o curba lizibila.');
|
||||
tz_def('ADM_PLUS_STATISTICS_KEEP', 'Istoric pastrat (zile)');
|
||||
tz_def('ADM_PLUS_STATISTICS_KEEP_TIP', '0 pastreaza tot, ca jucatorii sa vada istoricul complet al contului de la inceputul inregistrarii.');
|
||||
|
||||
@@ -28,17 +28,17 @@ if ($session->alliance == $aid && $session->alliance > 0) {
|
||||
|
||||
<!-- Overview -->
|
||||
<a href="allianz.php" <?php if ($s === 0) { echo 'class="selected"'; } ?>>
|
||||
Overview
|
||||
<?php echo TZ_OVERVIEW; ?>
|
||||
</a>
|
||||
|
||||
| <!-- Forum -->
|
||||
<a href="allianz.php?s=2" <?php if ($s === 2) { echo 'class="selected"'; } ?>>
|
||||
Forum
|
||||
<?php echo TZ_FORUM; ?>
|
||||
</a>
|
||||
|
||||
| <!-- Chat -->
|
||||
<a href="allianz.php?s=6" <?php if ($s === 6) { echo 'class="selected"'; } ?>>
|
||||
Chat
|
||||
<?php echo TZ_CHAT; ?>
|
||||
</a>
|
||||
|
||||
| <!-- Attacks -->
|
||||
@@ -48,7 +48,7 @@ if ($session->alliance == $aid && $session->alliance > 0) {
|
||||
|
||||
| <!-- News -->
|
||||
<a href="allianz.php?s=4" <?php if ($s === 4) { echo 'class="selected"'; } ?>>
|
||||
News
|
||||
<?php echo TZ_NEWS; ?>
|
||||
</a>
|
||||
|
||||
<?php if (defined('NEW_FUNCTIONS_ALLIANCE_BONUSES') && NEW_FUNCTIONS_ALLIANCE_BONUSES) { ?>
|
||||
@@ -64,7 +64,7 @@ if ($session->alliance == $aid && $session->alliance > 0) {
|
||||
?>
|
||||
| <!-- Options -->
|
||||
<a href="allianz.php?s=5" <?php if ($s === 5) { echo 'class="selected"'; } ?>>
|
||||
Options
|
||||
<?php echo TZ_OPTIONS; ?>
|
||||
</a>
|
||||
<?php
|
||||
} else {
|
||||
|
||||
@@ -40,6 +40,23 @@ if (!isset($_SESSION['search']) || !is_numeric($_SESSION['search'])) {
|
||||
<?php echo TZ_THE_LARGEST_PLAYERS; ?>
|
||||
|
||||
<div id="submenu">
|
||||
<?php
|
||||
// Tabul de statistici grafice: apare doar cand functia e
|
||||
// pornita SI jucatorul are Plus activ.
|
||||
//
|
||||
// Iconita foloseste acelasi tipar ca vecinele ei: un
|
||||
// img gol (img/x.gif) cu imaginea pusa din CSS prin
|
||||
// clasa. Sprite-ul e la gpack/<pachet>/img/s/stats.gif,
|
||||
// 30x63, cu starea normala sus si cea activa jos.
|
||||
if (defined('NEW_FUNCTIONS_PLUS_STATISTICS') && NEW_FUNCTIONS_PLUS_STATISTICS
|
||||
&& isset($session->plus) && (int) $session->plus == 1) {
|
||||
$psLabel = defined('PLUSSTATS_TITLE') ? PLUSSTATS_TITLE : 'Graphical statistics';
|
||||
$psLabel = htmlspecialchars($psLabel, ENT_QUOTES, 'UTF-8');
|
||||
echo '<a title="' . $psLabel . '" href="statistiken.php?id=50">'
|
||||
. '<img class="btn_stats" src="img/x.gif" alt="' . $psLabel . '" />'
|
||||
. '</a>';
|
||||
}
|
||||
?>
|
||||
<a title="<?php echo TZ_TOP_10; ?>" href="statistiken.php?id=7">
|
||||
<img class="btn_top10" src="img/x.gif" alt="<?php echo TZ_TOP_10; ?>" />
|
||||
</a>
|
||||
|
||||
@@ -37,6 +37,23 @@ if (!isset($_SESSION['search']) || !is_numeric($_SESSION['search'])) {
|
||||
<th colspan="5">
|
||||
<?php echo TZ_THE_MOST_SUCCESSFUL_ATTACKERS; ?>
|
||||
<div id="submenu">
|
||||
<?php
|
||||
// Tabul de statistici grafice: apare doar cand functia e
|
||||
// pornita SI jucatorul are Plus activ.
|
||||
//
|
||||
// Iconita foloseste acelasi tipar ca vecinele ei: un
|
||||
// img gol (img/x.gif) cu imaginea pusa din CSS prin
|
||||
// clasa. Sprite-ul e la gpack/<pachet>/img/s/stats.gif,
|
||||
// 30x63, cu starea normala sus si cea activa jos.
|
||||
if (defined('NEW_FUNCTIONS_PLUS_STATISTICS') && NEW_FUNCTIONS_PLUS_STATISTICS
|
||||
&& isset($session->plus) && (int) $session->plus == 1) {
|
||||
$psLabel = defined('PLUSSTATS_TITLE') ? PLUSSTATS_TITLE : 'Graphical statistics';
|
||||
$psLabel = htmlspecialchars($psLabel, ENT_QUOTES, 'UTF-8');
|
||||
echo '<a title="' . $psLabel . '" href="statistiken.php?id=50">'
|
||||
. '<img class="btn_stats" src="img/x.gif" alt="' . $psLabel . '" />'
|
||||
. '</a>';
|
||||
}
|
||||
?>
|
||||
<a title="<?php echo TZ_TOP_10; ?>" href="statistiken.php?id=7">
|
||||
<img class="btn_top10" src="img/x.gif" alt="<?php echo TZ_TOP_10; ?>" />
|
||||
</a>
|
||||
|
||||
@@ -37,6 +37,23 @@ if (!isset($_SESSION['search']) || !is_numeric($_SESSION['search'])) {
|
||||
<th colspan="5">
|
||||
<?php echo TZ_THE_MOST_SUCCESSFUL_DEFENDERS; ?>
|
||||
<div id="submenu">
|
||||
<?php
|
||||
// Tabul de statistici grafice: apare doar cand functia e
|
||||
// pornita SI jucatorul are Plus activ.
|
||||
//
|
||||
// Iconita foloseste acelasi tipar ca vecinele ei: un
|
||||
// img gol (img/x.gif) cu imaginea pusa din CSS prin
|
||||
// clasa. Sprite-ul e la gpack/<pachet>/img/s/stats.gif,
|
||||
// 30x63, cu starea normala sus si cea activa jos.
|
||||
if (defined('NEW_FUNCTIONS_PLUS_STATISTICS') && NEW_FUNCTIONS_PLUS_STATISTICS
|
||||
&& isset($session->plus) && (int) $session->plus == 1) {
|
||||
$psLabel = defined('PLUSSTATS_TITLE') ? PLUSSTATS_TITLE : 'Graphical statistics';
|
||||
$psLabel = htmlspecialchars($psLabel, ENT_QUOTES, 'UTF-8');
|
||||
echo '<a title="' . $psLabel . '" href="statistiken.php?id=50">'
|
||||
. '<img class="btn_stats" src="img/x.gif" alt="' . $psLabel . '" />'
|
||||
. '</a>';
|
||||
}
|
||||
?>
|
||||
<a title="<?php echo TZ_TOP_10; ?>" href="statistiken.php?id=7">
|
||||
<img class="btn_top10" src="img/x.gif" alt="<?php echo TZ_TOP_10; ?>" />
|
||||
</a>
|
||||
|
||||
@@ -47,7 +47,31 @@
|
||||
<table cellpadding="1" cellspacing="1">
|
||||
<thead>
|
||||
<tr>
|
||||
<th><?php echo TZ_TOP_10_PLAYERS; ?><div id="submenu"><a title="<?php echo TZ_TOP_10; ?>" href="statistiken.php?id=7"><img class="active btn_top10" src="img/x.gif" alt="<?php echo TZ_TOP_10; ?>"></a><a title="<?php echo DEFENDER; ?>" href="statistiken.php?id=32"><img class="btn_def" src="img/x.gif" alt="<?php echo DEFENDER; ?>"></a><a title="<?php echo ATTACKER; ?>" href="statistiken.php?id=31"><img class="btn_off" src="img/x.gif" alt="<?php echo ATTACKER; ?>"></a></div><div id="submenu2"></div></th>
|
||||
<th><?php echo TZ_TOP_10_PLAYERS; ?>
|
||||
<div id="submenu">
|
||||
<?php
|
||||
// Tabul de statistici grafice: apare doar cand functia e
|
||||
// pornita SI jucatorul are Plus activ.
|
||||
//
|
||||
// Iconita foloseste acelasi tipar ca vecinele ei: un
|
||||
// img gol (img/x.gif) cu imaginea pusa din CSS prin
|
||||
// clasa. Sprite-ul e la gpack/<pachet>/img/s/stats.gif,
|
||||
// 30x63, cu starea normala sus si cea activa jos.
|
||||
if (defined('NEW_FUNCTIONS_PLUS_STATISTICS') && NEW_FUNCTIONS_PLUS_STATISTICS
|
||||
&& isset($session->plus) && (int) $session->plus == 1) {
|
||||
$psLabel = defined('PLUSSTATS_TITLE') ? PLUSSTATS_TITLE : 'Graphical statistics';
|
||||
$psLabel = htmlspecialchars($psLabel, ENT_QUOTES, 'UTF-8');
|
||||
echo '<a title="' . $psLabel . '" href="statistiken.php?id=50">'
|
||||
. '<img class="btn_stats" src="img/x.gif" alt="' . $psLabel . '" />'
|
||||
. '</a>';
|
||||
}
|
||||
?>
|
||||
<a title="<?php echo TZ_TOP_10; ?>" href="statistiken.php?id=7"><img class="active btn_top10" src="img/x.gif" alt="<?php echo TZ_TOP_10; ?>"></a>
|
||||
<a title="<?php echo DEFENDER; ?>" href="statistiken.php?id=32"><img class="btn_def" src="img/x.gif" alt="<?php echo DEFENDER; ?>"></a>
|
||||
<a title="<?php echo ATTACKER; ?>" href="statistiken.php?id=31"><img class="btn_off" src="img/x.gif" alt="<?php echo ATTACKER; ?>"></a>
|
||||
</div><div id="submenu2">
|
||||
</div>
|
||||
</th>
|
||||
</tr>
|
||||
</thead>
|
||||
</table>
|
||||
|
||||
@@ -0,0 +1,307 @@
|
||||
<?php
|
||||
#################################################################################
|
||||
## Statistici grafice (Travian Plus) ##
|
||||
## --------------------------------------------------------------------------- ##
|
||||
## Arata evolutia in timp a contului: rangul, populatia si armata. ##
|
||||
## Datele se strang pentru toti jucatorii, dar tabul se vede doar cu Plus. ##
|
||||
## ##
|
||||
## Graficele sunt SVG generat aici, in PHP. Fara biblioteca externa si fara ##
|
||||
## CDN: serverul poate fi in spatele unui proxy sau fara acces la internet, ##
|
||||
## iar o pagina de statistici nu are ce cauta sa depinda de asa ceva. ##
|
||||
#################################################################################
|
||||
|
||||
// -------------------------------------------------
|
||||
// ACCES: doar conturile cu Plus
|
||||
// -------------------------------------------------
|
||||
$psHasPlus = (isset($session->plus) && (int) $session->plus == 1);
|
||||
$psEnabled = defined('NEW_FUNCTIONS_PLUS_STATISTICS') && NEW_FUNCTIONS_PLUS_STATISTICS;
|
||||
|
||||
/**
|
||||
* Deseneaza un grafic de linie ca SVG.
|
||||
*
|
||||
* $points - lista de perechi [timestamp, valoare]
|
||||
* $invert - true pentru rang, unde valoarea mai MICA e mai buna, deci axa se
|
||||
* deseneaza invers (locul 1 sus)
|
||||
*/
|
||||
function ps_line_chart(array $points, $title, $color = '#7db72f', $invert = false)
|
||||
{
|
||||
$w = 560;
|
||||
$h = 170;
|
||||
$padL = 52;
|
||||
$padR = 12;
|
||||
$padT = 22;
|
||||
$padB = 26;
|
||||
|
||||
$out = '<svg width="' . $w . '" height="' . $h . '" viewBox="0 0 ' . $w . ' ' . $h . '"'
|
||||
. ' xmlns="http://www.w3.org/2000/svg" style="max-width:100%;height:auto;">';
|
||||
$out .= '<rect width="' . $w . '" height="' . $h . '" fill="#fff" stroke="#c9c9c9"/>';
|
||||
$out .= '<text x="8" y="14" font-family="Arial" font-size="11" font-weight="bold" fill="#333">'
|
||||
. htmlspecialchars($title, ENT_QUOTES, 'UTF-8') . '</text>';
|
||||
|
||||
if (count($points) < 2) {
|
||||
$out .= '<text x="' . ($w / 2) . '" y="' . ($h / 2) . '" font-family="Arial" font-size="11"'
|
||||
. ' fill="#999" text-anchor="middle">'
|
||||
. htmlspecialchars(defined('PLUSSTATS_NODATA') ? PLUSSTATS_NODATA : 'Not enough data yet', ENT_QUOTES, 'UTF-8')
|
||||
. '</text></svg>';
|
||||
|
||||
return $out;
|
||||
}
|
||||
|
||||
$values = array_map(function ($p) { return (float) $p[1]; }, $points);
|
||||
$times = array_map(function ($p) { return (int) $p[0]; }, $points);
|
||||
|
||||
$minV = min($values);
|
||||
$maxV = max($values);
|
||||
|
||||
// o linie perfect plata ar imparti la zero; ii dam putin spatiu
|
||||
if ($maxV - $minV < 0.0001) {
|
||||
$maxV = $minV + 1;
|
||||
}
|
||||
|
||||
$minT = min($times);
|
||||
$maxT = max($times);
|
||||
$spanT = max(1, $maxT - $minT);
|
||||
|
||||
$plotW = $w - $padL - $padR;
|
||||
$plotH = $h - $padT - $padB;
|
||||
|
||||
$x = function ($t) use ($padL, $plotW, $minT, $spanT) {
|
||||
return $padL + ($t - $minT) / $spanT * $plotW;
|
||||
};
|
||||
$y = function ($v) use ($padT, $plotH, $minV, $maxV, $invert) {
|
||||
$frac = ($v - $minV) / ($maxV - $minV);
|
||||
|
||||
// la rang, valoarea mica inseamna loc bun, deci o punem sus
|
||||
return $invert ? $padT + $frac * $plotH : $padT + (1 - $frac) * $plotH;
|
||||
};
|
||||
|
||||
// grila si etichete pe axa verticala
|
||||
for ($i = 0; $i <= 3; $i++) {
|
||||
$v = $minV + ($maxV - $minV) * $i / 3;
|
||||
$yy = $y($v);
|
||||
$out .= '<line x1="' . $padL . '" y1="' . round($yy, 1) . '" x2="' . ($w - $padR)
|
||||
. '" y2="' . round($yy, 1) . '" stroke="#eee" stroke-width="1"/>';
|
||||
$out .= '<text x="' . ($padL - 5) . '" y="' . (round($yy, 1) + 3) . '" font-family="Arial"'
|
||||
. ' font-size="9" fill="#888" text-anchor="end">' . number_format($v) . '</text>';
|
||||
}
|
||||
|
||||
// linia propriu-zisa
|
||||
$d = '';
|
||||
|
||||
foreach ($points as $i => $p) {
|
||||
$d .= ($i === 0 ? 'M' : 'L') . round($x($p[0]), 1) . ',' . round($y($p[1]), 1) . ' ';
|
||||
}
|
||||
|
||||
// suprafata de sub linie, pentru lizibilitate
|
||||
$area = $d . 'L' . round($x($times[count($times) - 1]), 1) . ',' . ($padT + $plotH)
|
||||
. ' L' . round($x($times[0]), 1) . ',' . ($padT + $plotH) . ' Z';
|
||||
|
||||
$out .= '<path d="' . $area . '" fill="' . $color . '" fill-opacity="0.15"/>';
|
||||
$out .= '<path d="' . $d . '" fill="none" stroke="' . $color . '" stroke-width="2"/>';
|
||||
|
||||
// punctele de capat, cu valorile
|
||||
$first = $points[0];
|
||||
$lastP = $points[count($points) - 1];
|
||||
|
||||
foreach (array($first, $lastP) as $p) {
|
||||
$out .= '<circle cx="' . round($x($p[0]), 1) . '" cy="' . round($y($p[1]), 1)
|
||||
. '" r="3" fill="' . $color . '"/>';
|
||||
}
|
||||
|
||||
// datele de la capete
|
||||
$out .= '<text x="' . $padL . '" y="' . ($h - 8) . '" font-family="Arial" font-size="9" fill="#888">'
|
||||
. date('d.m', $minT) . '</text>';
|
||||
$out .= '<text x="' . ($w - $padR) . '" y="' . ($h - 8) . '" font-family="Arial" font-size="9"'
|
||||
. ' fill="#888" text-anchor="end">' . date('d.m', $maxT) . '</text>';
|
||||
|
||||
// valoarea curenta, in dreapta sus
|
||||
$out .= '<text x="' . ($w - $padR) . '" y="14" font-family="Arial" font-size="11"'
|
||||
. ' font-weight="bold" fill="' . $color . '" text-anchor="end">'
|
||||
. number_format($lastP[1]) . '</text>';
|
||||
|
||||
$out .= '</svg>';
|
||||
|
||||
return $out;
|
||||
}
|
||||
?>
|
||||
|
||||
<style>
|
||||
.ps-wrap{max-width:600px}
|
||||
.ps-head{width:100%;margin-bottom:10px}
|
||||
.ps-chart{margin-bottom:10px}
|
||||
.ps-note{color:#777;font-size:11px;margin:6px 0 12px 0}
|
||||
.ps-locked{border:1px solid #e0c86a;background:#fdf6df;padding:10px;color:#7a5c00;font-size:12px}
|
||||
.ps-sum{width:100%;border-collapse:collapse;font-size:12px;margin-top:10px}
|
||||
.ps-sum td,.ps-sum th{border:1px solid #dcdcdc;padding:3px 6px}
|
||||
.ps-sum th{background:#f2f2f2;text-align:left}
|
||||
.ps-delta-up{color:#1f7a1f;font-weight:bold}
|
||||
.ps-delta-down{color:#a33;font-weight:bold}
|
||||
</style>
|
||||
|
||||
<div class="ps-wrap">
|
||||
|
||||
<?php
|
||||
// Acelasi cap de tabel ca celelalte pagini de clasament, ca sa nu dispara
|
||||
// navigatia cu iconite cand intri aici. Iconita de statistici e marcata
|
||||
// "active", asa cum face si ally_top10.tpl pentru pagina curenta.
|
||||
?>
|
||||
<table cellpadding="1" cellspacing="1" id="player" class="ps-head">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>
|
||||
<?php echo defined('PLUSSTATS_TITLE') ? PLUSSTATS_TITLE : 'Graphical statistics'; ?>
|
||||
|
||||
<div id="submenu">
|
||||
<a title="<?php echo defined('PLUSSTATS_TITLE') ? PLUSSTATS_TITLE : 'Graphical statistics'; ?>" href="statistiken.php?id=50">
|
||||
<img class="active btn_stats" src="img/x.gif" alt="<?php echo defined('PLUSSTATS_TITLE') ? PLUSSTATS_TITLE : 'Graphical statistics'; ?>" />
|
||||
</a>
|
||||
<a title="<?php echo TZ_TOP_10; ?>" href="statistiken.php?id=7">
|
||||
<img class="btn_top10" src="img/x.gif" alt="<?php echo TZ_TOP_10; ?>" />
|
||||
</a>
|
||||
<a title="<?php echo DEFENDER; ?>" href="statistiken.php?id=32">
|
||||
<img class="btn_def" src="img/x.gif" alt="<?php echo DEFENDER; ?>" />
|
||||
</a>
|
||||
<a title="<?php echo ATTACKER; ?>" href="statistiken.php?id=31">
|
||||
<img class="btn_off" src="img/x.gif" alt="<?php echo ATTACKER; ?>" />
|
||||
</a>
|
||||
</div>
|
||||
</th>
|
||||
</tr>
|
||||
</thead>
|
||||
</table>
|
||||
|
||||
<?php
|
||||
if (!$psEnabled) {
|
||||
echo '<div class="ps-locked">'
|
||||
. (defined('PLUSSTATS_DISABLED') ? PLUSSTATS_DISABLED
|
||||
: 'Graphical statistics are not enabled on this server.')
|
||||
. '</div></div>';
|
||||
return;
|
||||
}
|
||||
|
||||
if (!$psHasPlus) {
|
||||
echo '<div class="ps-locked">'
|
||||
. (defined('PLUSSTATS_NEEDPLUS') ? PLUSSTATS_NEEDPLUS
|
||||
: 'Graphical statistics are a Travian Plus feature. Activate Plus to see the development of your account.')
|
||||
. '</div></div>';
|
||||
return;
|
||||
}
|
||||
|
||||
// -------------------------------------------------
|
||||
// DATELE
|
||||
// -------------------------------------------------
|
||||
$psRows = array();
|
||||
$psUid = (int) $session->uid;
|
||||
$psQ = @mysqli_query($database->dblink,
|
||||
"SELECT recorded_at, `rank`, population, villages, troop_count, troop_upkeep
|
||||
FROM " . TB_PREFIX . "player_statistics_history
|
||||
WHERE uid = " . $psUid . "
|
||||
ORDER BY recorded_at ASC
|
||||
LIMIT 400");
|
||||
|
||||
while ($psQ && ($psRow = mysqli_fetch_assoc($psQ))) {
|
||||
$psRows[] = $psRow;
|
||||
}
|
||||
|
||||
if (count($psRows) < 2) {
|
||||
echo '<div class="ps-locked">'
|
||||
. (defined('PLUSSTATS_WAIT') ? PLUSSTATS_WAIT
|
||||
: 'Your account is being recorded. The graphs appear once at least two snapshots exist.')
|
||||
. '</div></div>';
|
||||
return;
|
||||
}
|
||||
|
||||
$psSeries = array('rank' => array(), 'population' => array(), 'villages' => array(),
|
||||
'troop_upkeep' => array(), 'troop_count' => array());
|
||||
|
||||
foreach ($psRows as $psRow) {
|
||||
$t = (int) $psRow['recorded_at'];
|
||||
|
||||
// rangul 0 inseamna "neclasat inca" - il sarim, ca sa nu strice scara
|
||||
if ((int) $psRow['rank'] > 0) {
|
||||
$psSeries['rank'][] = array($t, (int) $psRow['rank']);
|
||||
}
|
||||
|
||||
$psSeries['population'][] = array($t, (int) $psRow['population']);
|
||||
$psSeries['villages'][] = array($t, (int) $psRow['villages']);
|
||||
$psSeries['troop_upkeep'][] = array($t, (int) $psRow['troop_upkeep']);
|
||||
$psSeries['troop_count'][] = array($t, (int) $psRow['troop_count']);
|
||||
}
|
||||
|
||||
echo '<div class="ps-note">'
|
||||
. (defined('PLUSSTATS_INTRO') ? PLUSSTATS_INTRO
|
||||
: 'The development of your account over time.')
|
||||
. '</div>';
|
||||
|
||||
echo '<div class="ps-chart">'
|
||||
. ps_line_chart($psSeries['rank'],
|
||||
defined('PLUSSTATS_RANK') ? PLUSSTATS_RANK : 'Ranking',
|
||||
'#3b7dd8', true)
|
||||
. '</div>';
|
||||
|
||||
echo '<div class="ps-chart">'
|
||||
. ps_line_chart($psSeries['population'],
|
||||
defined('PLUSSTATS_POP') ? PLUSSTATS_POP : 'Population',
|
||||
'#7db72f')
|
||||
. '</div>';
|
||||
|
||||
echo '<div class="ps-chart">'
|
||||
. ps_line_chart($psSeries['villages'],
|
||||
defined('PLUSSTATS_VILLAGES') ? PLUSSTATS_VILLAGES : 'Villages',
|
||||
'#8e6fc4')
|
||||
. '</div>';
|
||||
|
||||
echo '<div class="ps-chart">'
|
||||
. ps_line_chart($psSeries['troop_upkeep'],
|
||||
defined('PLUSSTATS_ARMY') ? PLUSSTATS_ARMY : 'Army strength (crop upkeep per hour)',
|
||||
'#d9822b')
|
||||
. '</div>';
|
||||
|
||||
// -------------------------------------------------
|
||||
// REZUMAT: acum fata de primul instantaneu
|
||||
// -------------------------------------------------
|
||||
$psFirst = $psRows[0];
|
||||
$psLast = $psRows[count($psRows) - 1];
|
||||
|
||||
$psFields = array(
|
||||
'rank' => defined('PLUSSTATS_RANK') ? PLUSSTATS_RANK : 'Ranking',
|
||||
'population' => defined('PLUSSTATS_POP') ? PLUSSTATS_POP : 'Population',
|
||||
'villages' => defined('PLUSSTATS_VILLAGES') ? PLUSSTATS_VILLAGES : 'Villages',
|
||||
'troop_count' => defined('PLUSSTATS_TROOPS') ? PLUSSTATS_TROOPS : 'Troops',
|
||||
'troop_upkeep' => defined('PLUSSTATS_UPKEEP') ? PLUSSTATS_UPKEEP : 'Crop upkeep per hour',
|
||||
);
|
||||
?>
|
||||
|
||||
<table class="ps-sum">
|
||||
<tr>
|
||||
<th><?php echo defined('PLUSSTATS_METRIC') ? PLUSSTATS_METRIC : 'Metric'; ?></th>
|
||||
<th style="width:100px;text-align:right;"><?php echo date('d.m.Y', (int) $psFirst['recorded_at']); ?></th>
|
||||
<th style="width:100px;text-align:right;"><?php echo defined('PLUSSTATS_NOW') ? PLUSSTATS_NOW : 'Now'; ?></th>
|
||||
<th style="width:90px;text-align:right;"><?php echo defined('PLUSSTATS_CHANGE') ? PLUSSTATS_CHANGE : 'Change'; ?></th>
|
||||
</tr>
|
||||
<?php
|
||||
foreach ($psFields as $psKey => $psLabel) {
|
||||
$a = (int) $psFirst[$psKey];
|
||||
$b = (int) $psLast[$psKey];
|
||||
$d = $b - $a;
|
||||
|
||||
// la rang, scaderea numarului inseamna urcare in clasament
|
||||
$good = ($psKey === 'rank') ? ($d < 0) : ($d > 0);
|
||||
$cls = ($d == 0) ? '' : ($good ? 'ps-delta-up' : 'ps-delta-down');
|
||||
$sign = ($d > 0) ? '+' : '';
|
||||
?>
|
||||
<tr>
|
||||
<td><?php echo $psLabel; ?></td>
|
||||
<td style="text-align:right;"><?php echo number_format($a); ?></td>
|
||||
<td style="text-align:right;"><b><?php echo number_format($b); ?></b></td>
|
||||
<td style="text-align:right;" class="<?php echo $cls; ?>"><?php echo $sign . number_format($d); ?></td>
|
||||
</tr>
|
||||
<?php } ?>
|
||||
</table>
|
||||
|
||||
<div class="ps-note">
|
||||
<?php echo defined('PLUSSTATS_FOOT') ? PLUSSTATS_FOOT
|
||||
: 'Army strength is measured by crop upkeep, which is the game\'s own weighting: it counts a strong unit for more than a weak one. Troops reinforcing other players still count as yours.'; ?>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
@@ -209,7 +209,13 @@ function cron_reset_db_caches()
|
||||
continue;
|
||||
}
|
||||
|
||||
$prop->setAccessible(true);
|
||||
// Din PHP 8.1 proprietatile private sunt accesibile prin reflectie
|
||||
// fara acest apel, iar din 8.5 apelul e depreciat si umple
|
||||
// error_log cu zeci de avertismente la fiecare tick de cron.
|
||||
// Il pastram doar pentru versiunile vechi, unde chiar e necesar.
|
||||
if (PHP_VERSION_ID < 80100) {
|
||||
$prop->setAccessible(true);
|
||||
}
|
||||
|
||||
if (is_array($prop->getValue())) {
|
||||
$prop->setValue(null, []);
|
||||
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 835 B |
@@ -7881,6 +7881,9 @@ div.alliance div#submenu img.btn_def, div.statistics div#submenu img.btn_def {
|
||||
div.alliance div#submenu img.btn_off, div.statistics div#submenu img.btn_off {
|
||||
background-image: url("../../img/s/off.gif");
|
||||
}
|
||||
div.statistics div#submenu img.btn_stats {
|
||||
background-image: url("../../img/s/stats.gif");
|
||||
}
|
||||
div.statistics div#submenu img.btn_top10 {
|
||||
background-image: url("../../img/s/top10.gif");
|
||||
}
|
||||
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 835 B |
@@ -7881,6 +7881,9 @@ div.alliance div#submenu img.btn_def, div.statistics div#submenu img.btn_def {
|
||||
div.alliance div#submenu img.btn_off, div.statistics div#submenu img.btn_off {
|
||||
background-image: url("../../img/s/off.gif");
|
||||
}
|
||||
div.statistics div#submenu img.btn_stats {
|
||||
background-image: url("../../img/s/stats.gif");
|
||||
}
|
||||
div.statistics div#submenu img.btn_top10 {
|
||||
background-image: url("../../img/s/top10.gif");
|
||||
}
|
||||
|
||||
@@ -168,6 +168,26 @@ define("ALLIANCE_BONUS_PCT_LARGE", 4);
|
||||
// Gold cost to triple a donation.
|
||||
define("ALLIANCE_BONUS_TRIPLE_GOLD", 3);
|
||||
|
||||
// ***** Graphical statistics (Travian Plus)
|
||||
// The game periodically records each player's rank, population, villages, and
|
||||
// army from the moment this feature is enabled. These snapshots are then used
|
||||
// to generate the account progression graphs.
|
||||
//
|
||||
// Data is collected for ALL players, but the Statistics tab is visible ONLY to
|
||||
// users with an active Plus account. Otherwise, players who purchase Plus would
|
||||
// open the page and see an empty graph immediately after paying.
|
||||
define("NEW_FUNCTIONS_PLUS_STATISTICS", %PLUSSTATS%);
|
||||
|
||||
// Number of hours between snapshots. On a fast server, a single day represents
|
||||
// a significant amount of gameplay, so taking a snapshot every 6 hours provides
|
||||
// a smooth graph without filling the database table too quickly.
|
||||
define("PLUS_STATS_INTERVAL_HOURS", %PLUSSTATSHOURS%);
|
||||
|
||||
// Number of days to retain historical data. Set to 0 to keep all snapshots,
|
||||
// allowing the complete account progression to be displayed. Even over the
|
||||
// lifetime of an entire server, this only amounts to a few tens of thousands of records.
|
||||
define("PLUS_STATS_KEEP_DAYS", %PLUSSTATSKEEP%);
|
||||
|
||||
// ***** Graphic Pack
|
||||
//
|
||||
// SERVER_GP is the pack every player sees by default (chosen at install or in
|
||||
|
||||
@@ -84,6 +84,17 @@ class Process {
|
||||
// Bonusuri de alianta (port T4)
|
||||
$findReplace["%ALLIANCEBONUSES%"] = (isset($_POST['alliance_bonuses']) && $_POST['alliance_bonuses'] === 'true') ? 'true' : 'false';
|
||||
|
||||
// Statistici grafice (Travian Plus)
|
||||
$findReplace["%PLUSSTATS%"] = (isset($_POST['plus_statistics']) && $_POST['plus_statistics'] === 'false') ? 'false' : 'true';
|
||||
|
||||
$psHours = isset($_POST['plus_stats_hours']) ? (float) $_POST['plus_stats_hours'] : 6;
|
||||
if ($psHours < 0.25 || $psHours > 168) { $psHours = 6; }
|
||||
$findReplace["%PLUSSTATSHOURS%"] = $psHours;
|
||||
|
||||
$psKeep = isset($_POST['plus_stats_keep']) ? (int) $_POST['plus_stats_keep'] : 0;
|
||||
if ($psKeep < 0 || $psKeep > 3650) { $psKeep = 0; }
|
||||
$findReplace["%PLUSSTATSKEEP%"] = $psKeep;
|
||||
|
||||
$findReplace["%GP%"] = (isset($_POST['gpack']) && $_POST['gpack'] === 'true') ? 'true' : 'false';
|
||||
$findReplace["%SSERVER%"] = $_POST['sserver'];
|
||||
$findReplace["%SPORT%"] = $_POST['sport'];
|
||||
|
||||
@@ -312,6 +312,12 @@ foreach($mechs as $k => $l){
|
||||
<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>Plus graphical statistics</label><select class="input" name="plus_statistics">
|
||||
<option value="true" selected>Yes – record account history, graphs for Plus players</option>
|
||||
<option value="false">No</option>
|
||||
</select></div>
|
||||
<div><label>Statistics snapshot interval (hours)</label><input class="input" type="text" name="plus_stats_hours" value="6"></div>
|
||||
<div><label>Statistics history kept (days, 0 = forever)</label><input class="input" type="text" name="plus_stats_keep" value="0"></div>
|
||||
<div><label>Alliance bonuses (T4)</label><select class="input" name="alliance_bonuses">
|
||||
<option value="false" selected>No</option>
|
||||
<option value="true">Yes</option>
|
||||
|
||||
@@ -55,6 +55,9 @@ if (!empty($_GET['id'])) {
|
||||
case '8':
|
||||
echo HEROES;
|
||||
break;
|
||||
case '50':
|
||||
echo defined('PLUSSTATS_TITLE') ? PLUSSTATS_TITLE : 'Graphical statistics';
|
||||
break;
|
||||
case '0':
|
||||
echo GENERAL;
|
||||
break;
|
||||
@@ -194,6 +197,11 @@ if(isset($_GET['id'])) {
|
||||
case 43:
|
||||
include("Templates/Ranking/ally_top10.tpl");
|
||||
break;
|
||||
case 50:
|
||||
// Statistici grafice (Travian Plus). Sablonul isi verifica singur si
|
||||
// flagul, si contul Plus, deci intrarea directa pe URL nu ocoleste nimic.
|
||||
include("Templates/Ranking/statistics.tpl");
|
||||
break;
|
||||
case 0:
|
||||
include("Templates/Ranking/general.tpl");
|
||||
break;
|
||||
|
||||
@@ -407,6 +407,35 @@ CREATE TABLE IF NOT EXISTS `%PREFIX%alliance_donation_log` (
|
||||
--
|
||||
|
||||
|
||||
-- --------------------------------------------------------
|
||||
|
||||
--
|
||||
-- Table structure for table `%PREFIX%player_statistics_history`
|
||||
-- Periodic snapshots used by the Travian Plus graphical statistics page.
|
||||
-- Recorded for every player; only Plus accounts may view the graphs.
|
||||
--
|
||||
|
||||
CREATE TABLE IF NOT EXISTS `%PREFIX%player_statistics_history` (
|
||||
`id` int(11) NOT NULL AUTO_INCREMENT,
|
||||
`uid` int(11) NOT NULL,
|
||||
`recorded_at` int(11) NOT NULL,
|
||||
`rank` int(11) NOT NULL DEFAULT '0',
|
||||
`population` int(11) NOT NULL DEFAULT '0',
|
||||
`villages` smallint(6) NOT NULL DEFAULT '0',
|
||||
`troop_count` int(11) NOT NULL DEFAULT '0',
|
||||
`troop_upkeep` int(11) NOT NULL DEFAULT '0',
|
||||
`attack_points` bigint(20) NOT NULL DEFAULT '0',
|
||||
`defence_points` bigint(20) NOT NULL DEFAULT '0',
|
||||
PRIMARY KEY (`id`),
|
||||
UNIQUE KEY `uid_time` (`uid`, `recorded_at`),
|
||||
KEY `recorded_at` (`recorded_at`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
|
||||
|
||||
--
|
||||
-- Dumping data for table `%PREFIX%player_statistics_history`
|
||||
--
|
||||
|
||||
|
||||
-- --------------------------------------------------------
|
||||
|
||||
--
|
||||
|
||||
Reference in New Issue
Block a user