Files
firestorm/BTFrstrm/gen_weapon_spreadsheets.py
T

112 lines
4.0 KiB
Python

#!/usr/bin/env python3
"""Generate special_weapon_locations.csv and rear_facing_weapons.csv from stock mech subsystems."""
import csv
from pathlib import Path
BASE = Path("Gameleap/mw4/Content")
MECH_TABLE = BASE / "Tables" / "MechTable.tbl"
OUT_DIR = Path("BTFrstrm")
def parse_ini(path):
sections, cur_sec, cur_dict = [], None, {}
with open(path, 'r', encoding='latin-1', errors='replace') as f:
for raw in f:
line = raw.strip()
if line.startswith('[') and line.endswith(']'):
if cur_sec is not None:
sections.append((cur_sec, cur_dict))
cur_sec, cur_dict = line[1:-1], {}
elif '=' in line and cur_sec is not None:
k, _, v = line.partition('=')
cur_dict[k.strip()] = v.strip()
if cur_sec is not None:
sections.append((cur_sec, cur_dict))
return sections
def find_dir_ci(parent, name):
"""Case-insensitive directory lookup for Linux."""
exact = parent / name
if exact.exists():
return exact
name_lower = name.lower()
for child in parent.iterdir():
if child.is_dir() and child.name.lower() == name_lower:
return child
return None
def weapon_model(model_path):
return Path(model_path.replace('\\', '/')).stem
# Read chassis list from MechTable.tbl
chassis_list = []
with open(MECH_TABLE, 'r', encoding='latin-1') as f:
for raw in f:
line = raw.strip()
if not line or line.startswith('//') or line.startswith('[') or '=' not in line:
continue
name, _, rel = line.partition('=')
# rel is like "Mechs\Atlas\Atlas.instance"
parts = rel.strip().replace('\\', '/').split('/')
chassis_list.append((name.strip(), parts)) # parts = ['Mechs', 'Atlas', 'Atlas.instance']
print(f"Found {len(chassis_list)} chassis in MechTable.tbl")
HDR = ['Chassis', 'InternalLocation', 'Model', 'Site', 'AmmoCount', 'GroupIndex', 'WeaponFacing']
special_rows, rear_rows, missing = [], [], []
mechs_dir = BASE / "Mechs"
for chassis_name, path_parts in chassis_list:
# path_parts[1] is the mech directory name (e.g. 'Atlas', 'MadCat_MkII', 'Urbanmech')
if len(path_parts) < 2:
missing.append(chassis_name)
continue
mech_dir = find_dir_ci(mechs_dir, path_parts[1])
if not mech_dir:
missing.append(f"{chassis_name} (dir not found: {path_parts[1]})")
continue
subs = [f for f in mech_dir.glob('*.subsystems') if f.suffix == '.subsystems']
if not subs:
missing.append(f"{chassis_name} (no .subsystems in {mech_dir.name})")
continue
subsys_file = subs[0]
sections = parse_ini(subsys_file)
for sec_name, fields in sections:
if 'WeaponSubsystem' not in fields.get('Model', ''):
continue
loc = fields.get('InternalLocation', '')
model = weapon_model(fields.get('Model', ''))
site = fields.get('Site', '')
ammo = fields.get('AmmoCount', '')
group = fields.get('GroupIndex', '')
facing = fields.get('WeaponFacing', '')
if loc in ('Special1', 'Special2'):
special_rows.append([chassis_name, loc, model, site, ammo, group, facing])
if facing and facing != '0':
rear_rows.append([chassis_name, loc, model, site, ammo, group, facing])
# Write CSVs
out1 = OUT_DIR / 'special_weapon_locations.csv'
with open(out1, 'w', newline='') as f:
w = csv.writer(f)
w.writerow(HDR)
w.writerows(special_rows)
out2 = OUT_DIR / 'rear_facing_weapons.csv'
with open(out2, 'w', newline='') as f:
w = csv.writer(f)
w.writerow(HDR)
w.writerows(rear_rows)
print(f"Spreadsheet 1 ? Special1/2 weapon locations: {len(special_rows)} rows -> {out1}")
print(f"Spreadsheet 2 ? Non-forward WeaponFacing: {len(rear_rows)} rows -> {out2}")
if missing:
print(f"\nSkipped: {missing}")