nmarshall commited on
Commit
952b689
·
1 Parent(s): fba7687

qvm: weapon selection request

Browse files
docs/ASSET_PIPELINE_TODO.md CHANGED
@@ -403,3 +403,6 @@ Research progress: RE-569 [report](research/QVM_MAIN_CONSUMERS.md); remaining na
403
 
404
 
405
  Research progress: RE-571 [report](research/QVM_WEAPON_LOOKUP.md); remaining native/content/runtime/platform scope stays open.
 
 
 
 
403
 
404
 
405
  Research progress: RE-571 [report](research/QVM_WEAPON_LOOKUP.md); remaining native/content/runtime/platform scope stays open.
406
+
407
+
408
+ Research progress: RE-572 [report](research/QVM_WEAPON_SELECT.md); remaining native/content/runtime/platform scope stays open.
docs/FINDINGS.md CHANGED
@@ -761,3 +761,6 @@ Bounded qagame paths recover bomb-plant/inactivity correction requests, direct f
761
 
762
 
763
  **RE-571 — Weapon slot lookup and numeric return contract:** 31691 searches the first16 packed weapon slots, compares their low bytes to the full requested integer and returns the first index or−1 without changing game state. [Evidence](research/QVM_WEAPON_LOOKUP.md).
 
 
 
 
761
 
762
 
763
  **RE-571 — Weapon slot lookup and numeric return contract:** 31691 searches the first16 packed weapon slots, compares their low bytes to the full requested integer and returns the first index or−1 without changing game state. [Evidence](research/QVM_WEAPON_LOOKUP.md).
764
+
765
+
766
+ **RE-572 — Weapon selection request gates and transition effects:** 48798 validates requested IDs1..27 and actual slot presence, emits30/parameter0, sets state2/timer0-or300 and timed torso54, then resets counters/resources and clears bits64/8/512 without switching slots. [Evidence](research/QVM_WEAPON_SELECT.md).
docs/PROVISIONAL_TODO.md CHANGED
@@ -717,3 +717,6 @@ Research progress: RE-569 [report](research/QVM_MAIN_CONSUMERS.md); remaining na
717
 
718
 
719
  Research progress: RE-571 [report](research/QVM_WEAPON_LOOKUP.md); remaining native/content/runtime/platform scope stays open.
 
 
 
 
717
 
718
 
719
  Research progress: RE-571 [report](research/QVM_WEAPON_LOOKUP.md); remaining native/content/runtime/platform scope stays open.
720
+
721
+
722
+ Research progress: RE-572 [report](research/QVM_WEAPON_SELECT.md); remaining native/content/runtime/platform scope stays open.
docs/RESEARCH_LEDGER.md CHANGED
@@ -551,3 +551,8 @@ Actual54444 reload/interaction order exposes timer interference before the weapo
551
  ## 2026-10-20 — RE-571 Weapon slot lookup and numeric return contract (separate task commit)
552
 
553
  31691 searches the first16 packed weapon slots, compares their low bytes to the full requested integer and returns the first index or−1 without changing game state. 111 fixtures cover slot0/1/7/15, excluded slot16, duplicates, absent entries, upper-byte canaries and requests outside the low-byte range. Full suite: 803 tests pass. Report regenerates byte-identically (318642 bytes). Storage/filter, links and whitespace checks pass. No assets/Rust runtime/shared VM evaluator changed; native/reference/legal/full platform scope remains open.
 
 
 
 
 
 
551
  ## 2026-10-20 — RE-571 Weapon slot lookup and numeric return contract (separate task commit)
552
 
553
  31691 searches the first16 packed weapon slots, compares their low bytes to the full requested integer and returns the first index or−1 without changing game state. 111 fixtures cover slot0/1/7/15, excluded slot16, duplicates, absent entries, upper-byte canaries and requests outside the low-byte range. Full suite: 803 tests pass. Report regenerates byte-identically (318642 bytes). Storage/filter, links and whitespace checks pass. No assets/Rust runtime/shared VM evaluator changed; native/reference/legal/full platform scope remains open.
554
+
555
+
556
+ ## 2026-10-20 — RE-572 Weapon selection request gates and transition effects (separate task commit)
557
+
558
+ 48798 validates requested IDs1..27 and actual slot presence, emits30/parameter0, sets state2/timer0-or300 and timed torso54, then resets counters/resources and clears bits64/8/512 without switching slots. 76 fixtures independently check every guard, slot15 versus excluded16, state3 magazine exception overridden by state8, actual child order and all retained weapon records. Full suite: 807 tests pass. Report regenerates byte-identically (531673 bytes). Storage/filter, links and whitespace checks pass. No assets/Rust runtime/shared VM evaluator changed; native/reference/legal/full platform scope remains open.
docs/REVERSE_ENGINEERING_TODO.md CHANGED
@@ -757,3 +757,6 @@ Purpose: turn the supplied installation into an evidence-backed specification of
757
 
758
 
759
  - [x] RE-571 Weapon slot lookup and numeric return contract ([report](research/QVM_WEAPON_LOOKUP.md)).
 
 
 
 
757
 
758
 
759
  - [x] RE-571 Weapon slot lookup and numeric return contract ([report](research/QVM_WEAPON_LOOKUP.md)).
760
+
761
+
762
+ - [x] RE-572 Weapon selection request gates and transition effects ([report](research/QVM_WEAPON_SELECT.md)).
docs/research/QVM_WEAPON_SELECT.md ADDED
@@ -0,0 +1,11 @@
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Weapon selection request gates and transition effects
2
+
3
+ RE-572. Reproduce with `python3 scripts/analyze_qvm_weapon_select.py`; check with `python3 scripts/test_qvm_weapon_select.py`. The [machine report](qvm-weapon-select.json) retains source identity and bounded fixtures.
4
+
5
+ Complete48798 runs through49025 with actual31691 slot search,29913 event queue and39552 timed torso. Before range/presence checks, state3 with a nonempty magazine blocks unless PS220 bit8 is set. Requested integer must be1..27; weapon state2 and state bit1 reject. A missing first16-slot match rejects.
6
+
7
+ Acceptance emits event30 parameter0, sets PS148=2, sets PS44=0 if the currently selected low-byte ID is0 else300, requests timed torso54, zeros PS204/188/196 and clears state bits64/8/512. Selection itself leaves active slot and every packed weapon record unchanged. Animation durations are supplied321,0 or−1 records; kind3 blocks torso mutation but not duration storage.
8
+
9
+ 76 probes distinguish request validation from the lookup's wider equality contract and preserve unrelated state. Completion49028 and its fallback behavior are the next step; live weapon legality and native animation/audio playback remain open.
10
+
11
+ No original executable/full QVM/native collision/physics/rendering executes. Native responses and legal input domains are supplied or unverified where stated; full runtime/macOS/Linux Rust/Bevy/Solari gameplay remains open.
docs/research/README.md CHANGED
@@ -318,3 +318,6 @@ The extension collector adds five focused tests for native tail calls, command-r
318
 
319
 
320
  [RE-571: Weapon slot lookup and numeric return contract](QVM_WEAPON_LOOKUP.md). Reproduce with `python3 scripts/analyze_qvm_weapon_lookup.py`; check with `python3 scripts/test_qvm_weapon_lookup.py`.
 
 
 
 
318
 
319
 
320
  [RE-571: Weapon slot lookup and numeric return contract](QVM_WEAPON_LOOKUP.md). Reproduce with `python3 scripts/analyze_qvm_weapon_lookup.py`; check with `python3 scripts/test_qvm_weapon_lookup.py`.
321
+
322
+
323
+ [RE-572: Weapon selection request gates and transition effects](QVM_WEAPON_SELECT.md). Reproduce with `python3 scripts/analyze_qvm_weapon_select.py`; check with `python3 scripts/test_qvm_weapon_select.py`.
docs/research/qvm-weapon-select.json ADDED
The diff for this file is too large to render. See raw diff
 
scripts/analyze_qvm_weapon_select.py ADDED
@@ -0,0 +1,30 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/usr/bin/env python3
2
+ """Complete48798 weapon selection request with actual31691/animation/events."""
3
+ import itertools
4
+ from pathlib import Path
5
+ from qvm_research_support import source,execute
6
+ from qvm_weapon_support import weapon_seed,weapon_state
7
+ from qvm_suffix_support import handlers
8
+ from analyze_qvm_weapon_lookup import lookup
9
+ from analyze_qvm_acceleration import PS,FRAME
10
+ from analyze_qvm_animation_contacts import TABLE
11
+ from analyze_qvm import write_json
12
+ LOCAL=0x74000000
13
+
14
+ def select(ins,m,requested,cmd=(0,0,0)):
15
+ m=dict(m);before=weapon_state(m);m[LOCAL+56]=requested;duration=m[TABLE+m[FRAME+248]*2560+54*32+28];hs=handlers();hs[31691]=lookup
16
+ m,c,r=execute(ins,48799,49026,m,cmd,LOCAL,hs)
17
+ return m,{'requested':requested,'kind':m[PS+4],'duration':duration,'initial':before,'execution':r,'final':weapon_state(m)}
18
+
19
+ def main():
20
+ q,raw,h,ins=source();rows=[]
21
+ for request,where,old in itertools.product([-1,0,1,22,27,28],[-1,0,15,16],[0,1]):
22
+ m=weapon_seed(raw,h);m[PS+312]=old|(2<<8)
23
+ if where>=0:m[PS+312+4*where]=(request&255)|(3<<8)
24
+ rows.append(select(ins,m,request)[1])
25
+ for ws,mag,flags in itertools.product([0,2,3],[0,1],[0,8,1,512|64]):
26
+ m=weapon_seed(raw,h);m.update({PS+312:1|(mag<<8),PS+312+15*4:22,PS+148:ws,PS+220:flags});rows.append(select(ins,m,22)[1])
27
+ for changes in [{PS+4:3},{PS+80:999},{TABLE+54*32+28:0},{TABLE+54*32+28:-1}]:
28
+ m=weapon_seed(raw,h);m.update({PS+312:1,PS+316:22,PS+220:512|64|8});m.update(changes);rows.append(select(ins,m,22)[1])
29
+ write_json(Path('docs/research/qvm-weapon-select.json'),{'source':q['source'],'sha256':q['sha256'],'probes':rows,'limits':'Complete finite48798 with actual31691/39552/29913 children. Animation duration supplied321 except explicit0/−1; legal selection domain, subsequent completion and original playback unverified.'})
30
+ if __name__=='__main__':main()
scripts/test_qvm_weapon_select.py ADDED
@@ -0,0 +1,31 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import json,unittest,copy
2
+ from pathlib import Path
3
+ from test_qvm_water_events import enqueue
4
+
5
+ def accepted(p):
6
+ a=p['initial'];r=p['requested'];return not (not a['state220']&8 and a['weapon_state']==3 and a['packed']&65280) and 0<r<28 and a['weapon_state']!=2 and not a['state220']&1 and any(v&255==r for v in a['weapons'])
7
+
8
+ def select_state(p):
9
+ a=copy.deepcopy(p['initial'])
10
+ if accepted(p):
11
+ a['queue']=enqueue(a['queue'],[30]);a['weapon_state']=2;a['weapon_timer']=300 if a['packed']&255 else 0;a['torso_timer']=p['duration']&0xffffffff
12
+ if p['kind']<3:a['torso']=((a['torso']&128)^128)|54
13
+ a['counter204']=a['resource']=a['resource_timer']=0;a['state220']&=~(64|8|512)
14
+ return a
15
+ class WeaponSelectTests(unittest.TestCase):
16
+ @classmethod
17
+ def setUpClass(cls):cls.r=json.loads(Path('docs/research/qvm-weapon-select.json').read_text())
18
+ def test_complete_guard_matrix_and_exact_state(self):
19
+ self.assertEqual(len(self.r['probes']),76)
20
+ for p in self.r['probes']:self.assertEqual(p['final'],select_state(p))
21
+ def test_ordered_children_and_parameter(self):
22
+ for p in self.r['probes']:
23
+ targets=[c['target'] for c in p['execution']['calls']]
24
+ if accepted(p):self.assertEqual(targets,[31691,29913,39552]);self.assertEqual(p['execution']['calls'][1]['args'],{'8':30,'12':0,'16':65536})
25
+ else:self.assertIn(targets,[[],[31691]])
26
+ def test_selection_request_does_not_switch_slot_or_packed_words(self):
27
+ for p in self.r['probes']:self.assertEqual(p['initial']['slot'],p['final']['slot']);self.assertEqual(p['initial']['weapons'],p['final']['weapons']);self.assertEqual(p['initial']['inventory'],p['final']['inventory'])
28
+ def test_state8_overrides_state3_nonempty_magazine_guard(self):
29
+ rows=[p for p in self.r['probes'] if p['initial']['weapon_state']==3 and p['initial']['packed']&65280 and not p['initial']['state220']&1];self.assertTrue(rows)
30
+ for p in rows:self.assertEqual(accepted(p),bool(p['initial']['state220']&8))
31
+ if __name__=='__main__':unittest.main()