655 lines
24 KiB
Markdown
655 lines
24 KiB
Markdown
# mech_loadouts.csv Catch-Up Notes
|
||
|
||
This document is for future AI agents or maintainers who need to understand how [mech_loadouts.csv](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, 0–100 |
|
||
| `ArmorRating` | `ArmorRating` | mechlab bar value, 0–100 |
|
||
| `SpeedRating` | `SpeedRating` | mechlab bar value, 0–100 |
|
||
| `HeatRating` | `HeatRating` | mechlab bar value, 0–100 |
|
||
| `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` (0–5)
|
||
|
||
**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` (0–5)
|
||
- 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.
|
||
|