89 lines
3.6 KiB
Python
89 lines
3.6 KiB
Python
#!/usr/bin/env python
|
|
# Forensics for the 11 [projectile] BYSTANDER receipts of the weapons_sweep
|
|
# run: classify every DET lock pointer by aim-point motion (a mech lock TRACKS
|
|
# the walking enemy; a scenery/wreck lock is stationary), then test each
|
|
# receipt: struck id vs the shooter's own id, det-to-aim distance, and the
|
|
# paired IMPACT delivery.
|
|
import io
|
|
import math
|
|
import re
|
|
|
|
RX_DET = re.compile(r"\[projectile\] DET at\(([^)]*)\) dmg=([\d.eE+\-]+) "
|
|
r"lead=(\d+) tgt=(\S+) aim\(([^)]*)\)")
|
|
RX_BYS = re.compile(r"\[projectile\] BYSTANDER id=(\d+) t=(\S+) at\(([^)]*)\) "
|
|
r"dmg=([\d.eE+\-]+) lockedTgt=(\S+)")
|
|
RX_RST = re.compile(r"\[respawn\] Mech::Reset (\d+):(\d+) ")
|
|
|
|
|
|
def p3(s):
|
|
a = [float(x) for x in s.split(",")]
|
|
return a
|
|
|
|
|
|
def dist(a, b):
|
|
return math.sqrt(sum((a[i] - b[i]) ** 2 for i in range(3)))
|
|
|
|
|
|
for fn in ("ws_a.log", "ws_b.log"):
|
|
lines = io.open("/c/git/bt411/content/" + fn.replace("/", ""),
|
|
encoding="latin-1", errors="replace").read().splitlines() \
|
|
if False else io.open("C:/git/bt411/content/" + fn,
|
|
encoding="latin-1", errors="replace").read().splitlines()
|
|
own = None
|
|
dets = {} # tgt ptr -> list of (lineno, aim)
|
|
bys = [] # (lineno, id, at, dmg, lockedTgt)
|
|
for i, l in enumerate(lines):
|
|
m = RX_DET.search(l)
|
|
if m and m.group(4) != "0x0" and float(m.group(2)) > 0.0:
|
|
dets.setdefault(m.group(4), []).append((i, p3(m.group(5))))
|
|
continue
|
|
m = RX_BYS.search(l)
|
|
if m:
|
|
bys.append((i, int(m.group(1)), p3(m.group(3)),
|
|
float(m.group(4)), m.group(5)))
|
|
continue
|
|
m = RX_RST.search(l)
|
|
if m and own is None:
|
|
own = int(m.group(2))
|
|
print("=== %s (own mech entity=%s) ===" % (fn, own))
|
|
# classify pointers: max pairwise aim distance within a 1500-line window
|
|
cls = {}
|
|
for ptr, lst in sorted(dets.items(), key=lambda kv: -len(kv[1])):
|
|
move = 0.0
|
|
for j in range(1, len(lst)):
|
|
if lst[j][0] - lst[j - 1][0] <= 1500:
|
|
d = dist(lst[j][1], lst[j - 1][1])
|
|
if d > move:
|
|
move = d
|
|
cls[ptr] = "MECH-TRACKING" if move > 60.0 else "STATIONARY"
|
|
print(" lock %s damage-DETs=%3d max local aim motion=%7.1fu -> %s"
|
|
% (ptr, len(lst), move, cls[ptr]))
|
|
ok = True
|
|
for (i, mid, at, dmg, ptr) in bys:
|
|
# find this receipt's own DET (next damage DET line)
|
|
aim = None
|
|
imp = False
|
|
for j in range(i, min(i + 4, len(lines))):
|
|
m = RX_DET.search(lines[j])
|
|
if m and aim is None:
|
|
aim = p3(m.group(5))
|
|
if "[projectile] IMPACT damage=" in lines[j]:
|
|
imp = True
|
|
d_aim = dist(at, aim) if aim else -1.0
|
|
verdict = []
|
|
if mid == own:
|
|
verdict.append("SELF-STRIKE (geometry bug)")
|
|
if cls.get(ptr) == "MECH-TRACKING":
|
|
verdict.append("LOCK WAS THE MECH (exclusion failed)")
|
|
if aim is not None and d_aim < 30.0:
|
|
verdict.append("det at the lock's own aim point")
|
|
if not imp:
|
|
verdict.append("no paired IMPACT delivery")
|
|
tag = "TRUE-POSITIVE" if not verdict else "FALSE-POSITIVE: " + "; ".join(verdict)
|
|
if verdict:
|
|
ok = False
|
|
print(" bys@%-6d struck=%d dmg=%g lock=%s(%s) det-to-aim=%.0fu imp=%d %s"
|
|
% (i + 1, mid, dmg, ptr, cls.get(ptr, "?"), d_aim, imp, tag))
|
|
print(" %s: %s" % (fn, "all receipts TRUE positives" if ok
|
|
else "FALSE POSITIVES PRESENT"))
|