mirror of
https://github.com/Shadowss/TravianZ.git
synced 2026-07-16 17:46:09 +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>
|
||||
|
||||
|
||||
@@ -98,6 +98,11 @@ class Account {
|
||||
$form->addError("name", USRNM_TAKEN);
|
||||
} elseif (User::exists($database, $_POST['name'])) {
|
||||
$form->addError("name", USRNM_TAKEN);
|
||||
} elseif (class_exists('RegBlock') && RegBlock::isBlockedName($database, $_POST['name'])) {
|
||||
// Registration blocklist (admin: blockReg).
|
||||
$form->addError("name", defined('REG_BLOCKED_NAME')
|
||||
? REG_BLOCKED_NAME
|
||||
: 'This username is not allowed. Please choose another.');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -119,6 +124,11 @@ class Account {
|
||||
$form->addError("email", EMAIL_INVALID);
|
||||
} elseif (User::exists($database, $_POST['email'])) {
|
||||
$form->addError("email", EMAIL_TAKEN);
|
||||
} elseif (class_exists('RegBlock') && RegBlock::isBlockedEmail($database, $_POST['email'])) {
|
||||
// Registration blocklist: exact address or whole domain (admin: blockReg).
|
||||
$form->addError("email", defined('REG_BLOCKED_EMAIL')
|
||||
? REG_BLOCKED_EMAIL
|
||||
: 'Registration with this e-mail address or domain is not allowed.');
|
||||
}
|
||||
|
||||
// Tribe
|
||||
|
||||
@@ -0,0 +1,80 @@
|
||||
<?php
|
||||
#################################################################################
|
||||
## -= YOU MAY NOT REMOVE OR CHANGE THIS NOTICE =- ##
|
||||
## --------------------------------------------------------------------------- ##
|
||||
## Filename blockReg.php ##
|
||||
## Type BACKEND (Registration blocklist add/remove) ##
|
||||
## Developed by: Shadow ##
|
||||
## License: TravianZ Project ##
|
||||
## Copyright: TravianZ (c) 2010-2026. All rights reserved. ##
|
||||
#################################################################################
|
||||
|
||||
require_once(__DIR__ . '/../csrf.php');
|
||||
if (!isset($_SESSION)) session_start();
|
||||
if ($_SESSION['access'] < 9) {
|
||||
admin_deny('You must be signed in as an administrator to do this. '
|
||||
. 'Your session may have expired — please return to the admin panel and sign in again.');
|
||||
}
|
||||
|
||||
csrf_verify();
|
||||
|
||||
include_once("../../config.php");
|
||||
|
||||
$autoprefix = '';
|
||||
for ($i = 0; $i < 5; $i++) {
|
||||
$autoprefix = str_repeat('../', $i);
|
||||
if (file_exists($autoprefix . 'autoloader.php')) break;
|
||||
}
|
||||
include_once($autoprefix . "GameEngine/Database.php");
|
||||
include_once($autoprefix . "GameEngine/RegBlock.php");
|
||||
|
||||
$admid = (int)($_SESSION['id'] ?? 0);
|
||||
|
||||
// Defence in depth: confirm the acting account really is an admin.
|
||||
$check = mysqli_query($GLOBALS['link'],
|
||||
"SELECT access FROM " . TB_PREFIX . "users WHERE id = " . $admid);
|
||||
$acc = $check ? mysqli_fetch_assoc($check) : null;
|
||||
if (!$acc || (int)$acc['access'] < ADMIN) {
|
||||
admin_deny('Your session may have expired — please sign in again.');
|
||||
}
|
||||
|
||||
$do = $_POST['do'] ?? '';
|
||||
|
||||
if ($do === 'add') {
|
||||
$type = $_POST['type'] ?? '';
|
||||
$value = $_POST['value'] ?? '';
|
||||
$note = $_POST['note'] ?? '';
|
||||
list($ok, $msg) = RegBlock::add($type, $value, $note, $admid);
|
||||
|
||||
if ($ok) {
|
||||
$logMsg = 'Registration block added: ' . $type . ' = ' . RegBlock_safe($value);
|
||||
$logMsg = mysqli_real_escape_string($GLOBALS['link'], $logMsg);
|
||||
mysqli_query($GLOBALS['link'],
|
||||
"INSERT INTO " . TB_PREFIX . "admin_log VALUES (0, " . $admid . ", '" . $logMsg . "', " . time() . ")");
|
||||
}
|
||||
header("Location: ../../../Admin/admin.php?p=blockReg&msg=" . urlencode($msg));
|
||||
exit;
|
||||
}
|
||||
|
||||
if ($do === 'remove') {
|
||||
$id = (int)($_POST['id'] ?? 0);
|
||||
if ($id > 0 && RegBlock::remove($id)) {
|
||||
mysqli_query($GLOBALS['link'],
|
||||
"INSERT INTO " . TB_PREFIX . "admin_log VALUES (0, " . $admid . ", 'Registration block removed (id " . $id . ")', " . time() . ")");
|
||||
header("Location: ../../../Admin/admin.php?p=blockReg&msg=" . urlencode('Block removed.'));
|
||||
exit;
|
||||
}
|
||||
header("Location: ../../../Admin/admin.php?p=blockReg&msg=" . urlencode('Could not remove block.'));
|
||||
exit;
|
||||
}
|
||||
|
||||
header("Location: ../../../Admin/admin.php?p=blockReg");
|
||||
exit;
|
||||
|
||||
/** Small helper: keep the admin-log message readable/short. */
|
||||
function RegBlock_safe($v)
|
||||
{
|
||||
$v = strtolower(trim((string)$v));
|
||||
return strlen($v) > 80 ? substr($v, 0, 77) . '...' : $v;
|
||||
}
|
||||
?>
|
||||
@@ -0,0 +1,81 @@
|
||||
<?php
|
||||
#################################################################################
|
||||
## -= YOU MAY NOT REMOVE OR CHANGE THIS NOTICE =- ##
|
||||
## --------------------------------------------------------------------------- ##
|
||||
## Filename goldPromo.php ##
|
||||
## Type BACKEND (Gold shop / promo codes) ##
|
||||
## Developed by: Shadow ##
|
||||
## License: TravianZ Project ##
|
||||
## Copyright: TravianZ (c) 2010-2026. All rights reserved. ##
|
||||
#################################################################################
|
||||
|
||||
require_once(__DIR__ . '/../csrf.php');
|
||||
if (!isset($_SESSION)) session_start();
|
||||
if ($_SESSION['access'] < ADMIN) {
|
||||
admin_deny('You must be signed in as an administrator to do this. '
|
||||
. 'Your session may have expired — please return to the admin panel and sign in again.');
|
||||
}
|
||||
|
||||
csrf_verify();
|
||||
|
||||
include_once("../../config.php");
|
||||
|
||||
$autoprefix = '';
|
||||
for ($i = 0; $i < 5; $i++) {
|
||||
$autoprefix = str_repeat('../', $i);
|
||||
if (file_exists($autoprefix . 'autoloader.php')) break;
|
||||
}
|
||||
include_once($autoprefix . "GameEngine/Database.php");
|
||||
include_once($autoprefix . "GameEngine/GoldShop.php");
|
||||
|
||||
$admid = (int)($_SESSION['id'] ?? 0);
|
||||
|
||||
$check = mysqli_query($GLOBALS['link'],
|
||||
"SELECT access FROM " . TB_PREFIX . "users WHERE id = " . $admid);
|
||||
$acc = $check ? mysqli_fetch_assoc($check) : null;
|
||||
if (!$acc || (int)$acc['access'] < ADMIN) {
|
||||
admin_deny('Your session may have expired — please sign in again.');
|
||||
}
|
||||
|
||||
$do = $_POST['do'] ?? '';
|
||||
$msg = '';
|
||||
|
||||
if ($do === 'create') {
|
||||
$code = $_POST['code'] ?? '';
|
||||
$gold = (int)($_POST['gold'] ?? 0);
|
||||
$maxUses = (int)($_POST['max_uses'] ?? 0);
|
||||
$perUser = isset($_POST['per_user']) ? 1 : 0;
|
||||
|
||||
// Optional expiry: number of days from now (0/empty = never).
|
||||
$expDays = (int)($_POST['expires_days'] ?? 0);
|
||||
$expires = $expDays > 0 ? time() + $expDays * 86400 : 0;
|
||||
|
||||
$note = $_POST['note'] ?? '';
|
||||
|
||||
list($ok, $msg) = GoldShop::createCode($code, $gold, $maxUses, $perUser, $expires, $note, $admid);
|
||||
if ($ok) {
|
||||
$logMsg = mysqli_real_escape_string($GLOBALS['link'],
|
||||
'Promo code created: ' . GoldShop::normCode($code) . ' (' . (int)$gold . ' gold)');
|
||||
mysqli_query($GLOBALS['link'],
|
||||
"INSERT INTO " . TB_PREFIX . "admin_log VALUES (0, " . $admid . ", '" . $logMsg . "', " . time() . ")");
|
||||
}
|
||||
} elseif ($do === 'toggle') {
|
||||
$id = (int)($_POST['id'] ?? 0);
|
||||
$active = (int)($_POST['active'] ?? 0);
|
||||
if ($id > 0) {
|
||||
GoldShop::setActive($id, $active);
|
||||
$msg = $active ? 'Code enabled.' : 'Code disabled.';
|
||||
}
|
||||
} elseif ($do === 'delete') {
|
||||
$id = (int)($_POST['id'] ?? 0);
|
||||
if ($id > 0) {
|
||||
GoldShop::deleteCode($id);
|
||||
mysqli_query($GLOBALS['link'],
|
||||
"INSERT INTO " . TB_PREFIX . "admin_log VALUES (0, " . $admid . ", 'Promo code deleted (id " . $id . ")', " . time() . ")");
|
||||
$msg = 'Code deleted.';
|
||||
}
|
||||
}
|
||||
|
||||
header("Location: ../../../Admin/admin.php?p=goldShop&msg=" . urlencode($msg));
|
||||
exit;
|
||||
?>
|
||||
@@ -0,0 +1,75 @@
|
||||
<?php
|
||||
#################################################################################
|
||||
## -= YOU MAY NOT REMOVE OR CHANGE THIS NOTICE =- ##
|
||||
## --------------------------------------------------------------------------- ##
|
||||
## Filename questSave.php ##
|
||||
## Type BACKEND (Quest editor save/reset) ##
|
||||
## Developed by: Shadow ##
|
||||
## License: TravianZ Project ##
|
||||
## Copyright: TravianZ (c) 2010-2026. All rights reserved. ##
|
||||
#################################################################################
|
||||
|
||||
require_once(__DIR__ . '/../csrf.php');
|
||||
if (!isset($_SESSION)) session_start();
|
||||
if ($_SESSION['access'] < ADMIN) {
|
||||
admin_deny('You must be signed in as an administrator to do this. '
|
||||
. 'Your session may have expired — please return to the admin panel and sign in again.');
|
||||
}
|
||||
|
||||
csrf_verify();
|
||||
|
||||
include_once("../../config.php");
|
||||
|
||||
$autoprefix = '';
|
||||
for ($i = 0; $i < 5; $i++) {
|
||||
$autoprefix = str_repeat('../', $i);
|
||||
if (file_exists($autoprefix . 'autoloader.php')) break;
|
||||
}
|
||||
include_once($autoprefix . "GameEngine/Database.php");
|
||||
include_once($autoprefix . "GameEngine/QuestConfig.php");
|
||||
|
||||
$admid = (int)($_SESSION['id'] ?? 0);
|
||||
|
||||
$check = mysqli_query($GLOBALS['link'],
|
||||
"SELECT access FROM " . TB_PREFIX . "users WHERE id = " . $admid);
|
||||
$acc = $check ? mysqli_fetch_assoc($check) : null;
|
||||
if (!$acc || (int)$acc['access'] < ADMIN) {
|
||||
admin_deny('Your session may have expired — please sign in again.');
|
||||
}
|
||||
|
||||
$do = $_POST['do'] ?? '';
|
||||
$variant = QuestConfig::normVariant($_POST['variant'] ?? 'standard');
|
||||
$msg = '';
|
||||
|
||||
if ($do === 'save' && isset($_POST['q']) && is_array($_POST['q'])) {
|
||||
$n = 0;
|
||||
foreach ($_POST['q'] as $qid => $fields) {
|
||||
if (!is_array($fields)) {
|
||||
continue;
|
||||
}
|
||||
QuestConfig::setQuest($variant, (int)$qid, [
|
||||
'enabled' => !empty($fields['enabled']),
|
||||
'wood' => $fields['wood'] ?? 0,
|
||||
'clay' => $fields['clay'] ?? 0,
|
||||
'iron' => $fields['iron'] ?? 0,
|
||||
'crop' => $fields['crop'] ?? 0,
|
||||
'gold' => $fields['gold'] ?? 0,
|
||||
'plus_days' => $fields['plus_days'] ?? 0,
|
||||
'req_level' => $fields['req_level'] ?? 0,
|
||||
'note' => $fields['note'] ?? '',
|
||||
]);
|
||||
$n++;
|
||||
}
|
||||
mysqli_query($GLOBALS['link'],
|
||||
"INSERT INTO " . TB_PREFIX . "admin_log VALUES (0, " . $admid . ", 'Quest editor: saved " . $n . " " . $variant . " quests', " . time() . ")");
|
||||
$msg = $n . ' quests saved (' . $variant . ').';
|
||||
} elseif ($do === 'reset') {
|
||||
QuestConfig::resetVariant($variant);
|
||||
mysqli_query($GLOBALS['link'],
|
||||
"INSERT INTO " . TB_PREFIX . "admin_log VALUES (0, " . $admid . ", 'Quest editor: reset " . $variant . " to defaults', " . time() . ")");
|
||||
$msg = $variant . ' quests reset to defaults.';
|
||||
}
|
||||
|
||||
header("Location: ../../../Admin/admin.php?p=questEditor&variant=" . urlencode($variant) . "&msg=" . urlencode($msg));
|
||||
exit;
|
||||
?>
|
||||
@@ -3250,6 +3250,7 @@ class Automation {
|
||||
$Attacker = $trapResult['Attacker'];
|
||||
|
||||
// we need to save the attacker heroid before the battle
|
||||
$AttackerHeroID = 0;
|
||||
if(isset($Attacker['uhero']) && $Attacker['uhero'] > 0){
|
||||
$AttackerHeroID = $database->getHeroField($from['owner'], "heroid");
|
||||
}
|
||||
@@ -3690,7 +3691,7 @@ class Automation {
|
||||
$reinf = $database->getEnforce($data['to'], $data['from']);
|
||||
$database->modifyEnforce($reinf['id'], 31, 1, 1);
|
||||
$data_fail = '0,0,4,1,0,0,0,0,0,0,0,0,0,0';
|
||||
$database->addNotice($to['owner'], $to['wref'], (isset($targetally) ? $targetally : 0), 8, 'village of the elders reinforcement ' . addslashes($to['name']), $data_fail, $AttackArrivalTime);
|
||||
$database->addNotice($to['owner'], $to['wref'], (isset($targetally) ? $targetally : 0), 8, 'village of the elders reinforcement ' . addslashes($to['name']), $data_fail, isset($AttackArrivalTime) ? $AttackArrivalTime : time());
|
||||
}
|
||||
|
||||
// Flow 2 of sendreinfunitsComplete(): a standard reinforcement delivery. Handles
|
||||
|
||||
@@ -6,9 +6,7 @@
|
||||
## Filename : festival.php ##
|
||||
## Type : Data Page for Festival ##
|
||||
## --------------------------------------------------------------------------- ##
|
||||
## Developed by : Dzoki ##
|
||||
## Refactored by : Shadow ##
|
||||
## Redesign by : Shadow ##
|
||||
## Developed by : Shadow ##
|
||||
## --------------------------------------------------------------------------- ##
|
||||
## Contact : cata7007@gmail.com ##
|
||||
## Project : TravianZ ##
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
## Filename : hero_items.php ##
|
||||
## Type : Static Data / Catalog for T4 Hero port ##
|
||||
## --------------------------------------------------------------------------- ##
|
||||
## Refactored by : Shadow ##
|
||||
## Developed by : Shadow ##
|
||||
## Project : TravianZ ##
|
||||
## GitHub : https://github.com/Shadowss/TravianZ ##
|
||||
## --------------------------------------------------------------------------- ##
|
||||
|
||||
@@ -0,0 +1,350 @@
|
||||
<?php
|
||||
#################################################################################
|
||||
## -= YOU MAY NOT REMOVE OR CHANGE THIS NOTICE =- ##
|
||||
## --------------------------------------------------------------------------- ##
|
||||
## Filename : GoldShop.php ##
|
||||
## Type : Gold shop / promo-code engine ##
|
||||
## --------------------------------------------------------------------------- ##
|
||||
## Developed by : Shadow ##
|
||||
## Project : TravianZ ##
|
||||
## GitHub : https://github.com/Shadowss/TravianZ ##
|
||||
## --------------------------------------------------------------------------- ##
|
||||
## License : TravianZ Project ##
|
||||
## Copyright : TravianZ (c) 2010-2026. All rights reserved. ##
|
||||
## --------------------------------------------------------------------------- ##
|
||||
#################################################################################
|
||||
|
||||
/**
|
||||
* GoldShop
|
||||
* -------------------------------------------------------------------------
|
||||
* Promo / voucher codes redeemable by players for gold. Admin creates codes
|
||||
* (fixed gold amount, optional max-uses, optional per-user-once, optional
|
||||
* expiry); players redeem them on the Plus page.
|
||||
*
|
||||
* "Free gold for bug hunters" is already covered by the existing admin pages
|
||||
* (Give Free Gold To Specific User / To All) — a single-use code created here
|
||||
* is also a convenient way to hand a bug hunter their reward.
|
||||
*
|
||||
* Self-contained (static, resolves DB link + optional Database from globals,
|
||||
* self-creates its tables). Use-claiming is atomic (conditional UPDATE) so a
|
||||
* limited code cannot be over-redeemed under concurrency.
|
||||
*/
|
||||
class GoldShop
|
||||
{
|
||||
private static function link()
|
||||
{
|
||||
if (isset($GLOBALS['link']) && $GLOBALS['link']) {
|
||||
return $GLOBALS['link'];
|
||||
}
|
||||
if (isset($GLOBALS['database']) && isset($GLOBALS['database']->dblink)) {
|
||||
return $GLOBALS['database']->dblink;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static function ensureSchema()
|
||||
{
|
||||
$link = self::link();
|
||||
if (!$link) {
|
||||
return;
|
||||
}
|
||||
@mysqli_query($link, "CREATE TABLE IF NOT EXISTS `" . TB_PREFIX . "gold_promo` (
|
||||
`id` int(11) NOT NULL AUTO_INCREMENT,
|
||||
`code` varchar(64) NOT NULL,
|
||||
`gold` int(11) NOT NULL DEFAULT 0,
|
||||
`max_uses` int(11) NOT NULL DEFAULT 0,
|
||||
`uses` int(11) NOT NULL DEFAULT 0,
|
||||
`per_user` tinyint(1) NOT NULL DEFAULT 1,
|
||||
`expires` int(11) NOT NULL DEFAULT 0,
|
||||
`active` tinyint(1) NOT NULL DEFAULT 1,
|
||||
`note` varchar(255) NOT NULL DEFAULT '',
|
||||
`created_by` int(11) NOT NULL DEFAULT 0,
|
||||
`time` int(11) NOT NULL DEFAULT 0,
|
||||
PRIMARY KEY (`id`),
|
||||
UNIQUE KEY `code` (`code`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8");
|
||||
|
||||
@mysqli_query($link, "CREATE TABLE IF NOT EXISTS `" . TB_PREFIX . "gold_promo_redeem` (
|
||||
`id` int(11) NOT NULL AUTO_INCREMENT,
|
||||
`promo_id` int(11) NOT NULL DEFAULT 0,
|
||||
`uid` int(11) NOT NULL DEFAULT 0,
|
||||
`gold` int(11) NOT NULL DEFAULT 0,
|
||||
`time` int(11) NOT NULL DEFAULT 0,
|
||||
PRIMARY KEY (`id`),
|
||||
KEY `promo_uid` (`promo_id`,`uid`),
|
||||
KEY `uid` (`uid`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8");
|
||||
}
|
||||
|
||||
/** Normalise a code: trim, uppercase, collapse to allowed charset. */
|
||||
public static function normCode($code)
|
||||
{
|
||||
$code = strtoupper(trim((string) $code));
|
||||
return preg_replace('/[^A-Z0-9._-]/', '', $code);
|
||||
}
|
||||
|
||||
/* ---- Admin management ---------------------------------------------- */
|
||||
|
||||
/**
|
||||
* Create a promo code.
|
||||
* @return array [ok(bool), message(string)]
|
||||
*/
|
||||
public static function createCode($code, $gold, $maxUses, $perUser, $expires, $note, $adminId)
|
||||
{
|
||||
$link = self::link();
|
||||
if (!$link) {
|
||||
return [false, 'No database connection.'];
|
||||
}
|
||||
self::ensureSchema();
|
||||
|
||||
$code = self::normCode($code);
|
||||
if ($code === '' || strlen($code) < 3) {
|
||||
return [false, 'Code must be at least 3 characters (A-Z 0-9 . _ -).'];
|
||||
}
|
||||
$gold = (int) $gold;
|
||||
if ($gold <= 0) {
|
||||
return [false, 'Gold amount must be positive.'];
|
||||
}
|
||||
$maxUses = max(0, (int) $maxUses);
|
||||
$perUser = $perUser ? 1 : 0;
|
||||
$expires = max(0, (int) $expires);
|
||||
$note = substr((string) $note, 0, 255);
|
||||
$admin = (int) $adminId;
|
||||
$now = time();
|
||||
|
||||
$stmt = mysqli_prepare($link,
|
||||
"INSERT INTO `" . TB_PREFIX . "gold_promo`
|
||||
(code, gold, max_uses, uses, per_user, expires, active, note, created_by, time)
|
||||
VALUES (?,?,?,0,?,?,1,?,?,?)");
|
||||
if (!$stmt) {
|
||||
return [false, 'Could not prepare statement.'];
|
||||
}
|
||||
mysqli_stmt_bind_param($stmt, 'siiiisii',
|
||||
$code, $gold, $maxUses, $perUser, $expires, $note, $admin, $now);
|
||||
$ok = mysqli_stmt_execute($stmt);
|
||||
$err = mysqli_stmt_errno($stmt);
|
||||
mysqli_stmt_close($stmt);
|
||||
|
||||
if (!$ok) {
|
||||
if ($err === 1062) {
|
||||
return [false, 'A code with that name already exists.'];
|
||||
}
|
||||
return [false, 'Could not create code.'];
|
||||
}
|
||||
return [true, 'Code "' . $code . '" created.'];
|
||||
}
|
||||
|
||||
/** All codes, newest first, each with a resolved status string. */
|
||||
public static function listCodes()
|
||||
{
|
||||
$link = self::link();
|
||||
$out = [];
|
||||
if (!$link) {
|
||||
return $out;
|
||||
}
|
||||
self::ensureSchema();
|
||||
$r = @mysqli_query($link,
|
||||
"SELECT * FROM `" . TB_PREFIX . "gold_promo` ORDER BY `time` DESC, id DESC");
|
||||
if ($r) {
|
||||
$now = time();
|
||||
while ($row = mysqli_fetch_assoc($r)) {
|
||||
$row['status'] = self::statusOf($row, $now);
|
||||
$out[] = $row;
|
||||
}
|
||||
mysqli_free_result($r);
|
||||
}
|
||||
return $out;
|
||||
}
|
||||
|
||||
private static function statusOf($row, $now)
|
||||
{
|
||||
if ((int) $row['active'] !== 1) {
|
||||
return 'Disabled';
|
||||
}
|
||||
if ((int) $row['expires'] > 0 && $now > (int) $row['expires']) {
|
||||
return 'Expired';
|
||||
}
|
||||
if ((int) $row['max_uses'] > 0 && (int) $row['uses'] >= (int) $row['max_uses']) {
|
||||
return 'Used up';
|
||||
}
|
||||
return 'Active';
|
||||
}
|
||||
|
||||
public static function setActive($id, $active)
|
||||
{
|
||||
$link = self::link();
|
||||
if (!$link) {
|
||||
return false;
|
||||
}
|
||||
self::ensureSchema();
|
||||
$stmt = mysqli_prepare($link,
|
||||
"UPDATE `" . TB_PREFIX . "gold_promo` SET active = ? WHERE id = ?");
|
||||
if (!$stmt) {
|
||||
return false;
|
||||
}
|
||||
$a = $active ? 1 : 0;
|
||||
$id = (int) $id;
|
||||
mysqli_stmt_bind_param($stmt, 'ii', $a, $id);
|
||||
$ok = mysqli_stmt_execute($stmt);
|
||||
mysqli_stmt_close($stmt);
|
||||
return $ok;
|
||||
}
|
||||
|
||||
public static function deleteCode($id)
|
||||
{
|
||||
$link = self::link();
|
||||
if (!$link) {
|
||||
return false;
|
||||
}
|
||||
self::ensureSchema();
|
||||
$id = (int) $id;
|
||||
$stmt = mysqli_prepare($link, "DELETE FROM `" . TB_PREFIX . "gold_promo` WHERE id = ?");
|
||||
if ($stmt) {
|
||||
mysqli_stmt_bind_param($stmt, 'i', $id);
|
||||
mysqli_stmt_execute($stmt);
|
||||
mysqli_stmt_close($stmt);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/** Recent redemptions (joined with code + username) for the admin view. */
|
||||
public static function recentRedemptions($limit = 30)
|
||||
{
|
||||
$link = self::link();
|
||||
$out = [];
|
||||
if (!$link) {
|
||||
return $out;
|
||||
}
|
||||
self::ensureSchema();
|
||||
$limit = max(1, min(200, (int) $limit));
|
||||
$r = @mysqli_query($link,
|
||||
"SELECT rr.time, rr.gold, rr.uid, u.username, p.code
|
||||
FROM `" . TB_PREFIX . "gold_promo_redeem` rr
|
||||
LEFT JOIN `" . TB_PREFIX . "users` u ON u.id = rr.uid
|
||||
LEFT JOIN `" . TB_PREFIX . "gold_promo` p ON p.id = rr.promo_id
|
||||
ORDER BY rr.id DESC LIMIT " . $limit);
|
||||
if ($r) {
|
||||
while ($row = mysqli_fetch_assoc($r)) {
|
||||
$out[] = $row;
|
||||
}
|
||||
mysqli_free_result($r);
|
||||
}
|
||||
return $out;
|
||||
}
|
||||
|
||||
/* ---- Player redemption --------------------------------------------- */
|
||||
|
||||
/**
|
||||
* Redeem a code for a player.
|
||||
* @return array [ok(bool), message(string), gold(int)]
|
||||
*/
|
||||
public static function redeem($uid, $code)
|
||||
{
|
||||
$uid = (int) $uid;
|
||||
if ($uid <= 0) {
|
||||
return [false, 'You must be logged in.', 0];
|
||||
}
|
||||
$link = self::link();
|
||||
if (!$link) {
|
||||
return [false, 'Service unavailable, try again later.', 0];
|
||||
}
|
||||
self::ensureSchema();
|
||||
|
||||
$code = self::normCode($code);
|
||||
if ($code === '') {
|
||||
return [false, 'Please enter a code.', 0];
|
||||
}
|
||||
|
||||
// Fetch the code row.
|
||||
$stmt = mysqli_prepare($link,
|
||||
"SELECT * FROM `" . TB_PREFIX . "gold_promo` WHERE code = ? LIMIT 1");
|
||||
if (!$stmt) {
|
||||
return [false, 'Service unavailable, try again later.', 0];
|
||||
}
|
||||
mysqli_stmt_bind_param($stmt, 's', $code);
|
||||
mysqli_stmt_execute($stmt);
|
||||
$res = mysqli_stmt_get_result($stmt);
|
||||
$promo = $res ? mysqli_fetch_assoc($res) : null;
|
||||
mysqli_stmt_close($stmt);
|
||||
|
||||
if (!$promo) {
|
||||
return [false, 'Invalid code.', 0];
|
||||
}
|
||||
$now = time();
|
||||
if ((int) $promo['active'] !== 1) {
|
||||
return [false, 'This code is no longer available.', 0];
|
||||
}
|
||||
if ((int) $promo['expires'] > 0 && $now > (int) $promo['expires']) {
|
||||
return [false, 'This code has expired.', 0];
|
||||
}
|
||||
if ((int) $promo['max_uses'] > 0 && (int) $promo['uses'] >= (int) $promo['max_uses']) {
|
||||
return [false, 'This code has already been fully redeemed.', 0];
|
||||
}
|
||||
|
||||
$promoId = (int) $promo['id'];
|
||||
$gold = (int) $promo['gold'];
|
||||
|
||||
// Per-user-once check.
|
||||
if ((int) $promo['per_user'] === 1) {
|
||||
$chk = mysqli_prepare($link,
|
||||
"SELECT 1 FROM `" . TB_PREFIX . "gold_promo_redeem` WHERE promo_id = ? AND uid = ? LIMIT 1");
|
||||
if ($chk) {
|
||||
mysqli_stmt_bind_param($chk, 'ii', $promoId, $uid);
|
||||
mysqli_stmt_execute($chk);
|
||||
mysqli_stmt_store_result($chk);
|
||||
$already = mysqli_stmt_num_rows($chk) > 0;
|
||||
mysqli_stmt_close($chk);
|
||||
if ($already) {
|
||||
return [false, 'You have already redeemed this code.', 0];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Atomically claim a use (guards against concurrent over-redemption).
|
||||
$claim = mysqli_prepare($link,
|
||||
"UPDATE `" . TB_PREFIX . "gold_promo`
|
||||
SET uses = uses + 1
|
||||
WHERE id = ? AND active = 1
|
||||
AND (max_uses = 0 OR uses < max_uses)
|
||||
AND (expires = 0 OR expires >= ?)");
|
||||
if (!$claim) {
|
||||
return [false, 'Service unavailable, try again later.', 0];
|
||||
}
|
||||
mysqli_stmt_bind_param($claim, 'ii', $promoId, $now);
|
||||
mysqli_stmt_execute($claim);
|
||||
$claimed = mysqli_stmt_affected_rows($claim) === 1;
|
||||
mysqli_stmt_close($claim);
|
||||
|
||||
if (!$claimed) {
|
||||
return [false, 'This code has already been fully redeemed.', 0];
|
||||
}
|
||||
|
||||
// Grant the gold. Prefer the Database helper (also writes gold_fin_log).
|
||||
$granted = false;
|
||||
if (isset($GLOBALS['database']) && method_exists($GLOBALS['database'], 'modifyGold')) {
|
||||
$GLOBALS['database']->modifyGold($uid, $gold, 1);
|
||||
$granted = true;
|
||||
}
|
||||
if (!$granted) {
|
||||
$g = mysqli_prepare($link,
|
||||
"UPDATE `" . TB_PREFIX . "users` SET gold = gold + ? WHERE id = ?");
|
||||
if ($g) {
|
||||
mysqli_stmt_bind_param($g, 'ii', $gold, $uid);
|
||||
mysqli_stmt_execute($g);
|
||||
mysqli_stmt_close($g);
|
||||
}
|
||||
}
|
||||
|
||||
// Record the redemption.
|
||||
$ins = mysqli_prepare($link,
|
||||
"INSERT INTO `" . TB_PREFIX . "gold_promo_redeem` (promo_id, uid, gold, time)
|
||||
VALUES (?,?,?,?)");
|
||||
if ($ins) {
|
||||
mysqli_stmt_bind_param($ins, 'iiii', $promoId, $uid, $gold, $now);
|
||||
mysqli_stmt_execute($ins);
|
||||
mysqli_stmt_close($ins);
|
||||
}
|
||||
|
||||
return [true, 'Success! ' . $gold . ' gold has been added to your account.', $gold];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,212 @@
|
||||
<?php
|
||||
#################################################################################
|
||||
## -= YOU MAY NOT REMOVE OR CHANGE THIS NOTICE =- ##
|
||||
## --------------------------------------------------------------------------- ##
|
||||
## Filename : Heatmap.php ##
|
||||
## Type : World-map heatmap aggregation (Admin tool) ##
|
||||
## --------------------------------------------------------------------------- ##
|
||||
## Developed by : Shadow ##
|
||||
## Project : TravianZ ##
|
||||
## GitHub : https://github.com/Shadowss/TravianZ ##
|
||||
## --------------------------------------------------------------------------- ##
|
||||
## License : TravianZ Project ##
|
||||
## Copyright : TravianZ (c) 2010-2026. All rights reserved. ##
|
||||
## --------------------------------------------------------------------------- ##
|
||||
#################################################################################
|
||||
|
||||
/**
|
||||
* Heatmap
|
||||
* -------------------------------------------------------------------------
|
||||
* Aggregates the world map into a coarse grid for the admin heatmap: village
|
||||
* density, per-tribe density, inactive-player density, and incoming-attack
|
||||
* density. Read-only — no schema, purely derived from existing tables
|
||||
* (vdata + wdata + users + movement). Helps with spawn / starting-balance
|
||||
* decisions and spotting attack hotspots or dead zones.
|
||||
*/
|
||||
class Heatmap
|
||||
{
|
||||
const DEFAULT_RES = 40; // grid is RES x RES cells
|
||||
const MIN_RES = 10;
|
||||
const MAX_RES = 90;
|
||||
const DEFAULT_INACTIVE_DAYS = 14;
|
||||
|
||||
/** Tribe id -> display name (for legend / tooltips). */
|
||||
public static function tribeNames()
|
||||
{
|
||||
return [
|
||||
1 => 'Romans', 2 => 'Teutons', 3 => 'Gauls',
|
||||
6 => 'Huns', 7 => 'Egyptians', 8 => 'Spartans', 9 => 'Vikings',
|
||||
];
|
||||
}
|
||||
|
||||
private static function link()
|
||||
{
|
||||
if (isset($GLOBALS['link']) && $GLOBALS['link']) {
|
||||
return $GLOBALS['link'];
|
||||
}
|
||||
if (isset($GLOBALS['database']) && isset($GLOBALS['database']->dblink)) {
|
||||
return $GLOBALS['database']->dblink;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/** Map radius: coordinates run -MAX .. +MAX on both axes. */
|
||||
private static function worldMax()
|
||||
{
|
||||
if (defined('WORLD_MAX') && (int) WORLD_MAX > 0) {
|
||||
return (int) WORLD_MAX;
|
||||
}
|
||||
return 200; // sane fallback
|
||||
}
|
||||
|
||||
/**
|
||||
* Build the heatmap grid.
|
||||
*
|
||||
* @param array $opts 'res' (cells per side), 'inactive_days'.
|
||||
* @return array {
|
||||
* res, world_max, cell_span, inactive_days,
|
||||
* cells => list of non-empty cells (see below),
|
||||
* max => ['villages'=>, 'inactive'=>, 'attacks'=>, 'pop'=>],
|
||||
* tribe_totals => [tribe => count],
|
||||
* totals => ['villages'=>, 'inactive'=>, 'attacks'=>, 'players'=>],
|
||||
* }
|
||||
*
|
||||
* Each cell:
|
||||
* cx, cy grid indices (0..res-1, cy from top)
|
||||
* x0,y0,x1,y1 world-coordinate bounds of the cell
|
||||
* villages, inactive, attacks, pop
|
||||
* tribes => [tribe => count]
|
||||
* dom => dominant tribe id (0 if none)
|
||||
*/
|
||||
public static function grid(array $opts = [])
|
||||
{
|
||||
$res = isset($opts['res']) ? (int) $opts['res'] : self::DEFAULT_RES;
|
||||
$res = max(self::MIN_RES, min(self::MAX_RES, $res));
|
||||
$days = isset($opts['inactive_days']) ? max(1, (int) $opts['inactive_days']) : self::DEFAULT_INACTIVE_DAYS;
|
||||
|
||||
$max = self::worldMax();
|
||||
$span = 2 * $max + 1; // total coordinate width
|
||||
$cellSpan = $span / $res; // coords per cell
|
||||
|
||||
$empty = [
|
||||
'res' => $res, 'world_max' => $max, 'cell_span' => $cellSpan,
|
||||
'inactive_days' => $days, 'cells' => [],
|
||||
'max' => ['villages' => 0, 'inactive' => 0, 'attacks' => 0, 'pop' => 0],
|
||||
'tribe_totals' => [], 'totals' => ['villages' => 0, 'inactive' => 0, 'attacks' => 0, 'players' => 0],
|
||||
];
|
||||
|
||||
$link = self::link();
|
||||
if (!$link) {
|
||||
return $empty;
|
||||
}
|
||||
|
||||
// cellIndex: map a coordinate to 0..res-1.
|
||||
$idx = function ($coord) use ($max, $span, $res) {
|
||||
$i = (int) floor(($coord + $max) / $span * $res);
|
||||
if ($i < 0) { $i = 0; }
|
||||
if ($i >= $res) { $i = $res - 1; }
|
||||
return $i;
|
||||
};
|
||||
|
||||
$cells = []; // "cx:cy" => cell
|
||||
$tribeTotals = [];
|
||||
$totVil = $totInact = $totAtk = 0;
|
||||
$players = [];
|
||||
|
||||
$touch = function ($cx, $cy) use (&$cells, $max, $cellSpan, $res) {
|
||||
$key = $cx . ':' . $cy;
|
||||
if (!isset($cells[$key])) {
|
||||
$x0 = -$max + $cx * $cellSpan;
|
||||
// cy is measured from the TOP (north = +y), so invert for y bounds.
|
||||
$y1 = $max - $cy * $cellSpan;
|
||||
$cells[$key] = [
|
||||
'cx' => $cx, 'cy' => $cy,
|
||||
'x0' => (int) round($x0), 'x1' => (int) round($x0 + $cellSpan),
|
||||
'y0' => (int) round($y1 - $cellSpan), 'y1' => (int) round($y1),
|
||||
'villages' => 0, 'inactive' => 0, 'attacks' => 0, 'pop' => 0,
|
||||
'tribes' => [],
|
||||
];
|
||||
}
|
||||
return $key;
|
||||
};
|
||||
|
||||
// ---- Villages + tribe + inactivity ----
|
||||
$now = time();
|
||||
$cut = $now - $days * 86400;
|
||||
$q = "SELECT w.x AS x, w.y AS y, u.tribe AS tribe, v.pop AS pop, u.timestamp AS ts, u.id AS uid
|
||||
FROM `" . TB_PREFIX . "vdata` v
|
||||
JOIN `" . TB_PREFIX . "wdata` w ON v.wref = w.id
|
||||
JOIN `" . TB_PREFIX . "users` u ON v.owner = u.id
|
||||
WHERE v.owner > 3 AND w.x IS NOT NULL AND w.y IS NOT NULL";
|
||||
if ($r = @mysqli_query($link, $q)) {
|
||||
while ($row = mysqli_fetch_assoc($r)) {
|
||||
$cx = $idx((int) $row['x']);
|
||||
// North is +y at the top of the map, so top row (cy=0) = +max.
|
||||
$cy = $idx(-(int) $row['y']);
|
||||
$key = $touch($cx, $cy);
|
||||
|
||||
$cells[$key]['villages']++;
|
||||
$cells[$key]['pop'] += (int) $row['pop'];
|
||||
$tribe = (int) $row['tribe'];
|
||||
if ($tribe > 0) {
|
||||
if (!isset($cells[$key]['tribes'][$tribe])) { $cells[$key]['tribes'][$tribe] = 0; }
|
||||
$cells[$key]['tribes'][$tribe]++;
|
||||
if (!isset($tribeTotals[$tribe])) { $tribeTotals[$tribe] = 0; }
|
||||
$tribeTotals[$tribe]++;
|
||||
}
|
||||
if ((int) $row['ts'] > 0 && (int) $row['ts'] < $cut) {
|
||||
$cells[$key]['inactive']++;
|
||||
$totInact++;
|
||||
}
|
||||
$totVil++;
|
||||
$players[(int) $row['uid']] = true;
|
||||
}
|
||||
mysqli_free_result($r);
|
||||
}
|
||||
|
||||
// ---- Incoming attacks in flight (sort_type 3 = attack, 4 = raid) ----
|
||||
$q2 = "SELECT w.x AS x, w.y AS y, COUNT(*) AS c
|
||||
FROM `" . TB_PREFIX . "movement` m
|
||||
JOIN `" . TB_PREFIX . "wdata` w ON m.`to` = w.id
|
||||
WHERE m.sort_type IN (3,4) AND m.proc = 0
|
||||
GROUP BY w.x, w.y";
|
||||
if ($r = @mysqli_query($link, $q2)) {
|
||||
while ($row = mysqli_fetch_assoc($r)) {
|
||||
$cx = $idx((int) $row['x']);
|
||||
$cy = $idx(-(int) $row['y']);
|
||||
$key = $touch($cx, $cy);
|
||||
$cells[$key]['attacks'] += (int) $row['c'];
|
||||
$totAtk += (int) $row['c'];
|
||||
}
|
||||
mysqli_free_result($r);
|
||||
}
|
||||
|
||||
// ---- Finalise: dominant tribe + maxima ----
|
||||
$maxV = $maxI = $maxA = $maxP = 0;
|
||||
$list = [];
|
||||
foreach ($cells as $c) {
|
||||
$dom = 0; $domCount = 0;
|
||||
foreach ($c['tribes'] as $t => $n) {
|
||||
if ($n > $domCount) { $domCount = $n; $dom = $t; }
|
||||
}
|
||||
$c['dom'] = $dom;
|
||||
if ($c['villages'] > $maxV) { $maxV = $c['villages']; }
|
||||
if ($c['inactive'] > $maxI) { $maxI = $c['inactive']; }
|
||||
if ($c['attacks'] > $maxA) { $maxA = $c['attacks']; }
|
||||
if ($c['pop'] > $maxP) { $maxP = $c['pop']; }
|
||||
$list[] = $c;
|
||||
}
|
||||
|
||||
return [
|
||||
'res' => $res, 'world_max' => $max, 'cell_span' => $cellSpan,
|
||||
'inactive_days' => $days,
|
||||
'cells' => $list,
|
||||
'max' => ['villages' => $maxV, 'inactive' => $maxI, 'attacks' => $maxA, 'pop' => $maxP],
|
||||
'tribe_totals' => $tribeTotals,
|
||||
'totals' => [
|
||||
'villages' => $totVil, 'inactive' => $totInact,
|
||||
'attacks' => $totAtk, 'players' => count($players),
|
||||
],
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -6,7 +6,7 @@
|
||||
## Filename : HeroAdventure.php ##
|
||||
## Type : T4 Hero port - adventures backend (Phase 3) ##
|
||||
## --------------------------------------------------------------------------- ##
|
||||
## Refactored by : Shadow ##
|
||||
## Developed by : Shadow ##
|
||||
## Project : TravianZ ##
|
||||
## GitHub : https://github.com/Shadowss/TravianZ ##
|
||||
## --------------------------------------------------------------------------- ##
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
## Filename : HeroAuction.php ##
|
||||
## Type : T4 Hero port - auction house backend (Phase 4) ##
|
||||
## --------------------------------------------------------------------------- ##
|
||||
## Refactored by : Shadow ##
|
||||
## Developed by : Shadow ##
|
||||
## Project : TravianZ ##
|
||||
## GitHub : https://github.com/Shadowss/TravianZ ##
|
||||
## --------------------------------------------------------------------------- ##
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
## Filename : HeroBattleBonus.php ##
|
||||
## Type : T4 Hero port - battle & speed integration (Phase 5) ##
|
||||
## --------------------------------------------------------------------------- ##
|
||||
## Refactored by : Shadow ##
|
||||
## Developed by : Shadow ##
|
||||
## Project : TravianZ ##
|
||||
## GitHub : https://github.com/Shadowss/TravianZ ##
|
||||
## --------------------------------------------------------------------------- ##
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
## Filename : HeroItems.php ##
|
||||
## Type : T4 Hero port - items backend (Phase 2) ##
|
||||
## --------------------------------------------------------------------------- ##
|
||||
## Refactored by : Shadow ##
|
||||
## Developed by : Shadow ##
|
||||
## Project : TravianZ ##
|
||||
## GitHub : https://github.com/Shadowss/TravianZ ##
|
||||
## --------------------------------------------------------------------------- ##
|
||||
@@ -15,14 +15,14 @@
|
||||
## --------------------------------------------------------------------------- ##
|
||||
#################################################################################
|
||||
## ##
|
||||
## Backend for hero inventory / equipment / consumables / silver. ##
|
||||
## - All statements are prepared (mysqli), all ids cast to int. ##
|
||||
## - Per-request memoization caches (invalidated on every write), matching ##
|
||||
## the Database.php cache convention. ##
|
||||
## - Consumables whose game mechanic lands in a later phase (bandages in ##
|
||||
## battle, cages in oasis attacks, law tablets in loyalty, artwork CP) ##
|
||||
## return HeroItems::USE_DEFERRED so the caller knows the item exists ##
|
||||
## but its effect is wired elsewhere. They are NOT silently consumed. ##
|
||||
## Backend for hero inventory / equipment / consumables / silver. ##
|
||||
## - All statements are prepared (mysqli), all ids cast to int. ##
|
||||
## - Per-request memoization caches (invalidated on every write), matching ##
|
||||
## the Database.php cache convention. ##
|
||||
## - Consumables whose game mechanic lands in a later phase (bandages in ##
|
||||
## battle, cages in oasis attacks, law tablets in loyalty, artwork CP) ##
|
||||
## return HeroItems::USE_DEFERRED so the caller knows the item exists ##
|
||||
## but its effect is wired elsewhere. They are NOT silently consumed. ##
|
||||
## ##
|
||||
#################################################################################
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
## Filename : PushProtection.php ##
|
||||
## Type : Push-Protection engine (Admin/Multihunter dashboard) ##
|
||||
## --------------------------------------------------------------------------- ##
|
||||
## Developed by : Shadow (Cătălin) ##
|
||||
## Developed by : Shadow ##
|
||||
## Project : TravianZ ##
|
||||
## GitHub : https://github.com/Shadowss/TravianZ ##
|
||||
## --------------------------------------------------------------------------- ##
|
||||
|
||||
@@ -0,0 +1,408 @@
|
||||
<?php
|
||||
#################################################################################
|
||||
## -= YOU MAY NOT REMOVE OR CHANGE THIS NOTICE =- ##
|
||||
## --------------------------------------------------------------------------- ##
|
||||
## Filename : QuestConfig.php ##
|
||||
## Type : Editable quest rewards (Admin quest editor) ##
|
||||
## --------------------------------------------------------------------------- ##
|
||||
## Developed by : Shadow (Cătălin) ##
|
||||
## Project : TravianZ ##
|
||||
## GitHub : https://github.com/Shadowss/TravianZ ##
|
||||
## --------------------------------------------------------------------------- ##
|
||||
## License : TravianZ Project ##
|
||||
## Copyright : TravianZ (c) 2010-2026. All rights reserved. ##
|
||||
## --------------------------------------------------------------------------- ##
|
||||
#################################################################################
|
||||
|
||||
/**
|
||||
* QuestConfig
|
||||
* -------------------------------------------------------------------------
|
||||
* Makes the (previously hardcoded) quest rewards editable from the admin panel.
|
||||
*
|
||||
* The quest system ships in two variants — extended (Templates/Ajax/quest_core.tpl)
|
||||
* and standard (quest_core25.tpl) — selected per player by $_SESSION['qtyp']==37.
|
||||
* The two have different reward values and quest sets, so config is keyed by
|
||||
* (variant, quest_id).
|
||||
*
|
||||
* This class is the SINGLE SOURCE OF TRUTH for what a completed quest grants:
|
||||
* quest_core*.tpl calls QuestConfig::grantReward() instead of the old hardcoded
|
||||
* modifyResource()/gold/plus lines (see "wiring" note in the admin editor). The
|
||||
* table is seeded on first use with the exact current values, so behaviour is
|
||||
* unchanged until an admin edits something.
|
||||
*
|
||||
* Self-contained (static, resolves DB link from globals, self-creates + seeds
|
||||
* its table).
|
||||
*/
|
||||
class QuestConfig
|
||||
{
|
||||
const V_EXTENDED = 'extended';
|
||||
const V_STANDARD = 'standard';
|
||||
|
||||
private static function link()
|
||||
{
|
||||
if (isset($GLOBALS['link']) && $GLOBALS['link']) {
|
||||
return $GLOBALS['link'];
|
||||
}
|
||||
if (isset($GLOBALS['database']) && isset($GLOBALS['database']->dblink)) {
|
||||
return $GLOBALS['database']->dblink;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/** Which quest variant is active for the current player/session. */
|
||||
public static function activeVariant()
|
||||
{
|
||||
return (isset($_SESSION['qtyp']) && (int) $_SESSION['qtyp'] === 37)
|
||||
? self::V_EXTENDED : self::V_STANDARD;
|
||||
}
|
||||
|
||||
public static function ensureSchema()
|
||||
{
|
||||
$link = self::link();
|
||||
if (!$link) {
|
||||
return;
|
||||
}
|
||||
@mysqli_query($link, "CREATE TABLE IF NOT EXISTS `" . TB_PREFIX . "quest_config` (
|
||||
`variant` varchar(16) NOT NULL DEFAULT 'standard',
|
||||
`quest_id` int(11) NOT NULL,
|
||||
`enabled` tinyint(1) NOT NULL DEFAULT 1,
|
||||
`wood` int(11) NOT NULL DEFAULT 0,
|
||||
`clay` int(11) NOT NULL DEFAULT 0,
|
||||
`iron` int(11) NOT NULL DEFAULT 0,
|
||||
`crop` int(11) NOT NULL DEFAULT 0,
|
||||
`gold` int(11) NOT NULL DEFAULT 0,
|
||||
`plus_days` float NOT NULL DEFAULT 0,
|
||||
`req_level` int(11) NOT NULL DEFAULT 0,
|
||||
`note` varchar(255) NOT NULL DEFAULT '',
|
||||
PRIMARY KEY (`variant`,`quest_id`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8");
|
||||
}
|
||||
|
||||
/** Seed the table with the current (extracted) hardcoded values, once. */
|
||||
public static function seedDefaults()
|
||||
{
|
||||
$link = self::link();
|
||||
if (!$link) {
|
||||
return;
|
||||
}
|
||||
self::ensureSchema();
|
||||
|
||||
// Only seed when empty, so admin edits are never overwritten.
|
||||
$r = @mysqli_query($link, "SELECT 1 FROM `" . TB_PREFIX . "quest_config` LIMIT 1");
|
||||
if ($r && mysqli_num_rows($r) > 0) {
|
||||
mysqli_free_result($r);
|
||||
return;
|
||||
}
|
||||
if ($r) { mysqli_free_result($r); }
|
||||
|
||||
$stmt = mysqli_prepare($link,
|
||||
"INSERT IGNORE INTO `" . TB_PREFIX . "quest_config`
|
||||
(variant, quest_id, enabled, wood, clay, iron, crop, gold, plus_days, req_level, note)
|
||||
VALUES (?,?,1,?,?,?,?,?,?,0,'')");
|
||||
if (!$stmt) {
|
||||
return;
|
||||
}
|
||||
foreach (self::defaults() as $variant => $quests) {
|
||||
foreach ($quests as $qid => $v) {
|
||||
$qid = (int) $qid;
|
||||
$w = (int) $v['wood']; $c = (int) $v['clay']; $i = (int) $v['iron'];
|
||||
$cr = (int) $v['crop']; $g = (int) $v['gold']; $pd = (float) $v['plus_days'];
|
||||
mysqli_stmt_bind_param($stmt, 'siiiiiid', $variant, $qid, $w, $c, $i, $cr, $g, $pd);
|
||||
mysqli_stmt_execute($stmt);
|
||||
}
|
||||
}
|
||||
mysqli_stmt_close($stmt);
|
||||
}
|
||||
|
||||
/* ---- Reads --------------------------------------------------------- */
|
||||
|
||||
/** All quest rows for a variant (seeds first). */
|
||||
public static function all($variant)
|
||||
{
|
||||
$variant = self::normVariant($variant);
|
||||
$link = self::link();
|
||||
$out = [];
|
||||
if (!$link) {
|
||||
return $out;
|
||||
}
|
||||
self::seedDefaults();
|
||||
$stmt = mysqli_prepare($link,
|
||||
"SELECT * FROM `" . TB_PREFIX . "quest_config` WHERE variant = ? ORDER BY quest_id ASC");
|
||||
if (!$stmt) {
|
||||
return $out;
|
||||
}
|
||||
mysqli_stmt_bind_param($stmt, 's', $variant);
|
||||
mysqli_stmt_execute($stmt);
|
||||
$res = mysqli_stmt_get_result($stmt);
|
||||
while ($res && $row = mysqli_fetch_assoc($res)) {
|
||||
$out[(int) $row['quest_id']] = $row;
|
||||
}
|
||||
mysqli_stmt_close($stmt);
|
||||
return $out;
|
||||
}
|
||||
|
||||
/** One quest's config, falling back to the hardcoded default if absent. */
|
||||
public static function get($variant, $qid)
|
||||
{
|
||||
$variant = self::normVariant($variant);
|
||||
$qid = (int) $qid;
|
||||
$link = self::link();
|
||||
if ($link) {
|
||||
self::ensureSchema();
|
||||
$stmt = mysqli_prepare($link,
|
||||
"SELECT * FROM `" . TB_PREFIX . "quest_config` WHERE variant = ? AND quest_id = ? LIMIT 1");
|
||||
if ($stmt) {
|
||||
mysqli_stmt_bind_param($stmt, 'si', $variant, $qid);
|
||||
mysqli_stmt_execute($stmt);
|
||||
$res = mysqli_stmt_get_result($stmt);
|
||||
$row = $res ? mysqli_fetch_assoc($res) : null;
|
||||
mysqli_stmt_close($stmt);
|
||||
if ($row) {
|
||||
return $row;
|
||||
}
|
||||
}
|
||||
}
|
||||
// Fallback to compiled-in defaults.
|
||||
$d = self::defaults();
|
||||
if (isset($d[$variant][$qid])) {
|
||||
$v = $d[$variant][$qid];
|
||||
return [
|
||||
'variant' => $variant, 'quest_id' => $qid, 'enabled' => 1,
|
||||
'wood' => $v['wood'], 'clay' => $v['clay'], 'iron' => $v['iron'],
|
||||
'crop' => $v['crop'], 'gold' => $v['gold'], 'plus_days' => $v['plus_days'],
|
||||
'req_level' => 0, 'note' => '',
|
||||
];
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/* ---- Write --------------------------------------------------------- */
|
||||
|
||||
public static function setQuest($variant, $qid, array $fields)
|
||||
{
|
||||
$variant = self::normVariant($variant);
|
||||
$link = self::link();
|
||||
if (!$link) {
|
||||
return false;
|
||||
}
|
||||
self::ensureSchema();
|
||||
|
||||
$qid = (int) $qid;
|
||||
$enabled = !empty($fields['enabled']) ? 1 : 0;
|
||||
$wood = (int) ($fields['wood'] ?? 0);
|
||||
$clay = (int) ($fields['clay'] ?? 0);
|
||||
$iron = (int) ($fields['iron'] ?? 0);
|
||||
$crop = (int) ($fields['crop'] ?? 0);
|
||||
$gold = (int) ($fields['gold'] ?? 0);
|
||||
$plus = (float) ($fields['plus_days'] ?? 0);
|
||||
$req = (int) ($fields['req_level'] ?? 0);
|
||||
$note = substr((string) ($fields['note'] ?? ''), 0, 255);
|
||||
|
||||
$stmt = mysqli_prepare($link,
|
||||
"INSERT INTO `" . TB_PREFIX . "quest_config`
|
||||
(variant, quest_id, enabled, wood, clay, iron, crop, gold, plus_days, req_level, note)
|
||||
VALUES (?,?,?,?,?,?,?,?,?,?,?)
|
||||
ON DUPLICATE KEY UPDATE enabled=VALUES(enabled), wood=VALUES(wood), clay=VALUES(clay),
|
||||
iron=VALUES(iron), crop=VALUES(crop), gold=VALUES(gold), plus_days=VALUES(plus_days),
|
||||
req_level=VALUES(req_level), note=VALUES(note)");
|
||||
if (!$stmt) {
|
||||
return false;
|
||||
}
|
||||
mysqli_stmt_bind_param($stmt, 'siiiiiiidis',
|
||||
$variant, $qid, $enabled, $wood, $clay, $iron, $crop, $gold, $plus, $req, $note);
|
||||
$ok = mysqli_stmt_execute($stmt);
|
||||
mysqli_stmt_close($stmt);
|
||||
return $ok;
|
||||
}
|
||||
|
||||
/** Reset a whole variant back to compiled-in defaults. */
|
||||
public static function resetVariant($variant)
|
||||
{
|
||||
$variant = self::normVariant($variant);
|
||||
$link = self::link();
|
||||
if (!$link) {
|
||||
return false;
|
||||
}
|
||||
self::ensureSchema();
|
||||
$stmt = mysqli_prepare($link,
|
||||
"DELETE FROM `" . TB_PREFIX . "quest_config` WHERE variant = ?");
|
||||
if ($stmt) {
|
||||
mysqli_stmt_bind_param($stmt, 's', $variant);
|
||||
mysqli_stmt_execute($stmt);
|
||||
mysqli_stmt_close($stmt);
|
||||
}
|
||||
self::seedDefaults();
|
||||
return true;
|
||||
}
|
||||
|
||||
/* ---- Reward granting (called from quest_core*.tpl) ----------------- */
|
||||
|
||||
/**
|
||||
* Grant a quest's reward from config. Replaces the old hardcoded
|
||||
* modifyResource()/gold/plus lines in the quest switch. Special side
|
||||
* effects (messages, FinishWoodcutter, etc.) stay in the template.
|
||||
*
|
||||
* @param object $database
|
||||
* @param object $session
|
||||
* @param int $qid
|
||||
* @param string|null $variant Auto-detected from session if null.
|
||||
*/
|
||||
public static function grantReward($database, $session, $qid, $variant = null)
|
||||
{
|
||||
try {
|
||||
$variant = $variant ? self::normVariant($variant) : self::activeVariant();
|
||||
$cfg = self::get($variant, $qid);
|
||||
if (!$cfg) {
|
||||
return;
|
||||
}
|
||||
|
||||
$vil = (isset($session->villages) && isset($session->villages[0])) ? $session->villages[0] : 0;
|
||||
$uid = 0;
|
||||
if (isset($session->uid)) {
|
||||
$uid = (int) $session->uid;
|
||||
} elseif (isset($session->userinfo) && isset($session->userinfo['id'])) {
|
||||
$uid = (int) $session->userinfo['id'];
|
||||
}
|
||||
|
||||
$w = (int) $cfg['wood']; $c = (int) $cfg['clay'];
|
||||
$i = (int) $cfg['iron']; $cr = (int) $cfg['crop'];
|
||||
if (($w || $c || $i || $cr) && $vil && method_exists($database, 'modifyResource')) {
|
||||
$database->modifyResource($vil, $w, $c, $i, $cr, 1);
|
||||
}
|
||||
|
||||
$gold = (int) $cfg['gold'];
|
||||
if ($gold > 0 && $uid > 0 && method_exists($database, 'modifyGold')) {
|
||||
$database->modifyGold($uid, $gold, 1);
|
||||
}
|
||||
|
||||
$plusDays = (float) $cfg['plus_days'];
|
||||
if ($plusDays > 0 && $uid > 0) {
|
||||
$sec = (int) round($plusDays * 86400);
|
||||
$now = time();
|
||||
$link = self::link();
|
||||
if ($link) {
|
||||
@mysqli_query($link, "UPDATE `" . TB_PREFIX . "users`
|
||||
SET plus = IF(plus > $now, plus + $sec, $now + $sec) WHERE id = $uid");
|
||||
}
|
||||
}
|
||||
} catch (\Throwable $e) {
|
||||
// never break the quest flow
|
||||
}
|
||||
}
|
||||
|
||||
/* ---- Helpers ------------------------------------------------------- */
|
||||
|
||||
public static function normVariant($v)
|
||||
{
|
||||
return ($v === self::V_EXTENDED) ? self::V_EXTENDED : self::V_STANDARD;
|
||||
}
|
||||
|
||||
/**
|
||||
* Quests that keep their original hardcoded logic in quest_core*.tpl and are
|
||||
* therefore NOT affected by edits here (conditional rewards, atomic-claim
|
||||
* milestones, special mechanics). Shown as read-only in the editor.
|
||||
* 2 = FinishWoodcutter (completes a building, not a resource grant)
|
||||
* 9 = conditional crop cost + spawned attack
|
||||
* 26 = (standard only) two-branch reward depending on a session flag
|
||||
* 91 = atomic-claim milestone (gold + Plus, issue #129)
|
||||
* 97 = atomic-claim milestone (gold + Plus, issue #129)
|
||||
*/
|
||||
public static function nativeQuests($variant)
|
||||
{
|
||||
$variant = self::normVariant($variant);
|
||||
return ($variant === self::V_STANDARD)
|
||||
? [2, 9, 26, 91, 97]
|
||||
: [2, 9, 91, 97];
|
||||
}
|
||||
|
||||
/**
|
||||
* Compiled-in default reward values, extracted from the shipped quest
|
||||
* templates (extended = quest_core.tpl, standard = quest_core25.tpl).
|
||||
* Used to seed the table and as a fallback.
|
||||
*/
|
||||
public static function defaults()
|
||||
{
|
||||
return [
|
||||
'extended' => [
|
||||
2 => ['wood'=>0,'clay'=>0,'iron'=>0,'crop'=>0,'gold'=>0,'plus_days'=>0],
|
||||
3 => ['wood'=>0,'clay'=>0,'iron'=>0,'crop'=>0,'gold'=>0,'plus_days'=>1],
|
||||
4 => ['wood'=>30,'clay'=>60,'iron'=>30,'crop'=>20,'gold'=>0,'plus_days'=>0],
|
||||
5 => ['wood'=>40,'clay'=>30,'iron'=>20,'crop'=>30,'gold'=>0,'plus_days'=>0],
|
||||
6 => ['wood'=>50,'clay'=>60,'iron'=>30,'crop'=>30,'gold'=>0,'plus_days'=>0],
|
||||
7 => ['wood'=>0,'clay'=>0,'iron'=>0,'crop'=>0,'gold'=>20,'plus_days'=>0],
|
||||
8 => ['wood'=>75,'clay'=>80,'iron'=>30,'crop'=>50,'gold'=>0,'plus_days'=>0],
|
||||
9 => ['wood'=>0,'clay'=>0,'iron'=>0,'crop'=>-200,'gold'=>0,'plus_days'=>0],
|
||||
10 => ['wood'=>75,'clay'=>90,'iron'=>30,'crop'=>50,'gold'=>0,'plus_days'=>0],
|
||||
11 => ['wood'=>0,'clay'=>0,'iron'=>0,'crop'=>0,'gold'=>0,'plus_days'=>2],
|
||||
12 => ['wood'=>60,'clay'=>30,'iron'=>40,'crop'=>90,'gold'=>0,'plus_days'=>0],
|
||||
13 => ['wood'=>150,'clay'=>180,'iron'=>30,'crop'=>130,'gold'=>0,'plus_days'=>0],
|
||||
14 => ['wood'=>60,'clay'=>50,'iron'=>40,'crop'=>30,'gold'=>0,'plus_days'=>0],
|
||||
15 => ['wood'=>50,'clay'=>30,'iron'=>60,'crop'=>20,'gold'=>0,'plus_days'=>0],
|
||||
16 => ['wood'=>75,'clay'=>75,'iron'=>40,'crop'=>40,'gold'=>0,'plus_days'=>0],
|
||||
17 => ['wood'=>100,'clay'=>90,'iron'=>100,'crop'=>60,'gold'=>0,'plus_days'=>0],
|
||||
18 => ['wood'=>0,'clay'=>0,'iron'=>0,'crop'=>0,'gold'=>0,'plus_days'=>0],
|
||||
19 => ['wood'=>80,'clay'=>90,'iron'=>60,'crop'=>40,'gold'=>0,'plus_days'=>0],
|
||||
20 => ['wood'=>70,'clay'=>120,'iron'=>90,'crop'=>50,'gold'=>0,'plus_days'=>0],
|
||||
21 => ['wood'=>0,'clay'=>0,'iron'=>0,'crop'=>0,'gold'=>0,'plus_days'=>0],
|
||||
22 => ['wood'=>200,'clay'=>200,'iron'=>700,'crop'=>450,'gold'=>0,'plus_days'=>0],
|
||||
23 => ['wood'=>0,'clay'=>0,'iron'=>0,'crop'=>0,'gold'=>0,'plus_days'=>0],
|
||||
24 => ['wood'=>300,'clay'=>320,'iron'=>360,'crop'=>570,'gold'=>0,'plus_days'=>0],
|
||||
28 => ['wood'=>0,'clay'=>0,'iron'=>0,'crop'=>0,'gold'=>15,'plus_days'=>0],
|
||||
29 => ['wood'=>240,'clay'=>280,'iron'=>180,'crop'=>100,'gold'=>0,'plus_days'=>0],
|
||||
30 => ['wood'=>600,'clay'=>750,'iron'=>600,'crop'=>300,'gold'=>0,'plus_days'=>0],
|
||||
31 => ['wood'=>900,'clay'=>850,'iron'=>600,'crop'=>300,'gold'=>0,'plus_days'=>0],
|
||||
32 => ['wood'=>1800,'clay'=>2000,'iron'=>1650,'crop'=>800,'gold'=>0,'plus_days'=>0],
|
||||
33 => ['wood'=>1600,'clay'=>1800,'iron'=>1950,'crop'=>1200,'gold'=>0,'plus_days'=>0],
|
||||
34 => ['wood'=>3400,'clay'=>2800,'iron'=>3600,'crop'=>2200,'gold'=>0,'plus_days'=>0],
|
||||
35 => ['wood'=>1050,'clay'=>800,'iron'=>900,'crop'=>750,'gold'=>0,'plus_days'=>0],
|
||||
36 => ['wood'=>1600,'clay'=>2000,'iron'=>1800,'crop'=>1300,'gold'=>0,'plus_days'=>0],
|
||||
37 => ['wood'=>0,'clay'=>0,'iron'=>0,'crop'=>0,'gold'=>0,'plus_days'=>0],
|
||||
91 => ['wood'=>0,'clay'=>0,'iron'=>0,'crop'=>0,'gold'=>15,'plus_days'=>1],
|
||||
92 => ['wood'=>217,'clay'=>247,'iron'=>177,'crop'=>207,'gold'=>0,'plus_days'=>0],
|
||||
93 => ['wood'=>217,'clay'=>247,'iron'=>177,'crop'=>207,'gold'=>0,'plus_days'=>0],
|
||||
94 => ['wood'=>217,'clay'=>247,'iron'=>177,'crop'=>207,'gold'=>0,'plus_days'=>0],
|
||||
95 => ['wood'=>217,'clay'=>247,'iron'=>177,'crop'=>207,'gold'=>0,'plus_days'=>0],
|
||||
96 => ['wood'=>217,'clay'=>247,'iron'=>177,'crop'=>207,'gold'=>0,'plus_days'=>0],
|
||||
97 => ['wood'=>0,'clay'=>0,'iron'=>0,'crop'=>0,'gold'=>20,'plus_days'=>2],
|
||||
],
|
||||
'standard' => [
|
||||
2 => ['wood'=>0,'clay'=>0,'iron'=>0,'crop'=>0,'gold'=>0,'plus_days'=>0],
|
||||
3 => ['wood'=>0,'clay'=>0,'iron'=>0,'crop'=>0,'gold'=>0,'plus_days'=>1],
|
||||
4 => ['wood'=>30,'clay'=>60,'iron'=>30,'crop'=>20,'gold'=>0,'plus_days'=>0],
|
||||
5 => ['wood'=>40,'clay'=>30,'iron'=>20,'crop'=>30,'gold'=>0,'plus_days'=>0],
|
||||
6 => ['wood'=>50,'clay'=>60,'iron'=>30,'crop'=>30,'gold'=>0,'plus_days'=>0],
|
||||
7 => ['wood'=>0,'clay'=>0,'iron'=>0,'crop'=>0,'gold'=>20,'plus_days'=>0],
|
||||
8 => ['wood'=>60,'clay'=>30,'iron'=>40,'crop'=>90,'gold'=>0,'plus_days'=>0],
|
||||
9 => ['wood'=>0,'clay'=>0,'iron'=>0,'crop'=>-200,'gold'=>0,'plus_days'=>0],
|
||||
10 => ['wood'=>100,'clay'=>80,'iron'=>40,'crop'=>40,'gold'=>0,'plus_days'=>0],
|
||||
11 => ['wood'=>0,'clay'=>0,'iron'=>0,'crop'=>0,'gold'=>0,'plus_days'=>2],
|
||||
12 => ['wood'=>75,'clay'=>140,'iron'=>40,'crop'=>40,'gold'=>0,'plus_days'=>0],
|
||||
13 => ['wood'=>75,'clay'=>80,'iron'=>30,'crop'=>50,'gold'=>0,'plus_days'=>0],
|
||||
14 => ['wood'=>120,'clay'=>200,'iron'=>140,'crop'=>100,'gold'=>0,'plus_days'=>0],
|
||||
15 => ['wood'=>150,'clay'=>180,'iron'=>30,'crop'=>130,'gold'=>0,'plus_days'=>0],
|
||||
16 => ['wood'=>60,'clay'=>50,'iron'=>40,'crop'=>30,'gold'=>0,'plus_days'=>0],
|
||||
17 => ['wood'=>50,'clay'=>30,'iron'=>60,'crop'=>20,'gold'=>0,'plus_days'=>0],
|
||||
18 => ['wood'=>75,'clay'=>75,'iron'=>40,'crop'=>40,'gold'=>0,'plus_days'=>0],
|
||||
19 => ['wood'=>100,'clay'=>90,'iron'=>100,'crop'=>60,'gold'=>0,'plus_days'=>0],
|
||||
20 => ['wood'=>0,'clay'=>0,'iron'=>0,'crop'=>0,'gold'=>0,'plus_days'=>0],
|
||||
21 => ['wood'=>80,'clay'=>90,'iron'=>60,'crop'=>40,'gold'=>0,'plus_days'=>0],
|
||||
22 => ['wood'=>70,'clay'=>120,'iron'=>90,'crop'=>50,'gold'=>0,'plus_days'=>0],
|
||||
23 => ['wood'=>80,'clay'=>90,'iron'=>60,'crop'=>40,'gold'=>0,'plus_days'=>0],
|
||||
24 => ['wood'=>80,'clay'=>90,'iron'=>60,'crop'=>40,'gold'=>0,'plus_days'=>0],
|
||||
25 => ['wood'=>70,'clay'=>100,'iron'=>90,'crop'=>100,'gold'=>0,'plus_days'=>0],
|
||||
26 => ['wood'=>200,'clay'=>200,'iron'=>700,'crop'=>250,'gold'=>0,'plus_days'=>0],
|
||||
27 => ['wood'=>0,'clay'=>0,'iron'=>0,'crop'=>0,'gold'=>15,'plus_days'=>0],
|
||||
28 => ['wood'=>80,'clay'=>70,'iron'=>60,'crop'=>40,'gold'=>0,'plus_days'=>0],
|
||||
29 => ['wood'=>100,'clay'=>60,'iron'=>90,'crop'=>40,'gold'=>0,'plus_days'=>0],
|
||||
30 => ['wood'=>100,'clay'=>140,'iron'=>90,'crop'=>50,'gold'=>0,'plus_days'=>0],
|
||||
91 => ['wood'=>0,'clay'=>0,'iron'=>0,'crop'=>0,'gold'=>15,'plus_days'=>1],
|
||||
92 => ['wood'=>217,'clay'=>247,'iron'=>177,'crop'=>207,'gold'=>0,'plus_days'=>0],
|
||||
93 => ['wood'=>217,'clay'=>247,'iron'=>177,'crop'=>207,'gold'=>0,'plus_days'=>0],
|
||||
94 => ['wood'=>217,'clay'=>247,'iron'=>177,'crop'=>207,'gold'=>0,'plus_days'=>0],
|
||||
95 => ['wood'=>217,'clay'=>247,'iron'=>177,'crop'=>207,'gold'=>0,'plus_days'=>0],
|
||||
96 => ['wood'=>217,'clay'=>247,'iron'=>177,'crop'=>207,'gold'=>0,'plus_days'=>0],
|
||||
97 => ['wood'=>0,'clay'=>0,'iron'=>0,'crop'=>0,'gold'=>20,'plus_days'=>2],
|
||||
],
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,226 @@
|
||||
<?php
|
||||
#################################################################################
|
||||
## -= YOU MAY NOT REMOVE OR CHANGE THIS NOTICE =- ##
|
||||
## --------------------------------------------------------------------------- ##
|
||||
## Filename : RegBlock.php ##
|
||||
## Type : Registration blocklist engine ##
|
||||
## --------------------------------------------------------------------------- ##
|
||||
## Developed by : Shadow ##
|
||||
## Project : TravianZ ##
|
||||
## GitHub : https://github.com/Shadowss/TravianZ ##
|
||||
## --------------------------------------------------------------------------- ##
|
||||
## License : TravianZ Project ##
|
||||
## Copyright : TravianZ (c) 2010-2026. All rights reserved. ##
|
||||
## --------------------------------------------------------------------------- ##
|
||||
#################################################################################
|
||||
|
||||
/**
|
||||
* RegBlock
|
||||
* -------------------------------------------------------------------------
|
||||
* Blocklist for registration: reject specific usernames, specific e-mail
|
||||
* addresses, or whole e-mail domains (e.g. an obscene username, or the whole
|
||||
* "yahoo.com" domain). Managed from the admin panel (blockReg), enforced in
|
||||
* Account::Signup().
|
||||
*
|
||||
* Match rules (all case-insensitive, exact — no accidental substring blocks):
|
||||
* - username : exact username match
|
||||
* - email : exact full-address match
|
||||
* - domain : the part after "@" of the candidate e-mail
|
||||
*
|
||||
* Self-contained (static, resolves DB link from globals, self-creates its
|
||||
* table) so both the registration flow and the admin panel can use it.
|
||||
*/
|
||||
class RegBlock
|
||||
{
|
||||
const T_USERNAME = 'username';
|
||||
const T_EMAIL = 'email';
|
||||
const T_DOMAIN = 'domain';
|
||||
|
||||
private static function link()
|
||||
{
|
||||
if (isset($GLOBALS['link']) && $GLOBALS['link']) {
|
||||
return $GLOBALS['link'];
|
||||
}
|
||||
if (isset($GLOBALS['database']) && isset($GLOBALS['database']->dblink)) {
|
||||
return $GLOBALS['database']->dblink;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/** Create the reg_block table if missing. */
|
||||
public static function ensureSchema()
|
||||
{
|
||||
$link = self::link();
|
||||
if (!$link) {
|
||||
return;
|
||||
}
|
||||
@mysqli_query($link, "CREATE TABLE IF NOT EXISTS `" . TB_PREFIX . "reg_block` (
|
||||
`id` int(11) NOT NULL AUTO_INCREMENT,
|
||||
`type` varchar(16) NOT NULL DEFAULT 'username',
|
||||
`value` varchar(255) NOT NULL DEFAULT '',
|
||||
`note` varchar(255) NOT NULL DEFAULT '',
|
||||
`added_by` int(11) NOT NULL DEFAULT 0,
|
||||
`time` int(11) NOT NULL DEFAULT 0,
|
||||
PRIMARY KEY (`id`),
|
||||
UNIQUE KEY `type_value` (`type`,`value`),
|
||||
KEY `type` (`type`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8");
|
||||
}
|
||||
|
||||
/** Normalise a value: trim + lowercase. */
|
||||
private static function norm($v)
|
||||
{
|
||||
return strtolower(trim((string) $v));
|
||||
}
|
||||
|
||||
/** Valid type check. */
|
||||
private static function validType($t)
|
||||
{
|
||||
return in_array($t, [self::T_USERNAME, self::T_EMAIL, self::T_DOMAIN], true);
|
||||
}
|
||||
|
||||
/* ---- Enforcement (called from registration) ------------------------ */
|
||||
|
||||
/** True if this username is blocked. */
|
||||
public static function isBlockedName($database, $name)
|
||||
{
|
||||
return self::matches(self::T_USERNAME, self::norm($name));
|
||||
}
|
||||
|
||||
/** True if this e-mail address OR its domain is blocked. */
|
||||
public static function isBlockedEmail($database, $email)
|
||||
{
|
||||
$email = self::norm($email);
|
||||
if ($email === '') {
|
||||
return false;
|
||||
}
|
||||
if (self::matches(self::T_EMAIL, $email)) {
|
||||
return true;
|
||||
}
|
||||
$at = strrpos($email, '@');
|
||||
if ($at !== false) {
|
||||
$domain = substr($email, $at + 1);
|
||||
if ($domain !== '' && self::matches(self::T_DOMAIN, $domain)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/** Low-level exact lookup. */
|
||||
private static function matches($type, $value)
|
||||
{
|
||||
$link = self::link();
|
||||
if (!$link || $value === '') {
|
||||
return false;
|
||||
}
|
||||
self::ensureSchema();
|
||||
$stmt = mysqli_prepare($link,
|
||||
"SELECT 1 FROM `" . TB_PREFIX . "reg_block` WHERE `type` = ? AND `value` = ? LIMIT 1");
|
||||
if (!$stmt) {
|
||||
return false;
|
||||
}
|
||||
mysqli_stmt_bind_param($stmt, 'ss', $type, $value);
|
||||
mysqli_stmt_execute($stmt);
|
||||
mysqli_stmt_store_result($stmt);
|
||||
$hit = mysqli_stmt_num_rows($stmt) > 0;
|
||||
mysqli_stmt_close($stmt);
|
||||
return $hit;
|
||||
}
|
||||
|
||||
/* ---- Admin management ---------------------------------------------- */
|
||||
|
||||
/** All blocks, newest first. */
|
||||
public static function all()
|
||||
{
|
||||
$link = self::link();
|
||||
$out = [];
|
||||
if (!$link) {
|
||||
return $out;
|
||||
}
|
||||
self::ensureSchema();
|
||||
$r = @mysqli_query($link,
|
||||
"SELECT * FROM `" . TB_PREFIX . "reg_block` ORDER BY `time` DESC, id DESC");
|
||||
if ($r) {
|
||||
while ($row = mysqli_fetch_assoc($r)) {
|
||||
$out[] = $row;
|
||||
}
|
||||
mysqli_free_result($r);
|
||||
}
|
||||
return $out;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a block. Returns [ok(bool), message(string)].
|
||||
* Domain values may be given with or without a leading "@".
|
||||
*/
|
||||
public static function add($type, $value, $note, $adminId)
|
||||
{
|
||||
$link = self::link();
|
||||
if (!$link) {
|
||||
return [false, 'No database connection.'];
|
||||
}
|
||||
self::ensureSchema();
|
||||
|
||||
$type = (string) $type;
|
||||
if (!self::validType($type)) {
|
||||
return [false, 'Invalid block type.'];
|
||||
}
|
||||
|
||||
$value = self::norm($value);
|
||||
if ($type === self::T_DOMAIN) {
|
||||
$value = ltrim($value, '@');
|
||||
}
|
||||
if ($value === '') {
|
||||
return [false, 'Value cannot be empty.'];
|
||||
}
|
||||
|
||||
// Light sanity checks.
|
||||
if ($type === self::T_EMAIL && strpos($value, '@') === false) {
|
||||
return [false, 'That does not look like a full e-mail address.'];
|
||||
}
|
||||
if ($type === self::T_DOMAIN && strpos($value, '.') === false) {
|
||||
return [false, 'That does not look like a domain (e.g. yahoo.com).'];
|
||||
}
|
||||
if (strlen($value) > 255) {
|
||||
return [false, 'Value too long.'];
|
||||
}
|
||||
|
||||
$note = substr((string) $note, 0, 255);
|
||||
$admin = (int) $adminId;
|
||||
$now = time();
|
||||
|
||||
$stmt = mysqli_prepare($link,
|
||||
"INSERT INTO `" . TB_PREFIX . "reg_block` (`type`,`value`,`note`,`added_by`,`time`)
|
||||
VALUES (?,?,?,?,?)
|
||||
ON DUPLICATE KEY UPDATE `note` = VALUES(`note`), `added_by` = VALUES(`added_by`), `time` = VALUES(`time`)");
|
||||
if (!$stmt) {
|
||||
return [false, 'Could not prepare statement.'];
|
||||
}
|
||||
mysqli_stmt_bind_param($stmt, 'sssii', $type, $value, $note, $admin, $now);
|
||||
$ok = mysqli_stmt_execute($stmt);
|
||||
mysqli_stmt_close($stmt);
|
||||
|
||||
return $ok ? [true, 'Block saved.'] : [false, 'Could not save block.'];
|
||||
}
|
||||
|
||||
/** Remove a block by id. */
|
||||
public static function remove($id)
|
||||
{
|
||||
$link = self::link();
|
||||
if (!$link) {
|
||||
return false;
|
||||
}
|
||||
self::ensureSchema();
|
||||
$stmt = mysqli_prepare($link,
|
||||
"DELETE FROM `" . TB_PREFIX . "reg_block` WHERE id = ?");
|
||||
if (!$stmt) {
|
||||
return false;
|
||||
}
|
||||
$id = (int) $id;
|
||||
mysqli_stmt_bind_param($stmt, 'i', $id);
|
||||
$ok = mysqli_stmt_execute($stmt);
|
||||
mysqli_stmt_close($stmt);
|
||||
return $ok;
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,5 @@
|
||||
<?php
|
||||
if (!class_exists('QuestConfig')) { $__qcf = dirname(__DIR__, 2) . '/GameEngine/QuestConfig.php'; if (is_file($__qcf)) include_once($__qcf); }
|
||||
|
||||
#################################################################################
|
||||
## -= YOU MAY NOT REMOVE OR CHANGE THIS NOTICE =- ##
|
||||
@@ -84,21 +85,18 @@ if (isset($qact)){
|
||||
case '3':
|
||||
$database->updateUserField($_SESSION['username'],'quest','3',0,false);
|
||||
$_SESSION['qst']= 3;
|
||||
QuestConfig::grantReward($database,$session,3);
|
||||
//Give Reward
|
||||
if(!$session->plus){
|
||||
mysqli_query($database->dblink,"UPDATE ".TB_PREFIX."users set plus = ('".mktime(date("H"),date("i"), date("s"),date("m") , date("d"), date("Y"))."')+86400 where `username`='".$user_sanitized."'") or die(mysqli_error($database->dblink));
|
||||
} else {
|
||||
$plus=$database->getUserField($_SESSION['username'],'plus','username');
|
||||
$plus+=86400;
|
||||
$database->updateUserField($_SESSION['username'],'plus',$plus,0);
|
||||
}
|
||||
break;
|
||||
|
||||
case '4':
|
||||
$database->updateUserField($_SESSION['username'],'quest','4',0);
|
||||
$_SESSION['qst']= 4;
|
||||
QuestConfig::grantReward($database,$session,4);
|
||||
//Give Reward
|
||||
$database->modifyResource($session->villages[0],30,60,30,20,1);
|
||||
break;
|
||||
|
||||
case 'rank':
|
||||
@@ -108,36 +106,34 @@ if (isset($qact)){
|
||||
case '5':
|
||||
$database->updateUserField($_SESSION['username'],'quest','5',0);
|
||||
$_SESSION['qst']= 5;
|
||||
QuestConfig::grantReward($database,$session,5);
|
||||
//Give Reward
|
||||
$database->modifyResource($session->villages[0],40,30,20,30,1);
|
||||
break;
|
||||
|
||||
case '6':
|
||||
$database->updateUserField($_SESSION['username'],'quest','6',0);
|
||||
$_SESSION['qst']= 6;
|
||||
QuestConfig::grantReward($database,$session,6);
|
||||
$Subject="Message From The Taskmaster";
|
||||
$Subject=Q6_SUBJECT;
|
||||
$Message=Q6_MESSAGE;
|
||||
$database->sendMessage($session->userinfo['id'],4,$Subject,$Message,0,0,0,0,0);
|
||||
$RB=true;
|
||||
//Give Reward
|
||||
$database->modifyResource($session->villages[0],50,60,30,30,1);
|
||||
break;
|
||||
|
||||
case '7':
|
||||
$database->updateUserField($_SESSION['username'],'quest','7',0);
|
||||
$_SESSION['qst']= 7;
|
||||
QuestConfig::grantReward($database,$session,7);
|
||||
//Give Reward
|
||||
$gold=$database->getUserField($_SESSION['username'],'gold','username');
|
||||
$gold+=20;
|
||||
$database->updateUserField($_SESSION['username'],'gold',$gold,0,false);
|
||||
break;
|
||||
|
||||
case '8':
|
||||
$database->updateUserField($_SESSION['username'],'quest','8',0,false);
|
||||
$_SESSION['qst']= 8;
|
||||
QuestConfig::grantReward($database,$session,8);
|
||||
//Give Reward
|
||||
$database->modifyResource($session->villages[0],75,80,30,50,1);
|
||||
break;
|
||||
|
||||
case '9':
|
||||
@@ -158,20 +154,17 @@ if (isset($qact)){
|
||||
case '10':
|
||||
$database->updateUserField($_SESSION['username'],'quest','10',0);
|
||||
$_SESSION['qst']= 10;
|
||||
QuestConfig::grantReward($database,$session,10);
|
||||
//Give Reward
|
||||
$database->modifyResource($session->villages[0],75,90,30,50,1);
|
||||
break;
|
||||
|
||||
case '11':
|
||||
$database->updateUserField($_SESSION['username'],'quest','11',0);
|
||||
$_SESSION['qst']= 11;
|
||||
QuestConfig::grantReward($database,$session,11);
|
||||
//Give Reward
|
||||
if(!$session->plus){
|
||||
mysqli_query($database->dblink,"UPDATE ".TB_PREFIX."users set plus = ('".mktime(date("H"),date("i"), date("s"),date("m") , date("d"), date("Y"))."')+172800 where `username`='".$user_sanitized."'") or die(mysqli_error());
|
||||
} else {
|
||||
$plus=$database->getUserField($_SESSION['username'],'plus','username');
|
||||
$plus+=172800;
|
||||
$database->updateUserField($_SESSION['username'],'plus',$plus,0);
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -183,22 +176,22 @@ if (isset($qact)){
|
||||
case '12':
|
||||
$database->updateUserField($_SESSION['username'],'quest','12',0);
|
||||
$_SESSION['qst']= 12;
|
||||
QuestConfig::grantReward($database,$session,12);
|
||||
//Give Reward
|
||||
$database->modifyResource($session->villages[0],60,30,40,90,1);
|
||||
break;
|
||||
|
||||
case '13':
|
||||
$database->updateUserField($_SESSION['username'],'quest','13',0);
|
||||
$_SESSION['qst']= 13;
|
||||
QuestConfig::grantReward($database,$session,13);
|
||||
//Give Reward
|
||||
$database->modifyResource($session->villages[0],150,180,30,130,1);
|
||||
break;
|
||||
|
||||
case '14':
|
||||
$database->updateUserField($_SESSION['username'],'quest','14',0);
|
||||
$_SESSION['qst']= 14;
|
||||
QuestConfig::grantReward($database,$session,14);
|
||||
//Give Reward
|
||||
$database->modifyResource($session->villages[0],60,50,40,30,1);
|
||||
break;
|
||||
|
||||
case 'lumber':
|
||||
@@ -208,143 +201,145 @@ if (isset($qact)){
|
||||
case '15':
|
||||
$database->updateUserField($_SESSION['username'],'quest','15',0);
|
||||
$_SESSION['qst']= 15;
|
||||
QuestConfig::grantReward($database,$session,15);
|
||||
//Give Reward
|
||||
$database->modifyResource($session->villages[0],50,30,60,20,1);
|
||||
break;
|
||||
|
||||
case '16':
|
||||
$database->updateUserField($_SESSION['username'],'quest','16',0);
|
||||
$_SESSION['qst']= 16;
|
||||
QuestConfig::grantReward($database,$session,16);
|
||||
//Give Reward
|
||||
$database->modifyResource($session->villages[0],75,75,40,40,1);
|
||||
break;
|
||||
|
||||
case '17':
|
||||
$database->updateUserField($_SESSION['username'],'quest','17',0);
|
||||
$_SESSION['qst']= 17;
|
||||
QuestConfig::grantReward($database,$session,17);
|
||||
//Give Reward
|
||||
$database->modifyResource($session->villages[0],100,90,100,60,1);
|
||||
break;
|
||||
|
||||
case '18':
|
||||
$database->updateUserField($_SESSION['username'],'quest','18',0);
|
||||
$_SESSION['qst']= 18;
|
||||
QuestConfig::grantReward($database,$session,18);
|
||||
break;
|
||||
|
||||
case '19':
|
||||
$database->updateUserField($_SESSION['username'],'quest','19',0);
|
||||
$_SESSION['qst']= 19;
|
||||
QuestConfig::grantReward($database,$session,19);
|
||||
//Give Reward
|
||||
$database->modifyResource($session->villages[0],80,90,60,40,1);
|
||||
break;
|
||||
|
||||
case '20':
|
||||
$database->updateUserField($_SESSION['username'],'quest','20',0);
|
||||
$_SESSION['qst']= 20;
|
||||
QuestConfig::grantReward($database,$session,20);
|
||||
//Give Reward
|
||||
$database->modifyResource($session->villages[0],70,120,90,50,1);
|
||||
break;
|
||||
|
||||
case '21':
|
||||
$database->updateUserField($_SESSION['username'],'quest','21',0);
|
||||
$_SESSION['qst']= 21;
|
||||
QuestConfig::grantReward($database,$session,21);
|
||||
break;
|
||||
|
||||
case '22':
|
||||
$database->updateUserField($_SESSION['username'],'quest','22',0);
|
||||
$_SESSION['qst']= 22;
|
||||
QuestConfig::grantReward($database,$session,22);
|
||||
//Give Reward
|
||||
$database->modifyResource($session->villages[0],200,200,700,450,1);
|
||||
break;
|
||||
|
||||
case '23':
|
||||
$database->updateUserField($_SESSION['username'],'quest','23',0);
|
||||
$_SESSION['qst']= 23;
|
||||
QuestConfig::grantReward($database,$session,23);
|
||||
break;
|
||||
|
||||
case '24':
|
||||
$database->updateUserField($_SESSION['username'],'quest','24',0);
|
||||
$_SESSION['qst']= 24;
|
||||
QuestConfig::grantReward($database,$session,24);
|
||||
//Give Reward
|
||||
$database->modifyResource($session->villages[0],300,320,360,570,1);
|
||||
break;
|
||||
|
||||
case '28':
|
||||
$dataarray[3] = 1;
|
||||
$database->updateUserField($_SESSION['username'],'quest','28',0);
|
||||
$_SESSION['qst']= 28;
|
||||
QuestConfig::grantReward($database,$session,28);
|
||||
//Give Reward
|
||||
$gold=$database->getUserField($_SESSION['username'],'gold','username');
|
||||
$gold+=15;
|
||||
$database->updateUserField($_SESSION['username'],'gold',$gold,0);
|
||||
break;
|
||||
|
||||
case '29':
|
||||
$dataarray[4] = 1;
|
||||
$database->updateUserField($_SESSION['username'],'quest','29',0);
|
||||
$_SESSION['qst']= 29;
|
||||
QuestConfig::grantReward($database,$session,29);
|
||||
//Give Reward
|
||||
$database->modifyResource($session->villages[0],240,280,180,100,1);
|
||||
break;
|
||||
|
||||
case '30':
|
||||
$dataarray[5] = 1;
|
||||
$database->updateUserField($_SESSION['username'],'quest','30',0);
|
||||
$_SESSION['qst']= 30;
|
||||
QuestConfig::grantReward($database,$session,30);
|
||||
//Give Reward
|
||||
$database->modifyResource($session->villages[0],600,750,600,300,1);
|
||||
break;
|
||||
|
||||
case '31':
|
||||
$dataarray[6] = 1;
|
||||
$database->updateUserField($_SESSION['username'],'quest','31',0);
|
||||
$_SESSION['qst']= 31;
|
||||
QuestConfig::grantReward($database,$session,31);
|
||||
//Give Reward
|
||||
$database->modifyResource($session->villages[0],900,850,600,300,1);
|
||||
break;
|
||||
|
||||
case '32':
|
||||
$dataarray[7] = 1;
|
||||
$database->updateUserField($_SESSION['username'],'quest','32',0);
|
||||
$_SESSION['qst']= 32;
|
||||
QuestConfig::grantReward($database,$session,32);
|
||||
//Give Reward
|
||||
$database->modifyResource($session->villages[0],1800,2000,1650,800,1);
|
||||
break;
|
||||
|
||||
case '33':
|
||||
$dataarray[8] = 1;
|
||||
$database->updateUserField($_SESSION['username'],'quest','33',0);
|
||||
$_SESSION['qst']= 33;
|
||||
QuestConfig::grantReward($database,$session,33);
|
||||
//Give Reward
|
||||
$database->modifyResource($session->villages[0],1600,1800,1950,1200,1);
|
||||
break;
|
||||
|
||||
case '34':
|
||||
$dataarray[9] = 1;
|
||||
$database->updateUserField($_SESSION['username'],'quest','34',0);
|
||||
$_SESSION['qst']= 34;
|
||||
QuestConfig::grantReward($database,$session,34);
|
||||
//Give Reward
|
||||
$database->modifyResource($session->villages[0],3400,2800,3600,2200,1);
|
||||
break;
|
||||
|
||||
case '35':
|
||||
$dataarray[10] = 1;
|
||||
$database->updateUserField($_SESSION['username'],'quest','35',0);
|
||||
$_SESSION['qst']= 35;
|
||||
QuestConfig::grantReward($database,$session,35);
|
||||
//Give Reward
|
||||
$database->modifyResource($session->villages[0],1050,800,900,750,1);
|
||||
break;
|
||||
|
||||
case '36':
|
||||
$database->updateUserField($_SESSION['username'],'quest','36',0);
|
||||
$_SESSION['qst']= 36;
|
||||
QuestConfig::grantReward($database,$session,36);
|
||||
//Give Reward
|
||||
$database->modifyResource($session->villages[0],1600,2000,1800,1300,1);
|
||||
break;
|
||||
|
||||
case '37':
|
||||
$database->updateUserField($_SESSION['username'],'quest','37',0);
|
||||
$_SESSION['qst']= 37;
|
||||
QuestConfig::grantReward($database,$session,37);
|
||||
break;
|
||||
|
||||
case '91':
|
||||
@@ -366,45 +361,45 @@ if (isset($qact)){
|
||||
$database->updateUserField($_SESSION['username'],'quest','92',0);
|
||||
$database->updateUserField($_SESSION['username'],'quest_time',''.(time()+$skipp_time).'',0);
|
||||
$_SESSION['qst']= 92;
|
||||
QuestConfig::grantReward($database,$session,92);
|
||||
$_SESSION['qst_time'] = time()+$skipp_time;
|
||||
//Give Reward
|
||||
$database->modifyResource($session->villages[0],217,247,177,207,1);
|
||||
break;
|
||||
|
||||
case '93':
|
||||
$database->updateUserField($_SESSION['username'],'quest','93',0);
|
||||
$database->updateUserField($_SESSION['username'],'quest_time',''.(time()+$skipp_time).'',0);
|
||||
$_SESSION['qst']= 93;
|
||||
QuestConfig::grantReward($database,$session,93);
|
||||
$_SESSION['qst_time'] = time()+$skipp_time;
|
||||
//Give Reward
|
||||
$database->modifyResource($session->villages[0],217,247,177,207,1);
|
||||
break;
|
||||
|
||||
case '94':
|
||||
$database->updateUserField($_SESSION['username'],'quest','94',0);
|
||||
$database->updateUserField($_SESSION['username'],'quest_time',''.(time()+$skipp_time).'',0);
|
||||
$_SESSION['qst']= 94;
|
||||
QuestConfig::grantReward($database,$session,94);
|
||||
$_SESSION['qst_time'] = time()+$skipp_time;
|
||||
//Give Reward
|
||||
$database->modifyResource($session->villages[0],217,247,177,207,1);
|
||||
break;
|
||||
|
||||
case '95':
|
||||
$database->updateUserField($_SESSION['username'],'quest','95',0);
|
||||
$database->updateUserField($_SESSION['username'],'quest_time',''.(time()+$skipp_time).'',0);
|
||||
$_SESSION['qst']= 95;
|
||||
QuestConfig::grantReward($database,$session,95);
|
||||
$_SESSION['qst_time'] = time()+$skipp_time;
|
||||
//Give Reward
|
||||
$database->modifyResource($session->villages[0],217,247,177,207,1);
|
||||
break;
|
||||
|
||||
case '96':
|
||||
$database->updateUserField($_SESSION['username'],'quest','96',0);
|
||||
$database->updateUserField($_SESSION['username'],'quest_time',''.(time()+$skipp_time).'',0);
|
||||
$_SESSION['qst']= 96;
|
||||
QuestConfig::grantReward($database,$session,96);
|
||||
$_SESSION['qst_time'] = time()+$skipp_time;
|
||||
//Give Reward
|
||||
$database->modifyResource($session->villages[0],217,247,177,207,1);
|
||||
break;
|
||||
|
||||
case '97':
|
||||
@@ -661,8 +656,26 @@ if ($barrack==0){ ?>
|
||||
|
||||
// Checking 2 warrior trained or no
|
||||
$units = $village->unitall;
|
||||
$unarray=array("",U1,U11,U21);
|
||||
$unarray2=array("","u1", "u11","u21");
|
||||
$unarray = array(
|
||||
"",
|
||||
U1,
|
||||
U11,
|
||||
U21,
|
||||
U51,
|
||||
U61,
|
||||
U71,
|
||||
U81
|
||||
);
|
||||
$unarray2 = array(
|
||||
"",
|
||||
"u1",
|
||||
"u11",
|
||||
"u21",
|
||||
"u51",
|
||||
"u61",
|
||||
"u71",
|
||||
"u81"
|
||||
);
|
||||
if ($units[$unarray2[$session->userinfo['tribe']]]<2){ ?>
|
||||
{"markup":"\n\t\t<div id=\"qstd\"><h1> <img class=\"point\" src=\"img\/x.gif\" alt=\"\" title=\"\"\/> <?php echo Q20; ?><\/h1><br \/><i>”<?php echo Q20_DESC; ?> <?php echo $unarray[$session->userinfo['tribe']];?>.”<\/i><br \/><br \/><div class=\"rew\"><p class=\"ta_aw\"><?php echo Q20_ORDER; ?> <?php echo $unarray[$session->userinfo['tribe']];?>.<\/div><br \/><span id=\"qst_accpt\"><\/span><\/div>\n\t\t<div id=\"qstbg\" class=\"units\"><\/div>\n\t\t","number":"-20","reward":false,"qgsrc":"q_l<?php echo $session->userinfo['tribe'];?>","msrc":"<?php echo $messagelol; ?>","altstep":99}
|
||||
<?php $_SESSION['qstnew']='0'; }else{ $_SESSION['qstnew']='1'; ?>
|
||||
@@ -779,7 +792,6 @@ if ($palace >= 10) {
|
||||
} elseif ($commandCenter >= 10) {
|
||||
$text = COMMANDCENTER;
|
||||
}
|
||||
|
||||
if ($residence < 10 && $palace < 10 && $commandCenter < 10) {
|
||||
?>
|
||||
{"markup":"\n\t\t<div id=\"qstd\"><h1> <img class=\"point\" src=\"img\/x.gif\" alt=\"\" title=\"\"\/> <?php echo Q33; ?><\/h1><br \/><i>”<?php echo Q33_DESC; ?>”<\/i><br \/><br \/><div class=\"rew\"><p class=\"ta_aw\"><?php echo Q33_ORDER; ?><\/div><br \/><span id=\"qst_accpt\"><\/span><\/div>\n\t\t<div id=\"qstbg\" class=\"neighbour\"><\/div>\n\t\t","number":"-33","reward":false,"qgsrc":"q_l<?php echo $session->userinfo['tribe'];?>","msrc":"<?php echo $messagelol; ?>","altstep":99}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
<?php
|
||||
if (!class_exists('QuestConfig')) { $__qcf = dirname(__DIR__, 2) . '/GameEngine/QuestConfig.php'; if (is_file($__qcf)) include_once($__qcf); }
|
||||
|
||||
#################################################################################
|
||||
## -= YOU MAY NOT REMOVE OR CHANGE THIS NOTICE =- ##
|
||||
@@ -81,21 +82,18 @@ if (isset($qact)){
|
||||
case '3':
|
||||
$database->updateUserField($_SESSION['username'],'quest','3',0);
|
||||
$_SESSION['qst']= 3;
|
||||
QuestConfig::grantReward($database,$session,3);
|
||||
//Give Reward
|
||||
if(!$session->plus){
|
||||
mysqli_query($database->dblink,"UPDATE ".TB_PREFIX."users set plus = ('".mktime(date("H"),date("i"), date("s"),date("m") , date("d"), date("Y"))."')+86400 where `username`='".$user_sanitized."'") or die(mysqli_error($database->dblink));
|
||||
} else {
|
||||
$plus=$database->getUserField($_SESSION['username'],'plus','username');
|
||||
$plus+=86400;
|
||||
$database->updateUserField($_SESSION['username'],'plus',$plus,0);
|
||||
}
|
||||
break;
|
||||
|
||||
case '4':
|
||||
$database->updateUserField($_SESSION['username'],'quest','4',0);
|
||||
$_SESSION['qst']= 4;
|
||||
QuestConfig::grantReward($database,$session,4);
|
||||
//Give Reward
|
||||
$database->modifyResource($session->villages[0],30,60,30,20,1);
|
||||
break;
|
||||
|
||||
case 'rank':
|
||||
@@ -105,28 +103,26 @@ if (isset($qact)){
|
||||
case '5':
|
||||
$database->updateUserField($_SESSION['username'],'quest','5',0);
|
||||
$_SESSION['qst']= 5;
|
||||
QuestConfig::grantReward($database,$session,5);
|
||||
//Give Reward
|
||||
$database->modifyResource($session->villages[0],40,30,20,30,1);
|
||||
break;
|
||||
|
||||
case '6':
|
||||
$database->updateUserField($_SESSION['username'],'quest','6',0);
|
||||
$_SESSION['qst']= 6;
|
||||
QuestConfig::grantReward($database,$session,6);
|
||||
$Subject=Q6_SUBJECT;
|
||||
$Message=Q6_MESSAGE;
|
||||
$database->sendMessage($session->userinfo['id'],4,$Subject,$Message,0,0,0,0,0);
|
||||
$RB=true;
|
||||
//Give Reward
|
||||
$database->modifyResource($session->villages[0],50,60,30,30,1);
|
||||
break;
|
||||
|
||||
case '7':
|
||||
$database->updateUserField($_SESSION['username'],'quest','7',0);
|
||||
$_SESSION['qst']= 7;
|
||||
QuestConfig::grantReward($database,$session,7);
|
||||
//Give Reward
|
||||
$gold=$database->getUserField($_SESSION['username'],'gold','username');
|
||||
$gold+=20;
|
||||
$database->updateUserField($_SESSION['username'],'gold',$gold,0);
|
||||
break;
|
||||
|
||||
case 'coor':
|
||||
@@ -137,8 +133,8 @@ if (isset($qact)){
|
||||
case '8':
|
||||
$database->updateUserField($_SESSION['username'],'quest','8',0);
|
||||
$_SESSION['qst']= 8;
|
||||
QuestConfig::grantReward($database,$session,8);
|
||||
//Give Reward
|
||||
$database->modifyResource($session->villages[0],60,30,40,90,1);
|
||||
break;
|
||||
|
||||
case '9':
|
||||
@@ -159,56 +155,53 @@ if (isset($qact)){
|
||||
case '10':
|
||||
$database->updateUserField($_SESSION['username'],'quest','10',0);
|
||||
$_SESSION['qst']= 10;
|
||||
QuestConfig::grantReward($database,$session,10);
|
||||
//Give Reward
|
||||
$database->modifyResource($session->villages[0],100,80,40,40,1);
|
||||
break;
|
||||
|
||||
case '11':
|
||||
$database->updateUserField($_SESSION['username'],'quest','11',0);
|
||||
$_SESSION['qst']= 11;
|
||||
QuestConfig::grantReward($database,$session,11);
|
||||
//Give Reward
|
||||
if(!$session->plus){
|
||||
mysqli_query($database->dblink,"UPDATE ".TB_PREFIX."users set plus = ('".mktime(date("H"),date("i"), date("s"),date("m") , date("d"), date("Y"))."')+172800 where `username`='".$user_sanitized."'") or die(mysqli_error($database->dblink));
|
||||
} else {
|
||||
$plus=$database->getUserField($_SESSION['username'],'plus','username');
|
||||
$plus+=172800;
|
||||
$database->updateUserField($_SESSION['username'],'plus',$plus,0);
|
||||
}
|
||||
break;
|
||||
|
||||
case '12':
|
||||
$database->updateUserField($_SESSION['username'],'quest','12',0);
|
||||
$_SESSION['qst']= 12;
|
||||
QuestConfig::grantReward($database,$session,12);
|
||||
//Give Reward
|
||||
$database->modifyResource($session->villages[0],75,140,40,40,1);
|
||||
break;
|
||||
|
||||
case '13':
|
||||
$database->updateUserField($_SESSION['username'],'quest','13',0);
|
||||
$_SESSION['qst']= 13;
|
||||
QuestConfig::grantReward($database,$session,13);
|
||||
//Give Reward
|
||||
$database->modifyResource($session->villages[0],75,80,30,50,1);
|
||||
break;
|
||||
|
||||
case '14':
|
||||
$database->updateUserField($_SESSION['username'],'quest','14',0);
|
||||
$_SESSION['qst']= 14;
|
||||
QuestConfig::grantReward($database,$session,14);
|
||||
//Give Reward
|
||||
$database->modifyResource($session->villages[0],120,200,140,100,1);
|
||||
break;
|
||||
|
||||
case '15':
|
||||
$database->updateUserField($_SESSION['username'],'quest','15',0);
|
||||
$_SESSION['qst']= 15;
|
||||
QuestConfig::grantReward($database,$session,15);
|
||||
//Give Reward
|
||||
$database->modifyResource($session->villages[0],150,180,30,130,1);
|
||||
break;
|
||||
|
||||
case '16':
|
||||
$database->updateUserField($_SESSION['username'],'quest','16',0);
|
||||
$_SESSION['qst']= 16;
|
||||
QuestConfig::grantReward($database,$session,16);
|
||||
//Give Reward
|
||||
$database->modifyResource($session->villages[0],60,50,40,30,1);
|
||||
break;
|
||||
|
||||
case 'lumber':
|
||||
@@ -218,64 +211,65 @@ if (isset($qact)){
|
||||
case '17':
|
||||
$database->updateUserField($_SESSION['username'],'quest','17',0);
|
||||
$_SESSION['qst']= 17;
|
||||
QuestConfig::grantReward($database,$session,17);
|
||||
//Give Reward
|
||||
$database->modifyResource($session->villages[0],50,30,60,20,1);
|
||||
break;
|
||||
|
||||
case '18':
|
||||
$database->updateUserField($_SESSION['username'],'quest','18',0);
|
||||
$_SESSION['qst']= 18;
|
||||
QuestConfig::grantReward($database,$session,18);
|
||||
//Give Reward
|
||||
$database->modifyResource($session->villages[0],75,75,40,40,1);
|
||||
break;
|
||||
|
||||
case '19':
|
||||
$database->updateUserField($_SESSION['username'],'quest','19',0);
|
||||
$_SESSION['qst']= 19;
|
||||
QuestConfig::grantReward($database,$session,19);
|
||||
//Give Reward
|
||||
$database->modifyResource($session->villages[0],100,90,100,60,1);
|
||||
break;
|
||||
|
||||
case '20':
|
||||
$database->updateUserField($_SESSION['username'],'quest','20',0);
|
||||
$_SESSION['qst']= 20;
|
||||
QuestConfig::grantReward($database,$session,20);
|
||||
break;
|
||||
|
||||
case '21':
|
||||
$_SESSION['dough']= true;
|
||||
$database->updateUserField($_SESSION['username'],'quest','21',0);
|
||||
$_SESSION['qst']= 21;
|
||||
QuestConfig::grantReward($database,$session,21);
|
||||
//Give Reward granary
|
||||
$database->modifyResource($session->villages[0],80,90,60,40,1);
|
||||
break;
|
||||
|
||||
case '22':
|
||||
$database->updateUserField($_SESSION['username'],'quest','22',0);
|
||||
$_SESSION['qst']= 22;
|
||||
QuestConfig::grantReward($database,$session,22);
|
||||
//Give Reward warehouse
|
||||
$database->modifyResource($session->villages[0],70,120,90,50,1);
|
||||
break;
|
||||
|
||||
case '23':
|
||||
$database->updateUserField($_SESSION['username'],'quest','23',0);
|
||||
$_SESSION['qst']= 23;
|
||||
QuestConfig::grantReward($database,$session,23);
|
||||
//Give Reward
|
||||
//$database->modifyResource($session->villages[0],80,90,60,40,1);
|
||||
break;
|
||||
|
||||
case '24':
|
||||
$database->updateUserField($_SESSION['username'],'quest','24',0);
|
||||
$_SESSION['qst']= 24;
|
||||
QuestConfig::grantReward($database,$session,24);
|
||||
//Give Reward rally point
|
||||
$database->modifyResource($session->villages[0],80,90,60,40,1);
|
||||
break;
|
||||
|
||||
case '25':
|
||||
//$dataarray[3] = 1;
|
||||
$database->updateUserField($_SESSION['username'],'quest','25',0);
|
||||
$_SESSION['qst']= 25;
|
||||
QuestConfig::grantReward($database,$session,25);
|
||||
//Give Reward barrack
|
||||
$database->modifyResource($session->villages[0],70,100,90,100,1);
|
||||
break;
|
||||
|
||||
case '26':
|
||||
@@ -295,10 +289,8 @@ if (isset($qact)){
|
||||
//$dataarray[5] = 1;
|
||||
$database->updateUserField($_SESSION['username'],'quest','27',0);
|
||||
$_SESSION['qst']= 27;
|
||||
QuestConfig::grantReward($database,$session,27);
|
||||
//Give Reward
|
||||
$gold=$database->getUserField($_SESSION['username'],'gold',1);
|
||||
$gold+=15;
|
||||
$database->updateUserField($_SESSION['username'],'gold',$gold,0);
|
||||
break;
|
||||
|
||||
case 'gold':
|
||||
@@ -309,24 +301,24 @@ if (isset($qact)){
|
||||
//$dataarray[6] = 1;
|
||||
$database->updateUserField($_SESSION['username'],'quest','28',0);
|
||||
$_SESSION['qst']= 28;
|
||||
QuestConfig::grantReward($database,$session,28);
|
||||
//Give Reward
|
||||
$database->modifyResource($session->villages[0],80,70,60,40,1);
|
||||
break;
|
||||
|
||||
case '29':
|
||||
//$dataarray[7] = 1;
|
||||
$database->updateUserField($_SESSION['username'],'quest','29',0);
|
||||
$_SESSION['qst']= 29;
|
||||
QuestConfig::grantReward($database,$session,29);
|
||||
//Give Reward
|
||||
$database->modifyResource($session->villages[0],100,60,90,40,1);
|
||||
break;
|
||||
|
||||
case '30':
|
||||
//$dataarray[8] = 1;
|
||||
$database->updateUserField($_SESSION['username'],'quest','30',0);
|
||||
$_SESSION['qst']= 30;
|
||||
QuestConfig::grantReward($database,$session,30);
|
||||
//Give Reward
|
||||
$database->modifyResource($session->villages[0],100,140,90,50,1);
|
||||
break;
|
||||
|
||||
case '91':
|
||||
@@ -348,45 +340,45 @@ if (isset($qact)){
|
||||
$database->updateUserField($_SESSION['username'],'quest','92',0);
|
||||
$database->updateUserField($_SESSION['username'],'quest_time',''.(time()+$skipp_time).'',0);
|
||||
$_SESSION['qst']= 92;
|
||||
QuestConfig::grantReward($database,$session,92);
|
||||
$_SESSION['qst_time'] = time()+$skipp_time;
|
||||
//Give Reward
|
||||
$database->modifyResource($session->villages[0],217,247,177,207,1);
|
||||
break;
|
||||
|
||||
case '93':
|
||||
$database->updateUserField($_SESSION['username'],'quest','93',0);
|
||||
$database->updateUserField($_SESSION['username'],'quest_time',''.(time()+$skipp_time).'',0);
|
||||
$_SESSION['qst']= 93;
|
||||
QuestConfig::grantReward($database,$session,93);
|
||||
$_SESSION['qst_time'] = time()+$skipp_time;
|
||||
//Give Reward
|
||||
$database->modifyResource($session->villages[0],217,247,177,207,1);
|
||||
break;
|
||||
|
||||
case '94':
|
||||
$database->updateUserField($_SESSION['username'],'quest','94',0);
|
||||
$database->updateUserField($_SESSION['username'],'quest_time',''.(time()+$skipp_time).'',0);
|
||||
$_SESSION['qst']= 94;
|
||||
QuestConfig::grantReward($database,$session,94);
|
||||
$_SESSION['qst_time'] = time()+$skipp_time;
|
||||
//Give Reward
|
||||
$database->modifyResource($session->villages[0],217,247,177,207,1);
|
||||
break;
|
||||
|
||||
case '95':
|
||||
$database->updateUserField($_SESSION['username'],'quest','95',0);
|
||||
$database->updateUserField($_SESSION['username'],'quest_time',''.(time()+$skipp_time).'',0);
|
||||
$_SESSION['qst']= 95;
|
||||
QuestConfig::grantReward($database,$session,95);
|
||||
$_SESSION['qst_time'] = time()+$skipp_time;
|
||||
//Give Reward
|
||||
$database->modifyResource($session->villages[0],217,247,177,207,1);
|
||||
break;
|
||||
|
||||
case '96':
|
||||
$database->updateUserField($_SESSION['username'],'quest','96',0);
|
||||
$database->updateUserField($_SESSION['username'],'quest_time',''.(time()+$skipp_time).'',0);
|
||||
$_SESSION['qst']= 96;
|
||||
QuestConfig::grantReward($database,$session,96);
|
||||
$_SESSION['qst_time'] = time()+$skipp_time;
|
||||
//Give Reward
|
||||
$database->modifyResource($session->villages[0],217,247,177,207,1);
|
||||
break;
|
||||
|
||||
case '97':
|
||||
|
||||
@@ -162,6 +162,31 @@ function formatRemainingTime($endTimestamp, $nowTimestamp) {
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<?php
|
||||
// Gold shop: promo-code redemption box (sits between Plus function and Gold Club).
|
||||
if (class_exists('GoldShop')):
|
||||
$__promoMsg = isset($promoMsg) ? $promoMsg : '';
|
||||
$__promoOk = isset($promoOk) ? $promoOk : false;
|
||||
$__action = htmlspecialchars($_SERVER['REQUEST_URI'] ?? 'plus.php?id=1', ENT_QUOTES, 'UTF-8');
|
||||
?>
|
||||
<table class="plusFunctions" cellpadding="1" cellspacing="1">
|
||||
<thead><tr><th colspan="5">Redeem a gold code</th></tr></thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td style="padding:10px 14px;">
|
||||
<?php if ($__promoMsg !== ''): ?>
|
||||
<div style="margin-bottom:8px;font-weight:bold;color:<?php echo $__promoOk ? '#2e7d32' : '#b3261e'; ?>;"><?php echo htmlspecialchars($__promoMsg, ENT_QUOTES, 'UTF-8'); ?></div>
|
||||
<?php endif; ?>
|
||||
<form method="post" action="<?php echo $__action; ?>" style="display:flex;gap:8px;align-items:center;max-width:460px;">
|
||||
<input type="text" name="redeem_code" maxlength="64" placeholder="Enter code" style="flex:1;padding:6px 8px;border:1px solid #b89968;border-radius:4px;text-transform:uppercase;" required>
|
||||
<input type="submit" value="Redeem" style="padding:6px 18px;background:#8a6d3b;color:#fff;border:0;border-radius:4px;cursor:pointer;font-weight:bold;">
|
||||
</form>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<?php endif; ?>
|
||||
|
||||
<table class="plusFunctions" cellpadding="1" cellspacing="1">
|
||||
<thead><tr><th colspan="5"><?php echo TZ_TRAVIAN_GOLD_CLUB; ?></th></tr>
|
||||
<tr><td></td><td><?php echo DESCRIPTION; ?></td><td><?php echo DURATION; ?></td><td><?php echo GOLD; ?></td><td><?php echo ACTION; ?></td></tr></thead>
|
||||
|
||||
@@ -5,16 +5,19 @@ $start_timer = $generator->pageLoadTimeStart();
|
||||
#################################################################################
|
||||
## -= YOU MAY NOT REMOVE OR CHANGE THIS NOTICE =- ##
|
||||
## --------------------------------------------------------------------------- ##
|
||||
## Project: TravianZ ##
|
||||
## Version: 18.05.2026 ##
|
||||
## Filename: a2b2.php ##
|
||||
## Developed by: Dzoki ##
|
||||
## Refactored by: Shadow ##
|
||||
## License: TravianZ Project ##
|
||||
## Copyright: TravianZ (c) 2010-2026. All rights reserved. ##
|
||||
## URLs: https://travianz.org ##
|
||||
## https://github.com/Shadowss/TravianZ ##
|
||||
## ##
|
||||
## Filename : a2b2.php ##
|
||||
## Type : In Game Account Gold Statement ##
|
||||
## --------------------------------------------------------------------------- ##
|
||||
## Developed by : Shadow ##
|
||||
## --------------------------------------------------------------------------- ##
|
||||
## Contact : cata7007@gmail.com ##
|
||||
## Project : TravianZ ##
|
||||
## URLs: : https://travianz.org ##
|
||||
## GitHub : https://github.com/Shadowss/TravianZ ##
|
||||
## --------------------------------------------------------------------------- ##
|
||||
## License : TravianZ Project ##
|
||||
## Copyright : TravianZ (c) 2010-2026. All rights reserved. ##
|
||||
## --------------------------------------------------------------------------- ##
|
||||
#################################################################################
|
||||
|
||||
use App\Utils\AccessLogger;
|
||||
|
||||
@@ -35,6 +35,18 @@ if(isset($_GET['newdid'])) {
|
||||
}
|
||||
else $building->procBuild($_GET);
|
||||
|
||||
// Gold shop: promo-code redemption (player-side). Best-effort; the engine
|
||||
// self-creates its tables and validates the code (active / expiry / uses /
|
||||
// once-per-player) before granting gold.
|
||||
$promoMsg = '';
|
||||
$promoOk = false;
|
||||
if (isset($_POST['redeem_code']) && class_exists('GoldShop')) {
|
||||
$__uid = isset($session) && isset($session->uid) ? (int)$session->uid : 0;
|
||||
$rr = GoldShop::redeem($__uid, $_POST['redeem_code']);
|
||||
$promoOk = $rr[0];
|
||||
$promoMsg = $rr[1];
|
||||
}
|
||||
|
||||
?>
|
||||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
||||
<html>
|
||||
|
||||
@@ -1183,6 +1183,88 @@ CREATE TABLE IF NOT EXISTS `%PREFIX%push_override` (
|
||||
PRIMARY KEY (`uid`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
|
||||
|
||||
-- --------------------------------------------------------
|
||||
|
||||
--
|
||||
-- Table structure for table `%prefix%reg_block`
|
||||
-- (Registration blocklist: blocked usernames / e-mails / e-mail domains)
|
||||
--
|
||||
|
||||
CREATE TABLE IF NOT EXISTS `%PREFIX%reg_block` (
|
||||
`id` int(11) NOT NULL AUTO_INCREMENT,
|
||||
`type` varchar(16) NOT NULL DEFAULT 'username',
|
||||
`value` varchar(255) NOT NULL DEFAULT '',
|
||||
`note` varchar(255) NOT NULL DEFAULT '',
|
||||
`added_by` int(11) NOT NULL DEFAULT 0,
|
||||
`time` int(11) NOT NULL DEFAULT 0,
|
||||
PRIMARY KEY (`id`),
|
||||
UNIQUE KEY `type_value` (`type`,`value`),
|
||||
KEY `type` (`type`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
|
||||
|
||||
-- --------------------------------------------------------
|
||||
|
||||
--
|
||||
-- Table structure for table `%prefix%gold_promo`
|
||||
-- (Gold shop: redeemable promo / voucher codes)
|
||||
--
|
||||
|
||||
CREATE TABLE IF NOT EXISTS `%PREFIX%gold_promo` (
|
||||
`id` int(11) NOT NULL AUTO_INCREMENT,
|
||||
`code` varchar(64) NOT NULL,
|
||||
`gold` int(11) NOT NULL DEFAULT 0,
|
||||
`max_uses` int(11) NOT NULL DEFAULT 0,
|
||||
`uses` int(11) NOT NULL DEFAULT 0,
|
||||
`per_user` tinyint(1) NOT NULL DEFAULT 1,
|
||||
`expires` int(11) NOT NULL DEFAULT 0,
|
||||
`active` tinyint(1) NOT NULL DEFAULT 1,
|
||||
`note` varchar(255) NOT NULL DEFAULT '',
|
||||
`created_by` int(11) NOT NULL DEFAULT 0,
|
||||
`time` int(11) NOT NULL DEFAULT 0,
|
||||
PRIMARY KEY (`id`),
|
||||
UNIQUE KEY `code` (`code`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
|
||||
|
||||
-- --------------------------------------------------------
|
||||
|
||||
--
|
||||
-- Table structure for table `%prefix%gold_promo_redeem`
|
||||
-- (Gold shop: per-player redemption log)
|
||||
--
|
||||
|
||||
CREATE TABLE IF NOT EXISTS `%PREFIX%gold_promo_redeem` (
|
||||
`id` int(11) NOT NULL AUTO_INCREMENT,
|
||||
`promo_id` int(11) NOT NULL DEFAULT 0,
|
||||
`uid` int(11) NOT NULL DEFAULT 0,
|
||||
`gold` int(11) NOT NULL DEFAULT 0,
|
||||
`time` int(11) NOT NULL DEFAULT 0,
|
||||
PRIMARY KEY (`id`),
|
||||
KEY `promo_uid` (`promo_id`,`uid`),
|
||||
KEY `uid` (`uid`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
|
||||
|
||||
-- --------------------------------------------------------
|
||||
|
||||
--
|
||||
-- Table structure for table `%prefix%quest_config`
|
||||
-- (Quest editor: editable per-variant quest rewards / requirements)
|
||||
--
|
||||
|
||||
CREATE TABLE IF NOT EXISTS `%PREFIX%quest_config` (
|
||||
`variant` varchar(16) NOT NULL DEFAULT 'standard',
|
||||
`quest_id` int(11) NOT NULL,
|
||||
`enabled` tinyint(1) NOT NULL DEFAULT 1,
|
||||
`wood` int(11) NOT NULL DEFAULT 0,
|
||||
`clay` int(11) NOT NULL DEFAULT 0,
|
||||
`iron` int(11) NOT NULL DEFAULT 0,
|
||||
`crop` int(11) NOT NULL DEFAULT 0,
|
||||
`gold` int(11) NOT NULL DEFAULT 0,
|
||||
`plus_days` float NOT NULL DEFAULT 0,
|
||||
`req_level` int(11) NOT NULL DEFAULT 0,
|
||||
`note` varchar(255) NOT NULL DEFAULT '',
|
||||
PRIMARY KEY (`variant`,`quest_id`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
|
||||
|
||||
--
|
||||
-- Dumping data for table `%prefix%login_log`
|
||||
--
|
||||
|
||||
Reference in New Issue
Block a user