104 lines
6.2 KiB
PHP
104 lines
6.2 KiB
PHP
<?php
|
|
declare(strict_types=1);
|
|
|
|
require_once __DIR__ . '/game_bootstrap.php';
|
|
|
|
ensureFpsMatchesTable();
|
|
|
|
$projectName = trim((string)($_SERVER['PROJECT_NAME'] ?? 'Strike Grid Arena'));
|
|
$projectDescription = trim((string)($_SERVER['PROJECT_DESCRIPTION'] ?? 'Browser FPS prototype with multiple guns, moving bots, and score tracking.'));
|
|
$projectImageUrl = $_SERVER['PROJECT_IMAGE_URL'] ?? '';
|
|
|
|
$matchId = filter_input(INPUT_GET, 'id', FILTER_VALIDATE_INT, ['options' => ['min_range' => 1]]);
|
|
$match = $matchId ? fetchMatchById((int)$matchId) : null;
|
|
$pageTitle = $match ? sprintf('Match #%d • %s', (int)$match['id'], $projectName) : 'Match not found';
|
|
?>
|
|
<!doctype html>
|
|
<html lang="en">
|
|
<head>
|
|
<meta charset="utf-8">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
<title><?= htmlspecialchars($pageTitle) ?></title>
|
|
<meta name="description" content="<?= htmlspecialchars($projectDescription) ?>">
|
|
<?php if ($projectDescription): ?>
|
|
<meta property="og:description" content="<?= htmlspecialchars($projectDescription) ?>">
|
|
<meta property="twitter:description" content="<?= htmlspecialchars($projectDescription) ?>">
|
|
<?php endif; ?>
|
|
<?php if ($projectImageUrl): ?>
|
|
<meta property="og:image" content="<?= htmlspecialchars($projectImageUrl) ?>">
|
|
<meta property="twitter:image" content="<?= htmlspecialchars($projectImageUrl) ?>">
|
|
<?php endif; ?>
|
|
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css" rel="stylesheet">
|
|
<link rel="stylesheet" href="/assets/css/custom.css?v=<?= urlencode((string)@filemtime(__DIR__ . '/assets/css/custom.css')) ?>">
|
|
</head>
|
|
<body class="app-shell" data-bs-theme="dark">
|
|
<nav class="navbar navbar-expand-lg border-bottom border-secondary-subtle bg-body-tertiary bg-opacity-75 sticky-top">
|
|
<div class="container py-2">
|
|
<a class="navbar-brand fw-semibold text-uppercase small-brand" href="/">Strike Grid Arena</a>
|
|
<a class="btn btn-outline-light btn-sm" href="/">Back to arena</a>
|
|
</div>
|
|
</nav>
|
|
<main class="container py-5">
|
|
<?php if ($match): ?>
|
|
<section class="surface-panel p-4 p-lg-5 mb-4">
|
|
<div class="d-flex flex-column flex-lg-row justify-content-between gap-3 align-items-lg-center mb-4">
|
|
<div>
|
|
<p class="eyebrow mb-2">Match detail</p>
|
|
<h1 class="h2 mb-2">#<?= (int)$match['id'] ?> — <?= htmlspecialchars($match['player_name']) ?></h1>
|
|
<p class="text-secondary mb-0">Recorded on <?= htmlspecialchars(date('M j, Y • H:i', strtotime((string)$match['created_at']))) ?> UTC</p>
|
|
</div>
|
|
<div class="text-lg-end">
|
|
<span class="score-pill d-inline-flex mb-2"><?= htmlspecialchars(strtoupper((string)$match['outcome'])) ?></span>
|
|
<div class="display-6 fw-semibold mb-0"><?= number_format((int)$match['score']) ?></div>
|
|
<small class="text-secondary">score</small>
|
|
</div>
|
|
</div>
|
|
<div class="row g-3 stats-grid">
|
|
<div class="col-6 col-md-3"><div class="metric-card"><span>Kills</span><strong><?= (int)$match['kills'] ?></strong></div></div>
|
|
<div class="col-6 col-md-3"><div class="metric-card"><span>Accuracy</span><strong><?= htmlspecialchars(number_format((float)$match['accuracy'], 1)) ?>%</strong></div></div>
|
|
<div class="col-6 col-md-3"><div class="metric-card"><span>Duration</span><strong><?= (int)$match['duration_seconds'] ?>s</strong></div></div>
|
|
<div class="col-6 col-md-3"><div class="metric-card"><span>Damage taken</span><strong><?= (int)$match['damage_taken'] ?></strong></div></div>
|
|
</div>
|
|
</section>
|
|
|
|
<section class="row g-4">
|
|
<div class="col-lg-7">
|
|
<div class="surface-panel p-4 h-100">
|
|
<h2 class="h5 mb-3">Combat report</h2>
|
|
<div class="table-responsive">
|
|
<table class="table table-dark table-borderless align-middle mb-0">
|
|
<tbody>
|
|
<tr><th scope="row" class="text-secondary fw-medium">Operator</th><td><?= htmlspecialchars($match['player_name']) ?></td></tr>
|
|
<tr><th scope="row" class="text-secondary fw-medium">Weapon</th><td><?= htmlspecialchars($match['weapon_name']) ?> <span class="text-secondary">(<?= htmlspecialchars($match['weapon_key']) ?>)</span></td></tr>
|
|
<tr><th scope="row" class="text-secondary fw-medium">Shots fired</th><td><?= (int)$match['shots_fired'] ?></td></tr>
|
|
<tr><th scope="row" class="text-secondary fw-medium">Shots landed</th><td><?= (int)$match['shots_hit'] ?></td></tr>
|
|
<tr><th scope="row" class="text-secondary fw-medium">Accuracy</th><td><?= htmlspecialchars(number_format((float)$match['accuracy'], 2)) ?>%</td></tr>
|
|
<tr><th scope="row" class="text-secondary fw-medium">Outcome</th><td><?= htmlspecialchars(ucfirst((string)$match['outcome'])) ?></td></tr>
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="col-lg-5">
|
|
<div class="surface-panel p-4 h-100">
|
|
<h2 class="h5 mb-3">What to try next</h2>
|
|
<ul class="list-unstyled compact-list mb-0">
|
|
<li>Run another round with a different weapon profile.</li>
|
|
<li>Compare accuracy between shotgun, SMG, and marksman loadouts.</li>
|
|
<li>Ask for the next iteration: maps, cover objects, bot teams, or better hit effects.</li>
|
|
</ul>
|
|
</div>
|
|
</div>
|
|
</section>
|
|
<?php else: ?>
|
|
<section class="surface-panel p-5 text-center">
|
|
<p class="eyebrow mb-2">Match detail</p>
|
|
<h1 class="h3 mb-3">No match found</h1>
|
|
<p class="text-secondary mb-4">This score card does not exist yet, or the id is invalid.</p>
|
|
<a class="btn btn-light" href="/">Return to the arena</a>
|
|
</section>
|
|
<?php endif; ?>
|
|
</main>
|
|
</body>
|
|
</html>
|