112 lines
4.0 KiB
Python
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}")
|