- Billiards: add native Russian Pyramid & American Eight-Ball pool with physics prediction, controls, and regression tests - Scratch Tickets: add dedicated counter, mat presentation, elliptical coin scraping, 4 ticket types, and payout effects - First-Person Dice: add native dice scene, hand anchor frames, throwing animation, and table perspective - City Wake & Weather: add arrival cutscene, alley geometry, weather/rain effects, and lighter/rocker animation - World Dressing: add hall paintings, furniture packs, hall lighting, and scene regression tests - Build & Tooling: update build.bat for modern MSVC toolchain, update launcher hash, and refresh shipping binaries
51 lines
2.3 KiB
Python
51 lines
2.3 KiB
Python
"""Expose native state in a test-only COFF copy; never patch instructions."""
|
|
from pathlib import Path
|
|
import struct
|
|
from check_card_exit_build import Coff
|
|
|
|
ROOT = Path(__file__).resolve().parents[2]
|
|
EXPOSE = {"casinoMap","hallLevel3D","outdoorRender3D","hallLights3D","hallLoungeDecor3D",
|
|
"hallRopeFurniture3D","hallLampFurniture3D","cityObjects3D","hallStreetLife3D","cityDecorPack3D",
|
|
"playerX","playerY","playerAngle","viewEye3D","viewCeiling3D","viewHorizon3D",
|
|
"worldMap3D","floorTexture3D","cityMap3D","cityPhase3D","cityTime3D","cityClock3D","arrivalState3D",
|
|
"screenBuffer","cityDepthBuffer3D","cityRayX3D","cityRayY3D","zBuffer","cityBackdrop3D",
|
|
"playerPlaneX","playerPlaneY"}
|
|
|
|
|
|
def main():
|
|
out = ROOT/"build/world"
|
|
out.mkdir(parents=True,exist_ok=True)
|
|
baseline = out/"prior-release.obj"
|
|
if not baseline.exists():
|
|
baseline.write_bytes((ROOT/"build/actions/actions-test.obj").read_bytes())
|
|
coff = Coff(baseline)
|
|
original = coff.data
|
|
data = bytearray(original)
|
|
start = struct.unpack_from("<I",data,8)[0]
|
|
changed,found = set(),set()
|
|
for index,name in coff.symbols.items():
|
|
at = start+index*18
|
|
_,section,kind,storage,_ = struct.unpack_from("<IhHBB",data,at+8)
|
|
target = None
|
|
if name in EXPOSE:
|
|
found.add(name)
|
|
target = 2
|
|
elif name in {"_ResolveCitySurface3D@4","_DrawCityVertical3D@28","_DrawCityHorizontal3D@24"} and kind==0x20 and storage==2 and section>0:
|
|
target = 3
|
|
if target is not None and target!=storage:
|
|
data[at+16] = target
|
|
changed.add(at+16)
|
|
assert found==EXPOSE,EXPOSE-found
|
|
assert {i for i,(a,b) in enumerate(zip(data,original)) if a!=b}==changed
|
|
(out/"base.obj").write_bytes(data)
|
|
source = (ROOT/"src_graphics/city_bins.inc").read_text(encoding="cp1251")
|
|
bodies = []
|
|
for name in ("ResolveCitySurface3D","DrawCityVertical3D","DrawCityHorizontal3D"):
|
|
body = source.split(name+" PROC",1)[1].split(name+" ENDP",1)[0]
|
|
bodies.append(name+" PROC"+body+name+" ENDP\n")
|
|
(out/"surfaces.inc").write_text("\n".join(bodies),encoding="ascii")
|
|
print("Prepared native renderer probe: storage visibility only, no modified code or relocations")
|
|
|
|
|
|
if __name__=="__main__":
|
|
main()
|