Fight bots locally to test out settings and warm up spreads.
${label}
; n.onclick = () => { browsingSkinId=i; renderLockerGrid(); document.getElementById('skin-title').innerText=name; document.getElementById('skin-ball').style.backgroundColor='#'+skinColors[i].toString(16); }; grid.appendChild(n); }); } document.getElementById('btn-equip').onclick = () => { if(ownedSkins[browsingSkinId]) { activeSkinId=browsingSkinId; saveCloudProfile(); triggerAddictiveToast(EQUIPPED: ${skinNames[browsingSkinId]}); } else if(userCoins >= skinPrices[browsingSkinId]) { userCoins-=skinPrices[browsingSkinId]; ownedSkins[browsingSkinId]=true; renderLockerGrid(); saveCloudProfile(); triggerAddictiveToast("SKIN UNLOCKED!"); } }; function updatePassButtons() { for(let i=1; i<=3; i++) { if(loggedRedemptions['bp-'+i]) { let btn = document.getElementById('bp-claim-'+i); btn.innerText = "CLAIMED"; btn.style.background = "#475569"; btn.disabled = true; } } } function executePassClaim(tier, val) { if(loggedRedemptions['bp-'+tier]) return; userCoins += val; loggedRedemptions['bp-'+tier] = true; saveCloudProfile(); updatePassButtons(); document.getElementById('coin-count').innerText = userCoins; triggerAddictiveToast(TIER CONQUERED: +${val} V-COINS); } document.getElementById('bp-claim-1').onclick = () => { executePassClaim(1, 50); }; document.getElementById('bp-claim-2').onclick = () => { executePassClaim(2, 100); }; document.getElementById('bp-claim-3').onclick = () => { executePassClaim(3, 200); }; document.getElementById('btn-promo').onclick = () => { let v = document.getElementById('promo-input').value.trim().toUpperCase(); if(loggedRedemptions[v]) return alert("Code used."); if(v==="FREE100") { userCoins+=100; loggedRedemptions[v]=true; triggerAddictiveToast("+100 V-COINS"); } else if(v==="ARENA500") { userCoins+=500; loggedRedemptions[v]=true; triggerAddictiveToast("+500 V-COINS"); } else { return alert("Invalid Code."); } saveCloudProfile(); document.getElementById('coin-count').innerText = userCoins; document.getElementById('promo-input').value = ""; }; document.getElementById('btn-solo').onclick = () => { startMatchArenaSector(true); }; // --- CLOUDFLARE MULTIPLAYER LOBBY HANDLERS --- document.getElementById('btn-host').onclick = () => { let isPrivate = document.getElementById('private-toggle').checked; let code = "ROOM" + Math.floor(1000 + Math.random() * 9000); document.getElementById('code-display').innerText = ROOM CODE: ${code}; document.getElementById('code-display').style.display = 'block'; socket = new WebSocket(${socket_base}/ws?room=${code}&private=${isPrivate}); bindSocketEvents(); }; document.getElementById('btn-join').onclick = () => { let entryCode = document.getElementById('code-input').value.trim().toUpperCase(); if(!entryCode) return alert("Enter code!"); socket = new WebSocket(${socket_base}/ws?room=${entryCode}); bindSocketEvents(); }; function bindSocketEvents() { socket.onopen = () => { document.getElementById('status').innerText="ONLINE"; startMatchArenaSector(false); }; socket.onmessage = (event) => { let d = JSON.parse(event.data); if(d.type==='reject') { alert(d.reason); location.reload(); } if(d.type==='move' && opponents.mesh) { opponents.mesh.position.set(d.p, d.p, d.p); opponents.mesh.rotation.y=d.r; } if(d.type==='build') spawnStructureMesh(d.t, d.p, d.r, false); if(d.type==='shot') renderWeaponBeamTracer(new THREE.Vector3(d.f,d.f,d.f), new THREE.Vector3(d.t,d.t,d.t), 0xec4899); if(d.type==='hit') { hp-=d.damage; document.getElementById('hp-display').innerText=hp; if(hp<=0){ hp=100; pPos.set((Math.random()-0.5)*20,1.8,(Math.random()-0.5)*20); socket.send(JSON.stringify({type:'elim'})); }} if(d.type==='elim') { elims++; document.getElementById('elims-display').innerText=elims; userCoins+=50; document.getElementById('coin-count').innerText=userCoins; saveCloudProfile(); } }; } function startMatchArenaSector(solo) { isLocalMode = solo; document.getElementById('global-nav').style.display = 'none'; document.getElementById('screen-play').classList.remove('active'); document.getElementById('hud').style.display = 'block'; document.body.requestPointerLock(); if(!scene) build3DGraphicsEngine(); if(isLocalMode) respawnTargetBot(); activeGame = true; } function build3DGraphicsEngine() { scene = new THREE.Scene(); scene.background = new THREE.Color(0x060814); camera = new THREE.PerspectiveCamera(75, window.innerWidth/window.innerHeight, 0.1, 1000); camera.position.copy(pPos); renderer = new THREE.WebGLRenderer({ antialias: true }); renderer.setSize(window.innerWidth, window.innerHeight); document.getElementById('canvas').appendChild(renderer.domElement); scene.add(new THREE.AmbientLight(0xffffff, 0.5)); let light = new THREE.DirectionalLight(0x38bdf8, 0.8); light.position.set(10,25,10); scene.add(light); let floor = new THREE.Mesh(new THREE.PlaneGeometry(100,100), new THREE.MeshStandardMaterial({color:0x0f172a})); floor.rotation.x = -Math.PI/2; scene.add(floor); let grid = new THREE.GridHelper(100, 25, 0x38bdf8, 0x1e293b); grid.position.y = 0.01; scene.add(grid); localPreview = new THREE.Mesh(new THREE.BoxGeometry(4,3,0.2), new THREE.MeshBasicMaterial({color:0x38bdf8, wireframe:true, transparent:true, opacity:0.4})); scene.add(localPreview); opponents.mesh = new THREE.Mesh(new THREE.CapsuleGeometry(0.5, 1.8, 4, 8), new THREE.MeshStandardMaterial({color: skinColors[activeSkinId]})); scene.add(opponents.mesh); document.addEventListener('keydown', (e) => { if(e.code === 'Escape') { activeGame=false; document.exitPointerLock(); document.getElementById('global-nav').style.display='block'; document.getElementById('screen-play').classList.add('active'); document.getElementById('hud').style.display='none'; return; } if(!activeGame) return; if(e.code==='KeyW') moveF=true; if(e.code==='KeyS') moveB=true; if(e.code==='KeyA') moveL=true; if(e.code==='KeyD') moveR=true; if(e.code==='Digit1') { activeSlot=1; localPreview.visible=false; } if(e.code==='Digit2') { activeSlot=4; localPreview.visible=false; } if(e.code==='Digit3') { activeSlot=2; localPreview.visible=true; } if(e.code==='Digit4') { activeSlot=3; localPreview.visible=true; } document.getElementById('w1').classList.toggle('active', activeSlot===1); document.getElementById('w4').classList.toggle('active', activeSlot===4); document.getElementById('w2').classList.toggle('active', activeSlot===2); document.getElementById('w3').classList.toggle('active', activeSlot===3); }); document.addEventListener('keyup', (e) => { if(e.code==='KeyW') moveF=false; if(e.code==='KeyS') moveB=false; if(e.code==='KeyA') moveL=false; if(e.code==='KeyD') moveR=false; }); document.addEventListener('mousemove', (e) => { if (document.pointerLockElement !== document.body) return; yaw -= e.movementX0.002; pitch -= e.movementY0.002; pitch = Math.max(-1.4, Math.min(1.4, pitch)); camera.rotation.order = "YXZ"; camera.rotation.set(pitch, yaw, 0); }); document.addEventListener('mousedown', (e) => { if(document.pointerLockElement !== document.body) { if(activeGame) document.body.requestPointerLock(); return; } if(e.button===0 && activeGame) { if(activeSlot===1 || activeSlot===4) deployFirearmsEngine(); else executeBuildPlacement(); } }); window.addEventListener('resize', () => { camera.aspect = window.innerWidth/window.innerHeight; camera.updateProjectionMatrix(); renderer.setSize(window.innerWidth, window.innerHeight); }); graphicsLoopEngine(); } function calculateRaycastGrid() { let v = new THREE.Vector3(); camera.getWorldDirection(v); let t = pPos.clone().add(v.multiplyScalar(5)); return { p: new THREE.Vector3(Math.round(t.x/4)*4, Math.max(0, Math.round(t.y/3)*3) + 1.5, Math.round(t.z/4)*4), r: Math.abs(Math.cos(yaw)) > Math.abs(Math.sin(yaw)) ? 0 : Math.PI/2 }; } function executeBuildPlacement() { let g = calculateRaycastGrid(); let type = activeSlot === 2 ? 'wall' : 'ramp'; spawnStructureMesh(type, [g.p.x, g.p.y, g.p.z], g.r, true); if(socket && !isLocalMode) socket.send(JSON.stringify({type:'build', t:type, p:[g.p.x, g.p.y, g.p.z], r:g.r})); } function spawnStructureMesh(t, p, r, local) { let m = new THREE.Mesh(new THREE.BoxGeometry(4, t==='wall'?3:0.2, t==='wall'?0.2:4.5), new THREE.MeshStandardMaterial({color: local?skinColors[activeSkinId]:0xec4899})); m.position.set(p, p, p); m.rotation.y = r; if(t==='ramp') m.rotation.x = -Math.PI/6; scene.add(m); structures.push(m); } function respawnTargetBot() { if(opponents.mesh) { opponents.mesh.position.set((Math.random()-0.5)*30, 0.9, (Math.random()-0.5)*30); } botTargets.vx=(Math.random()-0.5)*5; botTargets.vz=(Math.random()-0.5)*5; } function deployFirearmsEngine() { let isShotgun = (activeSlot === 4); let pellets = isShotgun ? 6 : 1; let hit = false; for(let i=0; i