24 KiB
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_playableWeapons_With_LocationsDefault_Installed_LocationsAvailable_Slot_Capacity_By_ZoneAvailable_Hardpointsnotes
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.hGameleap/mw4/Content/ShellScripts/MechLabHeaders.hGameleap/mw4/Content/Tables/MechChassisTable.tblGameleap/mw4/Content/Tables/MechTable.tblGameleap/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) G1SRM4@RightTorso(Front) G2ClanLRM10@LeftTorso(Side) G2
Derived from the mech¡¯s .subsystems file by reading weapon subsystem blocks.
Important notes:
WeaponFacing=0=>FrontWeaponFacing=1=>RearWeaponFacing=2=>Side- if
WeaponFacingis absent, it defaults toFront
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= MissileSlotsP= ProjectileSlotsB= BeamSlotsO= 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+RearorFront+Side
Core Data Sources
1. Mech registration and playability
Primary files:
Gameleap/code/mw4/Code/MW4/MechLabHeaders.hGameleap/mw4/Content/ShellScripts/MechLabHeaders.hGameleap/mw4/Content/Tables/MechChassisTable.tblGameleap/mw4/Content/Tables/MechTable.tblGameleap/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 resourceInternalLocation=where the weapon is mountedSite=mount port nameGroupIndex=weapon group numberWeaponFacing=optional facing metadataAmmoCount=for ammo-using weapons
The .subsystems file is the source for:
Weapons_With_LocationsDefault_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_ZoneAvailable_Hardpoints
4. Weapon slot type rules in code
Relevant code:
Gameleap/code/mw4/Code/MW4/MWDamageObject.cppGameleap/code/mw4/Code/MW4/MWDamageObject.hppGameleap/code/mw4/Code/MW4/MechLab.cppGameleap/code/mw4/Code/MW4/Subsystem_Tool.cppGameleap/code/mw4/Code/MW4/Weapon_Tool.cppGameleap/code/mw4/Code/MW4/Weapon.hppGameleap/code/mw4/Code/MW4/Weapon.cppGameleap/code/mw4/Code/MW4/hudweapon.cpp
What the code does:
- reads slot counts from
.damage - reads
InternalLocationandWeaponFacingfrom.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= front1= rear2= side
Code references:
Gameleap/code/mw4/Code/MW4/Weapon_Tool.cppGameleap/code/mw4/Code/MW4/Weapon.hppGameleap/code/mw4/Code/MW4/Weapon.cppGameleap/code/mw4/Code/MW4/hudweapon.cppGameleap/code/mw4/Code/MW4/MechLab.cpp
Important nuance:
- a zone name like
LeftTorsodoes 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 1G2= 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/ .subsystemsweapon blocks.damageinternal 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
.instancefile when present - otherwise detect the first matching
.subsystems/.damagefile 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:
- update or verify the mech
.data,.instance,.subsystems, and.damagefiles - ensure the mech is added to the active ID header(s)
- update
MechChassisTable.tblandMechTable.tbl - update
core.buildand any related build manifests - add any needed string IDs or script references
- confirm the mech has the expected loose or packed art assets
- 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.hGameleap/mw4/Content/ShellScripts/MechLabHeaders.hGameleap/mw4/Content/Tables/MechChassisTable.tblGameleap/mw4/Content/Tables/MechTable.tbl
Slot/hardpoint logic
Gameleap/code/mw4/Code/MW4/MWDamageObject.cppGameleap/code/mw4/Code/MW4/MechLab.cppGameleap/code/mw4/Code/MW4/Subsystem_Tool.cpp
Facing logic
Gameleap/code/mw4/Code/MW4/Weapon.cppGameleap/code/mw4/Code/MW4/Weapon.hppGameleap/code/mw4/Code/MW4/Weapon_Tool.cppGameleap/code/mw4/Code/MW4/hudweapon.cpp
Build manifests
Gameleap/mw4/Content/core.buildGameleap/mw4/Content/props.buildGameleap/mw4/Content/textures.build
Current State Summary
At the time this doc was written:
mech_loadouts.csvincludes 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:
EngineUpgradeblocks counted ?engine_upgrades(0–5)
Weapons — each weapon block contains:
Model=? weapon subsystem resource path (name extracted)InternalLocation=? zone nameSite=? mount port name (from armature)GroupIndex=? weapon group numberWeaponFacing=? 0=Front, 1=Rear, 2=Side (absent = Front)AmmoCount=? rounds for ammo-using weaponsEjectSite=? 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 zoneInternalHPValue? internal structure HPOmniSlots,BeamSlots,MissileSlots,ProjectileSlots? weapon slot counts
Special zones:
SpecialAttachedToZone=? which body section this special zone is attached toDamagePropagationZone=? 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
MinMaxSpeedandMaxSpeedfrom.data(m/s)MPSPerUpgradefrom.engine(m/s per tier)engine_upgradesfrom.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 × ?/180where?/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]
DamageAmountandNumFirecome fromWeaponSubsystems/<weapon>.datafollowing!includechains- Parsed by
load_weapon_damages()at server startup, cached inHandler.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>.bmpwhere 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.