Files
firestorm/BTFrstrm/mech_loadouts.md
T

24 KiB
Raw Blame History

mech_loadouts.csv Catch-Up Notes

This document is for future AI agents or maintainers who need to understand how mech_loadouts.csv was built, where each column comes from, and what files must be updated together when mech data changes.

Purpose

mech_loadouts.csv is a flattened mech audit sheet built from the FireStorm content tree. It combines:

  • mech identity and stat data
  • current in-game playability status
  • installed/default weapon loadouts
  • weapon facing and grouping metadata
  • zone hardpoint capacity
  • notes about missing registration, packaging, or asset support

The CSV is not a primary source of truth. It is a synthesized report built from the mech content files and several registration tables.

Current CSV Column Layout

The important derived columns are:

  • In_game_playable
  • Weapons_With_Locations
  • Default_Installed_Locations
  • Available_Slot_Capacity_By_Zone
  • Available_Hardpoints
  • notes

The existing stat columns before those are mostly direct mech data fields and were not re-derived during the audit.

What Each Derived Column Means

In_game_playable

Yes if the mech is currently in the active playable roster, No otherwise.

This was determined by comparing the mech folder set against the active registration chain:

  • Gameleap/code/mw4/Code/MW4/MechLabHeaders.h
  • Gameleap/mw4/Content/ShellScripts/MechLabHeaders.h
  • Gameleap/mw4/Content/Tables/MechChassisTable.tbl
  • Gameleap/mw4/Content/Tables/MechTable.tbl
  • Gameleap/mw4/Content/core.build
  • plus supporting string and packaging manifests

Practical rule:

  • folder presence alone does not make a mech playable
  • playable mechs must have the ID/table/build registrations aligned

Weapons_With_Locations

This column lists each installed weapon in the mech¡¯s default subsystem file, with:

  • the weapon name
  • the InternalLocation
  • the WeaponFacing
  • the weapon group

Current format:

  • WeaponName@Location(Facing) G#

Examples:

  • MediumPulseLaser@LeftTorso(Rear) G1
  • SRM4@RightTorso(Front) G2
  • ClanLRM10@LeftTorso(Side) G2

Derived from the mech¡¯s .subsystems file by reading weapon subsystem blocks.

Important notes:

  • WeaponFacing=0 => Front
  • WeaponFacing=1 => Rear
  • WeaponFacing=2 => Side
  • if WeaponFacing is absent, it defaults to Front

Default_Installed_Locations

A compact count summary of where the mech¡¯s default weapons are installed, based on InternalLocation in the .subsystems file.

Example:

  • LeftArmx2 | LeftTorsox3 | RightTorsox4 | RightArmx2

This is about installed weapons, not slot capacity.

Available_Slot_Capacity_By_Zone

A compact summary of zone capacities from the mech¡¯s .damage file.

Current format:

  • Zone(M# / P# / B# / O#)

Where:

  • M = MissileSlots
  • P = ProjectileSlots
  • B = BeamSlots
  • O = OmniSlots

Example:

  • LeftTorso(M0/P2/B2/O0)

This reflects what the mech can support in that zone, not what is currently installed.

Available_Hardpoints

A list of zones that have at least one positive slot count in the .damage file.

Current format:

  • LeftArm(Front)
  • LeftTorso(Front+Rear)
  • RightTorso(Side)

This column is a directional summary of where weapons can be mounted.

Important:

  • this is derived from slot capacity plus facing information from weapon loadouts
  • it is not a literal mechanical port map
  • if a zone has multiple facing types in the mech¡¯s default loadout, it can show a combined label such as Front+Rear or Front+Side

Core Data Sources

1. Mech registration and playability

Primary files:

  • Gameleap/code/mw4/Code/MW4/MechLabHeaders.h
  • Gameleap/mw4/Content/ShellScripts/MechLabHeaders.h
  • Gameleap/mw4/Content/Tables/MechChassisTable.tbl
  • Gameleap/mw4/Content/Tables/MechTable.tbl
  • Gameleap/mw4/Content/core.build

What they control:

  • which mechs are actually in the active roster
  • which IDs exist in code and script space
  • which mech resources are packed into the runtime build

If a mech folder exists but it is not listed in these files, it is usually not playable.

2. Default weapon loadout and weapon-facing metadata

Primary file:

  • Gameleap/mw4/Content/Mechs/<MechName>/<mech>.subsystems

Each weapon block typically contains:

  • Model= weapon subsystem resource
  • InternalLocation= where the weapon is mounted
  • Site= mount port name
  • GroupIndex= weapon group number
  • WeaponFacing= optional facing metadata
  • AmmoCount= for ammo-using weapons

The .subsystems file is the source for:

  • Weapons_With_Locations
  • Default_Installed_Locations
  • facing annotations in the hardpoint summaries

3. Slot capacity / hardpoint support

Primary file:

  • Gameleap/mw4/Content/Mechs/<MechName>/<mech>.damage

Each section such as [LeftArmInternal] or [RightTorsoInternal] may contain:

  • MissileSlots=
  • ProjectileSlots=
  • BeamSlots=
  • OmniSlots=

These are used to derive:

  • Available_Slot_Capacity_By_Zone
  • Available_Hardpoints

4. Weapon slot type rules in code

Relevant code:

  • Gameleap/code/mw4/Code/MW4/MWDamageObject.cpp
  • Gameleap/code/mw4/Code/MW4/MWDamageObject.hpp
  • Gameleap/code/mw4/Code/MW4/MechLab.cpp
  • Gameleap/code/mw4/Code/MW4/Subsystem_Tool.cpp
  • Gameleap/code/mw4/Code/MW4/Weapon_Tool.cpp
  • Gameleap/code/mw4/Code/MW4/Weapon.hpp
  • Gameleap/code/mw4/Code/MW4/Weapon.cpp
  • Gameleap/code/mw4/Code/MW4/hudweapon.cpp

What the code does:

  • reads slot counts from .damage
  • reads InternalLocation and WeaponFacing from .subsystems
  • maps weapon slot type and size from the weapon model
  • assigns weapons to valid locations during mechlab editing

Facing Semantics

Weapon facing is stored per weapon instance, not as a separate hardpoint label.

Values seen in the data/code:

  • 0 = front
  • 1 = rear
  • 2 = side

Code references:

  • Gameleap/code/mw4/Code/MW4/Weapon_Tool.cpp
  • Gameleap/code/mw4/Code/MW4/Weapon.hpp
  • Gameleap/code/mw4/Code/MW4/Weapon.cpp
  • Gameleap/code/mw4/Code/MW4/hudweapon.cpp
  • Gameleap/code/mw4/Code/MW4/MechLab.cpp

Important nuance:

  • a zone name like LeftTorso does not tell you the facing by itself
  • the facing comes from the weapon block¡¯s WeaponFacing
  • the same zone can contain multiple weapons with different facings

Group Index Meaning

The G1, G2, etc. suffix in Weapons_With_Locations is the weapon group number from GroupIndex in the subsystem file.

This is not a location or facing field.

Meaning:

  • G1 = weapon group 1
  • G2 = weapon group 2
  • and so on

How The Spreadsheet Was Built

The CSV was assembled by cross-referencing:

  • mech folder contents under Gameleap/mw4/Content/Mechs/
  • .subsystems weapon blocks
  • .damage internal zone capacities
  • active roster tables and IDs
  • string registration files
  • build manifests
  • loose UI art assets under Gameleap/mw4/hsh/

The output is a derived audit sheet, not a direct export from a single source file.

Known Pitfalls

1. Folder presence does not mean playable

Some mech folders exist but are not in the active roster tables or headers. These need ID/table/build integration before they are usable in-game.

2. File names are not always canonical

Some mechs use alternate base filenames inside their folder. Do not assume FolderName/FolderName.damage or FolderName/FolderName.subsystems always exist.

Prefer:

  • parse the .instance file when present
  • otherwise detect the first matching .subsystems / .damage file by extension and content

3. Available_Hardpoints is a summary, not a literal port map

It summarizes zones with capacity and facing hints, but it does not enumerate every exact port or site name.

4. Rear-facing weapons are per-instance

If a mech has one rear-mounted weapon in a torso zone, that does not mean all weapons in that zone are rear-facing.

Update Checklist For Future Changes

If a mech is added or changed, check these in order:

  1. update or verify the mech .data, .instance, .subsystems, and .damage files
  2. ensure the mech is added to the active ID header(s)
  3. update MechChassisTable.tbl and MechTable.tbl
  4. update core.build and any related build manifests
  5. add any needed string IDs or script references
  6. confirm the mech has the expected loose or packed art assets
  7. rebuild the CSV derived columns if the data changed

Useful File Map

Mech data

  • Gameleap/mw4/Content/Mechs/<MechName>/

Roster and IDs

  • Gameleap/code/mw4/Code/MW4/MechLabHeaders.h
  • Gameleap/mw4/Content/ShellScripts/MechLabHeaders.h
  • Gameleap/mw4/Content/Tables/MechChassisTable.tbl
  • Gameleap/mw4/Content/Tables/MechTable.tbl

Slot/hardpoint logic

  • Gameleap/code/mw4/Code/MW4/MWDamageObject.cpp
  • Gameleap/code/mw4/Code/MW4/MechLab.cpp
  • Gameleap/code/mw4/Code/MW4/Subsystem_Tool.cpp

Facing logic

  • Gameleap/code/mw4/Code/MW4/Weapon.cpp
  • Gameleap/code/mw4/Code/MW4/Weapon.hpp
  • Gameleap/code/mw4/Code/MW4/Weapon_Tool.cpp
  • Gameleap/code/mw4/Code/MW4/hudweapon.cpp

Build manifests

  • Gameleap/mw4/Content/core.build
  • Gameleap/mw4/Content/props.build
  • Gameleap/mw4/Content/textures.build

Current State Summary

At the time this doc was written:

  • mech_loadouts.csv includes playability, default loadout, facing, hardpoint, and notes columns
  • non-playable mechs are explicitly marked No
  • Templar and other mechs with rear or side mounts have facing visible in the CSV
  • the file is intended to be a living audit artifact for future data cleanup and enablement work

MechEditor Web App — Data Sources, Fields, and Conversions (documented 2026-07-23)

The MechEditor is a single-file Python HTTP server at /home/rich/Repositories/MechEditor/mech_editor.py.
It runs at localhost:8765, parses the firestorm content tree, and presents a full mech configuration editor in the browser.
This section documents every data field it reads, every conversion it performs, and every naming rule it enforces.


Data Files Parsed Per Mech

All files live under Gameleap/mw4/Content/Mechs/<MechDir>/.

.data file (parse_data())

Field in file Editor key Notes
VehicleTonnage tonnage chassis base tonnage (float)
MaxVehicleTonnage max_tonnage max loadout tonnage (float)
TechType tech $(Tech_IS) ? "IS", $(Tech_Clan) ? "Clan"
MaxHeat max_heat heat capacity (int)
VehicleTradeValue trade_value C-bills
DragoonValue dragoon used in Power Rating bar scaling
MinMaxSpeed min_max_speed base speed ceiling in m/s
MaxSpeed max_speed absolute speed ceiling in m/s (engine upgrades may not exceed this)
FullStopTurnRate full_stop_turn turn rate at zero speed, in degrees/sec
TopSpeedTurnRate top_speed_turn turn rate at top speed, in degrees/sec
Acceleration acceleration forward acceleration in m/s²
Decceleration decceleration forward braking in m/s²double-c spelling is canonical in the engine source
ReverseAccelerationMultiplier rev_accel_mult multiplier applied to Acceleration for reverse
ReverseDeccelerationMultiplier rev_decel_mult multiplier applied to Decceleration for reverse — double-c canonical
MinStandTransitionSpeed not surfaced animation threshold only — see note below
CanLoadJumpJets can_jj Yes/No
CanLoadECM can_ecm Yes/No
CanLoadBeagle can_bap Yes/No
CanLoadLightAmp can_lightamp Yes/No
CanLoadAMS can_ams Yes/No
CanLoadLAMS can_lams Yes/No
CanLoadIFF_Jammer can_iff Yes/No

MinStandTransitionSpeed is the speed (m/s) below which the mech switches from its walking animation to its idle/standing animation.
It is NOT a hard movement limit. It is purely an animation state machine threshold in Mech.cpp.
Code path: animStateEngine?RequestState(StandState) when currentSpeedMPS <= minStandTransitionSpeed.
Must be > 0 (validated in Vehicle_Tool.cpp). Argus = 12.631 m/s = 45.5 kph.

.instance file (parse_instance())

Field Editor key Notes
PowerRating PowerRating mechlab bar value, 0100
ArmorRating ArmorRating mechlab bar value, 0100
SpeedRating SpeedRating mechlab bar value, 0100
HeatRating HeatRating mechlab bar value, 0100
DoesHaveLightAmp has_lightamp 0 or 1, default 1 — whether LightAmp is currently installed

.subsystems file (parse_subsystems())

Provides: armor type + per-zone multipliers, installed heatsinks, jump jets, engine upgrades, weapons, electronics.

Armor block:

  • ArmorType= ? armor type string (Standard, FerroFiberus, Reactive, Reflective, Solarian)
  • Per-zone entries: LeftArm=1.0, RightTorso=2.5, etc. — multiplier for that zone

Engine:

  • EngineUpgrade blocks counted ? engine_upgrades (05)

Weapons — each weapon block contains:

  • Model= ? weapon subsystem resource path (name extracted)
  • InternalLocation= ? zone name
  • Site= ? mount port name (from armature)
  • GroupIndex= ? weapon group number
  • WeaponFacing= ? 0=Front, 1=Rear, 2=Side (absent = Front)
  • AmmoCount= ? rounds for ammo-using weapons
  • EjectSite= ? optional ejection site for ammo

Electronics: ECM, Beagle (BAP), AMS, LAMS, IFF_Jammer detected by subsystem model path.

.damage file (parse_damage())

Per zone section [ZoneInternal]:

  • BaseArmorValue ? starting armor (float)
  • MaxArmorValue ? hard cap on armor pts for that zone
  • InternalHPValue ? internal structure HP
  • OmniSlots, BeamSlots, MissileSlots, ProjectileSlots ? weapon slot counts

Special zones:

  • SpecialAttachedToZone= ? which body section this special zone is attached to
  • DamagePropagationZone= ? where overflow damage propagates

.engine file (parse_engine())

Field Editor key Notes
NumHeatSinks NumHeatSinks free heatsinks from engine (not in subsystems)
TonsPerUpgrade TonsPerUpgrade tonnage cost per engine upgrade tier
MPSPerUpgrade MPSPerUpgrade m/s speed gain per upgrade tier

.torso file (parse_torso())

Field Notes
TwistSpeed torso horizontal rotation speed — may be a macro reference
PitchSpeed torso vertical rotation speed — may be a macro reference
TwistRadius max horizontal twist angle — may be a macro reference
PitchRadius max vertical pitch angle — may be a macro reference
ArmRatioAngle ratio of arm tracking vs torso rotation — may be a macro reference

All torso fields may reference macros from Content/Defines/MechTorso.defines.
The editor resolves them using a preloaded TORSO_DEFINES dict. Notable values:

NORMAL_RATIO   = 40
SNAIL_TSPEED   = 40
NORMAL_TSPEED  = 60
FAST_TSPEED    = 80
WIDE_TRADIUS   = 160
NORMAL_PRADIUS = 40

Calculated Ratings and Conversions

Speed (kph)

top_speed_kph = min(MinMaxSpeed + MPSPerUpgrade × engine_upgrades, MaxSpeed) × 3.6
  • MinMaxSpeed and MaxSpeed from .data (m/s)
  • MPSPerUpgrade from .engine (m/s per tier)
  • engine_upgrades from .subsystems (05)
  • Multiply by 3.6 to convert m/s ? kph
  • Argus example: (20.28 + 1.11 × 10) × 3.6 = 113.5 kph

Speed Rating (bar)

speed_rating = (top_speed_mps / MaxSpeed) × 100   [capped at 100]

Turn Rate — degrees to radians

The .data file stores turn rates in degrees/sec. The mechlab UI label was changed to show rad/sec:

  • StringResource.rc: IDS_ML_CH_TURNRATE ? "Turn Rate (Top Speed Rad/Sec):"
  • Conversion: radians = degrees × ?/180 where ?/180 ? 0.017453
  • Argus: FullStopTurn = 75° = 1.309 rad/sec, TopSpeedTurn = 45° = 0.785 rad/sec

Acceleration / Deceleration (m/s²)

Stored directly in .data. Reverse values are derived:

reverse_accel = Acceleration × ReverseAccelerationMultiplier
reverse_decel = Decceleration × ReverseDeccelerationMultiplier

The double-c spelling (Decceleration, ReverseDeccelerationMultiplier) is canonical — it matches the engine source. Do not "fix" the spelling.

Heat Rating (bar)

total_hs = NumHeatSinks (engine) + installed_heatsinks (subsystems)
effective_hs = total_hs × (2 if Double else 1)
heat_rating = (effective_hs / MaxHeat) × 100   [capped at 100]

Power Rating (bar)

total_damage = ? (DamageAmount × NumFire)  for each installed weapon
power_rating = (total_damage / 80) × 100   [capped at 100]
  • DamageAmount and NumFire come from WeaponSubsystems/<weapon>.data following !include chains
  • Parsed by load_weapon_damages() at server startup, cached in Handler.weapon_damages
  • Argus example with default load: ~36.2 total damage ? 45 rating (stored = 42)

Armor Rating (bar)

for each zone:
    pts = multiplier × ARMOR_PTS_PER_TON[armor_type]
    effective = min(pts, MaxArmorValue[zone])
armor_rating = (? effective / ? MaxArmorValue) × 100

Armor pts per ton by type (from Adept/ResourceImagePool.cpp and game design):

Type Pts/ton
Standard 32
FerroFiberus 38
Reactive 30
Reflective 30
Solarian 60

Note: FerroFiberus is the canonical internal token (not player-visible). The player sees DNL_FERROFIB = "Ferro Fibrous" via string lookup.


Active-in-Game Detection

Source: Gameleap/mw4/Content/Tables/MechChassisTable.tbl

Format:

DisplayKey=Mechs\DirName\FileName.data
//CommentedKey=Mechs\DirName\FileName.data   <- inactive
  • Active = entry exists AND is not prefixed with //
  • Currently the only inactive mech: Dasher (commented out)
  • The editor shows a green ACTIVE IN GAME or red NOT IN GAME banner at top of Stats tab

hsh/ Image Naming Conventions

The hsh/ directory under Gameleap/mw4/ holds loose BMP files loaded at runtime (not packed into .mw4).
There are four relevant subdirectories, each with a different naming authority.

hsh/hud/ — in-game HUD damage silhouette (own mech)

hsh/MFD/ — MFD target display silhouette (target mech)

hsh/radar/hud/ — radar damage overlay

All three use identical stems sourced from huddamage.cpp texturename[] array.

Load path:

  • hud/MFD: hsh\<texturename>.bmp where texturename = hud\<stem> ? file = hsh/hud/<stem>.bmp
  • radar: hsh\radar\<texturename>.bmp ? file = hsh/radar/hud/<stem>.bmp

Code: render.cpp CRadar_Device::LoadRadarDamageTexture() and huddamage.cpp HUDDamage.

hsh/Mechs/ — mw4print scorecard portrait

Load path: recscore.cpp ? GetLocString(model->m_nameIndex) ? DNL_* string from StringResource.rc ? lowercased filename.
Different naming authority from the other three.


Complete Canonical Name Table

Key: mech directory name (case-insensitive) ? canonical stem for hsh/hud/, hsh/MFD/, hsh/radar/hud/.
Entries in bold differ from the directory name.

Directory hud/MFD/radar stem hsh/Mechs/ portrait filename
Annihilator annihilator annihilator.bmp
Archer archer archer.bmp
ArcticWolf arcticwolf arctic wolf.bmp
Ares ares ares.bmp
Argus argus argus.bmp
Assassin2 assassin2 assassin ii.bmp
Atlas atlas atlas.bmp
Avatar avatar avatar.bmp
Awesome awesome awesome.bmp
Battlemaster battlemaster battlemaster.bmp
Battlemaster2c battlemasteriic battlemaster iic.bmp
Behemoth behemoth behemoth.bmp
Behemoth2 behemothii behemoth ii.bmp
Blackhawk blackhawk black hawk.bmp
Blacknight blackknight black knight.bmp
Blacklanner blacklanner black lanner.bmp
Brigand brigand brigand.bmp
Bushwacker bushwacker bushwacker.bmp
Catapult catapult catapult.bmp
CauldronBorn cauldronborn cauldronborn.bmp (table key has hyphen; DNL does not)
Chimera chimera chimera.bmp
Commando commando commando.bmp
Cougar cougar cougar.bmp
Cyclops cyclops cyclops.bmp
Daishi daishi daishi.bmp
Deimos deimos deimos.bmp
Dragon dragon dragon.bmp
Fafnir fafnir fafnir.bmp
Flea flea flea.bmp
Gladiator gladiator gladiator.bmp
Grizzly grizzly grizzly.bmp
Hauptmann hauptmann hauptmann.bmp
Hellhound hellhound hellhound.bmp
Hellspawn hellspawn hellspawn.bmp
Highlander highlander highlander.bmp
Hollander hollanderii hollander ii.bmp
Hunchback hunchback hunchback.bmp
Kodiak kodiak kodiak.bmp
Loki loki loki.bmp
Longbow longbow longbow.bmp
Madcat madcat mad cat.bmp
Madcat_MKII madcat2 mad cat mkii.bmp
Masakari masakari masakari.bmp
Mauler mauler mauler.bmp
Novacat novacat nova cat.bmp
Osiris osiris osiris.bmp
Owens owens owens.bmp
Puma puma puma.bmp
Raven raven raven.bmp
Rifleman rifleman rifleman.bmp
Ryoken ryoken ryoken.bmp
Shadowcat shadowcat shadow cat.bmp
Solitaire solitaire solitaire.bmp
Sunder sunder sunder.bmp
Templar templar templar.bmp
Thanatos thanatos thanatos.bmp
Thor thor thor.bmp
Uller uller uller.bmp
Urbanmech urbanmech urbanmech.bmp
Uziel uziel uziel.bmp
Victor victor victor.bmp
Vulture vulture vulture.bmp
Warhammer warhammer warhammer.bmp
Wolfhound wolfhound wolfhound.bmp
Zeus zeus zeus.bmp

Critical mismatches where directory name ? hud/MFD stem (files must use the stem, not the dir name):

Directory Wrong name (dir-based) Correct name (stem)
Battlemaster2c battlemaster2c.bmp battlemasteriic.bmp
Behemoth2 behemoth2.bmp behemothii.bmp
Blacknight blacknight.bmp blackknight.bmp
Hollander hollander.bmp hollanderii.bmp
Madcat_MKII madcat_mkii.bmp madcat2.bmp

Portrait mismatches for hsh/Mechs/ (table key ? DNL string):

The MechChassisTable.tbl display key and GetLocString() DNL string differ for these mechs.
mw4print uses the DNL string. The table key is NOT the correct portrait filename for these 5 mechs.

Directory Table key (wrong for mw4print) DNL string (correct portrait stem)
Assassin2 AssassinII ? assassinii DNL_ASSASSIN2 "Assassin II" ? assassin ii.bmp
Battlemaster2c BattlemasterIIC ? battlemasteriic DNL_BATTLEMASTERIIC "Battlemaster IIc" ? battlemaster iic.bmp
Behemoth2 BehemothII ? behemothii DNL_BEHEMOTHII "Behemoth II" ? behemoth ii.bmp
CauldronBorn Cauldron-Born ? cauldron-born DNL_CAULDRONBORN "Cauldronborn" ? cauldronborn.bmp
Hollander HollanderII ? hollanderii DNL_HOLLANDERII "Hollander II" ? hollander ii.bmp

MechEditor Implementation Notes

The editor encodes all of the above knowledge in two Python dicts:

MECH_HSH_STEMS (in mech_editor.py)
Maps lowercase dir name ? canonical stem for hsh/hud/, hsh/MFD/, hsh/radar/hud/.
Source: huddamage.cpp texturename[] array.

MECH_PORTRAIT_OVERRIDES (in mech_editor.py)
Maps lowercase dir name ? portrait stem for hsh/Mechs/ where the DNL string differs from the chassis table key.
Source: DNL_* entries in Gameleap/code/mw4/Code/scriptstrings/StringResource.rc.

For all other mechs, the portrait stem is derived dynamically from MechChassisTable.tbl (display key, lowercased).

The Assets tab in the editor shows all four image types. When an image is missing, it displays:

Wants: hsh/<subdir>/<expected_filename>.bmp

so the user knows exactly what to rename or create.