<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:base="https://www.pandoraburo.ru/" xml:lang="ru">
  <id>https://www.pandoraburo.ru/tanchiki</id>
  <link href="https://www.pandoraburo.ru/tanchiki.xml" rel="self"/>
  <title>Танчики</title>
  <subtitle type="html">
&lt;html lang="ru"&gt;
&lt;head&gt;
&lt;meta charset="UTF-8"&gt;
&lt;meta name="viewport" content="width=device-width,initial-scale=1,maximum-scale=1,user-scalable=no"&gt;
&lt;title&gt;БРОНЕНОСЕЦ v2 · Живая сталь&lt;/title&gt;
&lt;style&gt;
:root{--ph:#39ff8a;--phd:#0d4a28;--ph2:#a6ffc7;--rd:#ff5340;--am:#ffb400;--cy:#4fd6e0;--mg:#b06cff;--bg:#05080a;--frame:#1a1f1c;--px:'Courier New',monospace;--disp:'Courier New',monospace}
*{margin:0;padding:0;box-sizing:border-box; -webkit-tap-highlight-color: transparent;}
html,body{height:100%; overflow: hidden;}
body{font-family:var(--px);background:#000;color:var(--ph);display:flex;align-items:center;justify-content:center;background:radial-gradient(ellipse at center,#0a1410 0%,#000 80%); touch-action: none;}
.monitor{position:relative;width:100vw;height:100vh;max-width:100%;max-height:100%;background:var(--frame);display:flex;flex-direction:column;align-items:center;justify-content:center;}
.screen{position:relative;width:100%;height:100%;background:#02080a;overflow:hidden;box-shadow:inset 0 0 80px rgba(57,255,138,.12);}
@media (min-width: 768px) {
  .screen::before{content:"";position:absolute;inset:0;pointer-events:none;z-index:40;background:repeating-linear-gradient(0deg,rgba(0,0,0,.25) 0 2px,transparent 2px 4px);mix-blend-mode:multiply}
}
canvas{position:absolute;inset:0;width:100%;height:100%;display:block; touch-action: none;}
.hud{position:absolute;top:10px;left:10px;right:10px;z-index:30;display:flex;justify-content:space-between;align-items:center;gap:8px;font-size:12px;color:var(--ph);text-shadow:0 0 6px var(--ph);pointer-events:none;flex-wrap:wrap}
.hud .blk{border:1px solid var(--phd);padding:5px 9px;border-radius:4px;background:rgba(5,15,10,.8);}
.hud b{color:var(--ph2)}
.lives{display:flex;gap:4px}
.life{width:18px;height:12px;background:var(--ph);box-shadow:0 0 6px var(--ph);clip-path:polygon(0 30%,30% 0,70% 0,100% 30%,100% 100%,70% 85%,50% 100%,30% 85%,0 100%);}
.mult{color:var(--am);text-shadow:0 0 6px var(--am);}
.foes{display:flex;gap:2px;flex-wrap:wrap;max-width:100px}
.foe{width:6px;height:6px;background:var(--rd);box-shadow:0 0 4px var(--rd)}
.bossbar{position:absolute;top:40px;left:10%;right:10%;height:8px;border:1px solid var(--phd);border-radius:4px;background:rgba(0,0,0,.6);z-index:30;display:none;overflow:hidden}
.bossbar.on{display:block}
.bossbar i{display:block;height:100%;background:linear-gradient(90deg,var(--rd),var(--am),var(--cy));border-radius:2px;transition:width .15s;box-shadow:0 0 10px var(--rd)}
.minimap{position:absolute;top:50px;right:10px;z-index:31;background:rgba(5,15,10,.8);border:1px solid var(--phd);border-radius:6px;padding:5px 7px;display:flex;gap:4px;align-items:center;min-height:26px}
.minimap .ml{font-size:9px;color:#4a5f4a;margin-right:5px;}
.minimap .mi{width:10px;height:10px;border-radius:2px;}
.ov{position:absolute;inset:0;z-index:50;display:none;align-items:center;justify-content:center;flex-direction:column;gap:14px;text-align:center;padding:20px;background:rgba(0,0,0,.85);}
.ov.show{display:flex;}
.ov h1{font-size:clamp(28px,8vw,54px);color:var(--ph);text-shadow:0 0 18px var(--ph);letter-spacing:3px;}
.ov h2{font-size:clamp(18px,5vw,38px);color:var(--ph);text-shadow:0 0 14px var(--ph);letter-spacing:2px}
.ov h2.rd{color:var(--rd);text-shadow:0 0 18px var(--rd)}
.ov p{color:var(--ph2);font-size:14px;max-width:90%;line-height:1.5}
.ov p b{color:var(--am);text-shadow:0 0 6px var(--am)}
.btn{font-family:var(--px);font-size:16px;background:transparent;color:var(--ph);border:2px solid var(--ph);padding:15px 30px;border-radius:6px;cursor:pointer;text-shadow:0 0 6px var(--ph);box-shadow:0 0 12px rgba(57,255,138,.4);transition:.2s;letter-spacing:2px; margin-top: 10px;}
.btn:active{transform:scale(0.95); background: var(--ph); color: #000;}
.btn.alt{border-color:var(--am);color:var(--am);text-shadow:0 0 6px var(--am);box-shadow:0 0 12px rgba(255,180,0,.4)}
.btn.cy{border-color:var(--cy);color:var(--cy);text-shadow:0 0 6px var(--cy);box-shadow:0 0 12px rgba(79,214,224,.4)}
@keyframes brn-pulse{0%,100%{box-shadow:0 0 12px rgba(57,255,138,.4)}50%{box-shadow:0 0 46px rgba(57,255,138,.95);transform:scale(1.06)}}
.brn-pulse{animation:brn-pulse 1.2s infinite}
.keys{display:flex;gap:6px;flex-wrap:wrap;justify-content:center; margin-bottom: 10px;}
.keys span{border:1px solid var(--phd);padding:6px 10px;border-radius:4px;font-size:10px;color:var(--ph2)}
.stat{display:grid;grid-template-columns:repeat(2, 1fr);gap:8px;max-width:300px;width:100%}
@media (min-width: 600px) { .stat { grid-template-columns: repeat(5, 1fr); max-width: 500px; } }
.stat div{border:1px solid var(--phd);padding:10px;border-radius:4px;background:rgba(5,15,10,.5)}
.stat b{display:block;font-size:18px;color:var(--am);text-shadow:0 0 8px var(--am)}
.stat span{font-size:10px;color:var(--ph2)}
.cd{font-size:48px;color:var(--am);text-shadow:0 0 18px var(--am);}
#fade{position:absolute;inset:0;background:#000;opacity:0;pointer-events:none;z-index:45;transition:opacity .8s}
#fade.on{opacity:1}
#fxred,#fxgold,#fxblue,#fxpickup{position:absolute;inset:0;pointer-events:none;opacity:0;z-index:42}
#fxred{background:radial-gradient(ellipse at center,transparent 40%,rgba(255,40,20,.55))}
#fxgold{background:radial-gradient(ellipse at center,transparent 40%,rgba(255,220,80,.5))}
#fxblue{background:radial-gradient(ellipse at center,transparent 40%,rgba(79,214,224,.5))}
#fxpickup{background:radial-gradient(ellipse at center,transparent 20%,rgba(255,255,255,.4))}

/* --- ДЖОЙСТИК (ВСЕГДА ВИДЕН НА МОБИЛЬНОМ) --- */
#joy{
  position:absolute; left:20px; bottom:20px; width:120px; height:120px; 
  border-radius:50%; border:2px solid rgba(57,255,138,0.5); 
  background:rgba(57,255,138,0.1); z-index:44; 
  display:none; /* Скрыт по умолчанию, покажется JS-ом на тач-устройствах */
  touch-action: none; user-select: none;
}
#stick{
  position:absolute; left:50%; top:50%; width:50px; height:50px; 
  margin:-25px 0 0 -25px; border-radius:50%; 
  background:rgba(57,255,138,0.8); box-shadow:0 0 15px var(--ph); 
  pointer-events: none; transition: transform 0.1s;
}
/* Показываем джойстик только если есть тач */
body.touch #joy { display: block; }

#fire{
  position:absolute; right:20px; bottom:20px; width:100px; height:100px; 
  border-radius:50%; background:rgba(255,83,64,0.2); border:2px solid var(--rd); 
  color:var(--rd); font-family:var(--px); font-size:14px; z-index:44; 
  display:none; text-shadow:0 0 6px var(--rd); box-shadow:0 0 14px rgba(255,83,64,.5); 
  touch-action: none; user-select: none;
}
#fire:active{background:rgba(255,83,64,0.5); transform: scale(0.95);}
body.touch #fire{display:block}

.combo-display{position:absolute;bottom:80px;left:50%;transform:translateX(-50%);z-index:35;font-size:22px;font-weight:800;color:var(--am);text-shadow:0 0 20px var(--am);pointer-events:none;opacity:0;transition:opacity .3s}
.combo-display.show{opacity:1}
.combo-display .num{font-size:36px}
.combo-display .label{font-size:14px;letter-spacing:3px;color:var(--ph2)}
.ach-wrap{position:absolute;top:60px;left:10px;z-index:36;display:flex;flex-direction:column;gap:6px;pointer-events:none;max-width:200px}
.ach{background:rgba(10,20,14,.9);border:1px solid var(--am);border-radius:6px;padding:8px 12px;color:var(--ph2);font-size:11px;box-shadow:0 0 14px rgba(255,180,0,.4);display:flex;gap:8px;align-items:center; animation: achIn 0.4s ease-out;}
.ach .ico{font-size:20px;}
.ach .tit{font-weight:800;color:var(--am);display:block;letter-spacing:1px}
@keyframes achIn{from{transform:translateX(-100%);opacity:0} to{transform:translateX(0);opacity:1}}
.toplist{margin-top:16px;max-width:90%;width:100%}
.toplist h3{font-size:12px;color:var(--ph);margin-bottom:8px;letter-spacing:2px}
.toprow{display:flex;justify-content:space-between;padding:6px 10px;border-bottom:1px dashed var(--phd);font-size:12px;color:var(--ph2)}
.toprow:first-child{color:var(--am)}
.toprow b{font-weight:800}
.musbtn{position:absolute;bottom:10px;left:10px;z-index:43;font-size:12px;padding:8px 12px;background:rgba(5,15,10,.8);border:1px solid var(--phd);color:var(--ph2);border-radius:6px;cursor:pointer;letter-spacing:1px}
.musbtn.on{border-color:var(--cy);color:var(--cy);box-shadow:0 0 10px rgba(79,214,224,.4)}
.arena-tag{position:absolute;top:10px;left:50%;transform:translateX(-50%);z-index:32;font-size:10px;padding:4px 12px;border:1px solid var(--phd);border-radius:4px;background:rgba(5,15,10,.8);color:var(--ph2);letter-spacing:2px;pointer-events:none}
&lt;/style&gt;
&lt;/head&gt;
&lt;body&gt;
&lt;div class="monitor"&gt;
  &lt;div class="screen"&gt;
    &lt;canvas id="cv"&gt;&lt;/canvas&gt;
    &lt;div class="arena-tag" id="arenaTag"&gt;ПОЛИГОН&lt;/div&gt;
    &lt;div class="hud"&gt;
      &lt;div class="blk"&gt;❤ &lt;span class="lives" id="hudLives"&gt;&lt;/span&gt;&lt;/div&gt;
      &lt;div class="blk"&gt;РАУНД &lt;b id="hudRound"&gt;1&lt;/b&gt;&lt;/div&gt;
      &lt;div class="blk"&gt;? &lt;b id="hudScore"&gt;0&lt;/b&gt;&lt;span class="mult" id="hudMult" style="display:none;margin-left:6px"&gt;×2&lt;/span&gt;&lt;/div&gt;
      &lt;div class="blk"&gt;? &lt;div class="foes" id="hudFoes"&gt;&lt;/div&gt;&lt;/div&gt;
    &lt;/div&gt;
    &lt;div class="bossbar" id="bossbar"&gt;&lt;i id="bossfill"&gt;&lt;/i&gt;&lt;/div&gt;
    &lt;div class="minimap" id="minimap"&gt;&lt;span class="ml"&gt;ОЧЕРЕДЬ&lt;/span&gt;&lt;/div&gt;
    &lt;div class="combo-display" id="comboDisplay"&gt;&lt;span class="num" id="comboNum"&gt;0&lt;/span&gt;&lt;br /&gt;&lt;span class="label"&gt;СЕРИЯ&lt;/span&gt;&lt;/div&gt;
    &lt;div class="ach-wrap" id="achWrap"&gt;&lt;/div&gt;

    &lt;div id="fxred"&gt;&lt;/div&gt;&lt;div id="fxgold"&gt;&lt;/div&gt;&lt;div id="fxblue"&gt;&lt;/div&gt;&lt;div id="fxpickup"&gt;&lt;/div&gt;
    &lt;div id="fade"&gt;&lt;/div&gt;

    &lt;div class="ov show" id="menuOv"&gt;
      &lt;h1&gt;БРОНЕНОСЕЦ&lt;/h1&gt;
      &lt;h2 style="font-size:16px;color:var(--ph2)"&gt;⚡ ЖИВАЯ СТАЛЬ ⚡&lt;/h2&gt;
      &lt;p&gt;Уничтожай врагов — &lt;b&gt;+1 жизнь&lt;/b&gt;. Каждый 5-й раунд — &lt;b&gt;БОСС&lt;/b&gt;.&lt;br /&gt;Серия ×2. Достижения.&lt;/p&gt;
      &lt;div class="keys"&gt;&lt;span&gt;WASD / Стрелки&lt;/span&gt;&lt;span&gt;Пробел / Кнопка&lt;/span&gt;&lt;/div&gt;
      &lt;div class="toplist" id="toplist"&gt;&lt;h3&gt;? РЕКОРДЫ&lt;/h3&gt;&lt;div id="toprows"&gt;&lt;/div&gt;&lt;/div&gt;
      &lt;button class="btn brn-pulse" id="startBtn"&gt;▶ В БОЙ&lt;/button&gt;
      &lt;div style="color:#a6ffc7;font-size:12px;margin-top:10px"&gt;НАЖМИ, ЧТОБЫ НАЧАТЬ&lt;/div&gt;
      &lt;button class="btn" id="achBtn" style="padding:8px 16px;font-size:10px; border-color: var(--mg); color: var(--mg);"&gt;? ДОСТИЖЕНИЯ&lt;/button&gt;
    &lt;/div&gt;

    &lt;div class="ov" id="introOv"&gt;&lt;h2 id="introT"&gt;РАУНД 1&lt;/h2&gt;&lt;p id="introP"&gt;&lt;/p&gt;&lt;/div&gt;
    &lt;div class="ov" id="endOv"&gt;&lt;h2 id="endT"&gt;РАУНД ЗАЧИЩЕН ✦&lt;/h2&gt;&lt;p id="endP"&gt;&lt;/p&gt;&lt;div class="cd" id="endCd"&gt;3&lt;/div&gt;&lt;/div&gt;

    &lt;div class="ov" id="overOv"&gt;
      &lt;h2 class="rd"&gt;? ТАНК ПОДБИТ&lt;/h2&gt;
      &lt;div class="stat"&gt;
        &lt;div&gt;&lt;b id="sK"&gt;0&lt;/b&gt;&lt;span&gt;убито&lt;/span&gt;&lt;/div&gt;
        &lt;div&gt;&lt;b id="sA"&gt;0%&lt;/b&gt;&lt;span&gt;точность&lt;/span&gt;&lt;/div&gt;
        &lt;div&gt;&lt;b id="sR"&gt;1&lt;/b&gt;&lt;span&gt;раунд&lt;/span&gt;&lt;/div&gt;
        &lt;div&gt;&lt;b id="sS"&gt;0&lt;/b&gt;&lt;span&gt;очки&lt;/span&gt;&lt;/div&gt;
        &lt;div&gt;&lt;b id="sB"&gt;0&lt;/b&gt;&lt;span&gt;рекорд&lt;/span&gt;&lt;/div&gt;
      &lt;/div&gt;
      &lt;div style="display:flex;gap:10px;flex-wrap:wrap;justify-content:center; margin-top: 15px;"&gt;
        &lt;button class="btn alt" id="againBtn"&gt;⟳ ЗАНОВО&lt;/button&gt;
        &lt;button class="btn" id="menuBtn"&gt;МЕНЮ&lt;/button&gt;
      &lt;/div&gt;
    &lt;/div&gt;

    &lt;div class="ov" id="pauseOv"&gt;&lt;h2&gt;⏸ ПАУЗА&lt;/h2&gt;&lt;button class="btn cy" id="resBtn"&gt;▶ ПРОДОЛЖИТЬ&lt;/button&gt;&lt;/div&gt;

    &lt;div class="ov" id="achOv"&gt;
      &lt;h2 style="font-size:24px"&gt;? ДОСТИЖЕНИЯ&lt;/h2&gt;
      &lt;p style="font-size:12px"&gt;Открыто &lt;b id="achCnt"&gt;0&lt;/b&gt;/9&lt;/p&gt;
      &lt;div class="achlist" id="achList" style="display:grid; grid-template-columns: 1fr; gap: 8px; width: 90%; max-height: 60vh; overflow-y: auto;"&gt;&lt;/div&gt;
      &lt;button class="btn" id="achClose" style="margin-top:14px"&gt;✖ ЗАКРЫТЬ&lt;/button&gt;
    &lt;/div&gt;

    
    &lt;div id="joy"&gt;&lt;div id="stick"&gt;&lt;/div&gt;&lt;/div&gt;
    &lt;button id="fire"&gt;? ОГОНЬ&lt;/button&gt;
    &lt;button class="musbtn" id="musbtn"&gt;♫ ЗВУК&lt;/button&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;script&gt;
(function(){
"use strict";

// --- Mobile Detection ---
const isTouch = 'ontouchstart' in window || navigator.maxTouchPoints &gt; 0;
if(isTouch) document.body.classList.add('touch');

const RM = matchMedia('(prefers-reduced-motion: reduce)').matches;
const W = 960, H = 608;
const cv = document.getElementById('cv');
const ctx = cv.getContext('2d', { alpha: false });

function resize() {
  const dpr = Math.min(window.devicePixelRatio || 1, 2);
  const rect = cv.parentElement.getBoundingClientRect();
  cv.width = rect.width * dpr;
  cv.height = rect.height * dpr;
  ctx.scale(dpr * (rect.width / W), dpr * (rect.height / H));
}
window.addEventListener('resize', resize);
resize();

function $(s){return document.querySelector(s)}
const R=(a,b)=&gt;a+Math.random()*(b-a), RI=(a,b)=&gt;Math.floor(R(a,b+1)), clamp=(v,a,b)=&gt;v&lt;a?a:v&gt;b?b:v, hyp=(x,y)=&gt;Math.sqrt(x*x+y*y);
const angDiff=(a,b)=&gt;{let d=(b-a)%(Math.PI*2);if(d&gt;Math.PI)d-=Math.PI*2;if(d&lt;-Math.PI)d+=Math.PI*2;return d};

function rr(x,y,w,h,r){ctx.beginPath();ctx.moveTo(x+r,y);ctx.arcTo(x+w,y,x+w,y+h,r);ctx.arcTo(x+w,y+h,x,y+h,r);ctx.arcTo(x,y+h,x,y,r);ctx.arcTo(x,y,x+w,y,r);ctx.closePath()}

/* ══════ АРЕНЫ ══════ */
const ARENAS=[
 {name:'ПОЛИГОН',bg1:'#0a1810',bg2:'#02080a',gridC:'rgba(57,255,138,.06)',brick:'#0d4a28',brickBrd:'#39ff8a',steel:'#1a3a2a',steelBrd:'#39ff8a',decoC:'rgba(57,255,138,',dustC:'#0d4a28',starC:'#a6ffc7'},
 {name:'ПУСТЫНЯ',bg1:'#2a1f0e',bg2:'#0f0a02',gridC:'rgba(255,180,90,.06)',brick:'#6a4820',brickBrd:'#d4a060',steel:'#4a3018',steelBrd:'#b87a40',decoC:'rgba(220,160,80,',dustC:'#5a3a10',starC:'#ffe27a'},
 {name:'ГОРОД',bg1:'#151922',bg2:'#05070c',gridC:'rgba(120,160,200,.06)',brick:'#3a3a45',brickBrd:'#7890a0',steel:'#1a2030',steelBrd:'#5a7890',decoC:'rgba(120,160,200,',dustC:'#2a2a35',starC:'#c0d4e0'},
 {name:'БАЗА',bg1:'#1a1018',bg2:'#05020a',gridC:'rgba(255,100,180,.06)',brick:'#4a2038',brickBrd:'#d050a0',steel:'#2a0a20',steelBrd:'#9a3078',decoC:'rgba(255,100,180,',dustC:'#3a1830',starC:'#ffc0e0'}
];
let arenaIdx=0, arena=ARENAS[0];
const CS=32, GW=30, GH=19;

/* ══════ ЗВУК ══════ */
let AC=null, muted=false, noiseBuf=null, musicOn=false, musicG=null, musicNodes=[];
let audioInitialized = false;

function initAudio() {
  if(audioInitialized) return;
  try {
    AC = new (window.AudioContext || window.webkitAudioContext)();
    const b = AC.createBuffer(1, AC.sampleRate * 0.5, AC.sampleRate);
    const d = b.getChannelData(0);
    for(let i=0; i&lt;d.length; i++) d[i] = Math.random()*2-1;
    noiseBuf = b;
    audioInitialized = true;
    if(AC.state === 'suspended') AC.resume();
  } catch(e) { console.warn("Audio not supported"); }
}

function tone(f,d,type,v,f2,dl){
  if(muted || !AC) return;
  const t=AC.currentTime+(dl||0), o=AC.createOscillator(), g=AC.createGain();
  o.type=type||'square'; o.frequency.setValueAtTime(f,t);
  if(f2) o.frequency.exponentialRampToValueAtTime(Math.max(f2,1),t+d);
  g.gain.setValueAtTime(v||.07,t); g.gain.exponentialRampToValueAtTime(.0001,t+d);
  o.connect(g); g.connect(AC.destination); o.start(t); o.stop(t+d);
}
function noiz(d,v,fq,dl){
  if(muted || !AC || !noiseBuf) return;
  const t=AC.currentTime+(dl||0), s=AC.createBufferSource(), g=AC.createGain(), f=AC.createBiquadFilter();
  s.buffer=noiseBuf; f.type='lowpass'; f.frequency.value=fq||800;
  g.gain.setValueAtTime(v||.15,t); g.gain.exponentialRampToValueAtTime(.0001,t+d);
  s.connect(f); f.connect(g); g.connect(AC.destination); s.start(t); s.stop(t+d);
}

const SFX={
  shoot:()=&gt;{tone(300,.08,'square',.05,90); noiz(.05,.04,3500)},
  eshoot:()=&gt;tone(200,.09,'square',.035,70),
  boom:s=&gt;{noiz(.45*s,.22,500); tone(100,.4,'triangle',.16,30)},
  brick:()=&gt;noiz(.12,.1,1200),
  ping:()=&gt;tone(1300,.05,'square',.04,900),
  hurt:()=&gt;{noiz(.3,.2,700); tone(160,.25,'sawtooth',.12,60)},
  life:()=&gt;{tone(660,.09,'triangle',.08); tone(990,.12,'triangle',.08,0,.09)},
  pick:()=&gt;{tone(700,.07,'square',.06); tone(1050,.09,'square',.06,0,.07)},
  laser:()=&gt;tone(220,.8,'sawtooth',.03,1100),
  fanfare:()=&gt;[523,659,784,1047].forEach((f,i)=&gt;tone(f,.16,'square',.08,0,i*.12)),
  over:()=&gt;tone(300,.5,'sawtooth',.1,60),
  bossAlert:()=&gt;{tone(180,.6,'sawtooth',.08,80); setTimeout(()=&gt;tone(240,.6,'sawtooth',.08,80),300)},
  ach:()=&gt;{tone(880,.08,'triangle',.09); setTimeout(()=&gt;tone(1320,.1,'triangle',.09),80); setTimeout(()=&gt;tone(1760,.14,'triangle',.09),180)}
};

const BASS=[55,55,73.42,73.42,65.41,65.41,82.41,82.41];
const ARP=[220,330,440,660,550,440,330,220,246,370,494,740,587,494,370,246];
function startMusic(){
  if(musicOn || muted || !AC) return;
  musicG=AC.createGain(); musicG.gain.value=.07; musicG.connect(AC.destination);
  musicOn=true;
  const bpm=108, beat=60/bpm; let step=0, t0=AC.currentTime+.1;
  function sched(){
    if(!musicOn) return;
    const now=AC.currentTime;
    while(t0 &lt; now + 0.5){
      const bStep=step%8;
      const bo=AC.createOscillator(), bg=AC.createGain();
      bo.type='sawtooth'; bo.frequency.value=BASS[bStep];
      bg.gain.setValueAtTime(0,t0); bg.gain.linearRampToValueAtTime(.18,t0+.01); bg.gain.exponentialRampToValueAtTime(.001,t0+beat*.9);
      const bf=AC.createBiquadFilter(); bf.type='lowpass'; bf.frequency.value=300;
      bo.connect(bf); bf.connect(bg); bg.connect(musicG); bo.start(t0); bo.stop(t0+beat);
      
      const aStep=step%16;
      const ao=AC.createOscillator(), ag=AC.createGain();
      ao.type='triangle'; ao.frequency.value=ARP[aStep];
      ag.gain.setValueAtTime(0,t0); ag.gain.linearRampToValueAtTime(.08,t0+.005); ag.gain.exponentialRampToValueAtTime(.001,t0+beat*.45);
      ao.connect(ag); ag.connect(musicG); ao.start(t0); ao.stop(t0+beat*.5);
      t0+=beat/2; step++;
    }
    musicNodes.push(setTimeout(sched, 80));
  }
  sched();
}
function stopMusic(){
  musicOn=false; musicNodes.forEach(clearTimeout); musicNodes=[];
  if(musicG){try{musicG.gain.exponentialRampToValueAtTime(.0001,AC.currentTime+.3)}catch(e){}}
}

$('#musbtn').addEventListener('click', function(e){
  e.stopPropagation();
  initAudio();
  if(!musicOn){ startMusic(); this.classList.add('on'); this.textContent='♫ ON'; }
  else { stopMusic(); this.classList.remove('on'); this.textContent='♫ OFF'; }
});

/* ══════ ДОСТИЖЕНИЯ ══════ */
const ACHS={
  firstBlood:{t:'ПЕРВАЯ КРОВЬ',i:'?',d:'Уничтожь первого врага'},
  bossKill:{t:'ЦАРЕУБИЙЦА',i:'?',d:'Убей босса'},
  streak10:{t:'ЖНЕЦ',i:'?',d:'Серия из 10 убийств'},
  nineLives:{t:'КОШАЧИЙ ЦАРЬ',i:'?',d:'Накопи 9 жизней'},
  accuracy80:{t:'СНАЙПЕР',i:'?',d:'Точность 80%+ за игру'},
  round10:{t:'МАРАФОНЕЦ',i:'?',d:'Дойди до 10 раунда'},
  round20:{t:'ЛЕГЕНДА',i:'⭐',d:'Дойди до 20 раунда'},
  score5k:{t:'5000',i:'?',d:'Набери 5000 очков'},
  allArenas:{t:'СТРАННИК',i:'?️',d:'Побывай на всех 4 аренах'}
};
let achUnlocked={};
try{ achUnlocked=JSON.parse(localStorage.getItem('bron_ach_v2')||'{}') }catch(e){ achUnlocked={} }
function saveAch(){ try{ localStorage.setItem('bron_ach_v2', JSON.stringify(achUnlocked)) }catch(e){} }
function unlockAch(id){
  if(achUnlocked[id]) return;
  achUnlocked[id]=Date.now(); saveAch();
  const a=ACHS[id];
  const el=document.createElement('div'); el.className='ach';
  el.innerHTML='&lt;span class="ico"&gt;'+a.i+'&lt;/span&gt;&lt;div&gt;&lt;span class="tit"&gt;'+a.t+'&lt;/span&gt;&lt;span&gt;'+a.d+'&lt;/span&gt;&lt;/div&gt;';
  $('#achWrap').appendChild(el);
  SFX.ach();
  setTimeout(()=&gt;el.remove(), 4000);
  renderAchList();
}
function renderAchList(){
  const list=$('#achList'); list.innerHTML=''; let cnt=0;
  Object.keys(ACHS).forEach(id=&gt;{
    const a=ACHS[id], on=!!achUnlocked[id]; if(on) cnt++;
    const d=document.createElement('div'); 
    d.style.cssText = `border:1px solid ${on?'var(--am)':'var(--phd)'}; padding:8px; border-radius:6px; background:rgba(5,15,10,0.5); display:flex; gap:8px; align-items:center; color:${on?'var(--ph2)':'#4a5f4a'}`;
    d.innerHTML=`&lt;span style="font-size:18px"&gt;${on?a.i:'?'}&lt;/span&gt;&lt;div&gt;&lt;b style="color:${on?'var(--am)':'#4a5f4a'}"&gt;${a.t}&lt;/b&gt;&lt;br&gt;&lt;span style="font-size:10px"&gt;${a.d}&lt;/span&gt;&lt;/div&gt;`;
    list.appendChild(d);
  });
  $('#achCnt').textContent=cnt;
}
$('#achBtn').addEventListener('click', (e)=&gt;{ e.stopPropagation(); renderAchList(); $('#menuOv').classList.remove('show'); $('#achOv').classList.add('show'); });
$('#achClose').addEventListener('click', (e)=&gt;{ e.stopPropagation(); $('#achOv').classList.remove('show'); $('#menuOv').classList.add('show'); });

/* ══════ ТОП-3 ══════ */
let topScores=[];
try{ topScores=JSON.parse(localStorage.getItem('bron_top_v2')||'[]') }catch(e){ topScores=[] }
function saveTop(){ try{ localStorage.setItem('bron_top_v2', JSON.stringify(topScores)) }catch(e){} }
function addTopScore(s,k,r){
  topScores.push({s,k,r,d:new Date().toLocaleDateString('ru-RU',{day:'2-digit',month:'2-digit'})});
  topScores.sort((a,b)=&gt;b.s-a.s); topScores=topScores.slice(0,3); saveTop(); renderTopList();
}
function renderTopList(){
  const rows=$('#toprows'); rows.innerHTML='';
  if(!topScores.length){ rows.innerHTML='&lt;div class="toprow" style="justify-content:center;color:#4a5f4a"&gt;пока пусто&lt;/div&gt;'; return; }
  const medals=['?','?','?'];
  topScores.forEach((t,i)=&gt;{
    const d=document.createElement('div'); d.className='toprow';
    d.innerHTML=`&lt;span&gt;${medals[i]}&lt;/span&gt;&lt;span&gt;&lt;b&gt;${t.s}&lt;/b&gt; очк · Р${t.r}&lt;/span&gt;&lt;span&gt;${t.d}&lt;/span&gt;`;
    rows.appendChild(d);
  });
}
renderAchList(); renderTopList();

/* ══════ СОСТОЯНИЕ ══════ */
let state='menu', tSec=0;
let grid=new Uint8Array(GW*GH), deco=[], bushes=[], craters=[], stars=[];
for(let i=0;i&lt;120;i++) stars.push({x:R(0,W),y:R(0,H),r:R(.3,1.8),b:R(.2,.8),s:R(.02,.08)});
let bullets=[], parts=[], rings=[], floats=[], warns=[], pickups=[];
let enemies=[], bossPending=false, queue=[];
let spawnT=0;
let round=1, score=0, lives=3, kills=0, shots=0, hitsN=0, best=0;
try{ best=topScores.length?topScores[0].s:0 }catch(e){}
let streakN=0, lastKill=-99, streakOn=false, dblT=0;
let shake=0, recoil=0, shakeMul=RM?0:1, pMul=RM?.35:1;
let keys={}, firing=false, joyX=0, joyY=0;
let endTimer=null;
let visitedArenas=new Set();

const P={x:W/2,y:H-80,a:-Math.PI/2,r:15,barrel:24,sp:0,cd:0,inv:0,flash:0,rec:0,shield:false,rapidT:0,dead:false,dustT:0,engineT:0};
function curMult(){ return (streakOn?2:1)*(dblT&gt;0?2:1) }

const PAL={
  player:{tr:'#0d4a28',b1:'#39ff8a',b2:'#0d8a42',tu:'#a6ffc7',bar:'#0d4a28'},
  scout:{tr:'#4a3a10',b1:'#ffd23f',b2:'#b88a00',tu:'#ffe27a',bar:'#6a4a00'},
  assault:{tr:'#4a1512',b1:'#ff6a4d',b2:'#c92c14',tu:'#ff8d6e',bar:'#7a1a0a'},
  heavy:{tr:'#2a1a4a',b1:'#b06cff',b2:'#6a3aaa',tu:'#d4a4ff',bar:'#3a1a6a'},
  sniper:{tr:'#0f2a3a',b1:'#4fd6e0',b2:'#1a7a9e',tu:'#a6eff5',bar:'#0d4a60'},
  boss:{tr:'#2a0a0a',b1:'#ff4040',b2:'#8a1010',tu:'#ff8080',bar:'#4a0505'}
};
const ETYPES={
  scout:{hp:1,sp:115,turn:3.4,cool:2.1,bs:250,spread:.3,range:540,score:100,r:13,barrel:20},
  assault:{hp:1,sp:82,turn:2.6,cool:1.55,bs:275,spread:.22,range:470,score:150,r:15,barrel:24},
  heavy:{hp:3,sp:46,turn:1.7,cool:2.5,bs:300,spread:.07,range:640,score:300,r:19,barrel:28},
  sniper:{hp:1,sp:62,turn:2.2,cool:3.1,bs:390,spread:.02,range:820,score:250,r:13,barrel:32},
  boss:{hp:14,sp:40,turn:1.3,cool:2.1,bs:285,spread:.12,range:760,score:1000,r:34,barrel:46}
};

function cellAt(x,y){ const cx=(x/CS)|0, cy=(y/CS)|0; if(cx&lt;0||cy&lt;0||cx&gt;=GW||cy&gt;=GH) return 2; return grid[cy*GW+cx] }
function setc(x,y,v){ if(x&gt;=0&amp;&amp;y&gt;=0&amp;&amp;x&lt;GW&amp;&amp;y&lt;GH) grid[y*GW+x]=v }
function clearZone(px,py,rad){ for(let y=0;y&lt;GH;y++) for(let x=0;x&lt;GW;x++){ const dx=x*CS+16-px, dy=y*CS+16-py; if(hyp(dx,dy)&lt;rad) grid[y*GW+x]=0 } }
const SPAWNS=[[70,70],[W-70,70],[70,H-70],[W-70,H-70],[W/2,64]];

function genArena(){
  grid.fill(0); deco=[]; bushes=[];
  for(let i=0;i&lt;40;i++) deco.push({x:R(0,W),y:R(0,H),r:R(14,50),a:R(.02,.06),ph:R(0,6.28),s:R(.01,.04)});
  for(let k=0;k&lt;5;k++){ const y=RI(3,GH-6), x=RI(2,7), len=RI(2,4), vert=Math.random()&lt;.35;
    for(let j=0;j&lt;len;j++){ if(vert){ setc(x,y+j,1); setc(GW-1-x,y+j,1) } else { setc(x+j,y,1); setc(GW-1-x-j,y,1) } } }
  const spots=[[5,4],[9,9],[5,14]];
  for(let s2=0;s2&lt;spots.length;s2++){ if(Math.random()&lt;.8){ const sx=spots[s2][0], sy=spots[s2][1];
    setc(sx,sy,2); setc(sx+1,sy,2); setc(sx,sy+1,2); setc(sx+1,sy+1,2);
    setc(GW-2-sx,sy,2); setc(GW-1-sx,sy,2); setc(GW-2-sx,sy+1,2); setc(GW-1-sx,sy+1,2); } }
  for(let b=0;b&lt;5;b++) bushes.push({x:R(80,W-80),y:R(80,H-80),r:R(26,40),s:R(0,7)});
  SPAWNS.forEach(p=&gt;clearZone(p[0],p[1],80));
  clearZone(W/2,H-80,90);
}
function circleBlocked(x,y,r){
  const x0=Math.max(0,((x-r)/CS)|0), x1=Math.min(GW-1,((x+r)/CS)|0), y0=Math.max(0,((y-r)/CS)|0), y1=Math.min(GH-1,((y+r)/CS)|0);
  for(let cy=y0;cy&lt;=y1;cy++) for(let cx=x0;cx&lt;=x1;cx++){ if(grid[cy*GW+cx]){ const rx=cx*CS, ry=cy*CS, nx=clamp(x,rx,rx+CS), ny=clamp(y,ry,ry+CS); if(hyp(x-nx,y-ny)&lt;r) return true; } }
  return false;
}
function los(x1,y1,x2,y2){ const d=hyp(x2-x1,y2-y1), n=(d/14)|0; for(let i=1;i&lt;n;i++){ const x=x1+(x2-x1)*i/n, y=y1+(y2-y1)*i/n; if(cellAt(x,y)&gt;0) return false } return true }

function addShake(v){ shake=Math.min(20,shake+v*shakeMul) }
function addRecoil(v){ recoil=Math.min(8,recoil+v*shakeMul) }
function flash(dom){ const el=$(dom); el.style.opacity='1'; setTimeout(()=&gt;el.style.opacity='0', 200); }

function fade(show,cb){
  const f=$('#fade');
  if(show){ f.classList.add('on'); setTimeout(cb||function(){}, 800); }
  else { setTimeout(()=&gt;{ f.classList.remove('on'); if(cb) cb(); }, 50); }
}

function floatTxt(x,y,txt,col,big){ floats.push({x,y,txt,col:col||'#a6ffc7',t:1.2,big}); if(floats.length&gt;24) floats.shift() }
function ringFx(x,y,c,r0){ rings.push({x,y,r:r0||8,vr:RM?120:260,a:.9,col:c}) }
function part(p){ parts.push(p); if(parts.length&gt;360) parts.shift() }

function boom(x,y,s,col,extra){
  const n=Math.round((16*s+4)*pMul);
  for(let i=0;i&lt;n;i++){ const a=R(0,6.28), v=R(30,190)*s; part({tp:'fire',x,y,vx:Math.cos(a)*v,vy:Math.sin(a)*v,t:R(.25,.5),m:.5,r:R(3,7)*s,c:i%3?col:'#a6ffc7'}) }
  for(let i=0;i&lt;8*s*pMul;i++){ const a=R(0,6.28); part({tp:'smoke',x:x+R(-8,8),y:y+R(-8,8),vx:Math.cos(a)*R(10,40),vy:Math.sin(a)*R(10,40)-20,t:R(.5,.9),m:.9,r:R(6,12)*s}) }
  for(let i=0;i&lt;7*s*pMul;i++){ const a=R(0,6.28); part({tp:'deb',x,y,vx:Math.cos(a)*R(60,240)*s,vy:Math.sin(a)*R(60,240)*s,t:R(.4,.8),m:.8,r:R(2,4),a2:R(0,6.28),vr:R(-8,8),c:col}) }
  if(extra){ for(let i=0;i&lt;12*s*pMul;i++){ const a=R(0,6.28), v=R(50,160)*s; part({tp:'spark',x,y,vx:Math.cos(a)*v,vy:Math.sin(a)*v,t:R(.15,.35),m:.35,c:extra}) } }
  part({tp:'flash',x,y,t:.12,m:.12,r:26*s});
  ringFx(x,y,col,10);
  if(s&gt;1){ craters.push({x,y,r:R(14,22)*Math.min(s,1.4)}); if(craters.length&gt;60) craters.shift() }
  addShake(5*s); SFX.boom(Math.min(s,1.4));
  if(s&gt;1.5) flash('#fxgold');
}
function turretFly(e){ part({tp:'tur',x:e.x,y:e.y,vx:R(-90,90),vy:R(-120,-30),t:1,m:1,r:e.r*.55,a2:e.a,vr:R(-7,7),pal:PAL[e.type]||PAL.assault}) }
function sparks(x,y,n){ for(let i=0;i&lt;n*pMul;i++){ const a=R(0,6.28); part({tp:'spark',x,y,vx:Math.cos(a)*R(80,260),vy:Math.sin(a)*R(80,260),t:R(.15,.3),m:.3,c:'#a6ffc7'}) } }
function dust(x,y){ part({tp:'dust',x,y,vx:R(-8,8),vy:R(-8,8),t:.5,m:.5,r:R(3,6)}) }

let lastLives=-1, lastScore=-1, lastFoes=-1, lastQueue='';
function syncHUD(){
  if(lives!==lastLives){ lastLives=lives; let h=''; for(let i=0;i&lt;lives;i++) h+='&lt;span class="life"&gt;&lt;/span&gt;'; $('#hudLives').innerHTML=h }
  if(score!==lastScore){ lastScore=score; $('#hudScore').textContent=score }
  $('#hudRound').textContent=round;
  $('#hudMult').style.display=(streakOn||dblT&gt;0)?'inline':'none';
  $('#hudMult').textContent='×'+curMult();
  const rem=queue.length+warns.length+enemies.length;
  if(rem!==lastFoes){ lastFoes=rem; let f=''; for(let i=0;i&lt;rem;i++) f+='&lt;span class="foe"&gt;&lt;/span&gt;'; $('#hudFoes').innerHTML=f||'&lt;span style="color:var(--ph);font-size:9px"&gt;ЧИСТО&lt;/span&gt;' }
  const boss=enemies.find(e=&gt;e.type==='boss');
  $('#bossbar').classList.toggle('on',!!boss);
  if(boss) $('#bossfill').style.width=(boss.hp/boss.maxHp*100)+'%';
  
  const qstr=queue.slice(0,5).join(',')+(queue.length&gt;5?'+'+(queue.length-5):'');
  if(qstr!==lastQueue){
    lastQueue=qstr;
    const mm=$('#minimap'); mm.innerHTML='&lt;span class="ml"&gt;ОЧЕРЕДЬ&lt;/span&gt;';
    queue.slice(0,5).forEach(t=&gt;{
      const m=document.createElement('span'); m.className='mi';
      const c=PAL[t]?PAL[t].b1:'#fff';
      m.style.background=c; m.style.boxShadow='0 0 6px '+c;
      mm.appendChild(m);
    });
    if(queue.length&gt;5){ const more=document.createElement('span'); more.className='ml'; more.textContent='+'+(queue.length-5); mm.appendChild(more) }
  }
}

function fireBullet(t,foe,spread,bs,big){
  const a=t.a+R(-spread,spread), sp=bs;
  bullets.push({x:t.x+Math.cos(a)*(t.r+t.barrel),y:t.y+Math.sin(a)*(t.r+t.barrel),vx:Math.cos(a)*sp,vy:Math.sin(a)*sp,foe,r:big?6:4.2,big});
  t.flash=.07; t.rec=1;
  if(!foe) addRecoil(3);
}
function playerFire(){ if(P.cd&gt;0||P.dead) return; P.cd=P.rapidT&gt;0?.22:.45; fireBullet(P,false,.03,430); shots++; SFX.shoot() }

function hitPlayer(){
  if(P.inv&gt;0||P.dead||state!=='playing') return;
  if(P.shield){ P.shield=false; P.inv=1; ringFx(P.x,P.y,'#4fd6e0',20); SFX.ping(); floatTxt(P.x,P.y-30,'ЩИТ ПОГАС','#4fd6e0'); flash('#fxblue'); return }
  lives--; P.inv=2; flash('#fxred'); addShake(13); SFX.hurt();
  boom(P.x,P.y,.7,'#ff8d6e','#ffb400');
  floatTxt(P.x,P.y-34,'−1 ❤','#ff5340'); syncHUD();
  if(lives&lt;=0){ P.dead=true; turretFly({x:P.x,y:P.y,r:P.r,a:P.a,type:'player'}); boom(P.x,P.y,2,'#39ff8a','#a6ffc7'); state='dying'; SFX.over(); setTimeout(showGameOver,1400) }
}
function killEnemy(e){
  e.dead=true; kills++;
  if(kills===1) unlockAch('firstBlood');
  const mult=curMult(), pts=e.score*mult; score+=pts;
  if(score&gt;=5000) unlockAch('score5k');
  const extra=e.type==='boss'?'#ffb400':null;
  boom(e.x,e.y,e.type==='boss'?2.4:1.1,PAL[e.type].b1,extra);
  turretFly(e);
  floatTxt(e.x,e.y-30,'+'+pts,'#a6ffc7',e.type==='boss');
  if(e.type==='boss') unlockAch('bossKill');
  if(lives&lt;9){ lives++; flash('#fxgold'); SFX.life(); floatTxt(e.x,e.y-52,'+1 ЖИЗНЬ','#a6ffc7'); if(lives===9) unlockAch('nineLives') }
  if(tSec-lastKill&lt;4) streakN++; else streakN=1;
  lastKill=tSec;
  if(streakN&gt;=3&amp;&amp;!streakOn){ streakOn=true; floatTxt(P.x,P.y-40,'СЕРИЯ ×2!','#ffb400',true); flash('#fxgold') }
  if(streakN&gt;=10) unlockAch('streak10');
  updateComboDisplay(); rollPickup(e); syncHUD();
  if(state==='playing'&amp;&amp;!queue.length&amp;&amp;!warns.length&amp;&amp;!enemies.some(o=&gt;!o.dead)){ state='clearing'; setTimeout(roundEnd,900) }
}
function updateComboDisplay(){
  const el=$('#comboDisplay'), num=$('#comboNum');
  if(streakN&gt;=3){ num.textContent=streakN; el.classList.add('show') } else { el.classList.remove('show') }
}
function damageEnemy(e,b){ if(e.spawnT&gt;0) return; e.hp--; hitsN++; sparks(b.x,b.y,6); SFX.ping(); if(e.hp&lt;=0) killEnemy(e) }
function rollPickup(e){
  const ch=e.type==='boss'?1:.2; if(Math.random()&gt;ch) return;
  const r=Math.random(), tp=r&lt;.3?'shield':r&lt;.6?'rapid':r&lt;.9?'double':'life';
  pickups.push({x:clamp(e.x,40,W-40),y:clamp(e.y,40,H-40),tp,t:8,ph:R(0,6)})
}
function buildQueue(n){
  queue=[];
  if(n%5===0){ bossPending=true; for(let i=0;i&lt;4;i++) queue.push(Math.random()&lt;.5?'scout':'assault'); return }
  const total=Math.min(4+2*(n-1),16);
  for(let i=0;i&lt;total;i++){ let r=Math.random(), t; if(n&lt;2) t=r&lt;.55?'scout':'assault';
    else if(n&lt;4) t=r&lt;.4?'scout':r&lt;.75?'assault':'heavy';
    else t=r&lt;.34?'scout':r&lt;.62?'assault':r&lt;.82?'heavy':'sniper';
    queue.push(t) }
}
function hideAll(){ ['menuOv','introOv','endOv','overOv','pauseOv','achOv'].forEach(id=&gt;$('#'+id).classList.remove('show')) }

function roundIntro(n){
  arenaIdx=Math.floor((n-1)/5)%ARENAS.length;
  arena=ARENAS[arenaIdx];
  visitedArenas.add(arenaIdx);
  if(visitedArenas.size===4) unlockAch('allArenas');
  $('#arenaTag').textContent=arena.name;
  fade(true, ()=&gt;{
    round=n; buildQueue(n); genArena();
    bullets=[]; pickups=[]; warns=[]; enemies=[]; parts=[]; rings=[];
    P.x=W/2; P.y=H-80; P.a=-Math.PI/2; P.inv=1.5; P.cd=0; P.dead=false; P.rapidT=0; dblT=0; streakOn=false; streakN=0;
    updateComboDisplay(); spawnT=1;
    const en=queue.length+(bossPending?1:0);
    $('#introT').textContent='РАУНД '+n+(n%5===0?' · БОСС':'');
    $('#introP').innerHTML=(n%5===0?'⚠ &lt;b&gt;БОСС&lt;/b&gt; на арене! ':'')+'Арена: &lt;b&gt;'+arena.name+'&lt;/b&gt; · Врагов: &lt;b&gt;'+en+'&lt;/b&gt;'+(n%3===0?' · в конце &lt;b&gt;+1 жизнь&lt;/b&gt;':'');
    hideAll(); $('#introOv').classList.add('show'); syncHUD();
    setTimeout(()=&gt;{ fade(false, ()=&gt;{ $('#introOv').classList.remove('show'); state='playing' }) }, 1400);
  });
}
function roundEnd(){
  if(state!=='clearing') return; state='roundend'; SFX.fanfare();
  if(round&gt;=10) unlockAch('round10'); if(round&gt;=20) unlockAch('round20');
  const bonus=round%3===0&amp;&amp;lives&lt;9;
  if(round%3===0){ lives=Math.min(9,lives+1); flash('#fxgold'); syncHUD() }
  $('#endT').textContent='РАУНД '+round+' ЗАЧИЩЕН';
  $('#endP').innerHTML='Жизни: &lt;b&gt;'+lives+'&lt;/b&gt;'+(bonus?' · бонус &lt;b&gt;+1&lt;/b&gt;!':'')+' · Счёт: &lt;b&gt;'+score+'&lt;/b&gt;';
  hideAll(); $('#endOv').classList.add('show');
  let c=3; $('#endCd').textContent=c;
  clearInterval(endTimer); endTimer=setInterval(()=&gt;{ c--; if(c&gt;0) $('#endCd').textContent=c; else { clearInterval(endTimer); roundIntro(round+1) } }, 1000);
}
function showGameOver(){
  state='gameover';
  if(shots&amp;&amp;hitsN/shots&gt;=.8&amp;&amp;kills&gt;=5) unlockAch('accuracy80');
  if(score&gt;best){ best=score }
  addTopScore(score,kills,round);
  $('#sK').textContent=kills; $('#sA').textContent=(shots?Math.round(hitsN/shots*100):0)+'%';
  $('#sR').textContent=round; $('#sS').textContent=score; $('#sB').textContent=best;
  hideAll(); $('#overOv').classList.add('show');
  stopMusic();
}
function fullReset(){ score=0; lives=3; kills=0; shots=0; hitsN=0; craters=[]; lastLives=-1; lastScore=-1; lastFoes=-1; lastQueue=''; streakN=0; streakOn=false; dblT=0; visitedArenas=new Set(); updateComboDisplay(); renderTopList(); roundIntro(1); if(!muted &amp;&amp; audioInitialized) startMusic() }

function fieldCount(){ return enemies.length+warns.length }
function updSpawn(dt){
  if(bossPending){ bossPending=false; warns.push({x:W/2,y:96,t:1.3,type:'boss'}); SFX.bossAlert(); flash('#fxred') }
  spawnT-=dt;
  const cap=round%5===0?5:4;
  if(spawnT&lt;=0&amp;&amp;queue.length&amp;&amp;fieldCount()&lt;cap){
    const type=queue.shift(), pts=SPAWNS.filter(p=&gt;hyp(p[0]-P.x,p[1]-P.y)&gt;200);
    const pt=(pts.length?pts:SPAWNS)[RI(0,(pts.length?pts:SPAWNS).length-1)];
    warns.push({x:pt[0],y:pt[1],t:.85,type});
    spawnT=Math.max(.75,1.5-(round-1)*.07);
  }
  for(let i=warns.length-1;i&gt;=0;i--){ const w=warns[i]; w.t-=dt; if(w.t&lt;=0){ warns.splice(i,1); spawnEnemy(w.type,w.x,w.y) } }
}
function spawnEnemy(type,x,y){
  const T=ETYPES[type], sc=Math.min(1.5,1+(round-1)*.05);
  const e={type,x,y,a:Math.atan2(P.y-y,P.x-x),r:T.r,hp:type==='boss'?12+round:T.hp,sp:T.sp*sc,turn:T.turn,cool:R(.5,T.cool),cool2:1.4,bs:T.bs,spread:T.spread,range:T.range,score:T.score,barrel:T.barrel,flash:0,rec:0,spawnT:.35,dead:false,avoidT:0,avoidDir:1,orbitDir:Math.random()&lt;.5?1:-1,orbitT:R(2,5),aiming:false,aimT:0,aimX:0,aimY:0,dodgeCd:0,dodgeT:0,dodgeDir:1,dustT:0,phase:0,phaseTimer:0};
  e.maxHp=e.hp;
  enemies.push(e); ringFx(x,y,PAL[type].b1,e.r+6); noiz(.15,.06,900);
  if(type==='boss'){ for(let i=0;i&lt;6;i++){ const a=i/6*Math.PI*2; part({tp:'fire',x:x+Math.cos(a)*20,y:y+Math.sin(a)*20,vx:Math.cos(a)*30,vy:Math.sin(a)*30,t:.5,m:.5,r:4,c:'#ff4040'}) } }
}
function moveEnt(t,dt,spd){
  let nx=t.x+Math.cos(t.a)*spd*dt, ny=t.y+Math.sin(t.a)*spd*dt, moved=0;
  if(!circleBlocked(nx,t.y,t.r)){ t.x=nx; moved+=Math.abs(spd*dt) }
  if(!circleBlocked(t.x,ny,t.r)){ t.y=ny; moved+=Math.abs(spd*dt) }
  t.x=clamp(t.x,t.r+4,W-t.r-4); t.y=clamp(t.y,t.r+4,H-t.r-4); return moved;
}
function updEnemy(e,dt){
  if(e.spawnT&gt;0){ e.spawnT-=dt; return }
  e.flash=Math.max(0,e.flash-dt); e.rec=Math.max(0,e.rec-dt*4); e.cool-=dt; e.dodgeCd-=dt; e.dodgeT-=dt;
  if(e.type==='boss'){ e.phaseTimer-=dt; if(e.phaseTimer&lt;=0){ e.phase=(e.phase+1)%3; e.phaseTimer=3+R(0,2);
    if(e.phase===1) floatTxt(e.x,e.y-40,'РЕЖИМ ОГНЯ','#ffb400',true);
    if(e.phase===2) floatTxt(e.x,e.y-40,'УСКОРЕНИЕ','#4fd6e0',true) } }
  const dx=P.x-e.x, dy=P.y-e.y, dist=hyp(dx,dy), ang=Math.atan2(dy,dx);
  if(e.dodgeCd&lt;=0&amp;&amp;e.type!=='boss'){ for(let i=0;i&lt;bullets.length;i++){ const b=bullets[i]; if(b.foe) continue; const bd=hyp(b.x-e.x,b.y-e.y);
    if(bd&lt;110){ const movingToward=((e.x-b.x)*b.vx+(e.y-b.y)*b.vy)&gt;0; if(movingToward&amp;&amp;Math.random()&lt;(e.type==='scout'?.75:e.type==='sniper'?.5:.4)){ e.dodgeT=.35; e.dodgeDir=Math.random()&lt;.5?1:-1; e.dodgeCd=1.1; break } } } }
  if(e.dodgeT&gt;0){ e.a+=e.dodgeDir*e.turn*1.4*dt; moveEnt(e,dt,e.sp); return }
  let desired=ang, moveF=1;
  if(e.type==='scout'){ e.orbitT-=dt; if(e.orbitT&lt;=0){ e.orbitDir*=-1; e.orbitT=R(2.5,5) }
    if(dist&gt;240) desired=ang; else if(dist&lt;160) desired=ang+Math.PI; else desired=ang+e.orbitDir*Math.PI/2;
    if(e.cool&lt;=0&amp;&amp;Math.abs(angDiff(e.a,ang))&lt;.5&amp;&amp;dist&lt;e.range){ fireBullet(e,true,e.spread,e.bs); e.cool=ETYPES.scout.cool*Math.max(.6,1-(round-1)*.04); SFX.eshoot() } }
  else if(e.type==='assault'){ if(dist&gt;160) desired=ang; else desired=ang+e.orbitDir*.9;
    e.orbitT-=dt; if(e.orbitT&lt;=0){ e.orbitDir*=-1; e.orbitT=R(2,4) }
    moveF=dist&lt;110?.4:1;
    if(e.cool&lt;=0&amp;&amp;Math.abs(angDiff(e.a,ang))&lt;.45&amp;&amp;dist&lt;e.range){ fireBullet(e,true,e.spread,e.bs); e.cool=ETYPES.assault.cool*Math.max(.6,1-(round-1)*.04); SFX.eshoot() } }
  else if(e.type==='heavy'){ if(dist&gt;280) desired=ang; else moveF=0;
    if(e.cool&lt;=0&amp;&amp;Math.abs(angDiff(e.a,ang))&lt;.3&amp;&amp;dist&lt;e.range){ fireBullet(e,true,e.spread,e.bs,true); e.cool=ETYPES.heavy.cool*Math.max(.6,1-(round-1)*.04); SFX.eshoot(); addShake(2) } }
  else if(e.type==='sniper'){ if(e.aiming){ e.aimT-=dt; e.aimX=P.x; e.aimY=P.y; e.a+=angDiff(e.a,ang)*4*dt;
    if(e.aimT&lt;=0){ e.aiming=false; fireBullet(e,true,e.spread,e.bs); e.cool=ETYPES.sniper.cool*Math.max(.6,1-(round-1)*.04) } return }
    if(dist&gt;360) desired=ang; else if(dist&lt;240) desired=ang+Math.PI; else moveF=.3;
    if(e.cool&lt;=0&amp;&amp;dist&lt;e.range&amp;&amp;los(e.x,e.y,P.x,P.y)){ e.aiming=true; e.aimT=1; e.aimX=P.x; e.aimY=P.y; SFX.laser(); moveF=0 } }
  else if(e.type==='boss'){ const phaseSpeed=e.phase===2?1.6:1;
    if(dist&gt;250) desired=ang; else if(dist&lt;170) desired=ang+Math.PI; else desired=ang+.7;
    moveF=.7*phaseSpeed; const fireRate=e.phase===1?.7:1;
    if(e.cool&lt;=0&amp;&amp;Math.abs(angDiff(e.a,ang))&lt;.5){ const count=e.phase===1?5:3;
      for(let s=0;s&lt;count;s++){ const spread=(s-(count-1)/2)*.15; fireBullet(e,true,spread,e.bs) }
      e.cool=ETYPES.boss.cool*fireRate; SFX.eshoot(); addShake(4) }
    e.cool2-=dt; if(e.cool2&lt;=0&amp;&amp;Math.abs(angDiff(e.a,ang))&lt;.35){ fireBullet(e,true,.03,e.bs+60,true); e.cool2=1.5; SFX.eshoot() } }
  if(e.avoidT&gt;0){ e.avoidT-=dt; desired=e.a+e.avoidDir*1.2; moveF=1 }
  e.a+=clamp(angDiff(e.a,desired),-e.turn*dt,e.turn*dt);
  if(moveF&gt;0){ const intent=e.sp*moveF*dt, moved=moveEnt(e,dt,e.sp*moveF);
    if(moved&lt;intent*.3&amp;&amp;e.avoidT&lt;=0){ e.avoidT=.7; e.avoidDir=Math.random()&lt;.5?1:-1 }
    e.dustT-=dt; if(e.dustT&lt;=0){ dust(e.x-Math.cos(e.a)*e.r,e.y-Math.sin(e.a)*e.r); e.dustT=.12 } }
  for(let j=0;j&lt;enemies.length;j++){ const o=enemies[j]; if(o===e||o.dead) continue; const d2=hyp(o.x-e.x,o.y-e.y), min=e.r+o.r+4;
    if(d2&lt;min&amp;&amp;d2&gt;0){ const push=(min-d2)/2, ax=(e.x-o.x)/d2, ay=(e.y-o.y)/d2;
      if(!circleBlocked(e.x+ax*push,e.y+ay*push,e.r)){ e.x+=ax*push; e.y+=ay*push } } }
}

function update(dt){
  tSec+=dt;
  P.cd-=dt; P.inv=Math.max(0,P.inv-dt); P.flash=Math.max(0,P.flash-dt); P.rec=Math.max(0,P.rec-dt*4);
  P.rapidT=Math.max(0,P.rapidT-dt); dblT=Math.max(0,dblT-dt);
  recoil=Math.max(0,recoil-dt*24);
  if(streakOn&amp;&amp;tSec-lastKill&gt;4){ streakOn=false; updateComboDisplay() }
  if(state==='playing'||state==='clearing'){
    if(!P.dead){
      let fwd=0, turn=0;
      if(keys.KeyW||keys.ArrowUp) fwd=1; if(keys.KeyS||keys.ArrowDown) fwd=-1;
      if(keys.KeyA||keys.ArrowLeft) turn=-1; if(keys.KeyD||keys.ArrowRight) turn=1;
      // Управление с джойстика
      if(Math.abs(joyX)&gt;.15||Math.abs(joyY)&gt;.15){ turn=joyX; fwd=-joyY }
      P.a+=turn*3.2*dt;
      const sp=fwd&gt;0?155:fwd&lt;0?-95:0;
      if(sp){ const moved=moveEnt(P,dt,sp); P.dustT-=dt; if(P.dustT&lt;=0&amp;&amp;moved&gt;0){ dust(P.x-Math.cos(P.a)*P.r,P.y-Math.sin(P.a)*P.r); P.dustT=.09 }
        if(moved&gt;10){ P.engineT+=dt; if(P.engineT&gt;.04){ P.engineT=0; for(let i=0;i&lt;2;i++){ const a=P.a+Math.PI+R(-.5,.5), v=R(10,25);
          part({tp:'smoke',x:P.x-Math.cos(P.a)*P.r+R(-4,4),y:P.y-Math.sin(P.a)*P.r+R(-4,4),vx:Math.cos(a)*v,vy:Math.sin(a)*v-R(2,8),t:R(.3,.5),m:.5,r:R(3,6)}) } } } }
      if(firing||keys.Space) playerFire();
    }
    if(state==='playing') updSpawn(dt);
    for(let i=enemies.length-1;i&gt;=0;i--){ const e=enemies[i]; if(e.dead){ enemies.splice(i,1); continue } updEnemy(e,dt) }
    for(let i=bullets.length-1;i&gt;=0;i--){
      const b=bullets[i]; b.x+=b.vx*dt; b.y+=b.vy*dt; let del=false;
      if(b.x&lt;4||b.y&lt;4||b.x&gt;W-4||b.y&gt;H-4){ del=true } else {
        const v=cellAt(b.x,b.y);
        if(v===1){ grid[((b.y/CS)|0)*GW+((b.x/CS)|0)]=0; SFX.brick(); sparks(b.x,b.y,5);
          for(let k=0;k&lt;5*pMul;k++) part({tp:'deb',x:b.x,y:b.y,vx:R(-90,90),vy:R(-90,90),t:.5,m:.5,r:R(2,3.5),a2:R(0,6.28),vr:R(-9,9),c:arena.brick});
          craters.push({x:b.x,y:b.y,r:9}); if(craters.length&gt;60) craters.shift(); del=true }
        else if(v===2){ sparks(b.x,b.y,7); SFX.ping(); del=true } }
      if(!del){ if(b.foe){ if(!P.dead&amp;&amp;hyp(b.x-P.x,b.y-P.y)&lt;P.r+b.r){ hitPlayer(); del=true } }
        else { for(let j=0;j&lt;enemies.length;j++){ const en=enemies[j]; if(en.spawnT&gt;0) continue; if(hyp(b.x-en.x,b.y-en.y)&lt;en.r+b.r){ damageEnemy(en,b); del=true; break } } } }
      if(del) bullets.splice(i,1);
    }
    for(let i=pickups.length-1;i&gt;=0;i--){ const pk=pickups[i]; pk.t-=dt; pk.ph+=dt*4;
      if(pk.t&lt;=0){ pickups.splice(i,1); continue }
      if(!P.dead&amp;&amp;hyp(pk.x-P.x,pk.y-P.y)&lt;P.r+18){
        let txt='', col='#a6ffc7';
        if(pk.tp==='shield'){ P.shield=true; txt='ЩИТ'; col='#4fd6e0'; flash('#fxblue') }
        else if(pk.tp==='rapid'){ P.rapidT=8; txt='ОГОНЬ x2'; col='#a6ffc7'; flash('#fxgold') }
        else if(pk.tp==='double'){ dblT=10; txt='ОЧКИ x2'; col='#ffb400'; flash('#fxgold') }
        else { lives=Math.min(9,lives+1); txt='+1 ЖИЗНЬ'; col='#39ff8a'; flash('#fxgold') }
        floatTxt(pk.x,pk.y-24,txt,col); SFX.pick(); ringFx(pk.x,pk.y,col,14); flash('#fxpickup');
        pickups.splice(i,1); syncHUD();
      } }
  }
  for(let i=parts.length-1;i&gt;=0;i--){ const p=parts[i]; p.t-=dt; if(p.t&lt;=0){ parts.splice(i,1); continue }
    p.x+=(p.vx||0)*dt; p.y+=(p.vy||0)*dt;
    if(p.tp==='deb'||p.tp==='tur'){ p.vx*=.96; p.vy*=.96; p.a2+=(p.vr||0)*dt }
    if(p.tp==='smoke') p.r+=8*dt }
  for(let i=rings.length-1;i&gt;=0;i--){ const r=rings[i]; r.r+=r.vr*dt; r.a-=dt*2.2; if(r.a&lt;=0) rings.splice(i,1) }
  for(let i=floats.length-1;i&gt;=0;i--){ const f=floats[i]; f.t-=dt; f.y-=28*dt; if(f.t&lt;=0) floats.splice(i,1) }
  shake=Math.max(0,shake-dt*30); syncHUD();
}

function drawTank(t,pal,alpha){
  ctx.save(); ctx.globalAlpha=alpha===undefined?1:alpha;
  ctx.translate(t.x,t.y);
  ctx.fillStyle='rgba(0,0,0,.4)'; ctx.beginPath(); ctx.ellipse(2,4,t.r*1.2,t.r*.95,0,0,7); ctx.fill();
  ctx.rotate(t.a);
  const rec=(t.rec||0)*4;
  ctx.fillStyle=pal.tr; rr(-t.r,-t.r-3,t.r*2,7,3); ctx.fill(); rr(-t.r,t.r-4,t.r*2,7,3); ctx.fill();
  ctx.fillStyle='rgba(0,0,0,.4)';
  for(let i=-t.r+3;i&lt;t.r-2;i+=6){ ctx.fillRect(i,-t.r-2,2,5); ctx.fillRect(i,t.r-3,2,5) }
  const g=ctx.createLinearGradient(0,-t.r,0,t.r); g.addColorStop(0,pal.b1); g.addColorStop(1,pal.b2);
  ctx.fillStyle=g; rr(-t.r,-t.r+3,t.r*2,t.r*2-6,5); ctx.fill();
  ctx.strokeStyle='rgba(0,0,0,.5)'; ctx.lineWidth=2; ctx.stroke();
  if(t.type==='heavy'||t.type==='boss'){ ctx.fillStyle='rgba(0,0,0,.3)'; ctx.fillRect(-t.r+4,-t.r+6,4,t.r*2-12); ctx.fillRect(t.r-8,-t.r+6,4,t.r*2-12) }
  ctx.fillStyle=pal.bar; ctx.fillRect(t.r*.2-2,-3,t.r+t.barrel-rec-t.r*.2+2,6);
  ctx.fillStyle='rgba(255,255,255,.3)'; ctx.fillRect(t.r*.2,-3,t.r+t.barrel-rec-t.r*.2,2);
  if(t.rapidT&gt;0&amp;&amp;t===P){ ctx.shadowColor='#a6ffc7'; ctx.shadowBlur=12 }
  const g2=ctx.createRadialGradient(-2,-2,1,0,0,t.r*.6); g2.addColorStop(0,pal.tu); g2.addColorStop(1,pal.b2);
  ctx.fillStyle=g2; ctx.beginPath(); ctx.arc(-rec*.4,0,t.r*.58,0,7); ctx.fill();
  ctx.strokeStyle='rgba(0,0,0,.5)'; ctx.stroke(); ctx.shadowBlur=0;
  ctx.restore();
  if(t.flash&gt;0){
    const mx=t.x+Math.cos(t.a)*(t.r+t.barrel), my=t.y+Math.sin(t.a)*(t.r+t.barrel);
    ctx.save(); ctx.translate(mx,my); ctx.rotate(R(0,6.28));
    ctx.fillStyle='rgba(255,255,220,.95)'; ctx.shadowColor='#a6ffc7'; ctx.shadowBlur=20;
    ctx.beginPath(); for(let s=0;s&lt;8;s++){ const rr2=s%2?4:11; ctx.lineTo(Math.cos(s*Math.PI/4)*rr2,Math.sin(s*Math.PI/4)*rr2) }
    ctx.closePath(); ctx.fill(); ctx.restore();
  }
  if(t.maxHp&amp;&amp;t.hp&lt;t.maxHp&amp;&amp;t.type!=='boss'){
    ctx.fillStyle='rgba(0,0,0,.6)'; ctx.fillRect(t.x-16,t.y-t.r-14,32,5);
    const hpCol=t.hp/t.maxHp&gt;.5?'#39ff8a':t.hp/t.maxHp&gt;.25?'#ffb400':'#ff5340';
    ctx.fillStyle=hpCol; ctx.fillRect(t.x-15,t.y-t.r-13,30*t.hp/t.maxHp,3);
  }
}

function draw(){
  ctx.save();
  ctx.fillStyle = arena.bg2;
  ctx.fillRect(0,0,W,H);

  if(shake&gt;0) ctx.translate(R(-shake,shake)*.5,R(-shake,shake)*.5);
  if(recoil&gt;0&amp;&amp;!P.dead){ ctx.translate(-Math.cos(P.a)*recoil,-Math.sin(P.a)*recoil) }
  
  const gg=ctx.createRadialGradient(W/2,H/2,100,W/2,H/2,620); gg.addColorStop(0,arena.bg1); gg.addColorStop(1,arena.bg2);
  ctx.fillStyle=gg; ctx.fillRect(-20,-20,W+40,H+40);
  
  ctx.strokeStyle=arena.gridC; ctx.lineWidth=1;
  for(let x=0;x&lt;=GW;x++){ ctx.beginPath(); ctx.moveTo(x*CS,0); ctx.lineTo(x*CS,H); ctx.stroke() }
  for(let y=0;y&lt;=GH;y++){ ctx.beginPath(); ctx.moveTo(0,y*CS); ctx.lineTo(W,y*CS); ctx.stroke() }
  
  stars.forEach(s=&gt;{ ctx.globalAlpha=s.b*(0.6+0.4*Math.sin(tSec*s.s)); ctx.fillStyle=arena.starC; ctx.beginPath(); ctx.arc(s.x,s.y,s.r,0,7); ctx.fill() }); ctx.globalAlpha=1;
  deco.forEach(d=&gt;{ ctx.fillStyle=arena.decoC+(d.a+0.08*Math.sin(tSec*d.s))+')'; ctx.beginPath(); ctx.ellipse(d.x,d.y,d.r,d.r*.7,0,0,7); ctx.fill() });
  craters.forEach(c=&gt;{ ctx.fillStyle='rgba(0,0,0,.5)'; ctx.beginPath(); ctx.ellipse(c.x,c.y,c.r,c.r*.8,0,0,7); ctx.fill();
    ctx.strokeStyle=arena.decoC+'.2)'; ctx.lineWidth=2; ctx.beginPath(); ctx.ellipse(c.x,c.y-2,c.r*.8,c.r*.6,0,Math.PI,6.28); ctx.stroke() });
    
  for(let cy=0;cy&lt;GH;cy++) for(let cx=0;cx&lt;GW;cx++){ const v=grid[cy*GW+cx]; if(!v) continue; const px=cx*CS, py=cy*CS;
    if(v===1){ ctx.fillStyle=arena.brick; ctx.fillRect(px,py,CS,CS); ctx.fillStyle='rgba(0,0,0,.4)'; ctx.fillRect(px,py+14,CS,3); ctx.fillRect(px+14,py,3,14); ctx.fillRect(px+6,py+17,3,15); ctx.strokeStyle=arena.brickBrd; ctx.lineWidth=1.5; ctx.strokeRect(px+1,py+1,CS-2,CS-2) }
    else { ctx.fillStyle=arena.steel; ctx.fillRect(px,py,CS,CS); ctx.strokeStyle=arena.steelBrd; ctx.lineWidth=2; ctx.strokeRect(px+1,py+1,CS-2,CS-2); ctx.fillStyle=arena.steelBrd; [[6,6],[26,6],[6,26],[26,26]].forEach(q=&gt;{ ctx.beginPath(); ctx.arc(px+q[0],py+q[1],2,0,7); ctx.fill() }) } }
    
  warns.forEach(w=&gt;{ const pl=.5+.5*Math.sin(tSec*12); ctx.strokeStyle='rgba(255,180,0,'+(0.35+pl*.5)+')'; ctx.lineWidth=3; ctx.beginPath(); ctx.arc(w.x,w.y,(w.type==='boss'?44:24)+pl*6,0,7); ctx.stroke(); ctx.fillStyle='rgba(255,180,0,.9)'; ctx.font='700 16px Courier New'; ctx.textAlign='center'; ctx.fillText('!',w.x,w.y+6) });
  
  pickups.forEach(pk=&gt;{ if(pk.t&lt;2&amp;&amp;Math.floor(pk.t*6)%2) return; const bob=Math.sin(pk.ph)*4;
    ctx.save(); ctx.translate(pk.x,pk.y+bob);
    ctx.fillStyle='rgba(0,0,0,.5)'; ctx.beginPath(); ctx.ellipse(0,14-bob,13,5,0,0,7); ctx.fill();
    const col=pk.tp==='shield'?'#4fd6e0':pk.tp==='rapid'?'#a6ffc7':pk.tp==='double'?'#ffb400':'#39ff8a';
    ctx.shadowColor=col; ctx.shadowBlur=20; ctx.fillStyle=arena.bg2; rr(-14,-14,28,28,7); ctx.fill();
    ctx.strokeStyle=col; ctx.lineWidth=2.5; ctx.stroke(); ctx.shadowBlur=0;
    ctx.font='15px Courier New'; ctx.textAlign='center'; ctx.textBaseline='middle'; ctx.fillStyle=col;
    ctx.fillText(pk.tp==='shield'?'S':pk.tp==='rapid'?'F':pk.tp==='double'?'x2':'+',0,1);
    ctx.textBaseline='alphabetic'; ctx.restore() });
    
  enemies.forEach(e=&gt;{ if(e.aiming){ const mx=e.x+Math.cos(e.a)*(e.r+e.barrel), my=e.y+Math.sin(e.a)*(e.r+e.barrel);
    ctx.save(); ctx.strokeStyle='rgba(255,60,50,'+(.45+.4*Math.sin(tSec*20))+')'; ctx.lineWidth=2; ctx.setLineDash([7,7]); ctx.lineDashOffset=-tSec*60;
    ctx.beginPath(); ctx.moveTo(mx,my); ctx.lineTo(e.aimX,e.aimY); ctx.stroke(); ctx.setLineDash([]);
    ctx.beginPath(); ctx.arc(e.aimX,e.aimY,9,0,7); ctx.stroke(); ctx.restore() } });
    
  enemies.forEach(e=&gt;{ const sc=e.spawnT&gt;0?1-e.spawnT/.35:1; ctx.save(); if(sc&lt;1){ ctx.translate(e.x,e.y); ctx.scale(sc,sc); ctx.translate(-e.x,-e.y) } drawTank(e,PAL[e.type]); ctx.restore() });
  
  if(!P.dead){
    const alpha=P.inv&gt;0&amp;&amp;Math.floor(tSec*10)%2?0.35:1;
    drawTank(P,PAL.player,alpha);
    if(P.shield){ ctx.save(); ctx.strokeStyle='rgba(79,214,224,'+(.6+.3*Math.sin(tSec*6))+')'; ctx.lineWidth=3; ctx.shadowColor='#4fd6e0'; ctx.shadowBlur=16; ctx.beginPath(); ctx.arc(P.x,P.y,P.r+9,0,7); ctx.stroke(); ctx.restore() }
    if(P.rapidT&gt;0){ ctx.save(); ctx.fillStyle='rgba(166,255,199,.15)'; ctx.shadowColor='#a6ffc7'; ctx.shadowBlur=30; ctx.beginPath(); ctx.arc(P.x,P.y,P.r+20,0,7); ctx.fill(); ctx.restore() }
  }
  
  bullets.forEach(b=&gt;{ const col=b.foe?(b.big?'#ff4040':'#ffb400'):'#a6ffc7';
    ctx.save(); ctx.shadowColor=col; ctx.shadowBlur=16; ctx.fillStyle=col; ctx.beginPath(); ctx.arc(b.x,b.y,b.r,0,7); ctx.fill(); ctx.shadowBlur=0;
    ctx.globalAlpha=.3; ctx.fillStyle='#fff'; ctx.beginPath(); ctx.arc(b.x-b.vx*.01,b.y-b.vy*.01,b.r*.5,0,7); ctx.fill(); ctx.globalAlpha=1; ctx.restore() });
    
  bushes.forEach(b=&gt;{ ctx.save(); ctx.globalAlpha=.65; for(let i=0;i&lt;5;i++){ const a=b.s+i*1.26, rr3=b.r*.55, bx=b.x+Math.cos(a)*b.r*.4, by=b.y+Math.sin(a)*b.r*.4;
    ctx.fillStyle=arena.brick; ctx.beginPath(); ctx.arc(bx,by,rr3,0,7); ctx.fill() }
    ctx.strokeStyle=arena.brickBrd; ctx.lineWidth=1; for(let i=0;i&lt;5;i++){ const a2=b.s+i*1.26, rr4=b.r*.55, bx2=b.x+Math.cos(a2)*b.r*.4, by2=b.y+Math.sin(a2)*b.r*.4; ctx.beginPath(); ctx.arc(bx2,by2,rr4,0,7); ctx.stroke() }
    ctx.restore() });
    
  parts.forEach(p=&gt;{ const k=p.t/p.m;
    if(p.tp==='fire'){ ctx.globalAlpha=k; ctx.fillStyle=p.c; ctx.shadowColor=p.c; ctx.shadowBlur=10; ctx.beginPath(); ctx.arc(p.x,p.y,p.r*k,0,7); ctx.fill(); ctx.shadowBlur=0 }
    else if(p.tp==='smoke'){ ctx.globalAlpha=k*.4; ctx.fillStyle=arena.dustC; ctx.beginPath(); ctx.arc(p.x,p.y,p.r,0,7); ctx.fill() }
    else if(p.tp==='deb'){ ctx.globalAlpha=k; ctx.save(); ctx.translate(p.x,p.y); ctx.rotate(p.a2); ctx.fillStyle=p.c||arena.dustC; ctx.fillRect(-p.r,-p.r,p.r*2,p.r*2); ctx.restore() }
    else if(p.tp==='spark'){ ctx.globalAlpha=k; ctx.strokeStyle=p.c; ctx.shadowColor=p.c; ctx.shadowBlur=8; ctx.lineWidth=2; ctx.beginPath(); ctx.moveTo(p.x,p.y); ctx.lineTo(p.x-p.vx*.03,p.y-p.vy*.03); ctx.stroke(); ctx.shadowBlur=0 }
    else if(p.tp==='dust'){ ctx.globalAlpha=k*.3; ctx.fillStyle=arena.dustC; ctx.beginPath(); ctx.arc(p.x,p.y,p.r,0,7); ctx.fill() }
    else if(p.tp==='flash'){ ctx.globalAlpha=k; ctx.fillStyle='rgba(255,255,255,.85)'; ctx.shadowColor='#fff'; ctx.shadowBlur=30; ctx.beginPath(); ctx.arc(p.x,p.y,p.r*k*2,0,7); ctx.fill(); ctx.shadowBlur=0 }
    else if(p.tp==='tur'){ ctx.globalAlpha=Math.min(1,k*1.5); ctx.save(); ctx.translate(p.x,p.y); ctx.rotate(p.a2); ctx.fillStyle=p.pal.b2; ctx.beginPath(); ctx.arc(0,0,p.r,0,7); ctx.fill(); ctx.fillStyle=p.pal.bar; ctx.fillRect(0,-2.5,p.r+9,5); ctx.restore() }
    ctx.globalAlpha=1 });
    
  rings.forEach(r=&gt;{ ctx.globalAlpha=Math.max(r.a,0); ctx.strokeStyle=r.col; ctx.shadowColor=r.col; ctx.shadowBlur=12; ctx.lineWidth=3; ctx.beginPath(); ctx.arc(r.x,r.y,r.r,0,7); ctx.stroke(); ctx.shadowBlur=0; ctx.globalAlpha=1 });
  floats.forEach(f=&gt;{ ctx.globalAlpha=Math.min(1,f.t); ctx.font=(f.big?'800 20px':'800 14px')+' Courier New'; ctx.textAlign='center'; ctx.fillStyle='rgba(0,0,0,.7)'; ctx.shadowColor=f.col; ctx.shadowBlur=10; ctx.fillText(f.txt,f.x,f.y); ctx.shadowBlur=0; ctx.globalAlpha=1 });
  ctx.restore();
}

let last=performance.now();
function loop(t){
  const dt=Math.min((t-last)/1000,.033); last=t;
  if(state==='playing'||state==='clearing'||state==='dying') update(dt);
  else { tSec+=dt; for(let i=parts.length-1;i&gt;=0;i--){ const p=parts[i]; p.t-=dt; p.x+=(p.vx||0)*dt; p.y+=(p.vy||0)*dt; if(p.t&lt;=0) parts.splice(i,1) }
    for(let i=rings.length-1;i&gt;=0;i--){ const r=rings[i]; r.r+=r.vr*dt; r.a-=dt*2.2; if(r.a&lt;=0) rings.splice(i,1) }
    for(let i=floats.length-1;i&gt;=0;i--){ floats[i].t-=dt; floats[i].y-=28*dt; if(floats[i].t&lt;=0) floats.splice(i,1) }
    shake=Math.max(0,shake-dt*30); recoil=Math.max(0,recoil-dt*24) }
  draw(); requestAnimationFrame(loop);
}

// --- INPUT HANDLING ---
window.addEventListener('keydown', e=&gt;{
  if(['ArrowUp','ArrowDown','ArrowLeft','ArrowRight','Space'].indexOf(e.code)&gt;=0) e.preventDefault();
  keys[e.code]=true;
  if(e.code==='KeyP'||e.code==='Escape') togglePause();
});
window.addEventListener('keyup', e=&gt;{ keys[e.code]=false });
window.addEventListener('blur', ()=&gt;{ if(state==='playing'||state==='clearing') togglePause(true) });
document.addEventListener('visibilitychange', ()=&gt;{ if(document.hidden&amp;&amp;(state==='playing'||state==='clearing')) togglePause(true) });

function togglePause(force){
  if(state==='playing'||state==='clearing'){ state='paused'; $('#pauseOv').classList.add('show'); if(musicOn&amp;&amp;musicG){ try{ musicG.gain.linearRampToValueAtTime(.02,AC.currentTime+.2) }catch(e){} } }
  else if(state==='paused'&amp;&amp;!force){ state='playing'; $('#pauseOv').classList.remove('show'); if(musicOn&amp;&amp;musicG){ try{ musicG.gain.linearRampToValueAtTime(.07,AC.currentTime+.2) }catch(e){} } }
}
$('#resBtn').addEventListener('click', (e)=&gt;{ e.stopPropagation(); togglePause() });

// --- TOUCH CONTROLS (FIXED) ---
const joy=$('#joy'), stick=$('#stick'), fireBtn=$('#fire');
let joyId=null, jcx=0, jcy=0;

// Функция обработки движения джойстика
function handleJoyMove(clientX, clientY) {
  const rect = joy.getBoundingClientRect();
  const centerX = rect.left + rect.width / 2;
  const centerY = rect.top + rect.height / 2;
  
  const dx = clientX - centerX;
  const dy = clientY - centerY;
  const distance = Math.hypot(dx, dy);
  const maxDist = 40; // Радиус хода стика
  
  let moveX = dx, moveY = dy;
  if (distance &gt; maxDist) {
    const ratio = maxDist / distance;
    moveX = dx * ratio;
    moveY = dy * ratio;
  }
  
  stick.style.transform = `translate(${moveX}px, ${moveY}px)`;
  joyX = moveX / maxDist; // Нормализация от -1 до 1
  joyY = moveY / maxDist;
}

// События джойстика
joy.addEventListener('touchstart', e =&gt; {
  e.preventDefault();
  const touch = e.changedTouches[0];
  joyId = touch.identifier;
  handleJoyMove(touch.clientX, touch.clientY);
}, {passive: false});

joy.addEventListener('touchmove', e =&gt; {
  e.preventDefault();
  for (let i = 0; i &lt; e.changedTouches.length; i++) {
    if (e.changedTouches[i].identifier === joyId) {
      handleJoyMove(e.changedTouches[i].clientX, e.changedTouches[i].clientY);
      break;
    }
  }
}, {passive: false});

const endJoy = e =&gt; {
  for (let i = 0; i &lt; e.changedTouches.length; i++) {
    if (e.changedTouches[i].identifier === joyId) {
      joyId = null;
      joyX = 0;
      joyY = 0;
      stick.style.transform = 'translate(0, 0)';
      break;
    }
  }
};
joy.addEventListener('touchend', endJoy);
joy.addEventListener('touchcancel', endJoy);

// Также поддержка мыши для джойстика (для тестов на ПК)
let mouseDownOnJoy = false;
joy.addEventListener('mousedown', e =&gt; {
  mouseDownOnJoy = true;
  handleJoyMove(e.clientX, e.clientY);
});
window.addEventListener('mousemove', e =&gt; {
  if (mouseDownOnJoy) handleJoyMove(e.clientX, e.clientY);
});
window.addEventListener('mouseup', () =&gt; {
  if (mouseDownOnJoy) {
    mouseDownOnJoy = false;
    joyX = 0; joyY = 0;
    stick.style.transform = 'translate(0, 0)';
  }
});

// Кнопка огня
fireBtn.addEventListener('touchstart', e =&gt; {
  e.preventDefault();
  initAudio();
  firing = true;
}, {passive: false});

fireBtn.addEventListener('touchend', e =&gt; {
  e.preventDefault();
  firing = false;
}, {passive: false});

fireBtn.addEventListener('mousedown', e =&gt; {
  e.preventDefault();
  initAudio();
  firing = true;
});
fireBtn.addEventListener('mouseup', () =&gt; firing = false);

// Кнопки меню
$('#startBtn').addEventListener('click', (e)=&gt;{ e.stopPropagation(); initAudio(); fullReset() });
$('#againBtn').addEventListener('click', (e)=&gt;{ e.stopPropagation(); initAudio(); fullReset() });
$('#menuBtn').addEventListener('click', (e)=&gt;{ e.stopPropagation(); hideAll(); $('#menuOv').classList.add('show'); state='menu'; genArena(); updateComboDisplay(); renderTopList(); stopMusic() });

// Блокировка скролла страницы
document.addEventListener('touchmove', function(e) { e.preventDefault(); }, { passive: false });

genArena(); syncHUD(); updateComboDisplay(); requestAnimationFrame(loop);

})();
&lt;/script&gt;
&lt;/body&gt;
&lt;/html&gt;

&lt;div class="br-wrap"&gt;
  &lt;div class="br-hint"&gt;▼ ЛИСТАЙТЕ ВНИЗ · РЕКЛАМА&lt;/div&gt;
  &lt;div class="br-ad" id="brAd"&gt;
    &lt;span class="br-tag"&gt;Реклама&lt;/span&gt;
    &lt;a class="br-slide br-s0 active" href="tel:89028733690"&gt;
      &lt;div&gt;&lt;div class="br-t"&gt;ЗДЕСЬ МОЖЕТ БЫТЬ&lt;br /&gt;ВАША РЕКЛАМА&lt;/div&gt;&lt;div class="br-s"&gt;8 902 873-36-90&lt;/div&gt;&lt;span class="br-cta"&gt;Позвонить&lt;/span&gt;&lt;/div&gt;
    &lt;/a&gt;
    &lt;a class="br-slide br-s1" href="http://brony-rf.ru" target="_blank" rel="noopener"&gt;
      &lt;div&gt;&lt;div class="br-t"&gt;БРОНЕВЫЕ СТАЛИ&lt;/div&gt;&lt;div class="br-s"&gt;Защита и надёжность&lt;/div&gt;&lt;span class="br-cta"&gt;На сайт →&lt;/span&gt;&lt;/div&gt;
    &lt;/a&gt;
    &lt;a class="br-slide br-s2" href="http://brony-rf.ru" target="_blank" rel="noopener"&gt;
      &lt;div&gt;&lt;div class="br-t"&gt;ПУЛЕСТОЙКИЕ СТАЛИ&lt;/div&gt;&lt;div class="br-s"&gt;Высокая стойкость&lt;/div&gt;&lt;span class="br-cta"&gt;На сайт →&lt;/span&gt;&lt;/div&gt;
    &lt;/a&gt;
    &lt;a class="br-slide br-s3" href="http://brony-rf.ru" target="_blank" rel="noopener"&gt;
      &lt;div&gt;&lt;div class="br-t"&gt;ИЗНОСОСТОЙКИЕ СТАЛИ&lt;/div&gt;&lt;div class="br-s"&gt;Долгий ресурс&lt;/div&gt;&lt;span class="br-cta"&gt;На сайт →&lt;/span&gt;&lt;/div&gt;
    &lt;/a&gt;
    &lt;div class="br-dots" id="brDots"&gt;&lt;/div&gt;
    &lt;div class="br-bar"&gt;&lt;i id="brBar"&gt;&lt;/i&gt;&lt;/div&gt;
  &lt;/div&gt;
  &lt;div class="br-foot"&gt;Броневые · пулестойкие · износостойкие стали — &lt;a href="http://brony-rf.ru" target="_blank" rel="noopener"&gt;brony-rf.ru&lt;/a&gt; · &lt;a href="tel:89028733690"&gt;8 902 873-36-90&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;style&gt;
.br-wrap{max-width:960px;margin:0 auto;padding:14px 12px 40px;font-family:'Courier New',monospace}
.br-hint{text-align:center;color:#39ff8a;font-size:12px;letter-spacing:2px;padding:10px 0;animation:br-bounce 1.6s infinite}
@keyframes br-bounce{0%,100%{transform:translateY(0)}50%{transform:translateY(6px)}}
.br-ad{position:relative;border:1px solid rgba(57,255,138,.4);border-radius:12px;overflow:hidden;aspect-ratio:3/1;min-height:120px;background:#0a0e14;font-size:15px}
.br-slide{position:absolute;inset:0;display:flex;align-items:center;padding:0 1.2em;opacity:0;transition:opacity .5s;text-decoration:none}
.br-slide.active{opacity:1}
.br-t{font-weight:800;color:#fff;line-height:1.15;font-size:1em}
.br-s{color:#a6ffc7;font-size:.68em;margin-top:.3em}
.br-cta{display:inline-block;margin-top:.5em;background:#39ff8a;color:#05261a;font-weight:700;font-size:.62em;padding:.4em 1em;border-radius:999px}
.br-s0{background:radial-gradient(120% 120% at 20% 0%,rgba(57,255,138,.2),transparent 55%),#101725}
.br-s1{background:linear-gradient(90deg,rgba(5,10,18,.9),rgba(5,10,18,.25)),linear-gradient(135deg,#3a4a3a,#16211a)}
.br-s2{background:linear-gradient(90deg,rgba(5,10,18,.9),rgba(5,10,18,.25)),linear-gradient(135deg,#4a5a6a,#22303c)}
.br-s3{background:linear-gradient(90deg,rgba(5,10,18,.9),rgba(5,10,18,.25)),linear-gradient(135deg,#5a5a5a,#262626)}
.br-tag{position:absolute;top:.5em;right:.6em;z-index:2;font-size:.5em;letter-spacing:.12em;text-transform:uppercase;color:#a6ffc7;background:rgba(10,14,20,.6);border:1px solid rgba(57,255,138,.25);padding:.25em .7em;border-radius:999px}
.br-dots{position:absolute;bottom:.5em;left:0;right:0;display:flex;justify-content:center;gap:.3em;z-index:2}
.br-dots i{width:.34em;height:.34em;border-radius:50%;background:rgba(255,255,255,.35);cursor:pointer;transition:.2s}
.br-dots i.on{background:#39ff8a;transform:scale(1.25)}
.br-bar{position:absolute;left:0;right:0;bottom:0;height:.14em;background:rgba(255,255,255,.12);z-index:2}
.br-bar i{display:block;height:100%;width:0;background:linear-gradient(90deg,#39ff8a,#a6ffc7)}
.br-foot{text-align:center;font-size:12px;color:#a6ffc7;margin-top:12px}
.br-foot a{color:#39ff8a}
&lt;/style&gt;
&lt;script&gt;
(function(){
  var ad=document.getElementById('brAd');if(!ad)return;
  var slides=ad.querySelectorAll('.br-slide');
  var dotsBox=document.getElementById('brDots');
  var bar=document.getElementById('brBar');
  var N=slides.length,idx=0,timer=null,INT=4000;
  for(var i=0;i&lt;N;i++){dotsBox.appendChild(document.createElement('i'));}
  var dots=dotsBox.querySelectorAll('i');
  var st=document.createElement('style');st.textContent='@keyframes brfill{from{width:0}to{width:100%}}';document.head.appendChild(st);
  function restart(){if(!bar)return;bar.style.animation='none';void bar.offsetWidth;bar.style.animation='brfill '+INT+'ms linear';}
  function show(i){idx=(i+N)%N;slides.forEach(function(s,k){s.classList.toggle('active',k===idx);});dots.forEach(function(d,k){d.classList.toggle('on',k===idx);});restart();}
  function start(){if(timer)clearInterval(timer);timer=setInterval(function(){show(idx+1);},INT);restart();}
  ad.addEventListener('mouseenter',function(){if(timer)clearInterval(timer);timer=null;});
  ad.addEventListener('mouseleave',start);
  dots.forEach(function(d,k){d.addEventListener('click',function(){show(k);});});
  show(0);start();
})();
&lt;/script&gt;</subtitle>
  <updated>2026-08-21T10:26:11Z</updated>
  <logo>https://pandoraburo.ru/ssl/u/pic/4b/bcd80a9d3e11f18b98ed4e8ec7cd6a/-/1787302250.png</logo>
  <author>
    <name>1592962</name>
    <uri>https://www.pandoraburo.ru/</uri>
  </author>
</feed>
