qvm: airborne locomotion
Browse files- docs/ASSET_PIPELINE_TODO.md +3 -0
- docs/FINDINGS.md +3 -0
- docs/PROVISIONAL_TODO.md +3 -0
- docs/RESEARCH_LEDGER.md +5 -0
- docs/REVERSE_ENGINEERING_TODO.md +3 -0
- docs/research/QVM_LOCOMOTION_PREFIX.md +11 -0
- docs/research/README.md +3 -0
- docs/research/qvm-locomotion-prefix.json +0 -0
- scripts/analyze_qvm_locomotion_prefix.py +24 -0
- scripts/test_qvm_locomotion_prefix.py +42 -0
docs/ASSET_PIPELINE_TODO.md
CHANGED
|
@@ -391,3 +391,6 @@ Research progress: RE-565 [report](research/QVM_PACKED_CONTROLS.md); remaining n
|
|
| 391 |
|
| 392 |
|
| 393 |
Research progress: RE-566 [report](research/QVM_WEAPON_PREFIX.md); remaining native/content/runtime/platform scope stays open.
|
|
|
|
|
|
|
|
|
|
|
|
| 391 |
|
| 392 |
|
| 393 |
Research progress: RE-566 [report](research/QVM_WEAPON_PREFIX.md); remaining native/content/runtime/platform scope stays open.
|
| 394 |
+
|
| 395 |
+
|
| 396 |
+
Research progress: RE-567 [report](research/QVM_LOCOMOTION_PREFIX.md); remaining native/content/runtime/platform scope stays open.
|
docs/FINDINGS.md
CHANGED
|
@@ -749,3 +749,6 @@ Bounded qagame paths recover bomb-plant/inactivity correction requests, direct f
|
|
| 749 |
|
| 750 |
|
| 751 |
**RE-566 — Mode switch and ordered weapon prefix:** 49327 cycles packed mode with release latch16 and ID-specific exceptions;50746 orders button latch, weapon timer decrement, resource countdown and mode switch before weapon selection. [Evidence](research/QVM_WEAPON_PREFIX.md).
|
|
|
|
|
|
|
|
|
|
|
|
| 749 |
|
| 750 |
|
| 751 |
**RE-566 — Mode switch and ordered weapon prefix:** 49327 cycles packed mode with release latch16 and ID-specific exceptions;50746 orders button latch, weapon timer decrement, resource countdown and mode switch before weapon selection. [Evidence](research/QVM_WEAPON_PREFIX.md).
|
| 752 |
+
|
| 753 |
+
|
| 754 |
+
**RE-567 — Airborne locomotion animation and bob cycle:** 47884 caches horizontal speed in FRAME216, then airborne animation priority combines water/crouch, traversal flags and state1024; traversal bob advances only for absolute forward input strictly above100. [Evidence](research/QVM_LOCOMOTION_PREFIX.md).
|
docs/PROVISIONAL_TODO.md
CHANGED
|
@@ -703,3 +703,6 @@ Research progress: RE-565 [report](research/QVM_PACKED_CONTROLS.md); remaining n
|
|
| 703 |
|
| 704 |
|
| 705 |
Research progress: RE-566 [report](research/QVM_WEAPON_PREFIX.md); remaining native/content/runtime/platform scope stays open.
|
|
|
|
|
|
|
|
|
|
|
|
| 703 |
|
| 704 |
|
| 705 |
Research progress: RE-566 [report](research/QVM_WEAPON_PREFIX.md); remaining native/content/runtime/platform scope stays open.
|
| 706 |
+
|
| 707 |
+
|
| 708 |
+
Research progress: RE-567 [report](research/QVM_LOCOMOTION_PREFIX.md); remaining native/content/runtime/platform scope stays open.
|
docs/RESEARCH_LEDGER.md
CHANGED
|
@@ -531,3 +531,8 @@ RE-549–558 each has its own code/tests/report/documentation commit. All759 tes
|
|
| 531 |
## 2026-10-20 — RE-566 Mode switch and ordered weapon prefix (separate task commit)
|
| 532 |
|
| 533 |
49327 cycles packed mode with release latch16 and ID-specific exceptions;50746 orders button latch, weapon timer decrement, resource countdown and mode switch before weapon selection. 82 mode fixtures and84 prefix fixtures independently check complete writes, source-order child state, death/flag early exits and negative timer preservation. Full suite: 787 tests pass. Report regenerates byte-identically (642934 bytes). Storage/filter, links and whitespace checks pass. No assets/Rust runtime/shared VM evaluator changed; native/reference/legal/full platform scope remains open.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 531 |
## 2026-10-20 — RE-566 Mode switch and ordered weapon prefix (separate task commit)
|
| 532 |
|
| 533 |
49327 cycles packed mode with release latch16 and ID-specific exceptions;50746 orders button latch, weapon timer decrement, resource countdown and mode switch before weapon selection. 82 mode fixtures and84 prefix fixtures independently check complete writes, source-order child state, death/flag early exits and negative timer preservation. Full suite: 787 tests pass. Report regenerates byte-identically (642934 bytes). Storage/filter, links and whitespace checks pass. No assets/Rust runtime/shared VM evaluator changed; native/reference/legal/full platform scope remains open.
|
| 534 |
+
|
| 535 |
+
|
| 536 |
+
## 2026-10-20 — RE-567 Airborne locomotion animation and bob cycle (separate task commit)
|
| 537 |
+
|
| 538 |
+
47884 caches horizontal speed in FRAME216, then airborne animation priority combines water/crouch, traversal flags and state1024; traversal bob advances only for absolute forward input strictly above100. 120 probes independently check horizontal sqrt input, frame versus PS field identity, all request order/effects, bob wrap, event5 threshold crossing and grounded stopping boundary. Full suite: 791 tests pass. Report regenerates byte-identically (1446102 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
|
@@ -743,3 +743,6 @@ Purpose: turn the supplied installation into an evidence-backed specification of
|
|
| 743 |
|
| 744 |
|
| 745 |
- [x] RE-566 Mode switch and ordered weapon prefix ([report](research/QVM_WEAPON_PREFIX.md)).
|
|
|
|
|
|
|
|
|
|
|
|
| 743 |
|
| 744 |
|
| 745 |
- [x] RE-566 Mode switch and ordered weapon prefix ([report](research/QVM_WEAPON_PREFIX.md)).
|
| 746 |
+
|
| 747 |
+
|
| 748 |
+
- [x] RE-567 Airborne locomotion animation and bob cycle ([report](research/QVM_LOCOMOTION_PREFIX.md)).
|
docs/research/QVM_LOCOMOTION_PREFIX.md
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Airborne locomotion animation and bob cycle
|
| 2 |
+
|
| 3 |
+
RE-567. Reproduce with `python3 scripts/analyze_qvm_locomotion_prefix.py`; check with `python3 scripts/test_qvm_locomotion_prefix.py`. The [machine report](qvm-locomotion-prefix.json) retains source identity and bounded fixtures.
|
| 4 |
+
|
| 5 |
+
47884 begins by loading initialized weapon class/tag and computing sqrt(vX²+vY²), storing the float at FRAME216. PS216 is a distinct retained word. Airborne is ground entity1023. Water level>1 first requests legs25, otherwise crouch flag1 requests42. Flags12 then select legs20 for nonzero signed forward,21 for zero, with the same torso request when flag8 is set. Absolute forward>100 advances bob by float32(.4×integer dt), truncates and masks255; crossing ((old+64) xor(new+64)) bit128 emits5.
|
| 6 |
+
|
| 7 |
+
If flags12 are absent, state1024 requests legs0 then torso0; otherwise flag2 requests torso68 then legs42. Recovered conditional animation helpers preserve timer/type/toggle rules, so earlier requests in the same body affect later ones.120 probes include masked animation aliases, positive timers, kind3, bob255 wrap, signed−128 input and high vertical velocity excluded from speed.
|
| 8 |
+
|
| 9 |
+
The entire airborne path runs to48714. Grounded execution explicitly stops at48209 before its animation/gait branch; that continuation is the next task. Native sqrt is supplied for finite values, and no actual skeletal playback, collision or original runtime executes. Legal animation naming and live speed/state reference parity 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
|
@@ -304,3 +304,6 @@ The extension collector adds five focused tests for native tail calls, command-r
|
|
| 304 |
|
| 305 |
|
| 306 |
[RE-566: Mode switch and ordered weapon prefix](QVM_WEAPON_PREFIX.md). Reproduce with `python3 scripts/analyze_qvm_weapon_prefix.py`; check with `python3 scripts/test_qvm_weapon_prefix.py`.
|
|
|
|
|
|
|
|
|
|
|
|
| 304 |
|
| 305 |
|
| 306 |
[RE-566: Mode switch and ordered weapon prefix](QVM_WEAPON_PREFIX.md). Reproduce with `python3 scripts/analyze_qvm_weapon_prefix.py`; check with `python3 scripts/test_qvm_weapon_prefix.py`.
|
| 307 |
+
|
| 308 |
+
|
| 309 |
+
[RE-567: Airborne locomotion animation and bob cycle](QVM_LOCOMOTION_PREFIX.md). Reproduce with `python3 scripts/analyze_qvm_locomotion_prefix.py`; check with `python3 scripts/test_qvm_locomotion_prefix.py`.
|
docs/research/qvm-locomotion-prefix.json
ADDED
|
The diff for this file is too large to render.
See raw diff
|
|
|
scripts/analyze_qvm_locomotion_prefix.py
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#!/usr/bin/env python3
|
| 2 |
+
"""47884 horizontal-speed cache and complete airborne animation/bob branch."""
|
| 3 |
+
import itertools
|
| 4 |
+
from pathlib import Path
|
| 5 |
+
from qvm_research_support import source,execute
|
| 6 |
+
from qvm_suffix_support import seed,state,handlers,weapon_config,weapon_words
|
| 7 |
+
from analyze_qvm_acceleration import PS,FRAME,word
|
| 8 |
+
from analyze_qvm_slide_prefix import vec
|
| 9 |
+
from analyze_qvm import write_json
|
| 10 |
+
LOCAL=0x71000000
|
| 11 |
+
|
| 12 |
+
def locomotion_prefix(ins,m,cmd=(0,0,0)):
|
| 13 |
+
before=state(m);velocity=vec(m,PS+32);ps216=m[PS+216];cfg=weapon_words(m,before['packed']&255)
|
| 14 |
+
m,c,r=execute(ins,47885,48714,m,cmd,LOCAL,handlers(),boundaries=[48209])
|
| 15 |
+
return m,{'initial':before,'commands':list(cmd),'buttons':m[FRAME+20],'level':m[FRAME+212],'dt':m[35023932],'kind':m[PS+4],'velocity':velocity,'config':cfg,'ps216_before':ps216,'ps216_after':m[PS+216],'execution':r,'final':state(m)}
|
| 16 |
+
|
| 17 |
+
def main():
|
| 18 |
+
q,raw,h,ins=source();rows=[]
|
| 19 |
+
for flags,level,forward,special in itertools.product([0,1,2,4,8,9,12],[0,2],[0,100,101,-128],[0,1024]):
|
| 20 |
+
cmd=(forward,0,0);m=weapon_config(seed(raw,h,cmd),raw,h);m.update({PS+312:1,PS+12:flags,PS+220:special,PS+68:1023,FRAME+212:level,PS+8:60,PS+32:word(3),PS+36:word(4),PS+40:word(-999),35023932:16});rows.append(locomotion_prefix(ins,m,cmd)[1])
|
| 21 |
+
for changes in [{PS+68:8},{PS+4:3},{PS+72:1},{PS+80:1},{PS+8:255},{35023932:200},{PS+76:148},{PS+84:148}]:
|
| 22 |
+
cmd=(127,0,0);m=weapon_config(seed(raw,h,cmd),raw,h);m.update({PS+312:22,PS+12:8,PS+68:1023,PS+8:60,35023932:16});m.update(changes);rows.append(locomotion_prefix(ins,m,cmd)[1])
|
| 23 |
+
write_json(Path('docs/research/qvm-locomotion-prefix.json'),{'source':q['source'],'sha256':q['sha256'],'probes':rows,'limits':'47884 prefix and complete airborne path only; grounded branch starts48209 and is stopped. Actual animation/event children, supplied sqrt, finite state; no skeletal rendering or physics executes.'})
|
| 24 |
+
if __name__=='__main__':main()
|
scripts/test_qvm_locomotion_prefix.py
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import json,unittest,copy,math
|
| 2 |
+
from pathlib import Path
|
| 3 |
+
from test_qvm_ground import word,n,f
|
| 4 |
+
from test_qvm_torso_selector import signed
|
| 5 |
+
from test_qvm_water_events import enqueue
|
| 6 |
+
|
| 7 |
+
def animation(a,entry,request,kind):
|
| 8 |
+
field,timer=('legs','leg_timer') if entry==39439 else ('torso','torso_timer')
|
| 9 |
+
if kind<3 and signed(a[timer])<=0 and a[field]!=request and a[field]&~128!=request:a[field]=((a[field]&128)^128)|request
|
| 10 |
+
|
| 11 |
+
def bob(a,dt,rate):
|
| 12 |
+
old=signed(a['bob']);new=int(f(f(old)+f(rate*f(dt))))&255;a['bob']=new;return bool(((old+64)^(new+64))&128)
|
| 13 |
+
|
| 14 |
+
def prefix_state(p):
|
| 15 |
+
a=copy.deepcopy(p['initial']);v=list(map(n,p['velocity']));a['speed']=word(math.sqrt(f(f(v[0]*v[0])+f(v[1]*v[1]))));requests=[]
|
| 16 |
+
def anim(entry,arg):requests.append((entry,arg));animation(a,entry,arg,p['kind'])
|
| 17 |
+
if a['ground']!=1023:return a,requests
|
| 18 |
+
flags=a['flags'];forward=p['commands'][0]
|
| 19 |
+
if p['level']>1:anim(39439,25)
|
| 20 |
+
elif flags&1:anim(39439,42)
|
| 21 |
+
if flags&12:
|
| 22 |
+
arg=20 if forward else 21;anim(39439,arg)
|
| 23 |
+
if flags&8:anim(39482,arg)
|
| 24 |
+
if abs(forward)>100 and bob(a,p['dt'],n(1053609165)):requests.append((39238,5));a['queue']=enqueue(a['queue'],[5])
|
| 25 |
+
elif a['state220']&1024:anim(39439,0);anim(39482,0)
|
| 26 |
+
elif flags&2:anim(39482,68);anim(39439,42)
|
| 27 |
+
return a,requests
|
| 28 |
+
class LocomotionPrefixTests(unittest.TestCase):
|
| 29 |
+
@classmethod
|
| 30 |
+
def setUpClass(cls):cls.r=json.loads(Path('docs/research/qvm-locomotion-prefix.json').read_text())
|
| 31 |
+
def test_airborne_complete_state_and_priority(self):
|
| 32 |
+
self.assertEqual(len(self.r['probes']),120)
|
| 33 |
+
for p in self.r['probes']:self.assertEqual(p['final'],prefix_state(p)[0])
|
| 34 |
+
def test_actual_ordered_animation_event_children(self):
|
| 35 |
+
for p in self.r['probes']:self.assertEqual([(c['target'],c['args']['8']) for c in p['execution']['calls'] if c['target']!=-107],prefix_state(p)[1])
|
| 36 |
+
def test_horizontal_speed_frame_cache_not_ps216(self):
|
| 37 |
+
for p in self.r['probes']:
|
| 38 |
+
self.assertEqual(p['ps216_before'],p['ps216_after']);self.assertEqual(p['execution']['calls'][0]['target'],-107);v=list(map(n,p['velocity']));self.assertEqual(p['execution']['calls'][0]['args']['8'],word(f(f(v[0]*v[0])+f(v[1]*v[1]))))
|
| 39 |
+
def test_grounded_boundary_and_strict_command_threshold(self):
|
| 40 |
+
for p in self.r['probes']:self.assertEqual(p['execution']['stop'],48209 if p['initial']['ground']!=1023 else 48714)
|
| 41 |
+
self.assertTrue(any(p['commands'][0]==100 and p['final']['bob']==p['initial']['bob'] for p in self.r['probes']));self.assertTrue(any(p['commands'][0]==101 and p['final']['bob']!=p['initial']['bob'] for p in self.r['probes']))
|
| 42 |
+
if __name__=='__main__':unittest.main()
|