mirror of
https://github.com/Shadowss/TravianZ.git
synced 2026-07-17 01:56:07 +00:00
Add (Admin Panel) : Multi-account detection, Push protection, Heatmap, Gold Shop and Blacklist user names
Add (Admin Panel) : Multi-account detection, Push protection, Heatmap, Gold Shop (redem codes), Blacklist user names and Quest Editor + fix some php notice Fix quest_core for mission 33,36, train 2 units, etc (NEW TRIBE) There are some temporary bugs that will be fixed in next commit (pagination for new heatmap, quest reward)
This commit is contained in:
@@ -0,0 +1,144 @@
|
||||
<?php
|
||||
|
||||
#################################################################################
|
||||
## -= YOU MAY NOT REMOVE OR CHANGE THIS NOTICE =- ##
|
||||
## --------------------------------------------------------------------------- ##
|
||||
## Filename : blockReg.tpl ##
|
||||
## Type : Admin Panel Frontend for block User Names ##
|
||||
## --------------------------------------------------------------------------- ##
|
||||
## Developed by : Shadow ##
|
||||
## --------------------------------------------------------------------------- ##
|
||||
## Contact : cata7007@gmail.com ##
|
||||
## Project : TravianZ ##
|
||||
## GitHub : https://github.com/Shadowss/TravianZ ##
|
||||
## --------------------------------------------------------------------------- ##
|
||||
## License : TravianZ Project ##
|
||||
## Copyright : TravianZ (c) 2010-2026. All rights reserved. ##
|
||||
## --------------------------------------------------------------------------- ##
|
||||
#################################################################################
|
||||
|
||||
if (!isset($_SESSION['access']) || $_SESSION['access'] < ADMIN) {
|
||||
echo '<p style="color:#f87171;padding:16px;">Access denied.</p>';
|
||||
return;
|
||||
}
|
||||
|
||||
$blocks = RegBlock::all();
|
||||
$msg = isset($_GET['msg']) ? (string)$_GET['msg'] : '';
|
||||
|
||||
$typeLabel = [
|
||||
RegBlock::T_USERNAME => 'Username',
|
||||
RegBlock::T_EMAIL => 'E-mail address',
|
||||
RegBlock::T_DOMAIN => 'E-mail domain',
|
||||
];
|
||||
?>
|
||||
<style>
|
||||
.rb-wrap{color:#e2e8f0;font-family:Verdana,Arial,sans-serif;font-size:12px;padding:6px 4px 26px;}
|
||||
.rb-wrap h2{font-size:18px;margin:0 0 4px;color:#fff;}
|
||||
.rb-wrap h2 span{color:#f59e0b;}
|
||||
.rb-intro{color:#94a3b8;font-size:11px;margin:0 0 14px;max-width:820px;line-height:1.5;}
|
||||
.rb-msg{background:#14532d;border:1px solid #166534;color:#bbf7d0;border-radius:6px;padding:8px 12px;font-size:11px;margin-bottom:14px;}
|
||||
.rb-card{background:#111827;border:1px solid #1f2937;border-radius:8px;padding:14px 16px;margin-bottom:18px;}
|
||||
.rb-card h3{margin:0 0 10px;font-size:13px;color:#fff;font-weight:bold;}
|
||||
.rb-add{display:flex;flex-wrap:wrap;gap:12px;align-items:flex-end;}
|
||||
.rb-add label{display:block;font-size:10px;text-transform:uppercase;letter-spacing:.6px;color:#94a3b8;margin-bottom:4px;}
|
||||
.rb-add select,.rb-add input{background:#0b1220;border:1px solid #334155;border-radius:6px;color:#e2e8f0;padding:7px 9px;}
|
||||
.rb-add input.val{width:230px;}
|
||||
.rb-add input.note{width:180px;}
|
||||
.rb-add button{background:#f59e0b;color:#111827;font-weight:bold;border:0;border-radius:6px;padding:9px 18px;cursor:pointer;}
|
||||
.rb-hint{color:#64748b;font-size:10px;margin-top:8px;}
|
||||
.rb-table{width:100%;border-collapse:collapse;background:#0b1220;border:1px solid #1f2937;border-radius:8px;overflow:hidden;}
|
||||
.rb-table th{background:#111827;text-align:left;padding:9px 10px;font-size:10px;text-transform:uppercase;letter-spacing:.5px;color:#94a3b8;border-bottom:1px solid #1f2937;}
|
||||
.rb-table td{padding:9px 10px;border-bottom:1px solid #14203a;vertical-align:middle;}
|
||||
.rb-table tr:hover td{background:#0f1a30;}
|
||||
.rb-type{display:inline-block;padding:2px 8px;border-radius:10px;font-size:10px;font-weight:bold;text-transform:uppercase;letter-spacing:.4px;}
|
||||
.t-username{background:#1e3a5f;color:#bfdbfe;}
|
||||
.t-email{background:#4c1d95;color:#ede9fe;}
|
||||
.t-domain{background:#0e7490;color:#cffafe;}
|
||||
.rb-val{font-family:monospace;color:#e2e8f0;}
|
||||
.rb-note{color:#94a3b8;font-size:11px;}
|
||||
.rb-del{background:#7f1d1d;color:#fecaca;border:0;border-radius:5px;padding:5px 12px;font-size:11px;cursor:pointer;}
|
||||
.rb-del:hover{background:#b91c1c;color:#fff;}
|
||||
.rb-empty{padding:24px;text-align:center;color:#64748b;}
|
||||
</style>
|
||||
|
||||
<div class="rb-wrap">
|
||||
<h2>Registration <span>Blocklist</span></h2>
|
||||
<p class="rb-intro">
|
||||
Block new registrations by a specific <b>username</b>, a specific <b>e-mail
|
||||
address</b>, or a whole <b>e-mail domain</b> (e.g. an obscene username, or the
|
||||
entire <span class="rb-val">yahoo.com</span> domain). Matching is exact and
|
||||
case-insensitive. Existing accounts are not affected — only new sign-ups.
|
||||
</p>
|
||||
|
||||
<?php if ($msg !== ''): ?>
|
||||
<div class="rb-msg"><?php echo e($msg); ?></div>
|
||||
<?php endif; ?>
|
||||
|
||||
<div class="rb-card">
|
||||
<h3>Add a block</h3>
|
||||
<form method="post" action="../GameEngine/Admin/Mods/blockReg.php" class="rb-add">
|
||||
<?php echo csrf_field(); ?>
|
||||
<input type="hidden" name="do" value="add">
|
||||
<div>
|
||||
<label>Type</label>
|
||||
<select name="type">
|
||||
<option value="<?php echo RegBlock::T_USERNAME; ?>">Username</option>
|
||||
<option value="<?php echo RegBlock::T_EMAIL; ?>">E-mail address</option>
|
||||
<option value="<?php echo RegBlock::T_DOMAIN; ?>">E-mail domain</option>
|
||||
</select>
|
||||
</div>
|
||||
<div>
|
||||
<label>Value</label>
|
||||
<input class="val" type="text" name="value" maxlength="255" placeholder="e.g. BadName / spam@x.com / yahoo.com" required>
|
||||
</div>
|
||||
<div>
|
||||
<label>Note (optional)</label>
|
||||
<input class="note" type="text" name="note" maxlength="255" placeholder="reason">
|
||||
</div>
|
||||
<button type="submit">Add block</button>
|
||||
</form>
|
||||
<div class="rb-hint">
|
||||
Domain: enter just the domain (<span class="rb-val">yahoo.com</span>), with or without the leading “@”.
|
||||
E-mail: the full address. Username: the exact name.
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="rb-card" style="padding:0;overflow:hidden;">
|
||||
<?php if (empty($blocks)): ?>
|
||||
<div class="rb-empty">No registration blocks yet.</div>
|
||||
<?php else: ?>
|
||||
<table class="rb-table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th style="width:130px;">Type</th>
|
||||
<th>Value</th>
|
||||
<th>Note</th>
|
||||
<th style="width:150px;">Added</th>
|
||||
<th style="width:90px;"></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<?php foreach ($blocks as $b):
|
||||
$t = $b['type'];
|
||||
$tClass = $t === RegBlock::T_USERNAME ? 't-username' : ($t === RegBlock::T_EMAIL ? 't-email' : 't-domain');
|
||||
?>
|
||||
<tr>
|
||||
<td><span class="rb-type <?php echo $tClass; ?>"><?php echo e($typeLabel[$t] ?? $t); ?></span></td>
|
||||
<td class="rb-val"><?php echo e($b['value']); ?></td>
|
||||
<td class="rb-note"><?php echo $b['note'] !== '' ? e($b['note']) : '—'; ?></td>
|
||||
<td class="rb-note"><?php echo $b['time'] ? date('Y-m-d H:i', (int)$b['time']) : '—'; ?></td>
|
||||
<td>
|
||||
<form method="post" action="../GameEngine/Admin/Mods/blockReg.php" onsubmit="return confirm('Remove this block?');">
|
||||
<?php echo csrf_field(); ?>
|
||||
<input type="hidden" name="do" value="remove">
|
||||
<input type="hidden" name="id" value="<?php echo (int)$b['id']; ?>">
|
||||
<button type="submit" class="rb-del">Remove</button>
|
||||
</form>
|
||||
</td>
|
||||
</tr>
|
||||
<?php endforeach; ?>
|
||||
</tbody>
|
||||
</table>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
</div>
|
||||
@@ -0,0 +1,204 @@
|
||||
<?php
|
||||
|
||||
#################################################################################
|
||||
## -= YOU MAY NOT REMOVE OR CHANGE THIS NOTICE =- ##
|
||||
## --------------------------------------------------------------------------- ##
|
||||
## Filename : goldShop.tpl ##
|
||||
## Type : Admin Panel Frontend for redeem Gold Codes ##
|
||||
## --------------------------------------------------------------------------- ##
|
||||
## Developed by : Shadow ##
|
||||
## --------------------------------------------------------------------------- ##
|
||||
## Contact : cata7007@gmail.com ##
|
||||
## Project : TravianZ ##
|
||||
## GitHub : https://github.com/Shadowss/TravianZ ##
|
||||
## --------------------------------------------------------------------------- ##
|
||||
## License : TravianZ Project ##
|
||||
## Copyright : TravianZ (c) 2010-2026. All rights reserved. ##
|
||||
## --------------------------------------------------------------------------- ##
|
||||
#################################################################################
|
||||
|
||||
if (!isset($_SESSION['access']) || $_SESSION['access'] < ADMIN) {
|
||||
echo '<p style="color:#f87171;padding:16px;">Access denied.</p>';
|
||||
return;
|
||||
}
|
||||
|
||||
$codes = GoldShop::listCodes();
|
||||
$redeems = GoldShop::recentRedemptions(25);
|
||||
$msg = isset($_GET['msg']) ? (string)$_GET['msg'] : '';
|
||||
?>
|
||||
<style>
|
||||
.gs-wrap{color:#e2e8f0;font-family:Verdana,Arial,sans-serif;font-size:12px;padding:6px 4px 26px;}
|
||||
.gs-wrap h2{font-size:18px;margin:0 0 4px;color:#fff;}
|
||||
.gs-wrap h2 span{color:#f59e0b;}
|
||||
.gs-intro{color:#94a3b8;font-size:11px;margin:0 0 14px;max-width:860px;line-height:1.5;}
|
||||
.gs-msg{background:#14532d;border:1px solid #166534;color:#bbf7d0;border-radius:6px;padding:8px 12px;font-size:11px;margin-bottom:14px;}
|
||||
.gs-card{background:#111827;border:1px solid #1f2937;border-radius:8px;padding:14px 16px;margin-bottom:18px;}
|
||||
.gs-card h3{margin:0 0 10px;font-size:13px;color:#fff;}
|
||||
.gs-add{display:flex;flex-wrap:wrap;gap:12px;align-items:flex-end;}
|
||||
.gs-add label{display:block;font-size:10px;text-transform:uppercase;letter-spacing:.6px;color:#94a3b8;margin-bottom:4px;}
|
||||
.gs-add input[type=text],.gs-add input[type=number]{background:#0b1220;border:1px solid #334155;border-radius:6px;color:#e2e8f0;padding:7px 9px;}
|
||||
.gs-add input.code{width:150px;text-transform:uppercase;}
|
||||
.gs-add input.num{width:90px;}
|
||||
.gs-add input.note{width:170px;}
|
||||
.gs-add .chk{display:flex;align-items:center;gap:6px;color:#cbd5e1;font-size:11px;padding-bottom:7px;}
|
||||
.gs-add button{background:#f59e0b;color:#111827;font-weight:bold;border:0;border-radius:6px;padding:9px 18px;cursor:pointer;}
|
||||
.gs-hint{color:#64748b;font-size:10px;margin-top:8px;}
|
||||
.gs-table{width:100%;border-collapse:collapse;background:#0b1220;border:1px solid #1f2937;border-radius:8px;}
|
||||
.gs-table th{background:#111827;text-align:left;padding:7px 7px;font-size:9px;text-transform:uppercase;letter-spacing:.3px;color:#94a3b8;border-bottom:1px solid #1f2937;white-space:nowrap;}
|
||||
.gs-table td{padding:6px 7px;border-bottom:1px solid #14203a;vertical-align:middle;font-size:11px;}
|
||||
.gs-table tr:hover td{background:#0f1a30;}
|
||||
.gs-table td.note-col{max-width:120px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;}
|
||||
.gs-scroll{overflow-x:auto;}
|
||||
.gs-code{font-family:monospace;font-weight:bold;color:#fde68a;}
|
||||
.badge{display:inline-block;padding:2px 8px;border-radius:10px;font-size:10px;font-weight:bold;text-transform:uppercase;letter-spacing:.4px;}
|
||||
.st-active{background:#14532d;color:#bbf7d0;}
|
||||
.st-disabled{background:#334155;color:#cbd5e1;}
|
||||
.st-expired{background:#7f1d1d;color:#fecaca;}
|
||||
.st-usedup{background:#78350f;color:#fde68a;}
|
||||
.gs-actions{display:flex;gap:6px;}
|
||||
.gs-actions button{border:0;border-radius:5px;padding:5px 10px;font-size:11px;cursor:pointer;}
|
||||
.b-toggle{background:#334155;color:#fff;}
|
||||
.b-toggle:hover{background:#f59e0b;color:#111827;}
|
||||
.b-del{background:#7f1d1d;color:#fecaca;}
|
||||
.b-del:hover{background:#b91c1c;color:#fff;}
|
||||
.gs-empty{padding:22px;text-align:center;color:#64748b;}
|
||||
.num{font-variant-numeric:tabular-nums;}
|
||||
.gs-side-note{color:#64748b;font-size:11px;margin-top:4px;}
|
||||
</style>
|
||||
|
||||
<div class="gs-wrap">
|
||||
<h2>Gold <span>Shop & Promo Codes</span></h2>
|
||||
<p class="gs-intro">
|
||||
Create promo / voucher codes players redeem for gold on the Plus page. Set a fixed
|
||||
gold amount, an optional total use-limit, whether each player may redeem it once,
|
||||
and an optional expiry. For a one-off bug-hunter reward, create a code with
|
||||
max-uses 1 — or use
|
||||
<a href="admin.php?p=usergold" style="color:#93c5fd;">Give Free Gold To Specific User</a> directly.
|
||||
</p>
|
||||
|
||||
<?php if ($msg !== ''): ?>
|
||||
<div class="gs-msg"><?php echo e($msg); ?></div>
|
||||
<?php endif; ?>
|
||||
|
||||
<div class="gs-card">
|
||||
<h3>Create a code</h3>
|
||||
<form method="post" action="../GameEngine/Admin/Mods/goldPromo.php" class="gs-add">
|
||||
<?php echo csrf_field(); ?>
|
||||
<input type="hidden" name="do" value="create">
|
||||
<div>
|
||||
<label>Code</label>
|
||||
<input class="code" type="text" name="code" maxlength="64" placeholder="BUGHUNT2026" required>
|
||||
</div>
|
||||
<div>
|
||||
<label>Gold</label>
|
||||
<input class="num" type="number" name="gold" min="1" value="100" required>
|
||||
</div>
|
||||
<div>
|
||||
<label>Max uses (0 = ∞)</label>
|
||||
<input class="num" type="number" name="max_uses" min="0" value="0">
|
||||
</div>
|
||||
<div>
|
||||
<label>Expires in (days, 0 = never)</label>
|
||||
<input class="num" type="number" name="expires_days" min="0" value="0">
|
||||
</div>
|
||||
<div class="chk">
|
||||
<input type="checkbox" name="per_user" id="per_user" checked>
|
||||
<label for="per_user" style="margin:0;text-transform:none;letter-spacing:0;">once per player</label>
|
||||
</div>
|
||||
<div>
|
||||
<label>Note (optional)</label>
|
||||
<input class="note" type="text" name="note" maxlength="255" placeholder="reason / campaign">
|
||||
</div>
|
||||
<button type="submit">Create</button>
|
||||
</form>
|
||||
<div class="gs-hint">Codes are case-insensitive; allowed characters: A-Z 0-9 . _ –</div>
|
||||
</div>
|
||||
|
||||
<div class="gs-card" style="padding:0;">
|
||||
<?php if (empty($codes)): ?>
|
||||
<div class="gs-empty">No promo codes yet.</div>
|
||||
<?php else: ?>
|
||||
<div class="gs-scroll">
|
||||
<table class="gs-table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Code</th>
|
||||
<th>Gold</th>
|
||||
<th>Uses</th>
|
||||
<th>Scope</th>
|
||||
<th>Expires</th>
|
||||
<th>Status</th>
|
||||
<th>Note</th>
|
||||
<th style="width:150px;"></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<?php foreach ($codes as $cd):
|
||||
$sc = strtolower(str_replace(' ', '', $cd['status']));
|
||||
$sClass = 'st-active';
|
||||
if ($cd['status'] === 'Disabled') $sClass = 'st-disabled';
|
||||
elseif ($cd['status'] === 'Expired') $sClass = 'st-expired';
|
||||
elseif ($cd['status'] === 'Used up') $sClass = 'st-usedup';
|
||||
?>
|
||||
<tr>
|
||||
<td class="gs-code"><?php echo e($cd['code']); ?></td>
|
||||
<td class="num"><?php echo number_format((int)$cd['gold']); ?></td>
|
||||
<td class="num"><?php echo (int)$cd['uses']; ?><?php echo ((int)$cd['max_uses'] > 0) ? ' / ' . (int)$cd['max_uses'] : ''; ?></td>
|
||||
<td><?php echo ((int)$cd['per_user'] === 1) ? 'once/player' : 'repeatable'; ?></td>
|
||||
<td class="num"><?php echo ((int)$cd['expires'] > 0) ? date('Y-m-d', (int)$cd['expires']) : '–'; ?></td>
|
||||
<td><span class="badge <?php echo $sClass; ?>"><?php echo e($cd['status']); ?></span></td>
|
||||
<td class="note-col" style="color:#94a3b8;"><?php echo $cd['note'] !== '' ? e($cd['note']) : '–'; ?></td>
|
||||
<td>
|
||||
<div class="gs-actions">
|
||||
<form method="post" action="../GameEngine/Admin/Mods/goldPromo.php">
|
||||
<?php echo csrf_field(); ?>
|
||||
<input type="hidden" name="do" value="toggle">
|
||||
<input type="hidden" name="id" value="<?php echo (int)$cd['id']; ?>">
|
||||
<input type="hidden" name="active" value="<?php echo ((int)$cd['active'] === 1) ? 0 : 1; ?>">
|
||||
<button type="submit" class="b-toggle"><?php echo ((int)$cd['active'] === 1) ? 'Disable' : 'Enable'; ?></button>
|
||||
</form>
|
||||
<form method="post" action="../GameEngine/Admin/Mods/goldPromo.php" onsubmit="return confirm('Delete this code?');">
|
||||
<?php echo csrf_field(); ?>
|
||||
<input type="hidden" name="do" value="delete">
|
||||
<input type="hidden" name="id" value="<?php echo (int)$cd['id']; ?>">
|
||||
<button type="submit" class="b-del">Delete</button>
|
||||
</form>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
<?php endforeach; ?>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
|
||||
<div class="gs-card">
|
||||
<h3>Recent redemptions</h3>
|
||||
<?php if (empty($redeems)): ?>
|
||||
<div class="gs-side-note">No redemptions yet.</div>
|
||||
<?php else: ?>
|
||||
<div class="gs-scroll">
|
||||
<table class="gs-table">
|
||||
<thead>
|
||||
<tr><th>When</th><th>Player</th><th>Code</th><th>Gold</th></tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<?php foreach ($redeems as $rd): ?>
|
||||
<tr>
|
||||
<td class="num" style="color:#94a3b8;"><?php echo $rd['time'] ? date('Y-m-d H:i', (int)$rd['time']) : '–'; ?></td>
|
||||
<td>
|
||||
<?php if (!empty($rd['uid'])): ?>
|
||||
<a href="admin.php?p=player&uid=<?php echo (int)$rd['uid']; ?>" style="color:#e2e8f0;text-decoration:none;"><?php echo e($rd['username'] ?? ('#' . $rd['uid'])); ?></a>
|
||||
<?php else: ?>–<?php endif; ?>
|
||||
</td>
|
||||
<td class="gs-code"><?php echo e($rd['code'] ?? '(deleted)'); ?></td>
|
||||
<td class="num"><?php echo number_format((int)$rd['gold']); ?></td>
|
||||
</tr>
|
||||
<?php endforeach; ?>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
</div>
|
||||
@@ -0,0 +1,265 @@
|
||||
<?php
|
||||
|
||||
#################################################################################
|
||||
## -= YOU MAY NOT REMOVE OR CHANGE THIS NOTICE =- ##
|
||||
## --------------------------------------------------------------------------- ##
|
||||
## Filename : heatmap.tpl ##
|
||||
## Type : Admin Panel Frontend for heatmap ##
|
||||
## --------------------------------------------------------------------------- ##
|
||||
## Developed by : Shadow ##
|
||||
## --------------------------------------------------------------------------- ##
|
||||
## Contact : cata7007@gmail.com ##
|
||||
## Project : TravianZ ##
|
||||
## GitHub : https://github.com/Shadowss/TravianZ ##
|
||||
## --------------------------------------------------------------------------- ##
|
||||
## License : TravianZ Project ##
|
||||
## Copyright : TravianZ (c) 2010-2026. All rights reserved. ##
|
||||
## --------------------------------------------------------------------------- ##
|
||||
#################################################################################
|
||||
|
||||
if (!isset($_SESSION['access']) || $_SESSION['access'] < MULTIHUNTER) {
|
||||
echo '<p style="color:#f87171;padding:16px;">Access denied.</p>';
|
||||
return;
|
||||
}
|
||||
|
||||
$res = isset($_GET['res']) && ctype_digit((string)$_GET['res']) ? (int)$_GET['res'] : Heatmap::DEFAULT_RES;
|
||||
$days = isset($_GET['days']) && ctype_digit((string)$_GET['days']) ? (int)$_GET['days'] : Heatmap::DEFAULT_INACTIVE_DAYS;
|
||||
|
||||
$data = Heatmap::grid(['res' => $res, 'inactive_days' => $days]);
|
||||
$tribeNames = Heatmap::tribeNames();
|
||||
|
||||
// Compact payload for the client: [cx,cy,villages,inactive,attacks,pop,dom,x0,y0,x1,y1]
|
||||
$payload = [];
|
||||
foreach ($data['cells'] as $c) {
|
||||
$payload[] = [$c['cx'], $c['cy'], $c['villages'], $c['inactive'], $c['attacks'], $c['pop'], $c['dom'], $c['x0'], $c['y0'], $c['x1'], $c['y1']];
|
||||
}
|
||||
$js = [
|
||||
'res' => $data['res'],
|
||||
'max' => $data['max'],
|
||||
'cells' => $payload,
|
||||
'tribeNames' => $tribeNames,
|
||||
];
|
||||
?>
|
||||
<style>
|
||||
.hm-wrap{color:#e2e8f0;font-family:Verdana,Arial,sans-serif;font-size:12px;padding:6px 4px 26px;}
|
||||
.hm-wrap h2{font-size:18px;margin:0 0 4px;color:#fff;}
|
||||
.hm-wrap h2 span{color:#f59e0b;}
|
||||
.hm-intro{color:#94a3b8;font-size:11px;margin:0 0 14px;max-width:860px;line-height:1.5;}
|
||||
.hm-filter{background:#111827;border:1px solid #1f2937;border-radius:8px;padding:12px 14px;display:flex;flex-wrap:wrap;gap:14px;align-items:flex-end;margin-bottom:14px;}
|
||||
.hm-filter label{display:block;font-size:10px;text-transform:uppercase;letter-spacing:.6px;color:#94a3b8;margin-bottom:4px;}
|
||||
.hm-filter input{background:#0b1220;border:1px solid #334155;border-radius:6px;color:#e2e8f0;padding:6px 8px;width:90px;}
|
||||
.hm-filter button{background:#f59e0b;color:#111827;font-weight:bold;border:0;border-radius:6px;padding:8px 16px;cursor:pointer;}
|
||||
.hm-layers{display:flex;gap:8px;margin-bottom:12px;flex-wrap:wrap;}
|
||||
.hm-layers button{background:#1e293b;color:#cbd5e1;border:1px solid #334155;border-radius:6px;padding:8px 16px;cursor:pointer;font-size:12px;}
|
||||
.hm-layers button.active{background:#f59e0b;color:#111827;border-color:#f59e0b;font-weight:bold;}
|
||||
.hm-stage{display:flex;gap:14px;align-items:flex-start;flex-wrap:nowrap;}
|
||||
.hm-map{position:relative;background:#0b1220;border:1px solid #1f2937;border-radius:8px;padding:8px;flex:1 1 0;min-width:0;}
|
||||
.hm-map svg{display:block;background:#0a0f1c;border-radius:4px;width:100%;height:auto;max-width:520px;}
|
||||
.hm-tip{position:absolute;pointer-events:none;background:#0b1220;border:1px solid #475569;border-radius:6px;padding:7px 9px;font-size:11px;color:#e2e8f0;display:none;z-index:10;white-space:nowrap;box-shadow:0 4px 14px rgba(0,0,0,.5);}
|
||||
.hm-side{flex:0 0 186px;min-width:0;}
|
||||
.hm-card{background:#111827;border:1px solid #1f2937;border-radius:8px;padding:12px 14px;margin-bottom:14px;}
|
||||
.hm-card h3{margin:0 0 8px;font-size:12px;color:#fff;text-transform:uppercase;letter-spacing:.5px;}
|
||||
.hm-stat{display:flex;justify-content:space-between;padding:3px 0;color:#cbd5e1;}
|
||||
.hm-stat b{color:#fff;}
|
||||
.hm-legend{display:flex;flex-direction:column;gap:5px;}
|
||||
.hm-legend .row{display:flex;align-items:center;gap:8px;font-size:11px;color:#cbd5e1;}
|
||||
.hm-legend .sw{width:16px;height:12px;border-radius:3px;display:inline-block;}
|
||||
.hm-scale{height:12px;border-radius:3px;margin:4px 0;}
|
||||
.hm-note{color:#64748b;font-size:10px;margin-top:6px;line-height:1.4;}
|
||||
.tribebar{display:flex;height:16px;border-radius:4px;overflow:hidden;margin-top:6px;}
|
||||
.tribebar span{display:block;height:100%;}
|
||||
</style>
|
||||
|
||||
<div class="hm-wrap">
|
||||
<h2>World Map <span>Heatmap</span></h2>
|
||||
<p class="hm-intro">
|
||||
Density overlays on the world grid to help with starting balance: where villages
|
||||
cluster, which tribes dominate a region, where inactive players sit (dead zones /
|
||||
good spawn spots), and where attacks are currently landing. North (+y) is up.
|
||||
</p>
|
||||
|
||||
<form method="get" action="admin.php" class="hm-filter">
|
||||
<input type="hidden" name="p" value="heatmap">
|
||||
<div>
|
||||
<label>Grid resolution</label>
|
||||
<input type="number" name="res" min="<?php echo Heatmap::MIN_RES; ?>" max="<?php echo Heatmap::MAX_RES; ?>" value="<?php echo (int)$data['res']; ?>">
|
||||
</div>
|
||||
<div>
|
||||
<label>Inactive after (days)</label>
|
||||
<input type="number" name="days" min="1" max="365" value="<?php echo (int)$data['inactive_days']; ?>">
|
||||
</div>
|
||||
<button type="submit">Rebuild</button>
|
||||
</form>
|
||||
|
||||
<div class="hm-layers">
|
||||
<button data-layer="density" class="active">Village density</button>
|
||||
<button data-layer="tribe">Tribe density</button>
|
||||
<button data-layer="inactive">Inactivity</button>
|
||||
<button data-layer="attacks">Attacks</button>
|
||||
</div>
|
||||
|
||||
<div class="hm-stage">
|
||||
<div class="hm-map">
|
||||
<svg id="hm-svg" viewBox="0 0 600 600" preserveAspectRatio="xMidYMid meet"></svg>
|
||||
<div class="hm-tip" id="hm-tip"></div>
|
||||
</div>
|
||||
|
||||
<div class="hm-side">
|
||||
<div class="hm-card">
|
||||
<h3>Summary</h3>
|
||||
<div class="hm-stat"><span>Player villages</span><b><?php echo number_format($data['totals']['villages']); ?></b></div>
|
||||
<div class="hm-stat"><span>Players</span><b><?php echo number_format($data['totals']['players']); ?></b></div>
|
||||
<div class="hm-stat"><span>Inactive villages</span><b><?php echo number_format($data['totals']['inactive']); ?></b></div>
|
||||
<div class="hm-stat"><span>Attacks in flight</span><b><?php echo number_format($data['totals']['attacks']); ?></b></div>
|
||||
<div class="hm-note">Map <?php echo (int)$data['world_max']; ?>×<?php echo (int)$data['world_max']; ?> radius, <?php echo (int)$data['res']; ?>×<?php echo (int)$data['res']; ?> grid (≈<?php echo (int)round($data['cell_span']); ?> tiles/cell).</div>
|
||||
</div>
|
||||
|
||||
<div class="hm-card">
|
||||
<h3 id="hm-legend-title">Legend</h3>
|
||||
<div class="hm-legend" id="hm-legend"></div>
|
||||
</div>
|
||||
|
||||
<div class="hm-card">
|
||||
<h3>Tribe totals</h3>
|
||||
<?php
|
||||
$tt = $data['tribe_totals'];
|
||||
$sum = array_sum($tt);
|
||||
$tribeColors = [1=>'#dc2626',2=>'#2563eb',3=>'#16a34a',6=>'#a16207',7=>'#d97706',8=>'#7c3aed',9=>'#0891b2'];
|
||||
if ($sum > 0):
|
||||
?>
|
||||
<div class="tribebar">
|
||||
<?php foreach ($tt as $t => $n): if ($n<=0) continue; ?>
|
||||
<span style="width:<?php echo round($n/$sum*100,2); ?>%;background:<?php echo $tribeColors[$t]??'#64748b'; ?>;" title="<?php echo e(($tribeNames[$t]??('Tribe '.$t)).': '.$n); ?>"></span>
|
||||
<?php endforeach; ?>
|
||||
</div>
|
||||
<?php foreach ($tt as $t => $n): if ($n<=0) continue; ?>
|
||||
<div class="hm-stat"><span><span class="sw" style="background:<?php echo $tribeColors[$t]??'#64748b'; ?>;display:inline-block;width:10px;height:10px;border-radius:2px;margin-right:6px;"></span><?php echo e($tribeNames[$t]??('Tribe '.$t)); ?></span><b><?php echo number_format($n); ?></b></div>
|
||||
<?php endforeach; ?>
|
||||
<?php else: ?>
|
||||
<div class="hm-note">No player villages found.</div>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
(function(){
|
||||
var HM = <?php echo json_encode($js); ?>;
|
||||
var SIZE = 600, res = HM.res, px = SIZE / res;
|
||||
var svg = document.getElementById('hm-svg');
|
||||
var tip = document.getElementById('hm-tip');
|
||||
var legend = document.getElementById('hm-legend');
|
||||
var legendTitle = document.getElementById('hm-legend-title');
|
||||
var SVGNS = 'http://www.w3.org/2000/svg';
|
||||
var layer = 'density';
|
||||
|
||||
var tribeColors = {1:'#dc2626',2:'#2563eb',3:'#16a34a',6:'#a16207',7:'#d97706',8:'#7c3aed',9:'#0891b2'};
|
||||
|
||||
// Idx map: cx,cy -> cell array. cell = [cx,cy,vil,inact,atk,pop,dom,x0,y0,x1,y1]
|
||||
var rects = [];
|
||||
function mix(a,b,t){ // hex lerp
|
||||
function h(x){return parseInt(x,16);}
|
||||
var ar=h(a.substr(1,2)),ag=h(a.substr(3,2)),ab=h(a.substr(5,2));
|
||||
var br=h(b.substr(1,2)),bg=h(b.substr(3,2)),bb=h(b.substr(5,2));
|
||||
var r=Math.round(ar+(br-ar)*t),g=Math.round(ag+(bg-ag)*t),bl=Math.round(ab+(bb-ab)*t);
|
||||
return 'rgb('+r+','+g+','+bl+')';
|
||||
}
|
||||
function colorFor(cell){
|
||||
var v=cell[2],inact=cell[3],atk=cell[4],dom=cell[6];
|
||||
if(layer==='density'){
|
||||
if(v<=0) return null;
|
||||
var t=HM.max.villages? v/HM.max.villages:0;
|
||||
return mix('#1e293b','#f97316',Math.pow(t,0.6));
|
||||
}
|
||||
if(layer==='inactive'){
|
||||
if(inact<=0) return null;
|
||||
var t=HM.max.inactive? inact/HM.max.inactive:0;
|
||||
return mix('#1e293b','#a855f7',Math.pow(t,0.6));
|
||||
}
|
||||
if(layer==='attacks'){
|
||||
if(atk<=0) return null;
|
||||
var t=HM.max.attacks? atk/HM.max.attacks:0;
|
||||
return mix('#1e293b','#ef4444',Math.pow(t,0.5));
|
||||
}
|
||||
if(layer==='tribe'){
|
||||
if(!dom||v<=0) return null;
|
||||
var base=tribeColors[dom]||'#64748b';
|
||||
var t=HM.max.villages? v/HM.max.villages:0;
|
||||
return mix('#111827',base,0.35+0.65*Math.pow(t,0.5));
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
// build rects once
|
||||
HM.cells.forEach(function(cell){
|
||||
var r=document.createElementNS(SVGNS,'rect');
|
||||
r.setAttribute('x',cell[0]*px);
|
||||
r.setAttribute('y',cell[1]*px);
|
||||
r.setAttribute('width',Math.ceil(px));
|
||||
r.setAttribute('height',Math.ceil(px));
|
||||
r.setAttribute('shape-rendering','crispEdges');
|
||||
r.style.cursor='crosshair';
|
||||
r._cell=cell;
|
||||
r.addEventListener('mousemove',function(e){ showTip(e,cell); });
|
||||
r.addEventListener('mouseleave',function(){ tip.style.display='none'; });
|
||||
svg.appendChild(r);
|
||||
rects.push(r);
|
||||
});
|
||||
|
||||
function showTip(e,cell){
|
||||
var names=HM.tribeNames||{};
|
||||
var domName = cell[6]? (names[cell[6]]||('Tribe '+cell[6])) : '-';
|
||||
tip.innerHTML =
|
||||
'<b>x '+cell[7]+'..'+cell[9]+' , y '+cell[8]+'..'+cell[10]+'</b><br>'+
|
||||
'villages: '+cell[2]+' pop: '+cell[5].toLocaleString()+'<br>'+
|
||||
'inactive: '+cell[3]+' attacks: '+cell[4]+'<br>'+
|
||||
'dominant: '+domName;
|
||||
var host=svg.parentNode.getBoundingClientRect();
|
||||
tip.style.left=(e.clientX-host.left+12)+'px';
|
||||
tip.style.top=(e.clientY-host.top+12)+'px';
|
||||
tip.style.display='block';
|
||||
}
|
||||
|
||||
function paint(){
|
||||
rects.forEach(function(r){
|
||||
var c=colorFor(r._cell);
|
||||
if(c===null){ r.setAttribute('fill','#0a0f1c'); r.setAttribute('fill-opacity','0'); }
|
||||
else { r.setAttribute('fill',c); r.setAttribute('fill-opacity','1'); }
|
||||
});
|
||||
drawLegend();
|
||||
}
|
||||
|
||||
function drawLegend(){
|
||||
var titles={density:'Village density',tribe:'Tribe density',inactive:'Inactivity',attacks:'Attacks'};
|
||||
legendTitle.textContent=titles[layer]||'Legend';
|
||||
if(layer==='tribe'){
|
||||
var html=''; var names=HM.tribeNames||{};
|
||||
Object.keys(tribeColors).forEach(function(t){
|
||||
if(names[t]) html+='<div class="row"><span class="sw" style="background:'+tribeColors[t]+'"></span>'+names[t]+'</div>';
|
||||
});
|
||||
legend.innerHTML=html+'<div class="hm-note">Cell shows the dominant tribe; brighter = more villages.</div>';
|
||||
return;
|
||||
}
|
||||
var grad={density:['#1e293b','#f97316'],inactive:['#1e293b','#a855f7'],attacks:['#1e293b','#ef4444']}[layer];
|
||||
var maxKey={density:'villages',inactive:'inactive',attacks:'attacks'}[layer];
|
||||
var mx=HM.max[maxKey]||0;
|
||||
legend.innerHTML=
|
||||
'<div class="hm-scale" style="background:linear-gradient(90deg,'+grad[0]+','+grad[1]+')"></div>'+
|
||||
'<div class="row"><span>0</span><span style="margin-left:auto">'+mx+'</span></div>'+
|
||||
'<div class="hm-note">Darker/brighter cells = higher count in that region.</div>';
|
||||
}
|
||||
|
||||
var btns=document.querySelectorAll('.hm-layers button');
|
||||
btns.forEach(function(b){
|
||||
b.addEventListener('click',function(){
|
||||
btns.forEach(function(x){x.classList.remove('active');});
|
||||
b.classList.add('active');
|
||||
layer=b.getAttribute('data-layer');
|
||||
paint();
|
||||
});
|
||||
});
|
||||
|
||||
paint();
|
||||
})();
|
||||
</script>
|
||||
@@ -0,0 +1,126 @@
|
||||
<?php
|
||||
|
||||
#################################################################################
|
||||
## -= YOU MAY NOT REMOVE OR CHANGE THIS NOTICE =- ##
|
||||
## --------------------------------------------------------------------------- ##
|
||||
## Filename : questEditor.tpl ##
|
||||
## Type : Admin Panel Frontend for edit Quest ##
|
||||
## --------------------------------------------------------------------------- ##
|
||||
## Developed by : Shadow ##
|
||||
## --------------------------------------------------------------------------- ##
|
||||
## Contact : cata7007@gmail.com ##
|
||||
## Project : TravianZ ##
|
||||
## GitHub : https://github.com/Shadowss/TravianZ ##
|
||||
## --------------------------------------------------------------------------- ##
|
||||
## License : TravianZ Project ##
|
||||
## Copyright : TravianZ (c) 2010-2026. All rights reserved. ##
|
||||
## --------------------------------------------------------------------------- ##
|
||||
#################################################################################
|
||||
|
||||
if (!isset($_SESSION['access']) || $_SESSION['access'] < ADMIN) {
|
||||
echo '<p style="color:#f87171;padding:16px;">Access denied.</p>';
|
||||
return;
|
||||
}
|
||||
|
||||
$variant = (isset($_GET['variant']) && $_GET['variant'] === QuestConfig::V_EXTENDED)
|
||||
? QuestConfig::V_EXTENDED : QuestConfig::V_STANDARD;
|
||||
|
||||
$rows = QuestConfig::all($variant);
|
||||
$native = QuestConfig::nativeQuests($variant);
|
||||
$msg = isset($_GET['msg']) ? (string)$_GET['msg'] : '';
|
||||
?>
|
||||
<style>
|
||||
.qe-wrap{color:#e2e8f0;font-family:Verdana,Arial,sans-serif;font-size:12px;padding:6px 4px 26px;}
|
||||
.qe-wrap h2{font-size:18px;margin:0 0 4px;color:#fff;}
|
||||
.qe-wrap h2 span{color:#f59e0b;}
|
||||
.qe-intro{color:#94a3b8;font-size:11px;margin:0 0 14px;max-width:880px;line-height:1.5;}
|
||||
.qe-msg{background:#14532d;border:1px solid #166534;color:#bbf7d0;border-radius:6px;padding:8px 12px;font-size:11px;margin-bottom:14px;}
|
||||
.qe-warn{background:#422006;border:1px solid #92400e;color:#fbbf24;border-radius:6px;padding:8px 12px;font-size:11px;margin-bottom:14px;}
|
||||
.qe-tabs{display:flex;gap:8px;margin-bottom:14px;}
|
||||
.qe-tabs a{background:#1e293b;color:#cbd5e1;border:1px solid #334155;border-radius:6px;padding:8px 18px;text-decoration:none;font-size:12px;}
|
||||
.qe-tabs a.active{background:#f59e0b;color:#111827;border-color:#f59e0b;font-weight:bold;}
|
||||
.qe-table{width:100%;border-collapse:collapse;background:#0b1220;border:1px solid #1f2937;border-radius:8px;overflow:hidden;}
|
||||
.qe-table th{background:#111827;text-align:left;padding:8px 8px;font-size:10px;text-transform:uppercase;letter-spacing:.4px;color:#94a3b8;border-bottom:1px solid #1f2937;}
|
||||
.qe-table td{padding:5px 8px;border-bottom:1px solid #14203a;vertical-align:middle;}
|
||||
.qe-table tr:hover td{background:#0f1a30;}
|
||||
.qe-table input[type=number]{background:#0b1220;border:1px solid #334155;border-radius:5px;color:#e2e8f0;padding:5px 6px;width:64px;font-variant-numeric:tabular-nums;}
|
||||
.qe-table input.note{width:150px;}
|
||||
.qe-qid{font-weight:bold;color:#fde68a;font-family:monospace;}
|
||||
.qe-bar{display:flex;gap:10px;align-items:center;margin:14px 0;flex-wrap:wrap;}
|
||||
.qe-save{background:#f59e0b;color:#111827;font-weight:bold;border:0;border-radius:6px;padding:10px 22px;cursor:pointer;font-size:13px;}
|
||||
.qe-reset{background:#7f1d1d;color:#fecaca;border:0;border-radius:6px;padding:9px 16px;cursor:pointer;font-size:12px;}
|
||||
.qe-note{color:#64748b;font-size:10px;}
|
||||
</style>
|
||||
|
||||
<div class="qe-wrap">
|
||||
<h2>Quest <span>Editor</span></h2>
|
||||
<p class="qe-intro">
|
||||
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 <code>qtyp 37</code> get <b>extended</b>, everyone else <b>standard</b>).
|
||||
</p>
|
||||
|
||||
<?php if ($msg !== ''): ?><div class="qe-msg"><?php echo e($msg); ?></div><?php endif; ?>
|
||||
|
||||
<div class="qe-warn">
|
||||
Reward values are live via <code>QuestConfig::grantReward()</code> in the quest
|
||||
templates. Quests marked <b>fixed</b> 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.
|
||||
</div>
|
||||
|
||||
<div class="qe-tabs">
|
||||
<a href="admin.php?p=questEditor&variant=standard" class="<?php echo $variant===QuestConfig::V_STANDARD?'active':''; ?>">Standard (quest_core25)</a>
|
||||
<a href="admin.php?p=questEditor&variant=extended" class="<?php echo $variant===QuestConfig::V_EXTENDED?'active':''; ?>">Extended (quest_core)</a>
|
||||
</div>
|
||||
|
||||
<form method="post" action="../GameEngine/Admin/Mods/questSave.php">
|
||||
<?php echo csrf_field(); ?>
|
||||
<input type="hidden" name="do" value="save">
|
||||
<input type="hidden" name="variant" value="<?php echo e($variant); ?>">
|
||||
|
||||
<table class="qe-table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th style="width:44px;">Quest</th>
|
||||
<th style="width:44px;">On</th>
|
||||
<th>Wood</th><th>Clay</th><th>Iron</th><th>Crop</th>
|
||||
<th>Gold</th><th>Plus (days)</th><th>Req. level</th>
|
||||
<th>Note</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<?php foreach ($rows as $qid => $r): $isNative = in_array((int)$qid, $native, true); $dis = $isNative ? 'disabled' : ''; ?>
|
||||
<tr<?php echo $isNative ? ' style="opacity:.55;"' : ''; ?>>
|
||||
<td class="qe-qid"><?php echo (int)$qid; ?><?php if ($isNative): ?><br><span style="font-size:9px;color:#f59e0b;font-family:Verdana;font-weight:normal;">fixed</span><?php endif; ?></td>
|
||||
<td><input type="checkbox" name="q[<?php echo (int)$qid; ?>][enabled]" value="1" <?php echo ((int)$r['enabled']===1)?'checked':''; ?> <?php echo $dis; ?>></td>
|
||||
<td><input type="number" name="q[<?php echo (int)$qid; ?>][wood]" value="<?php echo (int)$r['wood']; ?>" <?php echo $dis; ?>></td>
|
||||
<td><input type="number" name="q[<?php echo (int)$qid; ?>][clay]" value="<?php echo (int)$r['clay']; ?>" <?php echo $dis; ?>></td>
|
||||
<td><input type="number" name="q[<?php echo (int)$qid; ?>][iron]" value="<?php echo (int)$r['iron']; ?>" <?php echo $dis; ?>></td>
|
||||
<td><input type="number" name="q[<?php echo (int)$qid; ?>][crop]" value="<?php echo (int)$r['crop']; ?>" <?php echo $dis; ?>></td>
|
||||
<td><input type="number" name="q[<?php echo (int)$qid; ?>][gold]" value="<?php echo (int)$r['gold']; ?>" <?php echo $dis; ?>></td>
|
||||
<td><input type="number" step="0.25" name="q[<?php echo (int)$qid; ?>][plus_days]" value="<?php echo rtrim(rtrim(number_format((float)$r['plus_days'],2,'.',''),'0'),'.') ?: '0'; ?>" <?php echo $dis; ?>></td>
|
||||
<td><input type="number" name="q[<?php echo (int)$qid; ?>][req_level]" value="<?php echo (int)$r['req_level']; ?>" <?php echo $dis; ?>></td>
|
||||
<td><input class="note" type="text" maxlength="255" name="q[<?php echo (int)$qid; ?>][note]" value="<?php echo e($r['note']); ?>" <?php echo $dis; ?>></td>
|
||||
</tr>
|
||||
<?php endforeach; ?>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<div class="qe-bar">
|
||||
<button type="submit" class="qe-save">Save all changes</button>
|
||||
<span class="qe-note">Saves every row for the <b><?php echo e($variant); ?></b> variant.</span>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
<form method="post" action="../GameEngine/Admin/Mods/questSave.php" onsubmit="return confirm('Reset ALL <?php echo e($variant); ?> quests to shipped defaults? Your edits for this variant will be lost.');">
|
||||
<?php echo csrf_field(); ?>
|
||||
<input type="hidden" name="do" value="reset">
|
||||
<input type="hidden" name="variant" value="<?php echo e($variant); ?>">
|
||||
<button type="submit" class="qe-reset">Reset this variant to defaults</button>
|
||||
</form>
|
||||
</div>
|
||||
+31
-2
@@ -44,6 +44,10 @@ include_once("../GameEngine/Data/buidata.php");
|
||||
include_once("../GameEngine/Artifacts.php");
|
||||
include_once("../GameEngine/MultiAccount.php");
|
||||
include_once("../GameEngine/PushProtection.php");
|
||||
include_once("../GameEngine/RegBlock.php");
|
||||
include_once("../GameEngine/Heatmap.php");
|
||||
include_once("../GameEngine/GoldShop.php");
|
||||
include_once("../GameEngine/QuestConfig.php");
|
||||
|
||||
// ─── SECURITY HELPERS ────────────────────────────────────────────────────────
|
||||
|
||||
@@ -99,6 +103,10 @@ function admin_validated_page(string $raw): string
|
||||
'alliance', 'editAli', 'delAli','editNewFunctions',
|
||||
'multiacc',
|
||||
'pushprot',
|
||||
'blockReg',
|
||||
'heatmap',
|
||||
'goldShop',
|
||||
'questEditor',
|
||||
];
|
||||
|
||||
return in_array($raw, $whitelist, true) ? $raw : '';
|
||||
@@ -181,6 +189,22 @@ if ($page !== '') {
|
||||
$subpage = 'Push Protection';
|
||||
break;
|
||||
|
||||
case 'blockReg':
|
||||
$subpage = 'Registration Blocklist';
|
||||
break;
|
||||
|
||||
case 'heatmap':
|
||||
$subpage = 'World Map Heatmap';
|
||||
break;
|
||||
|
||||
case 'goldShop':
|
||||
$subpage = 'Gold Shop & Promo Codes';
|
||||
break;
|
||||
|
||||
case 'questEditor':
|
||||
$subpage = 'Quest Editor';
|
||||
break;
|
||||
|
||||
case 'massmessage':
|
||||
$subpage = 'Mass Message';
|
||||
break;
|
||||
@@ -839,6 +863,7 @@ body.app #menu li.sub ul li a:hover{color:#d97706!important}
|
||||
<ul>
|
||||
<li><a href="?p=gold">Give All Free Gold</a></li>
|
||||
<li><a href="?p=usergold">Give Free Gold To Specific User</a></li>
|
||||
<li><a href="?p=goldShop">Gold Shop & Promo Codes</a></li>
|
||||
<li><a href="?p=maintenenceResetGold">Reset Gold</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
@@ -854,13 +879,16 @@ body.app #menu li.sub ul li a:hover{color:#d97706!important}
|
||||
<ul>
|
||||
<li><a href="?p=users">List Users</a></li>
|
||||
<li><a href="?p=addUsers">Create Users</a></li>
|
||||
<li><a href="?p=multiacc"><font color="Red"><b>Multi-Account Detection</b></font></a></li>
|
||||
<li><a href="?p=pushprot"><font color="Red"><b>Push Protection</b></font></a></li>
|
||||
<li><a href="?p=blockReg"><font color="Red"><b>Registration Blocklist</b></font></a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li class="sub"><a href="#">Admin</a>
|
||||
<ul>
|
||||
<li><a href="?p=admin_log"><font color="Red"><b>Admin Log</b></font></a></li>
|
||||
<li><a href="?p=multiacc"><font color="Red"><b>Multi-Account Detection</b></font></a></li>
|
||||
<li><a href="?p=pushprot"><font color="Red"><b>Push Protection</b></font></a></li>
|
||||
<li><a href="?p=heatmap"><font color="Red"><b>World Map Heatmap</b></font></a></li>
|
||||
<li><a href="?p=questEditor"><font color="Red"><b>Quest Editor</b></font></a></li>
|
||||
<li><a href="?p=debug_log">Debug Error Log</a></li>
|
||||
<li><a href="?p=config">Server Settings</a></li>
|
||||
<li><a href="?p=maintenance">Server Maintenance</a></li>
|
||||
@@ -882,6 +910,7 @@ body.app #menu li.sub ul li a:hover{color:#d97706!important}
|
||||
<li><a href="?p=ban">Ban</a></li>
|
||||
<li><a href="?p=multiacc">Multi-Account Detection</a></li>
|
||||
<li><a href="?p=pushprot">Push Protection</a></li>
|
||||
<li><a href="?p=heatmap">World Map Heatmap</a></li>
|
||||
<li><a href="?action=logout">Logout</a></li>
|
||||
</ul>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user