"""Nine-frame setup; then real native skating, AI decisions and pass physics."""
from pathlib import Path
import json,math
p=Path(outdir);s=json.loads((p/'spec.json').read_text());rows=[];team=s['team'];direction=s['direction'];px=s['px'];own=team*6;opp=(1-team)*6;carrier=own+2;receiver=own;weak=-1 if px>0 else 1;actor=own+(0 if weak==direction else 1);marker=opp+4
rw=lambda a:(wram[ram(a)]<<8)|wram[ram(a+1)]
def sw(a):v=rw(a);return v-65536 if v&32768 else v
def ww(a,v):v&=65535;wram[ram(a)]=v>>8;wram[ram(a+1)]=v&255
def put(i,x,y):
 b=0xb04a+128*i
 for off,v in [(0,x),(2,0),(0x14,y*direction),(0x16,0),(0x18,0),(0x1a,0),(0x28,0),(0x2a,0),(0x2c,0),(0x2e,-1),(0x30,0),(0x32,0),(0x36,0),(0x40,0),(0x42,8),(0x44,60),(0x46,230),(0x48,16),(0x58,0),(0x5a,0),(0x5c,0),(0x5e,0)]:ww(b+off,v)
 wram[ram(b+0x60)]=255;wram[ram(b+0x61)]=255;wram[ram(b+0x64)]=0;wram[ram(b+0x63)]=0
 flags=(64 if i//6 else 0)+(128 if (direction if i//6==team else -direction)==1 else 0);wram[ram(b+0x62)]=flags
 # Reset role and native base job consistently with the captured on-ice lineup.
 role=[5,3,4,2,1,0][i%6];ww(b+0x34,role);wram[ram(b+0x38)]={5:4,3:4,4:6,2:2,1:2,0:14}[role]
def test_tick(f):
 if f<100:return
 if 100<=f<=108:
  held.clear();ww(0xd046,1);ww(0xd04a,2);ww(0xf07c,0);ww(0xf0d4,0)
  for i in range(12):put(i,130 if i%2 else -130,0)
  put(own+5,0,-246);put(opp+5,0,246)
  for i in range(4):ww(0xc328+2*i,0);ww(0xc320+2*i,65535)
  put(carrier,px,180);wram[ram(0xb04a+carrier*128+0x38)]=16
  if s['kind']=='pass':
   put(receiver,0,220);ww(0xb04a+receiver*128+0x54,2 if px>0 else 6);put(marker,135 if px>0 else -135,170);ww(0xb04a+carrier*128+0x44,1)
   humans=[receiver,marker]
  else:
   put(actor,weak*100,170);put(marker,weak*60,230);humans=[carrier,marker]
  for pad,i in enumerate(humans):ww(0xc328+2*pad,i//6+1);ww(0xc320+2*pad,i);wram[ram(0xb04a+i*128+0x62)]|=8
  home_direction=direction if team==0 else -direction
  wram[ram(0xc2ea)]&=~0x53
  if home_direction==-1:wram[ram(0xc2ea)]|=2
  wram[ram(0xc2ec)]=0;wram[ram(0xc2ee)]&=~128;wram[ram(0xc2f2)]&=~4;wram[ram(0xc2fa)]&=~5
  ww(0xf07a,s.get('difficulty',1));ww(0xd050,0);ww(0xc468,290);ww(0xd058,1);ww(0xd052,0)
  ww(0xb7aa,carrier);ww(0xb74a,px);ww(0xb75e,180*direction)
  for addr in [0xb74c,0xb760,0xb762,0xb764,0xb772,0xb774,0xb776]:ww(addr,0)
  ww(0xbee0,-1);ww(0xbeda,-1);ww(0xf060,0);ww(0xf002,0)
 if f>108:
  b=0xb04a+actor*128;mark=0xb04a+marker*128;xy=[sw(b),sw(b+0x14)*direction];near=math.hypot(sw(b)-sw(mark),sw(b+0x14)-sw(mark+0x14))
  rows.append(dict(frame=f-108,owner=rw(0xb7aa),target=rw(0xbee0),passer=rw(0xbeda),carrier=carrier,receiver=receiver,actor=actor,xy=xy,mark_distance=round(near,3),open_slot=abs(xy[0])<=90 and 160<=xy[1]<=236 and near>=26,assignment=wram[ram(b+0x38+min(rw(b+0x36),7))],receiver_xy=[sw(0xb04a+receiver*128),sw(0xb05e+receiver*128)],receiver_flags=rw(0xb04a+receiver*128+0x62),controls=[rw(0xc320),rw(0xc322)],puck=[sw(0xb74a),sw(0xb75e)],height=sw(0xb762),velocity=[sw(0xb772),sw(0xb774)],shot=rw(0xbeec),score=[rw(0xc6da),rw(0xca3e)]))
 if f==308:(p/'trajectory.json').write_text(json.dumps(rows,indent=2)+'\n')
