/* Original Forge merge host; shared timing/motion pattern from Pocket Engine1.0. MIT. */ import {createTokens,collect} from './collector.mjs'; import {arenaStep,pulse} from './arena.mjs'; export const modes=['collector','arena','hybrid']; const clamp=(n,a,b)=>Math.max(a,Math.min(b,n)); export function createState(mode='hybrid'){ if(!modes.includes(mode))throw Error('Choose collector, arena or hybrid'); return {mode,status:'ready',age:0,remaining:20,player:{x:320,y:180},tokens:mode==='arena'?[]:createTokens(),hazards:[],collected:0,defeated:0,hp:3,charges:1,spawnClock:3,chargeClock:3,invulnerable:0,nextHazard:0,pulseHeld:false,events:[]}; } export function start(mode='hybrid'){const s=createState(mode);s.status='running';return s;} export function togglePause(s){if(s.status==='running')s.status='paused';else if(s.status==='paused')s.status='running';s.pulseHeld=false;} export function step(s,input={},dt=0.01){ if(s.status!=='running'||!Number.isFinite(dt)||dt<=0||dt>0.01+1e-9)return; s.events=[];s.age+=dt; const dx=Number(!!input.right)-Number(!!input.left),dy=Number(!!input.down)-Number(!!input.up),length=Math.hypot(dx,dy)||1; s.player.x=clamp(s.player.x+dx/length*180*dt,14,626);s.player.y=clamp(s.player.y+dy/length*180*dt,14,346); if(s.mode!=='arena')for(const event of collect(s)){s.events.push(event);s.collected++;if(s.mode==='hybrid')s.charges=Math.min(3,s.charges+1);} if(s.mode!=='collector'){ s.remaining=Math.max(0,s.remaining-dt);s.chargeClock-=dt; if(s.mode==='arena'&&s.chargeClock<=0){s.chargeClock+=3;s.charges=Math.min(3,s.charges+1);} if(input.pulse&&!s.pulseHeld)for(const event of pulse(s)){s.events.push(event);s.defeated+=event.removed;} s.pulseHeld=!!input.pulse; for(const event of arenaStep(s,dt)){s.events.push(event);if(event.type==='damage')s.hp-=event.amount;} } // Exactly one host owns outcomes. Donors report events and never start loops. if(s.hp<=0)s.status='lost'; else if(s.mode==='collector'&&s.collected===4)s.status='won'; else if(s.mode==='arena'&&s.remaining===0)s.status='won'; else if(s.mode==='hybrid'&&s.collected===4&&s.remaining===0)s.status='won'; } export function advance(s,input,elapsed){ if(!Number.isFinite(elapsed)||elapsed<=0)return; const dt=Math.min(0.1,elapsed),count=Math.ceil(dt/0.01); for(let i=0;i