<!-- SOLID CITY · part 3736 -->
d(station,'human',now.epoch,fn,'H-'+station+'-'+performance.now());}
function fireBattery(name,owner){const t=coordination.tasks[name];if(t.owner!==owner)return;const live=enemies.filter(e=>!e.dead);if(!live.length)return;const selected=name==='batteryA'?ship.targetA:ship.targetB;const target=live[selected%live.length];if(!target)return;const epoch=t.epoch,id='salvo-'+name+'-'+Math.floor(performance.now());coordination.command(name,owner,epoch,()=>{
    const offsets=[-10,-3,3,10];offsets.forEach((o,i)=>{shells.push({battery:name,owner,x:ship.x,y:ship.y-.035,tx:target.x,ty:target.y,target:target.id,life:1.4,offset:o/W,hit:false});emit('shot',{battery:name,owner,target:target.id,shell:i+1});});
    emit('salvo',{battery:name,owner,target:target.id});for(let i=0;i<12;i++)particle(ship.x+(name==='batteryA'?-.018:.018),ship.y-.03,'muzzle');
  },id);
}
function cycleTarget(name){const live=enemies.filter(e=>!e.dead);if(!live.length)return;if(name==='batteryA')ship.targetA=(ship.targetA+1)%live.length;else ship.targetB=(ship.targetB+1)%live.length;emit('target_selected',{battery:name,owner:'human',target:live[name==='batteryA'?ship.targetA:ship.targetB].id});}
function particle(x,y,type){particles.push({x,y,vx:(rand()-.5)*.14,vy:(rand()-.5)*.14,life:type==='boom'?1.2:.45,max:type==='boom'?1.2:.45,type});}
function hitEnemy(e,damage,s){e.hp-=damage;s.hit=true;emit('hit',{battery:s.battery,owner:s.owner,target:e.id,damage});for(let i=0;i<8;i++)particle(e.x,e.y,'hit');if(e.hp<=0&&!e.dead){e.dead=true;emit('threat_destroyed',{threat:e.id,battery:s.battery,owner:s.owner,kind:e.kind});for(let i=0;i<38;i++)particle(e.x,e.y,'boom');}}
function damageShip(amount,source){let absorbed=0;if(ship.shield>0){absorbed=Math.min(ship.shield,amount*.8);ship.shield-=absorbed;}const hull=Math.max(0,amount-absorbed);ship.hull-=hull;emit('damage_taken',{amount:+hull.toFixed(1),absorbed:+absorbed.toFixed(1),source});showWarning(absorbed>0?'SHIELD IMPACT':'HULL IMPACT');for(let i=0;i<18;i++)particle(ship.x,ship.y,'hit');if(ship.hull<=0)finish(false);}
function pointDefense(owner){if(ship.defCooldown>0)return;ship.defCooldown=.8;const before=enemyShots.length;enemyShots=enemyShots.filter(p=>{const d=Math.hypot(p.x-ship.x,p.y-ship.y);if(d<.18){emit('point_defense',{owner,projectile:p.id});for(let i=0;i<6;i++)particle(p.x,p.y,'muzzle');return false;}return true;});if(before!==enemyShots.length)emit('defense_intercept',{owner,count:before-enemyShots.length});}
function ai(dt){aiTick-=dt;if(aiTick>0)return;aiTick=.18;const nav=coordination.tasks.nav;if(nav.owner==='ai'){const ex=enemies.reduce((best,e)=>{const d=Math.hypot(e.x-ship.x,e.y-ship.y);return d<(best.d||9)?{d,e}:best;},{});const danger=enemyShots.find(p=>Math.hypot(p.x-ship.x,p.y-ship.y)<.24);let desired=.5;if(danger)desired=ship.x+(ship.x-danger.x>0?.2:-.2);else if(ex.e&&ex.d<.22)desired=ship.x+(ship.x-ex.e.x>0?.17:-.17);const epoch=nav.epoch;coordination.command('nav','ai',epoch,()=>{ship.navInput=Math.max(-1,Math.min(1,(desired-ship.x)*5));ship.boost=true;},'AI-nav-'+Math.floor(performance.now()/180));}
  ['batteryA','batteryB'].forEach((name,idx)=>{const t=coordination.tasks[name];if(t.owner==='ai'&&enemies.length){const live=enemies.filter(e=>!e.dead);if(live.length){if(name==='batteryA')ship.targetA=idx%live.length;else ship.targetB=(live.length-1);if(rand()<.72)fireBattery(name,'ai');}}});
  const def=coordination.tasks.defense;if(def.owner==='ai'){const nearest=enemyShots.reduce((a,p)=>Math.hypot(p.x-ship.x,p.y-ship.y)<Math.hypot((a||{x:9}).x-ship.x,(a||{y:9}).y-ship.y)?p:a,null);if(nearest){ship.shieldFace=nearest.x<ship.x?'left':'right';pointDefense('ai');}else ship.shieldFace='front';}
}
function update(dt){if(!running||paused||ended)return;
  ship.progress=Math.min(1,ship.progress+dt*(.0037+(ship.boost?.0015:0)));ship.boost=false;
  ship.vx+=(ship.navInput*.34-ship.vx*2.8)*dt;ship.x=Math.max(.12,Math.min(.88,ship.x+ship.vx*dt));ship.navInput*=.82;ship.shield=Math.min(100,ship.shield+dt*2.2);ship.defCooldown=Math.max(0,ship.defCooldown-dt);
  stars.forEach(s=>{s.y+=dt*(.055+s.z*.09);if(s.y>1){s.y=0;s.x=rand();}});
  nextSpawn-=dt;if(nextSpawn<=0){spawnEnemy();if(wave>=3&&rand()<.28)spawnEnemy('cruiser');nextSpawn=Math.max(.55,1.6-wave*.16+rand()*.8);}
  wave=Math.min(4,1+Math.floor(ship.progress*4));
  enemies.forEach(e=>{if(e.dead)return;e.x+=e.vx*dt;e.y+=e.vy*dt;e.fire-=dt;if(e.fire<=0&&e.y<.75){e.fire=1.15+rand()*1.25;const dx=ship.x-e.x,dy=ship.y-e.y,l=Math.hypot(dx,dy)||1;enemyShots.push({id:'P'+Math.floor(rand()*99999),x:e.x,y:e.y,vx:dx/l*.19,vy:dy/l*.19,life:4});emit('enemy_fire',{threat:e.id});}if(e.y>.94){e.dead=true;damageShip(e.kind==='cruiser'?18:9,e.id+' ram');}});
  shells.forEach(s=>{if(s.hit)return;s.life-=dt;const target=enemies.find(e=>e.id===s.target&&!e.dead);if(target){s.tx=target.x;s.ty=target.y;}const dx=s.tx-s.x,dy=s.ty-s.y,l=Math.hypot(dx,dy)||1;s.x+=dx/l*dt*.82;s.y+=dy/l*dt*.82;const e=enemies.find(e=>!e.dead&&Mat