qvm: health direction and knockback gates
Browse files- docs/ASSET_PIPELINE_TODO.md +6 -0
- docs/FINDINGS.md +6 -0
- docs/PROVISIONAL_TODO.md +6 -0
- docs/RESEARCH_LEDGER.md +8 -0
- docs/REVERSE_ENGINEERING_TODO.md +7 -1
- docs/research/QVM_CONTACT_HEALTH_BATCH.md +45 -0
- docs/research/QVM_DAMAGE_FACTOR_BATCH.md +3 -0
- docs/research/QVM_HEALTH_KNOCKBACK.md +7 -0
- docs/research/README.md +6 -0
- docs/research/qvm-health-knockback.json +0 -0
- scripts/analyze_qvm_health_knockback.py +19 -0
- scripts/test_qvm_health_knockback.py +38 -0
docs/ASSET_PIPELINE_TODO.md
CHANGED
|
@@ -832,3 +832,9 @@ Research progress: RE-721 [report](research/QVM_CONTACT_COMPLETE.md); remaining
|
|
| 832 |
|
| 833 |
|
| 834 |
Research progress: RE-722 [report](research/QVM_HEALTH_GATES.md); remaining native/content/runtime/platform scope stays open.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 832 |
|
| 833 |
|
| 834 |
Research progress: RE-722 [report](research/QVM_HEALTH_GATES.md); remaining native/content/runtime/platform scope stays open.
|
| 835 |
+
|
| 836 |
+
|
| 837 |
+
Research progress: RE-723 [report](research/QVM_HEALTH_KNOCKBACK.md); remaining native/content/runtime/platform scope stays open.
|
| 838 |
+
|
| 839 |
+
|
| 840 |
+
RE-714–723 batch complete: [complete contact and health prefixes](research/QVM_CONTACT_HEALTH_BATCH.md). Complete292545 now uses original-model contexts through actual factor/event/feedback children;211239 entry gates and knockback selection are bounded recoveries. Full health mutations/callbacks, native parity and playable Rust/Bevy/Solari work remain open. RE-713 is partially advanced and RE-724 tracks the next work.
|
docs/FINDINGS.md
CHANGED
|
@@ -1178,3 +1178,9 @@ RE-703–712 batch complete: [damage factor and contact dispatch](research/QVM_D
|
|
| 1178 |
|
| 1179 |
|
| 1180 |
**RE-722 — Health damage entry gates and client marker:** 211239 applies damageable/mode/method/protection/global gates before marking client4328 and optionally first cross-team tracking34999664; health is unchanged in the prefix. [Evidence](research/QVM_HEALTH_GATES.md).
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1178 |
|
| 1179 |
|
| 1180 |
**RE-722 — Health damage entry gates and client marker:** 211239 applies damageable/mode/method/protection/global gates before marking client4328 and optionally first cross-team tracking34999664; health is unchanged in the prefix. [Evidence](research/QVM_HEALTH_GATES.md).
|
| 1181 |
+
|
| 1182 |
+
|
| 1183 |
+
**RE-723 — Health normalization and knockback selection:** 211239 normalizes the supplied direction, selects knockback from30 original descriptors or method-specific integer damage, caps only above200, and applies flag/team rejection gates before later effects. [Evidence](research/QVM_HEALTH_KNOCKBACK.md).
|
| 1184 |
+
|
| 1185 |
+
|
| 1186 |
+
RE-714–723 batch complete: [complete contact and health prefixes](research/QVM_CONTACT_HEALTH_BATCH.md). Complete292545 now uses original-model contexts through actual factor/event/feedback children;211239 entry gates and knockback selection are bounded recoveries. Full health mutations/callbacks, native parity and playable Rust/Bevy/Solari work remain open. RE-713 is partially advanced and RE-724 tracks the next work.
|
docs/PROVISIONAL_TODO.md
CHANGED
|
@@ -1167,3 +1167,9 @@ Research progress: RE-721 [report](research/QVM_CONTACT_COMPLETE.md); remaining
|
|
| 1167 |
|
| 1168 |
|
| 1169 |
Research progress: RE-722 [report](research/QVM_HEALTH_GATES.md); remaining native/content/runtime/platform scope stays open.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1167 |
|
| 1168 |
|
| 1169 |
Research progress: RE-722 [report](research/QVM_HEALTH_GATES.md); remaining native/content/runtime/platform scope stays open.
|
| 1170 |
+
|
| 1171 |
+
|
| 1172 |
+
Research progress: RE-723 [report](research/QVM_HEALTH_KNOCKBACK.md); remaining native/content/runtime/platform scope stays open.
|
| 1173 |
+
|
| 1174 |
+
|
| 1175 |
+
RE-714–723 batch complete: [complete contact and health prefixes](research/QVM_CONTACT_HEALTH_BATCH.md). Complete292545 now uses original-model contexts through actual factor/event/feedback children;211239 entry gates and knockback selection are bounded recoveries. Full health mutations/callbacks, native parity and playable Rust/Bevy/Solari work remain open. RE-713 is partially advanced and RE-724 tracks the next work.
|
docs/RESEARCH_LEDGER.md
CHANGED
|
@@ -1250,3 +1250,11 @@ Complete292545 now composes eligibility, ordinary/special factors, event/impact
|
|
| 1250 |
## 2026-10-21 — RE-722 Health damage entry gates and client marker (separate task commit)
|
| 1251 |
|
| 1252 |
211239 applies damageable/mode/method/protection/global gates before marking client4328 and optionally first cross-team tracking34999664; health is unchanged in the prefix. 114 gate/tracking/client/method fixtures verify exact accepted/void-exit boundaries and both conditional writes with independent predicates. Full suite: 1337 tests pass. Report regenerates byte-identically (71028 bytes). Storage/filter, links and whitespace checks pass. No assets/Rust runtime/shared VM evaluator changed; native/reference/legal/full platform scope remains open.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1250 |
## 2026-10-21 — RE-722 Health damage entry gates and client marker (separate task commit)
|
| 1251 |
|
| 1252 |
211239 applies damageable/mode/method/protection/global gates before marking client4328 and optionally first cross-team tracking34999664; health is unchanged in the prefix. 114 gate/tracking/client/method fixtures verify exact accepted/void-exit boundaries and both conditional writes with independent predicates. Full suite: 1337 tests pass. Report regenerates byte-identically (71028 bytes). Storage/filter, links and whitespace checks pass. No assets/Rust runtime/shared VM evaluator changed; native/reference/legal/full platform scope remains open.
|
| 1253 |
+
|
| 1254 |
+
|
| 1255 |
+
## 2026-10-21 — RE-723 Health normalization and knockback selection (separate task commit)
|
| 1256 |
+
|
| 1257 |
+
211239 normalizes the supplied direction, selects knockback from30 original descriptors or method-specific integer damage, caps only above200, and applies flag/team rejection gates before later effects. 226 method/damage/direction/flag/team/spectator/client-state fixtures verify exact float32 words, original tables, return boundaries and unchanged health. Full suite: 1341 tests pass. Report regenerates byte-identically (372670 bytes). Storage/filter, links and whitespace checks pass. No assets/Rust runtime/shared VM evaluator changed; native/reference/legal/full platform scope remains open.
|
| 1258 |
+
|
| 1259 |
+
|
| 1260 |
+
Batch RE-714–723 closes ten independently checked research tasks in ten separate commits, advancing the Python baseline1300→1341. All ten new reports regenerate byte-identically below2MiB. See the [batch overview](research/QVM_CONTACT_HEALTH_BATCH.md) for findings, actual/captured child boundaries and remaining work. Original assets, Rust code and the shared VM evaluator remain unchanged. RE-713 remains partially open; RE-724 records the next scope.
|
docs/REVERSE_ENGINEERING_TODO.md
CHANGED
|
@@ -1182,7 +1182,7 @@ Purpose: turn the supplied installation into an evidence-backed specification of
|
|
| 1182 |
- [x] RE-712 Contact direction basis and health-damage dispatch ([report](research/QVM_CONTACT_DISPATCH.md)).
|
| 1183 |
|
| 1184 |
|
| 1185 |
-
- [ ] RE-713 Compose complete contact292545 and health211239, continue shared/pellet callers, capture native parity, and integrate Rust/Bevy/Solari toward playable macOS/Linux builds. See the [next ten tasks](research/QVM_DAMAGE_FACTOR_BATCH.md#remaining-limits-and-next-ten-tasks).
|
| 1186 |
|
| 1187 |
|
| 1188 |
- [x] RE-714 Ordinary contact factor composition ([report](research/QVM_CONTACT_FACTOR.md)).
|
|
@@ -1210,3 +1210,9 @@ Purpose: turn the supplied installation into an evidence-backed specification of
|
|
| 1210 |
|
| 1211 |
|
| 1212 |
- [x] RE-722 Health damage entry gates and client marker ([report](research/QVM_HEALTH_GATES.md)).
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1182 |
- [x] RE-712 Contact direction basis and health-damage dispatch ([report](research/QVM_CONTACT_DISPATCH.md)).
|
| 1183 |
|
| 1184 |
|
| 1185 |
+
- [ ] RE-713 Compose complete contact292545 and health211239, continue shared/pellet callers, capture native parity, and integrate Rust/Bevy/Solari toward playable macOS/Linux builds. See the [next ten tasks](research/QVM_DAMAGE_FACTOR_BATCH.md#remaining-limits-and-next-ten-tasks). Partially advanced by RE-714–723: complete contact composition, actual feedback and bounded health entry/knockback stages are recovered; full health/callback/native/platform work remains open.
|
| 1186 |
|
| 1187 |
|
| 1188 |
- [x] RE-714 Ordinary contact factor composition ([report](research/QVM_CONTACT_FACTOR.md)).
|
|
|
|
| 1210 |
|
| 1211 |
|
| 1212 |
- [x] RE-722 Health damage entry gates and client marker ([report](research/QVM_HEALTH_GATES.md)).
|
| 1213 |
+
|
| 1214 |
+
|
| 1215 |
+
- [x] RE-723 Health normalization and knockback selection ([report](research/QVM_HEALTH_KNOCKBACK.md)).
|
| 1216 |
+
|
| 1217 |
+
|
| 1218 |
+
- [ ] RE-724 Complete health211239 and impulse213009, compose actual contact/health/shared-pellet paths with original-model geometry, capture native parity and advance interactive Rust/Bevy/Solari on macOS/Linux. See the [next ten tasks](research/QVM_CONTACT_HEALTH_BATCH.md#remaining-limits-and-next-ten-tasks).
|
docs/research/QVM_CONTACT_HEALTH_BATCH.md
ADDED
|
@@ -0,0 +1,45 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Complete contact and health prefixes: RE-714–723
|
| 2 |
+
|
| 3 |
+
Ten separately checked tasks extend the [damage-factor batch](QVM_DAMAGE_FACTOR_BATCH.md). Complete292545 now uses cached original-model hit/miss contexts through its actual recovered factor, event and feedback children. Two bounded211239 stages recover entry gates and knockback selection; actual health/death effects and playable Rust/Bevy/Solari behavior remain open.
|
| 4 |
+
|
| 5 |
+
| Task | Completed scope | Evidence |
|
| 6 |
+
| --- | --- | --- |
|
| 7 |
+
| RE-714 | Ordinary contact composed with complete factor and scalar publication | [Factor handoff](QVM_CONTACT_FACTOR.md) |
|
| 8 |
+
| RE-715 | Special weapon4 scalar and actual equipment classification | [Special contact](QVM_CONTACT_SPECIAL.md) |
|
| 9 |
+
| RE-716 | Event eligibility and conditional announcement ABI | [Announcement gates](QVM_CONTACT_ANNOUNCEMENT.md) |
|
| 10 |
+
| RE-717 | Actual event constructor, normal codec, IDs and lethality prediction | [Event header](QVM_CONTACT_EVENT_HEADER.md) |
|
| 11 |
+
| RE-718 | Encoded scalar, exact point and normalized separation | [Event payload](QVM_CONTACT_EVENT_VALUE.md) |
|
| 12 |
+
| RE-719 | Forward/muzzle payload and actual feedback sum/time ledger | [Feedback](QVM_CONTACT_FEEDBACK.md) |
|
| 13 |
+
| RE-720 | Complete impact-only branch, event selection and zero returns | [Impact branch](QVM_CONTACT_IMPACT.md) |
|
| 14 |
+
| RE-721 | Complete292545 on original-model hit/miss contexts | [Complete contact](QVM_CONTACT_COMPLETE.md) |
|
| 15 |
+
| RE-722 | Health entry gates and conditional tracking/client markers | [Health gates](QVM_HEALTH_GATES.md) |
|
| 16 |
+
| RE-723 | Health direction normalization, knockback selection and later rejection | [Knockback selection](QVM_HEALTH_KNOCKBACK.md) |
|
| 17 |
+
|
| 18 |
+
## Findings and validation
|
| 19 |
+
|
| 20 |
+
Ordinary contact multiplies the complete289594 result by100 in float32, then forces scalar0 when the output location is zero. The special weapon4 path fixes scalar1, reclassifies head/torso through actual inventory and leaves the ordinary accumulator unchanged. Nonzero caller flag and scalar enable the hit event; announcement suppression is independent of event creation.
|
| 21 |
+
|
| 22 |
+
Actual277695/278138 constructs a temporary event and captures its native link request before the contact header writes IDs, location, part, normal code and predicted lethality. The event constructor stores snapped coordinates. The later contact payload overwrites trajectory base24 with the exact trace point while retaining snapped origin488. Ordinary event204 truncates scalar to integer; weapon4 uses accumulator×100 with upper cap100 and no lower cap. Separation is attacker-minus-target entity position normalized in source float32 order. Forward payload is global forward×500 truncated componentwise; weapon27 copies exact muzzle bytes. The event uses the earlier global forward, before the contact suffix rebuilds the basis from attacker angles.
|
| 23 |
+
|
| 24 |
+
Feedback executes actual285142. The contact gate suppresses same-team feedback in enabled modes and requires positive encoded value. The helper separately requires an attacker client, enabled mode and signed target ID0–64 inclusive, then adds the integer value and writes the current time in an8-byte ledger entry. Detached ID fixtures test boundaries without asserting live world identity. Impact-only contacts emit event109 for weapon30 or63 otherwise, requiring a nonzero caller flag and clear surface bit32, and always return0.
|
| 25 |
+
|
| 26 |
+
Complete292545 composes these paths with original context bytes and independently checked full event records, factor arithmetic, request arguments and returns. Original geometry is cached source-produced output; world collision and live frame selection do not execute.211239 remains captured at this caller boundary.
|
| 27 |
+
|
| 28 |
+
Inside211239, entry gates depend on damageability, mode/method, protection, client flags and several globals whose gameplay names remain unresolved. Accepted prefixes can set a first cross-team tracking flag and client4328. A later recovered slice normalizes the supplied direction in place or sets damage flag4 for null direction. It scans30 original descriptors for knockback, with method-specific integer damage overrides and upper cap200. Entity flag2048 or damage flag4 zeros the scalar. Spectator/team/friendly-fire/protection rejection can occur after direction mutation or scalar selection. No velocity impulse, armor/health subtraction, pain/death callback or final health publication runs in these slices.
|
| 29 |
+
|
| 30 |
+
The1300-test baseline gains41 checks, ending at1341 passing Python tests. Each new report regenerates byte-identically below2MiB. Event reports retain full initial/final/link records and hash large nested constructor child effects to avoid duplicating records. Source descriptor/format identity, storage/filter setup, documentation links and whitespace checks pass. Original assets, Rust code and the shared VM evaluator are unchanged. Native math/link/reference parity and Linux execution remain open.
|
| 31 |
+
|
| 32 |
+
## Remaining limits and next ten tasks
|
| 33 |
+
|
| 34 |
+
RE-713 is partially advanced: complete contact composition and health prefixes are done, while full health behavior, shared/pellet callers, native parity and Rust/Bevy/Solari integration remain open. RE-724 tracks the next work.
|
| 35 |
+
|
| 36 |
+
1. Recover211239 pointer fallbacks and special target-kind callback routing at211437–211509, then compose both health prefixes with the accepted contact request.
|
| 37 |
+
2. Recover attacker hit/team bookkeeping, minimum damage, client damage accumulators, direction/world-origin publication and method-specific flags through212157.
|
| 38 |
+
3. Recover special target checksum/class branches, method filters, random damage selection and callbacks through212478 with explicit randomness/native boundaries.
|
| 39 |
+
4. Recover mode10 lethal interception and method24 override branches through212621.
|
| 40 |
+
5. Recover ordinary health subtraction, protected health floor, client flag/meter effects, attacker/location attribution and health publication through212799.
|
| 41 |
+
6. Recover packed meter caps, pain/death callback requests, health clamp and direction/knockback handoff through the211239 void exit, including actual213009 velocity impulse behavior.
|
| 42 |
+
7. Compose complete211239 with complete292545 and original-model contexts, retaining explicit native/callback boundaries and independent all-state oracles.
|
| 43 |
+
8. Continue shared293732 trace/contact/statistics and successful295018 pellet aggregation using original-model geometry.
|
| 44 |
+
9. Recover native loader18183 ownership/endian/failure and capture original executable/DLL parity for geometry, math, inventory and live animation/clock domains.
|
| 45 |
+
10. Port verified asset/interpolation/geometry contracts into Rust, integrate Bevy/Solari, and validate the first interactive macOS/Linux slice with the remaining map/material/texture/audio/network/lifecycle/packaging work.
|
docs/research/QVM_DAMAGE_FACTOR_BATCH.md
CHANGED
|
@@ -41,3 +41,6 @@ RE-702 is partially advanced for contact/damage analysis, with its Bevy/native/i
|
|
| 41 |
8. Recover native loader18183 ownership/endian/failure behavior and capture native/executable parity for geometry, transcendental math and live frame/clock domains.
|
| 42 |
9. Add Rust frame/tag interpolation, hierarchy, geometry/classification contracts and Bevy asset resolution, preserving case and archive variants.
|
| 43 |
10. Build an interactive macOS/Linux Bevy/Solari slice and continue maps, materials, textures, audio, networking, lifecycle and packaging validation.
|
|
|
|
|
|
|
|
|
|
|
|
| 41 |
8. Recover native loader18183 ownership/endian/failure behavior and capture native/executable parity for geometry, transcendental math and live frame/clock domains.
|
| 42 |
9. Add Rust frame/tag interpolation, hierarchy, geometry/classification contracts and Bevy asset resolution, preserving case and archive variants.
|
| 43 |
10. Build an interactive macOS/Linux Bevy/Solari slice and continue maps, materials, textures, audio, networking, lifecycle and packaging validation.
|
| 44 |
+
|
| 45 |
+
|
| 46 |
+
Follow-up: [RE-714–723](QVM_CONTACT_HEALTH_BATCH.md) composes complete292545 and recovers211239 entry/normalization/knockback stages. Full health behavior and callbacks remain open; RE-713 is partially advanced and RE-724 records the next work.
|
docs/research/QVM_HEALTH_KNOCKBACK.md
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Health normalization and knockback selection
|
| 2 |
+
|
| 3 |
+
RE-723. Reproduce with `python3 scripts/analyze_qvm_health_knockback.py`; check with `python3 scripts/test_qvm_health_knockback.py`. The [machine report](qvm-health-knockback.json) retains source identity and bounded fixtures.
|
| 4 |
+
|
| 5 |
+
Actual211510–211849 rejects nonzero client4040, normalizes a nonnull direction in place through source-order float32 and modeled native sqrt, or ORs4 into damage flags for null direction. A distinct spectator-team3 attacker returns after normalization. A first-match scan covers original weapon count30, selecting4192 by method4200. Methods22/25/29 override with signed integer damage/2 converted to float;37 uses full integer damage. Only the upper bound200 is clamped. Entity552 bit2048 or damage flag4 forces selected knockback zero. Enabled-mode same-team friendly-fire-disabled contacts and entity552 bit16 return through the void exit, unless damage flag8 bypasses these two checks. Earlier spawn-protection gates are separate. Direction mutations and selected scalar can precede these rejections. This stage selects knockback only: no velocity impulse, armor, health or death effects are applied. Earlier target-kind callbacks and full211239 composition remain open.
|
| 6 |
+
|
| 7 |
+
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
|
@@ -768,3 +768,9 @@ The extension collector adds five focused tests for native tail calls, command-r
|
|
| 768 |
|
| 769 |
|
| 770 |
[RE-722: Health damage entry gates and client marker](QVM_HEALTH_GATES.md). Reproduce with `python3 scripts/analyze_qvm_health_gates.py`; check with `python3 scripts/test_qvm_health_gates.py`.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 768 |
|
| 769 |
|
| 770 |
[RE-722: Health damage entry gates and client marker](QVM_HEALTH_GATES.md). Reproduce with `python3 scripts/analyze_qvm_health_gates.py`; check with `python3 scripts/test_qvm_health_gates.py`.
|
| 771 |
+
|
| 772 |
+
|
| 773 |
+
[RE-723: Health normalization and knockback selection](QVM_HEALTH_KNOCKBACK.md). Reproduce with `python3 scripts/analyze_qvm_health_knockback.py`; check with `python3 scripts/test_qvm_health_knockback.py`.
|
| 774 |
+
|
| 775 |
+
|
| 776 |
+
[RE-714–723 batch overview and next tasks](QVM_CONTACT_HEALTH_BATCH.md).
|
docs/research/qvm-health-knockback.json
ADDED
|
The diff for this file is too large to render.
See raw diff
|
|
|
scripts/analyze_qvm_health_knockback.py
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#!/usr/bin/env python3
|
| 2 |
+
"""Health direction normalization, descriptor/special knockback and rejection gates."""
|
| 3 |
+
import itertools
|
| 4 |
+
from pathlib import Path
|
| 5 |
+
from qvm_research_support import source
|
| 6 |
+
from qvm_health_support import seed,run
|
| 7 |
+
from analyze_qvm import write_json
|
| 8 |
+
|
| 9 |
+
def main():
|
| 10 |
+
q,raw,h,ins=source();rows=[];m=seed(raw,h);table=[{'method':m[4200+432*w],'knockback_word':m[4192+432*w]} for w in range(m[17412])]
|
| 11 |
+
cases=[dict(method=method,damage=damage,direction=direction) for method,damage,direction in itertools.product([0,11,12,22,25,29,33,37,999],[-5,0,1,301,1000],[None,(0,0,0),(3,4,0)])]
|
| 12 |
+
cases += [dict(method=method,flags=flags,entity_flags=ef) for method,flags,ef in itertools.product([12,22,37],[0,4,8,12],[0,16,2048])]
|
| 13 |
+
cases += [dict(mode=mode,same_team=same,friendly_fire=ff,flags=flags,entity_flags=ef) for mode,same,ff,flags,ef in itertools.product([2,3,9],[False,True],[0,1],[0,8],[0,16])]
|
| 14 |
+
cases += [dict(attacker_team=3,self=self_hit,direction=direction) for self_hit,direction in itertools.product([False,True],[None,(3,4,0)])]
|
| 15 |
+
cases += [dict(client4040=1,direction=direction) for direction in [None,(0,0,0),(3,4,0)]]
|
| 16 |
+
for a in cases:
|
| 17 |
+
_,p=run(ins,seed(raw,h,**a),211510,211850);p['input']=a;rows.append(p)
|
| 18 |
+
write_json(Path('docs/research/qvm-health-knockback.json'),{'source':q['source'],'sha256':q['sha256'],'weapon_count':m[17412],'descriptor_table':table,'probes':rows,'limits':'Actual211510..211849 or void-exit213007; source-order normalization with modeled native sqrt. Knockback scalar is selected but no velocity impulse/armor/health/death effects are applied. Earlier target-kind callback routing not composed.'})
|
| 19 |
+
if __name__=='__main__':main()
|
scripts/test_qvm_health_knockback.py
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import json,math,unittest
|
| 2 |
+
from pathlib import Path
|
| 3 |
+
from test_qvm_ground import word,n,f
|
| 4 |
+
from test_qvm_contact_event_value import normalized
|
| 5 |
+
|
| 6 |
+
def oracle(a,table):
|
| 7 |
+
flags=a.get('flags',0);direction=a.get('direction',[3,4,0]);initial=list(map(word,direction or [3,4,0]));v=0
|
| 8 |
+
if a.get('client4040',0):return flags,initial,word(v),213007
|
| 9 |
+
if direction is None:flags|=4;result=initial
|
| 10 |
+
else:result=normalized(direction,(0,0,0))
|
| 11 |
+
if a.get('attacker_team',2)==3 and not a.get('self',False):return flags,result,word(v),213007
|
| 12 |
+
method=a.get('method',12);damage=a.get('damage',100)
|
| 13 |
+
for row in table:
|
| 14 |
+
if row['method']==method:v=n(row['knockback_word']);break
|
| 15 |
+
if method in (22,25,29):v=f(math.trunc(damage/2))
|
| 16 |
+
elif method==37:v=f(damage)
|
| 17 |
+
v=min(v,200.)
|
| 18 |
+
if a.get('entity_flags',0)&2048 or flags&4:v=0.
|
| 19 |
+
enabled=a.get('mode',3)>=3 and a.get('mode',3) not in (9,11);blocked=not flags&8 and (((not a.get('self',False)) and enabled and a.get('same_team',False) and not a.get('friendly_fire',0)) or a.get('entity_flags',0)&16)
|
| 20 |
+
return flags,result,word(v),213007 if blocked else 211850
|
| 21 |
+
|
| 22 |
+
class HealthKnockbackTests(unittest.TestCase):
|
| 23 |
+
@classmethod
|
| 24 |
+
def setUpClass(cls):cls.r=json.loads(Path('docs/research/qvm-health-knockback.json').read_text());cls.ps=cls.r['probes']
|
| 25 |
+
def test_independent_normalization_selection_and_rejection(self):
|
| 26 |
+
for p in self.ps:self.assertEqual((p['flags'],p['direction_words'],p['knockback_word'],p['execution']['stop']),oracle(p['input'],self.r['descriptor_table']),p['input'])
|
| 27 |
+
def test_original_table_identity_and_first_match_scan_domain(self):
|
| 28 |
+
from qvm_research_support import source
|
| 29 |
+
_,raw,h,_=source();self.assertEqual(self.r['weapon_count'],30)
|
| 30 |
+
for w,row in enumerate(self.r['descriptor_table']):
|
| 31 |
+
for field,base in [('method',4200),('knockback_word',4192)]:
|
| 32 |
+
p=h['data_offset']+base+432*w;self.assertEqual(row[field],int.from_bytes(raw[p:p+4],'little'))
|
| 33 |
+
def test_health_and_client_marker_not_changed_by_this_slice(self):
|
| 34 |
+
self.assertEqual(len(self.ps),226)
|
| 35 |
+
for p in self.ps:self.assertEqual(p['health'],100);self.assertEqual(p['client4328'],0);self.assertIsNone(p['execution']['return'])
|
| 36 |
+
def test_only_actual_mode_and_modeled_sqrt_children(self):
|
| 37 |
+
for p in self.ps:self.assertTrue(all(c['target'] in (-107,33715) for c in p['execution']['calls']))
|
| 38 |
+
if __name__=='__main__':unittest.main()
|