nmarshall commited on
Commit
c33cd79
·
1 Parent(s): 30afdd4

qvm: torso selection

Browse files
docs/ASSET_PIPELINE_TODO.md CHANGED
@@ -376,3 +376,6 @@ Research progress: RE-560 [report](research/QVM_FREEFLIGHT.md); remaining native
376
 
377
 
378
  Research progress: RE-561 [report](research/QVM_WATER_EVENTS.md); remaining native/content/runtime/platform scope stays open.
 
 
 
 
376
 
377
 
378
  Research progress: RE-561 [report](research/QVM_WATER_EVENTS.md); remaining native/content/runtime/platform scope stays open.
379
+
380
+
381
+ Research progress: RE-562 [report](research/QVM_TORSO_SELECTOR.md); remaining native/content/runtime/platform scope stays open.
docs/FINDINGS.md CHANGED
@@ -734,3 +734,6 @@ Bounded qagame paths recover bomb-plant/inactivity correction requests, direct f
734
 
735
 
736
  **RE-561 — Water transition event matrix and queue composition:** 48716 independently emits entry100/101, exit6, full-submersion7 and resurfacing8. Entry101 requires vertical velocity strictly below−500;0→3 and3→0 each enqueue two ordered events. [Evidence](research/QVM_WATER_EVENTS.md).
 
 
 
 
734
 
735
 
736
  **RE-561 — Water transition event matrix and queue composition:** 48716 independently emits entry100/101, exit6, full-submersion7 and resurfacing8. Entry101 requires vertical velocity strictly below−500;0→3 and3→0 each enqueue two ordered events. [Evidence](research/QVM_WATER_EVENTS.md).
737
+
738
+
739
+ **RE-562 — Torso selector priority and weapon class dispatch:** 49117 first rejects nonzero weapon state, then prioritizes legs25 over button8192/16384, then selects torso requests from a file-backed class jump table and tag22/25 exceptions. [Evidence](research/QVM_TORSO_SELECTOR.md).
docs/PROVISIONAL_TODO.md CHANGED
@@ -688,3 +688,6 @@ Research progress: RE-560 [report](research/QVM_FREEFLIGHT.md); remaining native
688
 
689
 
690
  Research progress: RE-561 [report](research/QVM_WATER_EVENTS.md); remaining native/content/runtime/platform scope stays open.
 
 
 
 
688
 
689
 
690
  Research progress: RE-561 [report](research/QVM_WATER_EVENTS.md); remaining native/content/runtime/platform scope stays open.
691
+
692
+
693
+ Research progress: RE-562 [report](research/QVM_TORSO_SELECTOR.md); remaining native/content/runtime/platform scope stays open.
docs/RESEARCH_LEDGER.md CHANGED
@@ -506,3 +506,8 @@ RE-549–558 each has its own code/tests/report/documentation commit. All759 tes
506
  ## 2026-10-19 — RE-561 Water transition event matrix and queue composition (separate task commit)
507
 
508
  48716 independently emits entry100/101, exit6, full-submersion7 and resurfacing8. Entry101 requires vertical velocity strictly below−500;0→3 and3→0 each enqueue two ordered events. 144 fixtures cover all16 legal level pairs, three velocity boundaries and sequence0/1/unsigned wrap; independent queue and mutation oracles pass. Full suite: 767 tests pass. Report regenerates byte-identically (588597 bytes). Storage/filter, links and whitespace checks pass. No assets/Rust runtime/shared VM evaluator changed; native/reference/legal/full platform scope remains open.
 
 
 
 
 
 
506
  ## 2026-10-19 — RE-561 Water transition event matrix and queue composition (separate task commit)
507
 
508
  48716 independently emits entry100/101, exit6, full-submersion7 and resurfacing8. Entry101 requires vertical velocity strictly below−500;0→3 and3→0 each enqueue two ordered events. 144 fixtures cover all16 legal level pairs, three velocity boundaries and sequence0/1/unsigned wrap; independent queue and mutation oracles pass. Full suite: 767 tests pass. Report regenerates byte-identically (588597 bytes). Storage/filter, links and whitespace checks pass. No assets/Rust runtime/shared VM evaluator changed; native/reference/legal/full platform scope remains open.
509
+
510
+
511
+ ## 2026-10-19 — RE-562 Torso selector priority and weapon class dispatch (separate task commit)
512
+
513
+ 49117 first rejects nonzero weapon state, then prioritizes legs25 over button8192/16384, then selects torso requests from a file-backed class jump table and tag22/25 exceptions. 93 probes cover initialized weapon IDs0..27, timer gates, classes−1..7, tag exceptions, toggle-bit aliases and priority conflicts with independent request/animation oracles. Full suite: 771 tests pass. Report regenerates byte-identically (545687 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
@@ -728,3 +728,6 @@ Purpose: turn the supplied installation into an evidence-backed specification of
728
 
729
 
730
  - [x] RE-561 Water transition event matrix and queue composition ([report](research/QVM_WATER_EVENTS.md)).
 
 
 
 
728
 
729
 
730
  - [x] RE-561 Water transition event matrix and queue composition ([report](research/QVM_WATER_EVENTS.md)).
731
+
732
+
733
+ - [x] RE-562 Torso selector priority and weapon class dispatch ([report](research/QVM_TORSO_SELECTOR.md)).
docs/research/QVM_TORSO_SELECTOR.md ADDED
@@ -0,0 +1,11 @@
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Torso selector priority and weapon class dispatch
2
+
3
+ RE-562. Reproduce with `python3 scripts/analyze_qvm_torso_selector.py`; check with `python3 scripts/test_qvm_torso_selector.py`. The [machine report](qvm-torso-selector.json) retains source identity and bounded fixtures.
4
+
5
+ Complete49117 is interpreted through49325 with actual39482→39338 animation writes. A nonzero PS148 returns immediately. Base legs25 requests torso64 even when buttons8192/16384 are set; those buttons otherwise request50. The selected packed weapon low byte indexes432-byte records at4032(class)/4196(tag). The source jump table21256..21280 maps classes0/1/5 to67,2 to66,3 to78,4 to tag22?66:72,6 to tag25?66:65; values outside0..6 default67.
6
+
7
+ The image table loader retains initialized words, distinct from explicitly marked synthetic class/tag overrides. Animation child gates preserve torso when its timer is positive, kind is3+, or the masked current torso already matches the request. Toggle bit128 follows the recovered helper.93 fixtures include every initialized weapon index0..27; index0 is a source-defined empty record, not a claim of selectable gameplay.
8
+
9
+ Remaining: map numeric requests to animation assets and actual weapon identity, validate live table population and invoke this consumer in source-order main suffix integration. Native rendering and Rust animation retargeting 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
@@ -289,3 +289,6 @@ The extension collector adds five focused tests for native tail calls, command-r
289
 
290
 
291
  [RE-561: Water transition event matrix and queue composition](QVM_WATER_EVENTS.md). Reproduce with `python3 scripts/analyze_qvm_water_events.py`; check with `python3 scripts/test_qvm_water_events.py`.
 
 
 
 
289
 
290
 
291
  [RE-561: Water transition event matrix and queue composition](QVM_WATER_EVENTS.md). Reproduce with `python3 scripts/analyze_qvm_water_events.py`; check with `python3 scripts/test_qvm_water_events.py`.
292
+
293
+
294
+ [RE-562: Torso selector priority and weapon class dispatch](QVM_TORSO_SELECTOR.md). Reproduce with `python3 scripts/analyze_qvm_torso_selector.py`; check with `python3 scripts/test_qvm_torso_selector.py`.
docs/research/qvm-torso-selector.json ADDED
The diff for this file is too large to render. See raw diff
 
scripts/analyze_qvm_torso_selector.py ADDED
@@ -0,0 +1,26 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/usr/bin/env python3
2
+ """49117 state/button/legs priority and file-backed class jump dispatch."""
3
+ from pathlib import Path
4
+ from qvm_research_support import source,execute
5
+ from qvm_suffix_support import seed,state,handlers,weapon_config,weapon_words
6
+ from analyze_qvm_acceleration import PS,FRAME
7
+ from analyze_qvm import write_json
8
+ LOCAL=0x6c000000
9
+
10
+ def torso(ins,m,cmd=(0,0,0)):
11
+ before=state(m);ident=m[PS+312+4*m[PS+144]]&255;cfg=weapon_words(m,ident);buttons=m[FRAME+20]
12
+ m,c,r=execute(ins,49118,49325,m,cmd,LOCAL,handlers())
13
+ return m,{'initial':before,'buttons':buttons,'config':cfg,'execution':r,'final':state(m)}
14
+
15
+ def main():
16
+ q,raw,h,ins=source();rows=[]
17
+ for ident in range(28):
18
+ for timer in [0,1]:
19
+ m=weapon_config(seed(raw,h),raw,h);m.update({PS+312:ident,PS+80:timer});rows.append(torso(ins,m)[1])
20
+ for klass in range(-1,8):
21
+ for tag in [22,25,99]:
22
+ m=weapon_config(seed(raw,h),raw,h);m.update({PS+312:1,4032+432:klass,4196+432:tag});p=torso(ins,m)[1];p['supplied_config_override']={'class':klass,'tag':tag};rows.append(p)
23
+ for changes in [{PS+148:1},{PS+76:25},{PS+76:153},{FRAME+20:8192},{FRAME+20:16384},{PS+76:25,FRAME+20:8192},{PS+4:3},{PS+84:67},{PS+84:195},{PS+80:-1}]:
24
+ m=weapon_config(seed(raw,h),raw,h);m.update(changes);p=torso(ins,m)[1];p['supplied_changes']={str(k):v for k,v in changes.items()};p['kind']=m[PS+4];rows.append(p)
25
+ write_json(Path('docs/research/qvm-torso-selector.json'),{'source':q['source'],'sha256':q['sha256'],'jump_table':{str(a):weapon_config({},raw,h)[a] for a in range(21256,21284,4)},'probes':rows,'limits':'Complete finite49117 with actual39482/39338. File-backed weapon class/tag/jump words and explicitly marked synthetic overrides; no live weapon table or skeletal playback validation.'})
26
+ if __name__=='__main__':main()
scripts/qvm_suffix_support.py CHANGED
@@ -23,3 +23,11 @@ def handlers():
23
  def apply(i,m,a,c):m,r=event(i,m,entry,a);return m,c,0,r
24
  return apply
25
  return {**{e:animation(e) for e in [39338,39383,39439,39482,39525,39552]},**{e:queued(e) for e in [39238,45887,29913]}}
 
 
 
 
 
 
 
 
 
23
  def apply(i,m,a,c):m,r=event(i,m,entry,a);return m,c,0,r
24
  return apply
25
  return {**{e:animation(e) for e in [39338,39383,39439,39482,39525,39552]},**{e:queued(e) for e in [39238,45887,29913]}}
26
+
27
+ def weapon_config(m,raw,h):
28
+ """Initialized image words only; no claim these equal live native tables."""
29
+ from qvm_research_support import constants
30
+ m.update(constants(raw,h,range(4000,16400,4)));m.update(constants(raw,h,range(21236,21284,4)));return m
31
+
32
+ def weapon_words(m,ident):
33
+ return {k:m[a+432*ident]&0xffffffff for k,a in [('class',4032),('capacity',4052),('reload',4056),('reload_extra',4060),('tag',4196)]}
scripts/test_qvm_torso_selector.py ADDED
@@ -0,0 +1,28 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import json,unittest,copy
2
+ from pathlib import Path
3
+
4
+ def signed(v):return v if v<0x80000000 else v-0x100000000
5
+
6
+ def request(p):
7
+ a=p['initial'];klass=signed(p['config']['class']);tag=p['config']['tag']
8
+ if a['weapon_state']:return None
9
+ if a['legs']&~128==25:return 64
10
+ if p['buttons']&(8192|16384):return 50
11
+ return {0:67,1:67,2:66,3:78,4:66 if tag==22 else 72,5:67,6:66 if tag==25 else 65}.get(klass,67)
12
+ class TorsoSelectorTests(unittest.TestCase):
13
+ @classmethod
14
+ def setUpClass(cls):cls.r=json.loads(Path('docs/research/qvm-torso-selector.json').read_text())
15
+ def test_source_table_targets(self):self.assertEqual(list(self.r['jump_table'].values()),[49217,49224,49231,49238,49245,49217,49286])
16
+ def test_all_weapon_classes_tags_and_guards(self):
17
+ self.assertEqual(len(self.r['probes']),93)
18
+ for p in self.r['probes']:
19
+ r=request(p);self.assertEqual([c['args']['8'] for c in p['execution']['calls']],[] if r is None else [r])
20
+ def test_animation_helper_exact_effect(self):
21
+ for p in self.r['probes']:
22
+ a=copy.deepcopy(p['initial']);r=request(p)
23
+ if r is not None and p.get('kind',0)<3 and signed(a['torso_timer'])<=0 and a['torso']&~128!=r:a['torso']=((a['torso']&128)^128)|r
24
+ self.assertEqual(p['final'],a)
25
+ def test_body_retains_packed_weapon_inventory_and_queue(self):
26
+ for p in self.r['probes']:
27
+ for key in ['packed','inventory','queue','weapon_timer','legs','state220']:self.assertEqual(p['initial'][key],p['final'][key])
28
+ if __name__=='__main__':unittest.main()