Bebsjdb / index.html
GidiHenzTech's picture
Create index.html
5aedecf verified
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>WARZONE X – Vivian Harris</title>
<style>
@import url('https://fonts.googleapis.com/css2?family=Oswald:wght@400;700&family=Rajdhani:wght@400;600;700&family=Share+Tech+Mono&display=swap');
:root {
--red: #e8001d;
--gold: #f0a500;
--dark: #0a0a0a;
--panel: #0d1117;
--border: #1e2a38;
--text: #c9d1d9;
--glow: rgba(232,0,29,0.4);
--blue: #1e90ff;
}
* { margin:0; padding:0; box-sizing:border-box; }
body {
background: var(--dark);
font-family: 'Rajdhani', sans-serif;
color: var(--text);
overflow: hidden;
height: 100vh;
width: 100vw;
}
/* ═══════════════ SCREENS ═══════════════ */
.screen { display:none; width:100%; height:100vh; position:absolute; top:0; left:0; }
.screen.active { display:flex; }
/* ═══════════════ MAIN MENU ═══════════════ */
#main-menu {
background: linear-gradient(135deg, #0a0a0a 0%, #0d1117 50%, #111827 100%);
flex-direction: row;
align-items: center;
position: relative;
overflow: hidden;
}
#main-menu::before {
content:'';
position:absolute; inset:0;
background:
radial-gradient(ellipse 60% 80% at 30% 50%, rgba(232,0,29,0.08) 0%, transparent 70%),
radial-gradient(ellipse 40% 60% at 80% 30%, rgba(240,165,0,0.05) 0%, transparent 70%);
pointer-events:none;
}
.scanlines {
position:absolute; inset:0; pointer-events:none; z-index:1;
background: repeating-linear-gradient(0deg, transparent, transparent 2px, rgba(0,0,0,0.15) 2px, rgba(0,0,0,0.15) 4px);
}
.menu-left {
flex:1; display:flex; flex-direction:column;
align-items:center; justify-content:center;
padding:40px; z-index:2;
}
.game-title {
font-family:'Oswald',sans-serif;
font-size:72px; font-weight:700;
letter-spacing:8px;
color:#fff;
text-shadow: 0 0 30px var(--red), 0 0 60px rgba(232,0,29,0.3);
line-height:1;
text-align:center;
}
.game-subtitle {
font-size:14px; letter-spacing:6px; color:var(--gold);
margin-top:8px; text-align:center;
font-family:'Share Tech Mono', monospace;
}
.divider {
width:200px; height:2px;
background: linear-gradient(90deg, transparent, var(--red), transparent);
margin:30px auto;
}
.menu-buttons { display:flex; flex-direction:column; gap:14px; width:280px; }
.menu-btn {
background: linear-gradient(135deg, rgba(14,21,32,0.9), rgba(10,10,10,0.95));
border: 1px solid var(--border);
border-left: 3px solid var(--red);
color: #fff;
padding: 16px 24px;
font-family:'Oswald',sans-serif;
font-size:18px;
letter-spacing:3px;
cursor:pointer;
transition: all 0.2s;
text-align:left;
clip-path: polygon(0 0, calc(100% - 12px) 0, 100% 12px, 100% 100%, 0 100%);
position:relative;
overflow:hidden;
}
.menu-btn::after {
content:'';
position:absolute; left:-100%; top:0; width:100%; height:100%;
background: linear-gradient(90deg, transparent, rgba(232,0,29,0.15), transparent);
transition: left 0.4s;
}
.menu-btn:hover { border-left-color:var(--gold); transform:translateX(4px); box-shadow:0 0 20px rgba(232,0,29,0.2); }
.menu-btn:hover::after { left:100%; }
.menu-btn .btn-icon { margin-right:12px; color:var(--red); }
/* ═══════════════ CHARACTER CARD ═══════════════ */
.menu-right {
width:380px; display:flex; flex-direction:column;
align-items:center; justify-content:center;
padding:40px; z-index:2; border-left:1px solid var(--border);
background: rgba(255,255,255,0.02);
}
.char-card {
background: linear-gradient(160deg, #0d1117, #111827);
border:1px solid var(--border);
border-top:2px solid var(--red);
padding:24px; width:100%;
clip-path: polygon(0 0, calc(100% - 20px) 0, 100% 20px, 100% 100%, 20px 100%, 0 calc(100% - 20px));
position:relative;
}
.char-card::before {
content:'OPERATOR';
position:absolute; top:10px; right:28px;
font-family:'Share Tech Mono',monospace;
font-size:10px; color:var(--red); letter-spacing:3px;
}
.char-avatar {
width:160px; height:160px; margin:0 auto 16px;
position:relative;
}
/* SVG Character Vivian Harris */
.char-avatar svg { width:100%; height:100%; }
.char-name {
font-family:'Oswald',sans-serif;
font-size:24px; font-weight:700;
color:#fff; text-align:center;
letter-spacing:3px;
}
.char-rank {
font-family:'Share Tech Mono',monospace;
font-size:11px; color:var(--gold);
text-align:center; letter-spacing:4px; margin-top:4px;
}
.char-stats {
display:grid; grid-template-columns:1fr 1fr;
gap:8px; margin-top:16px;
}
.stat-item { background:rgba(255,255,255,0.03); padding:8px 10px; border:1px solid rgba(255,255,255,0.06); }
.stat-label { font-size:10px; color:#666; letter-spacing:2px; }
.stat-val { font-family:'Share Tech Mono',monospace; font-size:16px; color:var(--gold); }
/* ═══════════════ MODE SELECT ═══════════════ */
#mode-select {
background: linear-gradient(135deg, #0a0c10, #0d1117);
flex-direction:column; align-items:center; justify-content:center;
gap:40px;
}
.mode-title {
font-family:'Oswald',sans-serif;
font-size:14px; letter-spacing:6px; color:var(--red);
}
.mode-cards { display:flex; gap:30px; }
.mode-card {
width:280px; background: linear-gradient(160deg, #0d1117, #0a0c10);
border:1px solid var(--border); cursor:pointer;
transition: all 0.3s; position:relative; overflow:hidden;
clip-path: polygon(0 0, calc(100% - 24px) 0, 100% 24px, 100% 100%, 24px 100%, 0 calc(100% - 24px));
}
.mode-card:hover { border-color:var(--red); transform:translateY(-6px); box-shadow:0 20px 40px rgba(232,0,29,0.2); }
.mode-card-img {
height:160px; display:flex; align-items:center; justify-content:center;
font-size:80px; background:rgba(0,0,0,0.3); position:relative; overflow:hidden;
}
.mode-card-img::after {
content:''; position:absolute; inset:0;
background:linear-gradient(180deg, transparent 50%, #0d1117 100%);
}
.mode-card-body { padding:20px; }
.mode-card-name { font-family:'Oswald',sans-serif; font-size:22px; letter-spacing:3px; color:#fff; }
.mode-card-desc { font-size:13px; color:#666; margin-top:6px; line-height:1.5; }
.mode-badge {
position:absolute; top:12px; right:12px; z-index:1;
background:var(--red); color:#fff;
font-family:'Share Tech Mono',monospace;
font-size:10px; padding:3px 8px; letter-spacing:2px;
}
/* ═══════════════ LOADOUT SCREEN ═══════════════ */
#loadout-screen {
background: linear-gradient(135deg, #080b10, #0d1117);
flex-direction:column; align-items:center;
padding:40px; gap:30px; overflow-y:auto;
}
.screen-header {
display:flex; align-items:center; gap:20px; width:100%; max-width:900px;
}
.back-btn {
background: rgba(255,255,255,0.04); border:1px solid var(--border);
color:var(--text); padding:8px 16px; cursor:pointer;
font-family:'Rajdhani',sans-serif; font-size:14px;
letter-spacing:2px; transition:all 0.2s;
}
.back-btn:hover { background:rgba(232,0,29,0.1); border-color:var(--red); color:var(--red); }
.screen-title { font-family:'Oswald',sans-serif; font-size:32px; letter-spacing:6px; color:#fff; }
.loadout-grid { display:flex; gap:30px; width:100%; max-width:900px; }
.gun-card {
flex:1; background: linear-gradient(160deg, #0d1117, #0a0c10);
border:2px solid var(--border); cursor:pointer; transition:all 0.3s;
clip-path: polygon(0 0, calc(100% - 16px) 0, 100% 16px, 100% 100%, 0 100%);
padding:24px; text-align:center;
}
.gun-card.selected { border-color:var(--red); box-shadow:0 0 30px rgba(232,0,29,0.3); }
.gun-card:hover { border-color:var(--gold); }
.gun-name { font-family:'Oswald',sans-serif; font-size:28px; letter-spacing:4px; color:#fff; }
.gun-type { font-size:12px; color:var(--gold); letter-spacing:3px; margin-bottom:16px; font-family:'Share Tech Mono',monospace; }
.gun-art { font-size:60px; margin:20px 0; }
.gun-stats { text-align:left; }
.gun-stat { display:flex; align-items:center; gap:10px; margin:8px 0; }
.gun-stat-label { font-size:12px; color:#666; width:80px; letter-spacing:1px; }
.gun-stat-bar { flex:1; height:4px; background:rgba(255,255,255,0.1); position:relative; }
.gun-stat-fill { height:100%; background:linear-gradient(90deg, var(--red), var(--gold)); transition:width 0.5s; }
.gun-select-indicator {
margin-top:16px; padding:10px;
background:rgba(232,0,29,0.1); border:1px solid var(--red);
font-family:'Share Tech Mono',monospace; font-size:12px;
color:var(--red); letter-spacing:3px; text-align:center;
display:none;
}
.gun-card.selected .gun-select-indicator { display:block; }
.loadout-confirm {
width:100%; max-width:900px;
}
.confirm-btn {
width:100%; padding:16px;
background:linear-gradient(135deg, var(--red), #a00015);
border:none; color:#fff;
font-family:'Oswald',sans-serif; font-size:20px; letter-spacing:6px;
cursor:pointer; transition:all 0.3s;
clip-path: polygon(0 0, calc(100% - 16px) 0, 100% 16px, 100% 100%, 16px 100%, 0 calc(100% - 16px));
}
.confirm-btn:hover { background:linear-gradient(135deg, #ff0020, var(--red)); box-shadow:0 0 30px var(--glow); }
.confirm-btn:disabled { background:#333; cursor:not-allowed; box-shadow:none; }
/* ═══════════════ BATTLE ROYALE LOBBY ═══════════════ */
#br-lobby {
background: linear-gradient(135deg, #080b10, #0d1117);
flex-direction:column; align-items:center;
padding:40px; gap:24px; overflow-y:auto;
}
.diff-grid { display:flex; gap:16px; }
.diff-btn {
padding:12px 24px; border:1px solid var(--border);
background:rgba(255,255,255,0.03); color:#888;
font-family:'Oswald',sans-serif; font-size:16px; letter-spacing:3px;
cursor:pointer; transition:all 0.2s;
clip-path: polygon(0 0, calc(100% - 10px) 0, 100% 10px, 100% 100%, 0 100%);
}
.diff-btn:hover, .diff-btn.selected { color:#fff; }
.diff-btn[data-diff="noob"].selected { border-color:#4ade80; color:#4ade80; box-shadow:0 0 15px rgba(74,222,128,0.2); }
.diff-btn[data-diff="easy"].selected { border-color:var(--blue); color:var(--blue); box-shadow:0 0 15px rgba(30,144,255,0.2); }
.diff-btn[data-diff="normal"].selected { border-color:var(--gold); color:var(--gold); box-shadow:0 0 15px rgba(240,165,0,0.2); }
.diff-btn[data-diff="hard"].selected { border-color:var(--red); color:var(--red); box-shadow:0 0 15px rgba(232,0,29,0.2); }
.connect-panel {
width:100%; max-width:700px;
background: rgba(255,255,255,0.02); border:1px solid var(--border);
padding:24px;
}
.connect-title { font-family:'Oswald',sans-serif; font-size:18px; letter-spacing:4px; color:var(--gold); margin-bottom:16px; }
.connect-row { display:flex; gap:12px; align-items:center; margin:10px 0; }
.connect-input {
flex:1; background:rgba(0,0,0,0.4); border:1px solid var(--border);
color:#fff; padding:10px 14px;
font-family:'Share Tech Mono',monospace; font-size:14px;
outline:none; transition:border 0.2s;
}
.connect-input:focus { border-color:var(--blue); }
.connect-btn {
padding:10px 20px; background:rgba(30,144,255,0.15);
border:1px solid var(--blue); color:var(--blue);
font-family:'Oswald',sans-serif; font-size:14px; letter-spacing:2px;
cursor:pointer; transition:all 0.2s;
}
.connect-btn:hover { background:rgba(30,144,255,0.3); }
.bt-status {
font-family:'Share Tech Mono',monospace; font-size:12px;
color:#666; margin-top:8px;
padding:8px 12px; background:rgba(0,0,0,0.3); border:1px solid rgba(255,255,255,0.05);
}
.bt-dot { display:inline-block; width:8px; height:8px; border-radius:50%; background:#666; margin-right:8px; }
.bt-dot.connected { background:#4ade80; box-shadow:0 0 8px #4ade80; animation:pulse 1s infinite; }
@keyframes pulse { 0%,100%{opacity:1} 50%{opacity:0.5} }
/* ═══════════════ GAME CANVAS ═══════════════ */
#game-screen {
flex-direction:column; position:relative;
}
#gameCanvas {
position:absolute; top:0; left:0;
width:100%; height:100%;
}
/* HUD */
#hud {
position:absolute; inset:0; pointer-events:none; z-index:10;
}
.hud-corner {
position:absolute; padding:16px 20px;
background:rgba(0,0,0,0.6); backdrop-filter:blur(4px);
}
#hud-tl { top:0; left:0; border-right:1px solid rgba(255,255,255,0.06); border-bottom:1px solid rgba(255,255,255,0.06); }
#hud-tr { top:0; right:0; border-left:1px solid rgba(255,255,255,0.06); border-bottom:1px solid rgba(255,255,255,0.06); text-align:right; }
#hud-bl { bottom:0; left:0; border-right:1px solid rgba(255,255,255,0.06); border-top:1px solid rgba(255,255,255,0.06); }
.hud-label { font-size:10px; color:#666; letter-spacing:3px; font-family:'Share Tech Mono',monospace; }
.hud-val { font-family:'Oswald',sans-serif; font-size:26px; color:#fff; line-height:1; }
.hud-val.danger { color:var(--red); animation:blink 0.5s infinite; }
@keyframes blink { 0%,100%{opacity:1} 50%{opacity:0.5} }
.health-bar-wrap { margin-top:6px; width:140px; height:6px; background:rgba(255,255,255,0.1); }
.health-bar { height:100%; background:linear-gradient(90deg,#4ade80,var(--gold)); transition:width 0.3s; }
.crosshair {
position:absolute; top:50%; left:50%;
transform:translate(-50%,-50%);
pointer-events:none;
}
.crosshair svg { opacity:0.85; }
#kill-feed {
position:absolute; top:16px; left:50%; transform:translateX(-50%);
display:flex; flex-direction:column; gap:4px; align-items:center;
pointer-events:none;
}
.kill-msg {
background:rgba(0,0,0,0.7); border-left:3px solid var(--red);
padding:4px 12px; font-family:'Share Tech Mono',monospace;
font-size:12px; color:#fff; animation:killSlide 3s forwards;
white-space:nowrap;
}
@keyframes killSlide { 0%{opacity:0;transform:translateY(-10px)} 10%{opacity:1;transform:translateY(0)} 80%{opacity:1} 100%{opacity:0} }
#zone-indicator {
position:absolute; top:80px; right:20px; pointer-events:none;
background:rgba(0,0,0,0.7); border:1px solid var(--red);
padding:8px 14px;
}
.zone-label { font-size:10px; color:var(--red); letter-spacing:3px; font-family:'Share Tech Mono',monospace; }
.zone-timer { font-family:'Oswald',sans-serif; font-size:22px; color:#fff; }
#minimap-wrap {
position:absolute; bottom:20px; right:20px;
width:160px; height:160px;
border:1px solid rgba(255,255,255,0.1);
background:rgba(0,0,0,0.5); overflow:hidden;
}
#minimap { width:100%; height:100%; }
.ammo-display {
font-family:'Oswald',sans-serif; font-size:28px; color:#fff;
}
.ammo-reserve { font-size:14px; color:#666; font-family:'Share Tech Mono',monospace; }
.gun-name-hud { font-family:'Share Tech Mono',monospace; font-size:11px; color:var(--gold); letter-spacing:3px; }
#alive-count { position:absolute; top:60px; right:20px; display:flex; align-items:center; gap:8px; }
.alive-icon { font-size:16px; }
.alive-num { font-family:'Oswald',sans-serif; font-size:22px; color:#fff; }
.alive-label { font-size:10px; color:#666; letter-spacing:2px; font-family:'Share Tech Mono',monospace; }
/* ═══════════════ GAME OVER ═══════════════ */
#game-over {
background:rgba(0,0,0,0.92);
flex-direction:column; align-items:center; justify-content:center;
gap:20px; z-index:100;
}
.go-title {
font-family:'Oswald',sans-serif; font-size:80px;
letter-spacing:12px; line-height:1;
}
.go-title.win { color:var(--gold); text-shadow:0 0 40px rgba(240,165,0,0.5); }
.go-title.loss { color:var(--red); text-shadow:0 0 40px var(--glow); }
.go-stats { display:flex; gap:40px; margin:20px 0; }
.go-stat { text-align:center; }
.go-stat-num { font-family:'Oswald',sans-serif; font-size:48px; color:#fff; }
.go-stat-label { font-size:12px; color:#666; letter-spacing:3px; font-family:'Share Tech Mono',monospace; }
/* ═══════════════ SHOOTING FLASH ═══════════════ */
#muzzle-flash { position:absolute; top:50%; left:50%; transform:translate(-50%,-50%); pointer-events:none; z-index:20; display:none; }
/* ═══════════════ DAMAGE INDICATOR ═══════════════ */
#damage-vignette { position:absolute; inset:0; pointer-events:none; z-index:9; transition:opacity 0.3s; opacity:0;
background:radial-gradient(ellipse at center, transparent 40%, rgba(232,0,29,0.6) 100%); }
/* scroll fix */
::-webkit-scrollbar { width:4px; }
::-webkit-scrollbar-track { background:#0a0a0a; }
::-webkit-scrollbar-thumb { background:var(--red); }
</style>
</head>
<body>
<!-- ═══════════ MAIN MENU ═══════════ -->
<div id="main-menu" class="screen active">
<div class="scanlines"></div>
<div class="menu-left">
<div class="game-title">WARZONE<br>X</div>
<div class="game-subtitle">β—† COMBAT REMASTERED β—†</div>
<div class="divider"></div>
<div class="menu-buttons">
<button class="menu-btn" onclick="showModeSelect()"><span class="btn-icon">βš”</span> PLAY</button>
<button class="menu-btn" onclick="showLoadout()"><span class="btn-icon">πŸ”«</span> LOADOUT</button>
<button class="menu-btn" style="opacity:0.5;cursor:default"><span class="btn-icon">βš™</span> SETTINGS</button>
</div>
</div>
<div class="menu-right">
<div class="char-card">
<!-- Vivian Harris SVG Character -->
<div class="char-avatar">
<svg viewBox="0 0 160 160" xmlns="http://www.w3.org/2000/svg">
<!-- Body / Outfit -->
<defs>
<radialGradient id="skinGrad" cx="50%" cy="30%" r="60%">
<stop offset="0%" stop-color="#C68642"/>
<stop offset="100%" stop-color="#8B5E3C"/>
</radialGradient>
<radialGradient id="faceGrad" cx="50%" cy="40%" r="60%">
<stop offset="0%" stop-color="#D4956A"/>
<stop offset="100%" stop-color="#A0632A"/>
</radialGradient>
</defs>
<!-- Torso / Red Jacket -->
<rect x="42" y="88" width="76" height="58" rx="4" fill="#cc0000"/>
<rect x="42" y="88" width="76" height="58" rx="4" fill="url(#redJacketGrad)" opacity="0.8"/>
<!-- Jacket detail lines -->
<line x1="80" y1="88" x2="80" y2="146" stroke="#990000" stroke-width="2"/>
<rect x="56" y="96" width="12" height="8" rx="2" fill="#ff3333" opacity="0.6"/>
<rect x="92" y="96" width="12" height="8" rx="2" fill="#ff3333" opacity="0.6"/>
<!-- Collar -->
<polygon points="70,88 80,100 90,88" fill="#880000"/>
<!-- Neck -->
<rect x="72" y="78" width="16" height="14" rx="3" fill="url(#faceGrad)"/>
<!-- Head -->
<ellipse cx="80" cy="64" rx="28" ry="30" fill="url(#faceGrad)"/>
<!-- Black Cap -->
<ellipse cx="80" cy="38" rx="30" ry="8" fill="#111"/>
<rect x="52" y="30" width="56" height="18" rx="6" fill="#1a1a1a"/>
<rect x="52" y="30" width="56" height="10" rx="4" fill="#222"/>
<!-- Cap brim -->
<ellipse cx="80" cy="48" rx="32" ry="5" fill="#111" opacity="0.8"/>
<!-- Cap logo -->
<circle cx="80" cy="38" r="6" fill="#e8001d" opacity="0.9"/>
<text x="80" y="42" text-anchor="middle" fill="#fff" font-size="7" font-weight="bold" font-family="Arial">VH</text>
<!-- Eyes -->
<ellipse cx="68" cy="62" rx="5" ry="6" fill="#fff"/>
<ellipse cx="92" cy="62" rx="5" ry="6" fill="#fff"/>
<circle cx="68" cy="63" r="3.5" fill="#3D2000"/>
<circle cx="92" cy="63" r="3.5" fill="#3D2000"/>
<circle cx="69" cy="62" r="1.2" fill="#000"/>
<circle cx="93" cy="62" r="1.2" fill="#000"/>
<!-- Eye shine -->
<circle cx="70" cy="61" r="1" fill="#fff" opacity="0.9"/>
<circle cx="94" cy="61" r="1" fill="#fff" opacity="0.9"/>
<!-- Eyebrows -->
<path d="M63 56 Q68 53 73 56" stroke="#5C3317" stroke-width="2.5" fill="none" stroke-linecap="round"/>
<path d="M87 56 Q92 53 97 56" stroke="#5C3317" stroke-width="2.5" fill="none" stroke-linecap="round"/>
<!-- Nose -->
<path d="M78 67 Q80 72 82 67" stroke="#8B5E3C" stroke-width="1.5" fill="none"/>
<!-- Smile -->
<path d="M72 76 Q80 82 88 76" stroke="#7A3A1A" stroke-width="2" fill="none" stroke-linecap="round"/>
<!-- Lips -->
<path d="M73 77 Q80 81 87 77" stroke="#c0392b" stroke-width="2.5" fill="none" stroke-linecap="round"/>
<!-- Hair strands -->
<path d="M52 50 Q48 62 50 76" stroke="#3D2000" stroke-width="4" fill="none" stroke-linecap="round"/>
<path d="M108 50 Q112 62 110 76" stroke="#3D2000" stroke-width="4" fill="none" stroke-linecap="round"/>
<!-- Arms -->
<rect x="22" y="88" width="20" height="50" rx="8" fill="#cc0000"/>
<rect x="118" y="88" width="20" height="50" rx="8" fill="#cc0000"/>
<!-- Hands -->
<ellipse cx="32" cy="140" rx="10" ry="8" fill="url(#faceGrad)"/>
<ellipse cx="128" cy="140" rx="10" ry="8" fill="url(#faceGrad)"/>
<!-- Gun in right hand -->
<rect x="130" y="128" width="22" height="8" rx="2" fill="#333"/>
<rect x="136" y="120" width="8" height="12" rx="1" fill="#444"/>
<!-- Boots -->
<rect x="52" y="142" width="22" height="16" rx="4" fill="#1a1a1a"/>
<rect x="86" y="142" width="22" height="16" rx="4" fill="#1a1a1a"/>
<!-- Tactical belt -->
<rect x="42" y="114" width="76" height="8" rx="2" fill="#880000"/>
<rect x="76" y="113" width="8" height="10" rx="1" fill="#cc8800"/>
</svg>
</div>
<div class="char-name">VIVIAN HARRIS</div>
<div class="char-rank">β—† ELITE OPERATOR β—†</div>
<div class="char-stats">
<div class="stat-item"><div class="stat-label">KILLS</div><div class="stat-val">2,847</div></div>
<div class="stat-item"><div class="stat-label">K/D RATIO</div><div class="stat-val">4.2</div></div>
<div class="stat-item"><div class="stat-label">WINS</div><div class="stat-val">183</div></div>
<div class="stat-item"><div class="stat-label">RANK</div><div class="stat-val">117</div></div>
</div>
</div>
</div>
</div>
<!-- ═══════════ MODE SELECT ═══════════ -->
<div id="mode-select" class="screen">
<div class="mode-title">β—† SELECT MODE β—†</div>
<div class="mode-cards">
<div class="mode-card" onclick="showLoadout()">
<div class="mode-badge">PVP</div>
<div class="mode-card-img">🎯</div>
<div class="mode-card-body">
<div class="mode-card-name">MULTIPLAYER</div>
<div class="mode-card-desc">Classic team deathmatch. Choose your loadout and dominate the battlefield against AI opponents.</div>
</div>
</div>
<div class="mode-card" onclick="showBRLobby()">
<div class="mode-badge">SOLO</div>
<div class="mode-card-img">πŸ—Ί</div>
<div class="mode-card-body">
<div class="mode-card-name">BATTLE ROYALE</div>
<div class="mode-card-desc">20 players, one survivor. Shrinking zone forces close combat. Last one standing wins.</div>
</div>
</div>
</div>
<button class="back-btn" onclick="showScreen('main-menu')">β—„ BACK</button>
</div>
<!-- ═══════════ LOADOUT ═══════════ -->
<div id="loadout-screen" class="screen">
<div class="screen-header">
<button class="back-btn" onclick="showScreen('mode-select')">β—„ BACK</button>
<div class="screen-title">LOADOUT</div>
</div>
<div class="loadout-grid">
<!-- M117 -->
<div class="gun-card" id="gun-117" onclick="selectGun('117')">
<div class="gun-type">ASSAULT RIFLE</div>
<div class="gun-name">M117</div>
<div class="gun-art">πŸ”«</div>
<div class="gun-stats">
<div class="gun-stat">
<div class="gun-stat-label">DAMAGE</div>
<div class="gun-stat-bar"><div class="gun-stat-fill" style="width:75%"></div></div>
</div>
<div class="gun-stat">
<div class="gun-stat-label">FIRE RATE</div>
<div class="gun-stat-bar"><div class="gun-stat-fill" style="width:88%"></div></div>
</div>
<div class="gun-stat">
<div class="gun-stat-label">ACCURACY</div>
<div class="gun-stat-bar"><div class="gun-stat-fill" style="width:65%"></div></div>
</div>
<div class="gun-stat">
<div class="gun-stat-label">RANGE</div>
<div class="gun-stat-bar"><div class="gun-stat-fill" style="width:80%"></div></div>
</div>
</div>
<div class="gun-select-indicator">● SELECTED</div>
</div>
<!-- M4 -->
<div class="gun-card" id="gun-m4" onclick="selectGun('m4')">
<div class="gun-type">CARBINE RIFLE</div>
<div class="gun-name">M4A1</div>
<div class="gun-art">πŸ”«</div>
<div class="gun-stats">
<div class="gun-stat">
<div class="gun-stat-label">DAMAGE</div>
<div class="gun-stat-bar"><div class="gun-stat-fill" style="width:60%"></div></div>
</div>
<div class="gun-stat">
<div class="gun-stat-label">FIRE RATE</div>
<div class="gun-stat-bar"><div class="gun-stat-fill" style="width:95%"></div></div>
</div>
<div class="gun-stat">
<div class="gun-stat-label">ACCURACY</div>
<div class="gun-stat-bar"><div class="gun-stat-fill" style="width:82%"></div></div>
</div>
<div class="gun-stat">
<div class="gun-stat-label">RANGE</div>
<div class="gun-stat-bar"><div class="gun-stat-fill" style="width:55%"></div></div>
</div>
</div>
<div class="gun-select-indicator">● SELECTED</div>
</div>
</div>
<div class="loadout-confirm">
<button class="confirm-btn" id="loadout-confirm-btn" onclick="confirmLoadout()" disabled>SELECT A WEAPON TO CONTINUE</button>
</div>
</div>
<!-- ═══════════ BATTLE ROYALE LOBBY ═══════════ -->
<div id="br-lobby" class="screen">
<div class="screen-header">
<button class="back-btn" onclick="showScreen('mode-select')">β—„ BACK</button>
<div class="screen-title">BATTLE ROYALE</div>
</div>
<div style="font-size:12px;color:#666;letter-spacing:3px;font-family:'Share Tech Mono',monospace;">β—† SELECT DIFFICULTY β—†</div>
<div class="diff-grid">
<button class="diff-btn" data-diff="noob" onclick="selectDiff('noob')">NOOB</button>
<button class="diff-btn" data-diff="easy" onclick="selectDiff('easy')">EASY</button>
<button class="diff-btn" data-diff="normal" onclick="selectDiff('normal')">NORMAL</button>
<button class="diff-btn" data-diff="hard" onclick="selectDiff('hard')">HARD</button>
</div>
<div style="font-size:12px;color:#666;letter-spacing:3px;font-family:'Share Tech Mono',monospace;margin-top:8px;">β—† CONNECTIVITY β—†</div>
<div class="connect-panel">
<div class="connect-title">πŸ”΅ BLUETOOTH / LAN CONNECT</div>
<p style="font-size:13px;color:#666;margin-bottom:14px;line-height:1.6;">Connect with a friend on the same network or Bluetooth. Enter their code to join their session.</p>
<div class="connect-row">
<input class="connect-input" placeholder="YOUR ROOM CODE: VH-2024" id="room-code" readonly value="VH-4829">
<button class="connect-btn" onclick="copyCode()">COPY</button>
</div>
<div class="connect-row">
<input class="connect-input" placeholder="ENTER FRIEND'S CODE..." id="friend-code" maxlength="7">
<button class="connect-btn" onclick="tryConnect()">JOIN</button>
</div>
<div class="bt-status">
<span class="bt-dot" id="bt-dot"></span>
<span id="bt-status-text">SEARCHING FOR DEVICES...</span>
</div>
</div>
<div class="loadout-confirm" style="max-width:700px;margin-top:10px;">
<button class="confirm-btn" id="br-start-btn" onclick="startBR()" disabled>SELECT DIFFICULTY TO DEPLOY</button>
</div>
</div>
<!-- ═══════════ GAME SCREEN ═══════════ -->
<div id="game-screen" class="screen">
<canvas id="gameCanvas"></canvas>
<div id="damage-vignette"></div>
<div id="muzzle-flash">
<svg width="60" height="60"><circle cx="30" cy="30" r="25" fill="rgba(255,200,50,0.9)"/><circle cx="30" cy="30" r="15" fill="#fff"/></svg>
</div>
<div id="hud">
<!-- Top Left: Health -->
<div class="hud-corner" id="hud-tl">
<div class="hud-label">HEALTH</div>
<div class="hud-val" id="hud-health">100</div>
<div class="health-bar-wrap"><div class="health-bar" id="health-bar" style="width:100%"></div></div>
</div>
<!-- Top Right: Kills + Alive -->
<div class="hud-corner" id="hud-tr">
<div class="hud-label">KILLS</div>
<div class="hud-val" id="hud-kills">0</div>
</div>
<!-- Alive count -->
<div id="alive-count">
<span class="alive-icon">πŸ‘€</span>
<div>
<div class="alive-num" id="hud-alive">20</div>
<div class="alive-label">ALIVE</div>
</div>
</div>
<!-- Bottom Left: Gun + Ammo -->
<div class="hud-corner" id="hud-bl">
<div class="gun-name-hud" id="hud-gun">M117</div>
<div class="ammo-display"><span id="hud-ammo">30</span></div>
<div class="ammo-reserve" id="hud-reserve">/ 120</div>
</div>
<!-- Zone Timer -->
<div id="zone-indicator">
<div class="zone-label">⬑ ZONE CLOSING</div>
<div class="zone-timer" id="zone-timer">60</div>
</div>
<!-- Kill Feed -->
<div id="kill-feed"></div>
<!-- Crosshair -->
<div class="crosshair">
<svg width="60" height="60" viewBox="0 0 60 60">
<line x1="30" y1="5" x2="30" y2="22" stroke="white" stroke-width="1.5" opacity="0.8"/>
<line x1="30" y1="38" x2="30" y2="55" stroke="white" stroke-width="1.5" opacity="0.8"/>
<line x1="5" y1="30" x2="22" y2="30" stroke="white" stroke-width="1.5" opacity="0.8"/>
<line x1="38" y1="30" x2="55" y2="30" stroke="white" stroke-width="1.5" opacity="0.8"/>
<circle cx="30" cy="30" r="3" fill="none" stroke="rgba(255,255,255,0.6)" stroke-width="1"/>
</svg>
</div>
<!-- Minimap -->
<div id="minimap-wrap">
<canvas id="minimap" width="160" height="160"></canvas>
</div>
</div>
</div>
<!-- ═══════════ GAME OVER ═══════════ -->
<div id="game-over" class="screen">
<div class="go-title" id="go-title">ELIMINATED</div>
<div style="font-size:14px;color:#666;letter-spacing:4px;font-family:'Share Tech Mono',monospace" id="go-sub">BETTER LUCK NEXT TIME, HARRIS</div>
<div class="go-stats">
<div class="go-stat"><div class="go-stat-num" id="go-kills">0</div><div class="go-stat-label">KILLS</div></div>
<div class="go-stat"><div class="go-stat-num" id="go-place">20</div><div class="go-stat-label">PLACEMENT</div></div>
<div class="go-stat"><div class="go-stat-num" id="go-time">0:00</div><div class="go-stat-label">SURVIVED</div></div>
</div>
<button class="confirm-btn" style="max-width:400px" onclick="backToMenu()">β—„ RETURN TO MENU</button>
</div>
<script>
// ═══════════════════════════════════════════════════════════
// STATE
// ═══════════════════════════════════════════════════════════
let selectedGun = null;
let selectedDiff = null;
let gameState = {};
let gameLoop = null;
let gameStartTime = 0;
const GUNS = {
'117': { name:'M117', damage:35, fireRate:150, ammo:30, reserve:120, color:'#f0a500' },
'm4': { name:'M4A1', damage:25, fireRate:80, ammo:30, reserve:150, color:'#1e90ff' }
};
const DIFF_CONFIG = {
noob: { botSpeed:0.3, botAccuracy:0.05, botReaction:3000, label:'NOOB' },
easy: { botSpeed:0.6, botAccuracy:0.12, botReaction:2000, label:'EASY' },
normal: { botSpeed:1.0, botAccuracy:0.22, botReaction:1200, label:'NORMAL' },
hard: { botSpeed:1.5, botAccuracy:0.38, botReaction:600, label:'HARD' }
};
// ═══════════════════════════════════════════════════════════
// NAVIGATION
// ═══════════════════════════════════════════════════════════
function showScreen(id) {
document.querySelectorAll('.screen').forEach(s => s.classList.remove('active'));
document.getElementById(id).classList.add('active');
}
function showModeSelect() { showScreen('mode-select'); }
function showLoadout() { showScreen('loadout-screen'); }
function showBRLobby() { showScreen('br-lobby'); simulateBluetooth(); }
function backToMenu() { stopGame(); showScreen('main-menu'); }
function selectGun(g) {
selectedGun = g;
document.querySelectorAll('.gun-card').forEach(c => c.classList.remove('selected'));
document.getElementById('gun-' + g).classList.add('selected');
const btn = document.getElementById('loadout-confirm-btn');
btn.disabled = false;
btn.textContent = '⚑ DEPLOY WITH ' + GUNS[g].name;
}
function confirmLoadout() {
if (!selectedGun) return;
startGame(false);
}
function selectDiff(d) {
selectedDiff = d;
document.querySelectorAll('.diff-btn').forEach(b => b.classList.remove('selected'));
document.querySelector('[data-diff="' + d + '"]').classList.add('selected');
const btn = document.getElementById('br-start-btn');
btn.disabled = false;
btn.textContent = '⚑ DEPLOY TO BATTLE ROYALE – ' + DIFF_CONFIG[d].label;
}
function copyCode() {
const v = document.getElementById('room-code').value;
navigator.clipboard?.writeText(v);
alert('Room code copied: ' + v);
}
function tryConnect() {
const code = document.getElementById('friend-code').value.trim();
if (!code) { alert('Enter a friend\'s room code first!'); return; }
const dot = document.getElementById('bt-dot');
const txt = document.getElementById('bt-status-text');
txt.textContent = 'CONNECTING TO ' + code + '...';
setTimeout(() => {
dot.classList.add('connected');
txt.textContent = 'CONNECTED β€” FRIEND JOINED SESSION';
}, 1800);
}
function simulateBluetooth() {
const dot = document.getElementById('bt-dot');
const txt = document.getElementById('bt-status-text');
dot.classList.remove('connected');
txt.textContent = 'SCANNING FOR NEARBY DEVICES...';
}
// ═══════════════════════════════════════════════════════════
// GAME ENGINE
// ═══════════════════════════════════════════════════════════
const canvas = document.getElementById('gameCanvas');
const ctx = canvas.getContext('2d');
const minimap = document.getElementById('minimap');
const mctx = minimap.getContext('2d');
function startGame(isMultiplayer) {
// Default gun if none selected
if (!selectedGun) selectedGun = '117';
if (!selectedDiff) selectedDiff = 'normal';
showScreen('game-screen');
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
const gun = GUNS[selectedGun];
const diff = DIFF_CONFIG[selectedDiff];
gameStartTime = Date.now();
// Map
const MAP_W = 2400, MAP_H = 2400;
// Buildings / obstacles
const buildings = [];
for (let i = 0; i < 40; i++) {
buildings.push({
x: 100 + Math.random() * (MAP_W - 200),
y: 100 + Math.random() * (MAP_H - 200),
w: 60 + Math.random() * 120,
h: 60 + Math.random() * 120,
color: `hsl(${200 + Math.random()*40}, 20%, ${12 + Math.random()*10}%)`
});
}
// Trees
const trees = [];
for (let i = 0; i < 80; i++) {
trees.push({
x: Math.random() * MAP_W,
y: Math.random() * MAP_H,
r: 20 + Math.random() * 25
});
}
// Player
const player = {
x: MAP_W / 2, y: MAP_H / 2,
w: 22, h: 22,
hp: 100, maxHp: 100,
speed: 3,
angle: 0,
kills: 0,
ammo: gun.ammo,
reserve: gun.reserve,
lastShot: 0,
alive: true
};
// Camera
const cam = { x: 0, y: 0 };
// Bots
const bots = [];
for (let i = 0; i < 20; i++) {
let bx, by;
do {
bx = 80 + Math.random() * (MAP_W - 160);
by = 80 + Math.random() * (MAP_H - 160);
} while (Math.hypot(bx - player.x, by - player.y) < 200);
bots.push({
x: bx, y: by, w: 20, h: 20,
hp: 60 + Math.random() * 40,
maxHp: 100,
speed: diff.botSpeed * (0.7 + Math.random() * 0.6),
angle: Math.random() * Math.PI * 2,
alive: true,
lastShot: 0,
shootInterval: diff.botReaction + Math.random() * 1000,
wanderTimer: 0,
wanderAngle: Math.random() * Math.PI * 2,
hue: Math.floor(Math.random() * 360),
name: ['WOLF','VIPER','GHOST','REAPER','SHADE','ROGUE','BLADE','STORM','HAWK','SKULL',
'DEMON','COBRA','TITAN','RAMBO','NINJA','DEATH','FLASH','CHAOS','OMEGA','ZERO'][i]
});
}
// Bullets
const bullets = [];
const botBullets = [];
// Zone
let zoneRadius = Math.min(MAP_W, MAP_H) * 0.48;
const zoneX = MAP_W / 2, zoneY = MAP_H / 2;
let zoneShrinking = false;
let zoneTimer = 60;
let zoneInterval = null;
// Keys
const keys = {};
document.addEventListener('keydown', e => keys[e.key.toLowerCase()] = true);
document.addEventListener('keyup', e => keys[e.key.toLowerCase()] = false);
// Mouse
let mouseX = canvas.width / 2, mouseY = canvas.height / 2;
canvas.addEventListener('mousemove', e => { mouseX = e.clientX; mouseY = e.clientY; });
canvas.addEventListener('click', shoot);
function shoot() {
if (!player.alive) return;
const now = Date.now();
if (now - player.lastShot < gun.fireRate) return;
if (player.ammo <= 0) {
if (player.reserve > 0) { player.ammo = Math.min(gun.ammo, player.reserve); player.reserve -= player.ammo; }
return;
}
player.lastShot = now;
player.ammo--;
// Muzzle flash
const mf = document.getElementById('muzzle-flash');
mf.style.display = 'block';
setTimeout(() => mf.style.display = 'none', 60);
const angle = Math.atan2(mouseY - canvas.height/2, mouseX - canvas.width/2);
const spread = selectedGun === 'm4' ? 0.05 : 0.08;
bullets.push({
x: player.x, y: player.y,
vx: Math.cos(angle + (Math.random()-0.5)*spread) * 18,
vy: Math.sin(angle + (Math.random()-0.5)*spread) * 18,
life: 80, damage: gun.damage
});
}
// Zone countdown
function startZoneTimer() {
zoneTimer = 60;
zoneShrinking = false;
clearInterval(zoneInterval);
zoneInterval = setInterval(() => {
zoneTimer--;
document.getElementById('zone-timer').textContent = zoneTimer;
if (zoneTimer <= 0) {
zoneShrinking = true;
zoneTimer = 30;
}
if (zoneShrinking && zoneRadius > 80) zoneRadius -= 4;
}, 1000);
}
startZoneTimer();
function addKillFeed(msg) {
const feed = document.getElementById('kill-feed');
const el = document.createElement('div');
el.className = 'kill-msg';
el.textContent = msg;
feed.appendChild(el);
setTimeout(() => el.remove(), 3000);
}
let frameId;
function update() {
// Player movement
if (player.alive) {
let dx = 0, dy = 0;
if (keys['w'] || keys['arrowup']) dy = -1;
if (keys['s'] || keys['arrowdown']) dy = 1;
if (keys['a'] || keys['arrowleft']) dx = -1;
if (keys['d'] || keys['arrowright']) dx = 1;
if (dx !== 0 && dy !== 0) { dx *= 0.707; dy *= 0.707; }
const nx = player.x + dx * player.speed;
const ny = player.y + dy * player.speed;
// Boundary
if (nx > 10 && nx < MAP_W - 10) player.x = nx;
if (ny > 10 && ny < MAP_H - 10) player.y = ny;
// Zone damage
const distZone = Math.hypot(player.x - zoneX, player.y - zoneY);
if (distZone > zoneRadius) {
player.hp -= 0.15;
showDamage();
}
}
// Camera follow
cam.x = player.x - canvas.width / 2;
cam.y = player.y - canvas.height / 2;
// Player angle toward mouse
player.angle = Math.atan2(mouseY - canvas.height/2, mouseX - canvas.width/2);
// Bullets
for (let i = bullets.length - 1; i >= 0; i--) {
const b = bullets[i];
b.x += b.vx; b.y += b.vy; b.life--;
if (b.life <= 0) { bullets.splice(i, 1); continue; }
// Hit bots
for (const bot of bots) {
if (!bot.alive) continue;
if (Math.abs(b.x - bot.x) < bot.w && Math.abs(b.y - bot.y) < bot.h) {
bot.hp -= b.damage;
bullets.splice(i, 1);
if (bot.hp <= 0) {
bot.alive = false;
player.kills++;
addKillFeed('🎯 VIVIAN HARRIS βœ• ' + bot.name);
}
break;
}
}
}
// Bot AI
const now = Date.now();
for (const bot of bots) {
if (!bot.alive) continue;
const dx = player.x - bot.x;
const dy = player.y - bot.y;
const dist = Math.hypot(dx, dy);
// Zone damage on bots
const bDist = Math.hypot(bot.x - zoneX, bot.y - zoneY);
if (bDist > zoneRadius) { bot.x += (zoneX - bot.x) * 0.01; bot.y += (zoneY - bot.y) * 0.01; }
if (dist < 600) {
// Chase player
bot.angle = Math.atan2(dy, dx);
bot.x += Math.cos(bot.angle) * bot.speed;
bot.y += Math.sin(bot.angle) * bot.speed;
// Shoot at player
if (dist < 400 && now - bot.lastShot > bot.shootInterval && player.alive) {
bot.lastShot = now;
const spread = 1 - diff.botAccuracy;
const angle = bot.angle + (Math.random() - 0.5) * spread * 1.5;
botBullets.push({
x: bot.x, y: bot.y,
vx: Math.cos(angle) * 12,
vy: Math.sin(angle) * 12,
life: 60, damage: 8 + Math.random() * 8
});
}
} else {
// Wander
bot.wanderTimer--;
if (bot.wanderTimer <= 0) {
bot.wanderAngle = Math.random() * Math.PI * 2;
bot.wanderTimer = 60 + Math.random() * 120;
}
bot.x += Math.cos(bot.wanderAngle) * bot.speed * 0.5;
bot.y += Math.sin(bot.wanderAngle) * bot.speed * 0.5;
bot.x = Math.max(10, Math.min(MAP_W-10, bot.x));
bot.y = Math.max(10, Math.min(MAP_H-10, bot.y));
}
}
// Bot bullets
for (let i = botBullets.length - 1; i >= 0; i--) {
const b = botBullets[i];
b.x += b.vx; b.y += b.vy; b.life--;
if (b.life <= 0) { botBullets.splice(i, 1); continue; }
if (player.alive && Math.abs(b.x - player.x) < 14 && Math.abs(b.y - player.y) < 14) {
player.hp -= b.damage;
botBullets.splice(i, 1);
showDamage();
if (player.hp <= 0) { player.alive = false; endGame(false); return; }
}
}
// Check win
const aliveCount = bots.filter(b => b.alive).length;
if (aliveCount === 0 && player.alive) { endGame(true); return; }
// Update HUD
const hp = Math.max(0, Math.round(player.hp));
document.getElementById('hud-health').textContent = hp;
document.getElementById('hud-health').className = 'hud-val' + (hp < 30 ? ' danger' : '');
document.getElementById('health-bar').style.width = hp + '%';
document.getElementById('health-bar').style.background = hp > 60 ? 'linear-gradient(90deg,#4ade80,#22c55e)' : hp > 30 ? 'linear-gradient(90deg,#f0a500,#eab308)' : 'linear-gradient(90deg,#e8001d,#ff4444)';
document.getElementById('hud-kills').textContent = player.kills;
document.getElementById('hud-alive').textContent = aliveCount + 1;
document.getElementById('hud-ammo').textContent = player.ammo;
document.getElementById('hud-reserve').textContent = '/ ' + player.reserve;
document.getElementById('hud-gun').textContent = gun.name;
}
let damageTimer = null;
function showDamage() {
document.getElementById('damage-vignette').style.opacity = '1';
clearTimeout(damageTimer);
damageTimer = setTimeout(() => document.getElementById('damage-vignette').style.opacity = '0', 300);
}
// ─── DRAW ───
function draw() {
ctx.clearRect(0, 0, canvas.width, canvas.height);
ctx.save();
ctx.translate(-cam.x, -cam.y);
// Ground
ctx.fillStyle = '#1a2210';
ctx.fillRect(0, 0, MAP_W, MAP_H);
// Ground texture grid
ctx.strokeStyle = 'rgba(255,255,255,0.025)';
ctx.lineWidth = 1;
for (let gx = 0; gx <= MAP_W; gx += 80) {
ctx.beginPath(); ctx.moveTo(gx, 0); ctx.lineTo(gx, MAP_H); ctx.stroke();
}
for (let gy = 0; gy <= MAP_H; gy += 80) {
ctx.beginPath(); ctx.moveTo(0, gy); ctx.lineTo(MAP_W, gy); ctx.stroke();
}
// Roads
ctx.fillStyle = '#222c1a';
ctx.fillRect(MAP_W/2 - 30, 0, 60, MAP_H);
ctx.fillRect(0, MAP_H/2 - 30, MAP_W, 60);
ctx.strokeStyle = 'rgba(255,255,100,0.15)';
ctx.setLineDash([40, 30]);
ctx.lineWidth = 2;
ctx.beginPath(); ctx.moveTo(MAP_W/2, 0); ctx.lineTo(MAP_W/2, MAP_H); ctx.stroke();
ctx.beginPath(); ctx.moveTo(0, MAP_H/2); ctx.lineTo(MAP_W, MAP_H/2); ctx.stroke();
ctx.setLineDash([]);
// Trees
for (const t of trees) {
ctx.fillStyle = '#1a3a0a';
ctx.beginPath(); ctx.arc(t.x, t.y, t.r, 0, Math.PI*2); ctx.fill();
ctx.fillStyle = '#234a10';
ctx.beginPath(); ctx.arc(t.x - t.r*0.2, t.y - t.r*0.2, t.r*0.6, 0, Math.PI*2); ctx.fill();
}
// Buildings
for (const b of buildings) {
ctx.fillStyle = b.color;
ctx.fillRect(b.x, b.y, b.w, b.h);
ctx.strokeStyle = 'rgba(255,255,255,0.08)';
ctx.lineWidth = 1;
ctx.strokeRect(b.x, b.y, b.w, b.h);
// Windows
ctx.fillStyle = 'rgba(255,220,100,0.15)';
for (let wx = b.x + 10; wx < b.x + b.w - 10; wx += 20) {
for (let wy = b.y + 10; wy < b.y + b.h - 10; wy += 20) {
ctx.fillRect(wx, wy, 8, 8);
}
}
}
// Zone circle
ctx.beginPath();
ctx.arc(zoneX, zoneY, zoneRadius, 0, Math.PI*2);
ctx.strokeStyle = 'rgba(100,180,255,0.5)';
ctx.lineWidth = 3;
ctx.stroke();
// Zone outside fill
ctx.save();
ctx.beginPath();
ctx.rect(0, 0, MAP_W, MAP_H);
ctx.arc(zoneX, zoneY, zoneRadius, 0, Math.PI*2, true);
ctx.fillStyle = 'rgba(0,50,150,0.18)';
ctx.fill();
ctx.restore();
// Bot bullets
for (const b of botBullets) {
ctx.fillStyle = '#ff6644';
ctx.beginPath(); ctx.arc(b.x, b.y, 4, 0, Math.PI*2); ctx.fill();
ctx.fillStyle = 'rgba(255,100,50,0.3)';
ctx.beginPath(); ctx.arc(b.x, b.y, 7, 0, Math.PI*2); ctx.fill();
}
// Player bullets
for (const b of bullets) {
ctx.fillStyle = '#ffe055';
ctx.beginPath(); ctx.arc(b.x, b.y, 5, 0, Math.PI*2); ctx.fill();
ctx.fillStyle = 'rgba(255,220,50,0.3)';
ctx.beginPath(); ctx.arc(b.x, b.y, 9, 0, Math.PI*2); ctx.fill();
}
// Bots
for (const bot of bots) {
if (!bot.alive) continue;
ctx.save();
ctx.translate(bot.x, bot.y);
ctx.rotate(bot.angle);
// Bot body
ctx.fillStyle = `hsl(${bot.hue},50%,35%)`;
ctx.fillRect(-bot.w/2, -bot.h/2, bot.w, bot.h);
ctx.strokeStyle = `hsl(${bot.hue},70%,55%)`;
ctx.lineWidth = 1.5;
ctx.strokeRect(-bot.w/2, -bot.h/2, bot.w, bot.h);
// Face dot
ctx.fillStyle = '#fff';
ctx.beginPath(); ctx.arc(5, 0, 3, 0, Math.PI*2); ctx.fill();
ctx.restore();
// HP bar
const hpPct = bot.hp / bot.maxHp;
ctx.fillStyle = '#333';
ctx.fillRect(bot.x - 16, bot.y - bot.h/2 - 10, 32, 4);
ctx.fillStyle = hpPct > 0.5 ? '#4ade80' : hpPct > 0.25 ? '#f0a500' : '#e8001d';
ctx.fillRect(bot.x - 16, bot.y - bot.h/2 - 10, 32 * hpPct, 4);
// Name tag
ctx.fillStyle = 'rgba(255,255,255,0.7)';
ctx.font = '9px Share Tech Mono, monospace';
ctx.textAlign = 'center';
ctx.fillText(bot.name, bot.x, bot.y - bot.h/2 - 14);
}
// Player
if (player.alive) {
ctx.save();
ctx.translate(player.x, player.y);
ctx.rotate(player.angle);
// Shadow
ctx.fillStyle = 'rgba(0,0,0,0.3)';
ctx.beginPath(); ctx.ellipse(3, 3, 14, 12, 0, 0, Math.PI*2); ctx.fill();
// Body
ctx.fillStyle = '#cc0000';
ctx.fillRect(-player.w/2, -player.h/2, player.w, player.h);
// Black cap indicator
ctx.fillStyle = '#111';
ctx.fillRect(-player.w/2, -player.h/2, player.w, player.h/3);
// Gun
ctx.fillStyle = '#555';
ctx.fillRect(4, -3, 18, 6);
ctx.fillStyle = '#333';
ctx.fillRect(18, -2, 6, 4);
// Direction dot
ctx.fillStyle = '#fff';
ctx.beginPath(); ctx.arc(8, 0, 2.5, 0, Math.PI*2); ctx.fill();
ctx.restore();
}
ctx.restore(); // un-translate
// ─── MINIMAP ───
mctx.fillStyle = '#0a0c10';
mctx.fillRect(0, 0, 160, 160);
const scale = 160 / MAP_W;
// Zone on minimap
mctx.beginPath();
mctx.arc(zoneX*scale, zoneY*scale, zoneRadius*scale, 0, Math.PI*2);
mctx.strokeStyle = 'rgba(100,180,255,0.6)'; mctx.lineWidth = 1.5; mctx.stroke();
// Buildings on minimap
mctx.fillStyle = 'rgba(255,255,255,0.08)';
for (const b of buildings) mctx.fillRect(b.x*scale, b.y*scale, b.w*scale, b.h*scale);
// Bots on minimap
for (const bot of bots) {
if (!bot.alive) continue;
mctx.fillStyle = '#e8001d';
mctx.beginPath(); mctx.arc(bot.x*scale, bot.y*scale, 3, 0, Math.PI*2); mctx.fill();
}
// Player on minimap
mctx.fillStyle = '#4ade80';
mctx.beginPath(); mctx.arc(player.x*scale, player.y*scale, 4, 0, Math.PI*2); mctx.fill();
mctx.strokeStyle = '#fff'; mctx.lineWidth = 1.5; mctx.stroke();
}
function gameFrame() {
update();
draw();
frameId = requestAnimationFrame(gameFrame);
}
gameLoop = { stop: () => { cancelAnimationFrame(frameId); clearInterval(zoneInterval); } };
frameId = requestAnimationFrame(gameFrame);
// End game
function endGame(win) {
cancelAnimationFrame(frameId);
clearInterval(zoneInterval);
const survived = Math.round((Date.now() - gameStartTime) / 1000);
const mins = Math.floor(survived / 60);
const secs = survived % 60;
const title = document.getElementById('go-title');
const sub = document.getElementById('go-sub');
if (win) {
title.textContent = 'VICTORY!';
title.className = 'go-title win';
sub.textContent = 'πŸ† VIVIAN HARRIS – WINNER WINNER';
} else {
title.textContent = 'ELIMINATED';
title.className = 'go-title loss';
sub.textContent = 'BETTER LUCK NEXT TIME, HARRIS';
}
const aliveLeft = bots.filter(b => b.alive).length;
document.getElementById('go-kills').textContent = player.kills;
document.getElementById('go-place').textContent = win ? '#1' : '#' + (aliveLeft + 2);
document.getElementById('go-time').textContent = mins + ':' + String(secs).padStart(2,'0');
showScreen('game-over');
}
}
function stopGame() {
if (gameLoop) { gameLoop.stop(); gameLoop = null; }
}
function startBR() {
if (!selectedDiff) return;
if (!selectedGun) selectedGun = '117';
startGame(true);
}
// Resize canvas on window resize
window.addEventListener('resize', () => {
const gc = document.getElementById('gameCanvas');
if (gc) { gc.width = window.innerWidth; gc.height = window.innerHeight; }
});
// Show main menu on load
showScreen('main-menu');
</script>
</body>
</html>