#!/usr/bin/env python3 """ run_game.py -- MUNGA game launcher: run the real Red Planet (rpl4opt) / BattleTech (btl4opt) game binaries against the virtual VelociRender board. Mirrors sda4's RP.BAT: `setenv t s n n` (THRUSTMASTER controls, slow clock, nosound, no gauges), 32RTM.EXE -x (Borland DPMI host -- the game binaries are PE images, not Watcom LE), -egg .egg, 32rtm -u. python run_game.py # RPDAVE rpl4opt -egg test.egg python run_game.py --egg last # a different .EGG python run_game.py --dir BTDAVE --exe btl4opt python run_game.py --setenv "t s n g" # e.g. g = gauges on python run_game.py --controls KEYBOARD # exact L4CONTROLS value (setenv's # presets: t=THRUSTMASTER,KEYBOARD # r=RIO,KEYBOARD; RIO = the pod's # serial board, dead hardware) python run_game.py --soft # software renderer reference Board loop runs inline (vrrun --view); the wire log is the primary instrument: unknown actions log as `EXTRA action 0x??`, and a stall right after one means that action expects a reply (this is how the FLYK protocol was decoded). """ import os, sys, subprocess, threading, atexit HERE = os.path.dirname(os.path.abspath(__file__)) STAGE = r"c:\temp\flykc" DOSBOX = r"G:\DOSBox-X\dosbox-x-vrlink.exe" CONF = os.path.join(HERE, "flyk_vr.conf") def main(): proddir, exe, egg, prefix, senv = "RPDAVE", "rpl4opt", "test", "game", "t s n n" controls = None for i, a in enumerate(sys.argv): if a == "--dir" and i + 1 < len(sys.argv): proddir = sys.argv[i + 1] if a == "--exe" and i + 1 < len(sys.argv): exe = sys.argv[i + 1] if a == "--egg" and i + 1 < len(sys.argv): egg = sys.argv[i + 1] if a == "--prefix" and i + 1 < len(sys.argv): prefix = sys.argv[i + 1] if a == "--setenv" and i + 1 < len(sys.argv): senv = sys.argv[i + 1] if a == "--controls" and i + 1 < len(sys.argv): controls = sys.argv[i + 1] if controls is not None: # pre-set L4CONTROLS and give SETENV a neutral first arg (anything but # t/r keeps a pre-existing value -- see SETENV.BAT's CONTROLSDONE path) senv = "k " + " ".join(senv.split()[1:]) root = os.path.join(STAGE, proddir) for need in (f"{exe}.exe", "32RTM.EXE", f"{egg}.egg", "SETENV.BAT"): if not any(f.lower() == need.lower() for f in os.listdir(root)): raise SystemExit(f"{proddir}\\{need} not staged -- run " f"stage_assets.py --game {proddir} first") with open(os.path.join(STAGE, "RUNSCN.BAT"), "w") as fp: fp.write(f"cd \\{proddir}\r\n") if controls is not None: fp.write(f"set L4CONTROLS={controls}\r\n") fp.write(f"call SETENV.BAT {senv}\r\n" f"32RTM.EXE -x\r\n") if "--netnub" in sys.argv: # pod-network hub wrapper (BTNET.BAT): netnub hosts the wattcp # net and launches the game with -net; -a forwards the egg args. # It hard-requires a packet driver ("NO PACKET DRIVER FOUND"): # load the drive's ODI stack against the emulated NE2000 # (LSL -> NE2000 ODI -> ODIPKT shim on int 0x60), WATTCP.CFG # gives the pod Milo's IP 200.0.0.86 from the egg # DOSBox-X embeds the Crynwr NE2000 packet driver on Z: -- # no ODI stack needed (the era-authentic LSL/ODIPKT combo's FTP # shim can't see Novell MLIDs under DOSBox anyway) fp.write("Z:\\SYSTEM\\NE2000.COM 0x60 3 0x300\r\n" f"set WATTCP.CFG=C:\\{proddir}\r\n" f"NETNUB.EXE -f {exe}.exe -a -egg {egg}.egg\r\n") else: fp.write(f"{exe}.exe -egg {egg}.egg\r\n") fp.write(f"32RTM.EXE -u\r\n") print(f"game: {proddir}\\{exe} -egg {egg}.egg setenv {senv}" + (f" L4CONTROLS={controls}" if controls else "") + f" (capture prefix: {prefix})") proc = [] def launch_dosbox(): env = dict(os.environ, VRLINK='1') p = subprocess.Popen([DOSBOX, "-conf", CONF], env=env, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL) proc.append(p) print(f"dosbox launched (pid {p.pid})") threading.Timer(2.0, launch_dosbox).start() atexit.register(lambda: [p.kill() for p in proc if p.poll() is None]) sys.argv = ["vrrun.py", prefix, "--view"] + ( ["--soft"] if "--soft" in sys.argv else []) import vrrun try: vrrun.main() except KeyboardInterrupt: pass if __name__ == "__main__": main()