Combat: AUTHENTIC weapon groups -- streamed per-mech button bindings + the real fire chain (task #5)
The recovered system: fire channels = LBE4ControlsManager buttonGroups (0x40/0x45/0x46/0x47); default groups = the per-mech type-6 controls-map resource in BTL4.RES, installed by the T0 CreateStreamedMappings the port already called -- it needed only the TriggerState attribute (id 0x13 PINNED to the binary value; fireImpulse@0x31C is the binary's TriggerState) and an input feed. Keyboard/harness now push press/release edges into the button groups; the gBT*Trigger bypasses, per-type keyboard split and 1,0 pulse hack are retired -- weapons sharing a button fire TOGETHER (madcat Trigger = 4 weapons). Myomers @4b9550/@4b95b8 misattribution corrected (they are MechWeapon ConfigureMappables/ChooseButton). Verified 2-node: kill through the authentic chain (12 hits vs ~36 pre-groups). Config-mode session (regrouping UI) = the remaining stage, KB-scoped. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Fable 5
parent
4554ea543a
commit
8ed6184d65
@@ -0,0 +1,85 @@
|
||||
import struct, math, numpy as np, sys
|
||||
from PIL import Image
|
||||
data=open("content/VIDEO/GEO/TSPHERE.BGF","rb").read()
|
||||
verts=[]; faces=[]
|
||||
def parse(p,end):
|
||||
while p+3<=end:
|
||||
tw=struct.unpack_from("<H",data,p)[0]; p+=2
|
||||
cid=tw&0x2fff; lw=4 if(tw&0x8000)else(2 if(tw&0x4000)else 1)
|
||||
if p+lw>end:return
|
||||
ln=data[p] if lw==1 else(struct.unpack_from("<H",data,p)[0] if lw==2 else struct.unpack_from("<I",data,p)[0])
|
||||
p+=lw
|
||||
if p+ln>end:return
|
||||
if cid==0x0089:
|
||||
for i in range(ln//32):
|
||||
o=p+i*32; x,y,z=struct.unpack_from("<fff",data,o); u,v=struct.unpack_from("<ff",data,o+24); verts.append((x,y,z,u,v))
|
||||
elif cid==0x0047:
|
||||
n=ln//4; idx=[struct.unpack_from("<I",data,p+i*4)[0] for i in range(n)]
|
||||
for f in range(0,(n//3)*3,3): faces.append((idx[f],idx[f+1],idx[f+2]))
|
||||
if cid in {0x3,0x70,0x40,0x41,0x42,0x46,0x48,0x10,0x20,0x30}: parse(p,p+ln)
|
||||
p+=ln
|
||||
if cid==0x5: break
|
||||
parse(8,len(data))
|
||||
V=[list(v[:3]) for v in verts]; UV=[list(v[3:]) for v in verts]; F=list(faces)
|
||||
def proj_cone(m):
|
||||
x,y,z=m; t=min(abs(z)/21.0,1.0); rI=10.5*(1-t); dy=y-8.25; r=math.hypot(x,dy)
|
||||
if r>1e-5: sc=rI/r; x*=sc; y=8.25+dy*sc
|
||||
return [x,y,z]
|
||||
def tess(passes):
|
||||
global V,UV,F
|
||||
for _ in range(passes):
|
||||
nF=[]; mid={}
|
||||
def gm(a,b):
|
||||
k=(min(a,b),max(a,b))
|
||||
if k in mid:return mid[k]
|
||||
pm=proj_cone([(V[a][0]+V[b][0])/2,(V[a][1]+V[b][1])/2,(V[a][2]+V[b][2])/2])
|
||||
V.append(pm); UV.append([(UV[a][0]+UV[b][0])/2,(UV[a][1]+UV[b][1])/2]); mid[k]=len(V)-1; return len(V)-1
|
||||
for (a,b,c) in F:
|
||||
ab=gm(a,b);bc=gm(b,c);ca=gm(c,a); nF+=[(a,ab,ca),(ab,b,bc),(ca,bc,c),(ab,bc,ca)]
|
||||
F=nF
|
||||
TESS=int(sys.argv[1]) if len(sys.argv)>1 else 3
|
||||
tess(TESS)
|
||||
Va=np.array(V); UVa=np.array(UV)
|
||||
bd=open("content/VIDEO/TEX/BINTA.VTX","rb").read(); w=h=64; off=57
|
||||
tex=np.frombuffer(bd[off:off+w*h*3],dtype=np.uint8).astype(float).reshape(h,w,3)/255.0
|
||||
texL=0.299*tex[:,:,0]+0.587*tex[:,:,1]+0.114*tex[:,:,2]
|
||||
def samp(u,v):
|
||||
uu=(u%1.0)*w-0.5; vv=(v%1.0)*h-0.5; x0=np.floor(uu).astype(int); y0=np.floor(vv).astype(int); fx=uu-x0; fy=vv-y0
|
||||
x0m=x0%w;x1m=(x0+1)%w;y0m=y0%h;y1m=(y0+1)%h
|
||||
return texL[y0m,x0m]*(1-fx)*(1-fy)+texL[y0m,x1m]*fx*(1-fy)+texL[y1m,x0m]*(1-fx)*fy+texL[y1m,x1m]*fx*fy
|
||||
def clip(poly,zn=0.1):
|
||||
out=[];n=len(poly)
|
||||
for i in range(n):
|
||||
A=poly[i];B=poly[(i+1)%n]
|
||||
if A[2]>=zn:out.append(A)
|
||||
if(A[2]>=zn)!=(B[2]>=zn): t=(zn-A[2])/(B[2]-A[2]); out.append(tuple(A[k]+(B[k]-A[k])*t for k in range(5)))
|
||||
return out
|
||||
def R(eyeUp,spin,fov=75.0,LO=(0.15,0.12,0.35),HI=(0.98,0.94,1.0),W=400,H=300):
|
||||
LO=np.array(LO);HI=np.array(HI)
|
||||
qx=Va[:,0];qy=Va[:,1]-eyeUp;qz=Va[:,2]; c,s=math.cos(spin),math.sin(spin)
|
||||
rx=qx*c-qy*s;ry=qx*s+qy*c; P=np.stack([rx,ry,qz],axis=1); f=(H/2)/math.tan(math.radians(fov)/2)
|
||||
img=np.zeros((H,W,3)); zb=np.full((H,W),1e18)
|
||||
for (a,b,cc) in F:
|
||||
tri=[(P[i][0],P[i][1],P[i][2],UVa[i][0],UVa[i][1]) for i in (a,b,cc)]
|
||||
cp=clip(tri)
|
||||
if len(cp)<3:continue
|
||||
for k in range(1,len(cp)-1):
|
||||
A,B,C=cp[0],cp[k],cp[k+1]
|
||||
def pr(p):return(W/2+f*p[0]/p[2],H/2-f*p[1]/p[2],p[2],p[3],p[4])
|
||||
xa,ya,za,ua,va=pr(A);xb,yb,zb2,ub,vb=pr(B);xc,yc,zc,uc,vc=pr(C)
|
||||
mnx=max(int(min(xa,xb,xc)),0);mxx=min(int(max(xa,xb,xc))+1,W-1);mny=max(int(min(ya,yb,yc)),0);mxy=min(int(max(ya,yb,yc))+1,H-1)
|
||||
if mnx>=mxx or mny>=mxy:continue
|
||||
den=((yb-yc)*(xa-xc)+(xc-xb)*(ya-yc))
|
||||
if abs(den)<1e-9:continue
|
||||
ys,xs=np.mgrid[mny:mxy+1,mnx:mxx+1];xf=xs+.5;yf=ys+.5
|
||||
l1=((yb-yc)*(xf-xc)+(xc-xb)*(yf-yc))/den;l2=((yc-ya)*(xf-xc)+(xa-xc)*(yf-yc))/den;l3=1-l1-l2
|
||||
m=(l1>=0)&(l2>=0)&(l3>=0)
|
||||
if not m.any():continue
|
||||
iz=l1/za+l2/zb2+l3/zc;z=1/iz; u=(l1*ua/za+l2*ub/zb2+l3*uc/zc)*z; v=(l1*va/za+l2*vb/zb2+l3*vc/zc)*z
|
||||
lum=np.clip(samp(u,v),0,1); col=LO[None,:]+(HI-LO)[None,:]*lum[...,None]
|
||||
yi=ys[m];xi=xs[m];zz=z[m];cl=zz<zb[yi,xi]; zb[yi[cl],xi[cl]]=zz[cl]; img[yi[cl],xi[cl]]=col[m][cl]
|
||||
return (np.clip(img,0,1)*255).astype(np.uint8)
|
||||
ig=np.array(Image.open("scratchpad/ingame_warp2.png").convert("RGB").resize((400,300)))
|
||||
row=[ig]+[R(eu,0.5) for eu in (0.0,4.0,8.25)]
|
||||
Image.fromarray(np.concatenate(row,axis=1)).save(f"scratchpad/cmp_tess{TESS}.png")
|
||||
print(f"TESS={TESS} verts={len(V)} faces={len(F)} -> cmp_tess{TESS}.png [IN-GAME | eyeUp=0,4,8.25]")
|
||||
Reference in New Issue
Block a user