"""Real native critical shots: camera-relative trail geometry and resident art."""
from pathlib import Path
import struct
_audit = Path(__file__).with_name('shot_balance_hook.py')
exec(compile(_audit.read_text(), str(_audit), 'exec'), globals())
_tick = test_tick
_previous_camera = None
_previous_history = []
_art = romdata[0x2e4200:0x2e4260]
_art_host = b''.join(_art[i:i+2][::-1] for i in range(0,len(_art),2))

def test_tick(f):
    global _previous_camera, _previous_history
    _tick(f)
    if t >= 0 and 'release' in c:
        age = t-1-c['release']
        assert rw(0xc2e8) <= 0x280, 'native sprite list overflow'
        positions = [[rw(0xc018+i*8),rw(0xc018+i*8+6)]
                     for i in range(min(rw(0xc2e8)//8,80))
                     if (rw(0xc018+i*8+4)&0x7ff) in (0x7fc,0x7fd,0x7fe)]
        # A complete draw-boundary snapshot survives a VBlank anywhere in the
        # subsequent history update. Never compare two different native frames.
        if rw(0x387c)==0x5052 and c.get('_projection_serial')!=rw(0x387e):
            c['_projection_serial']=rw(0x387e)
            camera=[sw(0x3824),sw(0x3826)]
            count=min(rw(0x3828),9)
            drawn=[]
            for i in range(min(rw(0x387a),6)):
                q=0x382a+i*8
                if rw(q+4)&0x7ff not in (0x7fc,0x7fd,0x7fe):break
                drawn.append([rw(q),rw(q+6)])
            if drawn:
                checks=[]
                for i,pos in enumerate(drawn):
                    anchor=[sw(0x3800+(i+1)*4),sw(0x3802+(i+1)*4)]
                    checks.append(i+1<count and pos==[(anchor[0]+camera[0])&65535,(anchor[1]-camera[1])&65535])
                correct=all(checks)
                c.setdefault('projection_checks',[]).append(correct)
                if not correct:c.setdefault('projection_failures',[]).append(dict(age=age,actual=drawn,camera=camera,checks=checks))
        if age == 8:
            n=core.retro_serialize_size();vb=C.create_string_buffer(n)
            assert core.retro_serialize(vb,n)
            raw=vb.raw
            # Fixed serialized-core ABI, independently checked through actual VDP
            # transfers; presentation headers may move or be absent during play.
            assert raw.startswith(b'GENPLUS-GX 1.7.6'),'unverified VRAM ABI'
            offset=74789
            vram=raw[offset:offset+65536]
            c['trail_measurement']=dict(sprites=len(positions),positions=positions,
                span_y=max((v[0] for v in positions),default=0)-min((v[0] for v in positions),default=0),
                tiles_valid=vram[0xff80:0xffe0] == _art_host,
                difficulty=rw(0xf07a),period=rw(0xd050),fighting=rw(0xf004),slot=rw(0xf06a))
            if idx==0:snap('trail')
    _previous_camera=[sw(0xbd1c),sw(0xbd18)]
    _previous_history=[[sw(0xf600+i*4),sw(0xf602+i*4)] for i in range(min(rw(0xf630),9))]
