"""Audited effects of the seven archive-04 executable setup blocks.

Addresses below are resource offsets, not load addresses. Reference operations
retain 16-bit wrapping and byte writes; they are not a gameplay implementation.
"""
import struct

DESCRIPTIONS = {
 ('04_012',0x1aac): ('Configure player approach', [
  'Set speed magnitude +3E=200, forward velocity +42=400; clear flag +07 bit 4.',
  'C79D: pitch=FF00, heading=EC00, nominal height=2560; empty boost and weapon energy, clear active boost high byte.']),
 ('04_012',0x1d51): ('Anchor two following objects to the player', [
  'Set player sub-cell X=C8, Y=BB; retain cell coordinates.',
  'Copy player cell X/Y to absolute object 1 high coordinate bytes and moving object 2 cell bytes.',
  'C79D: pitch=0, heading=0F20, nominal height=264; empty boost and weapon energy, clear active boost high byte.']),
 ('04_012',0x1d80): ('Raise object 1', ['Increment height high byte (+0D): height += 256 modulo 65536.']),
 ('04_012',0x1d95): ('Configure object 2 scripted motion', [
  'Set sub-cell X=4B, Y=46; height -= 2400 modulo 65536.',
  '8E24: speed magnitude=200, pitch=0C00; +68=clock+256, +5E=clock+1024 (16-bit); callback +66=8DDD.',
  'Callback 8DDD later switches to 8823 and clears flag bit 4 when its time comparison expires; full movement path not simulated.']),
 ('04_014',0xf91): ('Configure player and empty weapon 1 counter', [
  'Set speed magnitude=300, forward velocity=600; clear flag bit 4.',
  '5E59 with AL=0 clears 5E14 and 5E11 (weapon 1 reserve/working counters).',
  'C79D: pitch=FE00, preserve heading, nominal height=4096; empty boost and weapon energy, clear active boost high byte.']),
 ('04_015',0x28): ('Configure player and patch later native code', [
  'Copy player model pointer +22 into the immediate operand at resource offset 0066 of the later block at 0060.',
  'Clear flag bit 4. C79D: pitch=F500, preserve heading, nominal height=2432; boost and weapon energy=9FFF; carry set selects active boost high byte=28.']),
 ('04_015',0x60): ('Give object 2 the player model', [
  'Set object model pointer +22 from this instruction immediate, patched earlier at resource offset 0066.',
  'On disk the immediate is zero; executing this block alone without the earlier patch does not reproduce setup.']),
}

def describe_native(record,block):
    title,effects=DESCRIPTIONS[(record['resource'],block['offset'])]
    preceding=[o for o in record['objects'] if o['offset']<block['offset']]
    index=preceding[-1]['index'] if preceding else 0
    return dict(title=title,current_object_index=index,current_object='player' if index==0 else f'object {index}',effects=effects,reference='docs/mission-native-setup.md',note='Translated effects verified separately against original x86 with synthetic object/geometry state; source positions remain unmodified in this export.')

def reference(resource,offset,obj,stream,relative,globals_,model_height,clock):
    """Mutate a current 112-byte object, loaded shared block, and selected globals.

    Model-height subtraction belongs to C7C8, not to archive coordinates.
    Caller supplies the current object's model height and live clock.
    """
    def word(p):return struct.unpack_from('<H',obj,p)[0]
    def put(p,v):struct.pack_into('<H',obj,p,v&65535)
    def global_word(p,v):globals_[p]=v&255;globals_[p+1]=(v>>8)&255
    def place(pitch,heading,height,energy,carry=False):
        global_word(0x8540,energy);global_word(0x7fa6,energy)
        globals_[0x7f0e]=0x28 if carry else 0
        put(0x2c,pitch);put(0x2a,heading);put(0xc,height-model_height)
        put(0x62,obj[9]|obj[11]<<8);put(0x4a,word(0x62))
        for dst,src in ((0x38,8),(0x3a,10),(0x3c,12)):put(dst,word(src))
    key=(resource,offset)
    if key==('04_012',0x1aac):
        put(0x3e,200);put(0x42,400);obj[7]&=0xef
        place(0xff00,0xec00,2560,0)
    elif key==('04_012',0x1d51):
        obj[8]=0xc8;obj[10]=0xbb
        for d,s in ((3,9),(0x11,9),(5,11),(0x12,11)):stream[relative+40+d]=obj[s]
        place(0,0xf20,264,0)
    elif key==('04_012',0x1d80):put(12,word(12)+256)
    elif key==('04_012',0x1d95):
        obj[8]=0x4b;obj[10]=0x46;put(12,word(12)-2400)
        put(0x3e,200);put(0x2c,0xc00);put(0x68,clock+256);put(0x5e,clock+1024);put(0x66,0x8ddd)
    elif key==('04_014',0xf91):
        put(0x3e,300);put(0x42,600);obj[7]&=0xef
        globals_[0x5e14]=globals_[0x5e11]=0
        place(0xfe00,word(0x2a),4096,0)
    elif key==('04_015',0x28):
        struct.pack_into('<H',stream,relative+28+0x22,word(0x22));obj[7]&=0xef
        place(0xf500,word(0x2a),2432,0x9fff,True)
    elif key==('04_015',0x60):put(0x22,struct.unpack_from('<H',stream,relative+6)[0])
    else:raise ValueError(key)
