69 lines
4.1 KiB
Python
69 lines
4.1 KiB
Python
"""#73: post the zone-lottery discovery."""
|
|
import base64
|
|
import json
|
|
import subprocess
|
|
import urllib.request
|
|
|
|
REPO = r"C:\git\bt411"
|
|
BASE = "https://gitea.mysticmachines.com/api/v1/repos/VWE/BT411"
|
|
|
|
out = subprocess.run(["git", "credential", "fill"],
|
|
input="protocol=https\nhost=gitea.mysticmachines.com\n\n",
|
|
capture_output=True, text=True, cwd=REPO)
|
|
cred = dict(l.split("=", 1) for l in out.stdout.strip().splitlines() if "=" in l)
|
|
AUTH = "Basic " + base64.b64encode(
|
|
(cred["username"] + ":" + cred["password"]).encode()).decode()
|
|
|
|
|
|
def call(method, path, payload=None):
|
|
data = json.dumps(payload).encode() if payload is not None else None
|
|
r = urllib.request.Request(BASE + path, data=data, method=method)
|
|
r.add_header("Authorization", AUTH)
|
|
r.add_header("Content-Type", "application/json")
|
|
return json.load(urllib.request.urlopen(r))
|
|
|
|
|
|
BODY = """**INVESTIGATED 2026-07-29 -- this is mostly the authentic 1995 model, not a bug.**
|
|
|
|
The zone a hit credits is chosen by a **weighted lottery**, in binary-faithful code reading binary-shipped tables (`dmgtable.cpp`, stream format byte-verified):
|
|
|
|
1. impact point -> mech-local
|
|
2. **height layer**: `floor(layerCount * y / heightRef)`
|
|
3. **pie slice**: `atan2(z, x)` around the mech's vertical axis (a layer can rotate with live torso twist -- `rotateWithTorso`)
|
|
4. `DamageZonePercentTable::SelectZone()` = **`RandomUnit()` rolled against cumulative percent thresholds** (`@0x49de14`) -- each slice carries an authored *distribution* of zones
|
|
|
|
So aiming at the left arm at best biases WHICH SLICE the impact lands in; the zone within that slice is dice, by design. "Fired only at the left arm, damage reported all over the doll, no crits" is what this model produces. **Pixel-precise limb damage never existed in Tesla 4.10.**
|
|
|
|
Bench measurement (solo dummy, walked to 8u, aim pinned left / center / right across the silhouette, trigger held, `BT_DMG_LOG`):
|
|
|
|
```
|
|
aim LEFT 24 hits -> zones 15(x9) 12(x6) 2(x3) 14(x2) 9 21
|
|
aim CENTER 46 hits -> zones 2(x11) 13(x9) 7(x6) 6(x5) 21(x5) 0(x5)
|
|
aim RIGHT 45 hits -> zones 21(x9) 17(x7) 0(x7) 9(x6) 18(x5) 15(x5)
|
|
```
|
|
|
|
Scatter within one aim point = the percent tables. The distribution SHIFTING with aim = the slice selection responding. Both halves of the model visibly working.
|
|
|
|
@VGL-Lynx's LOD theory: right instinct (hit-test geometry != drawn mesh), wrong geometry -- it is not LOD-dependent. The port's pick ray tests the **whole-mech bounding BOX** (`Mech::PickRayHit`, an AABB slab test), and the binary's own pick code was never decompiled (the `0x37c/0x388/0x38c` writer sits in an un-exported gap), so the box is a port stand-in of unknown fidelity.
|
|
|
|
**The one residual question that IS potentially a real port bug:** theta computed from a flat box FACE clusters toward the slices facing the shooter, so FLANK slices (where arm-heavy percent tables presumably live) may be under-reachable from frontal shots compared with the pod -- which plausibly intersected the mech's *cylinder* (the damage table is literally cylindrical). Settling it needs:
|
|
- a per-hit probe logging `theta / layer / slice` (extend `BT_DMG_LOG`)
|
|
- a one-shot wheel dump for one mech (slices per layer + each slice's {percent, zone} entries + zone names)
|
|
|
|
If the wheel dump shows arm zones concentrated in flank slices AND the theta probe shows frontal shots cannot reach those slices, the fix is a ray-vs-cylinder pick (radius from the collision extents) replacing the box slab -- cylinder-consistent with the table the binary ships. If arm zones appear in the front slices' tables too, the field report is 100%% authored behavior and this closes as by-design.
|
|
|
|
Recommend telling the testers now that per-limb aiming is not how this game's damage works -- it will save another evening of controlled experiments chasing the lottery."""
|
|
|
|
|
|
def main():
|
|
marker = BODY.strip().splitlines()[0][:60]
|
|
for c in call("GET", "/issues/73/comments"):
|
|
if marker in c.get("body", ""):
|
|
print(" #73 already has this comment - skipped")
|
|
return
|
|
call("POST", "/issues/73/comments", {"body": BODY})
|
|
print(" commented on #73")
|
|
|
|
|
|
main()
|