#!/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}")