diff --git a/docs/MECHS.html b/docs/MECHS.html new file mode 100644 index 0000000..a3e6101 --- /dev/null +++ b/docs/MECHS.html @@ -0,0 +1,638 @@ + + + + + +BattleTech 4.11 — the mech roster + + + + +
+
+

BattleTech 4.11 · from btl4fe.cpp, L4GAUGE.CFG and the player's manual

+

Every mech,
and what it carries

+

All 18 mechs the menu offers — 8 base chassis + and 10 variants — each with its authored weapons roster, ammo bins and the + stat sheet from the original player's manual. The portraits are the game's own + mission-review images, shown in their undamaged state.

+ +
+
+ +
+
+
+ + + +
+ + 18 / 18 mechs +
+
+ +
+
+ Energy + Ballistic + Missile +
+ +
+
+
+
+ Black Hawk mission-review portrait +
Black Hawk chassis · with Nova
+
+

Black Hawk

+

blkhawk · base chassis

+

ER LARGE LASER5× ER MEDIUM LASER2× ER SMALL LASER2× SRM 6

+

10 weapons2 ammo binstorso FIXED

+
Tonnage
50 t
Armor points
1362
Reservoir
1600 L
Heat sinks
16
Torso
FIXED
0–100 kph
5.1 s
Top speed
190 kph
Super charged
280 kph
Gimped
60 kph
+

manual p. 29

+
+
+ + + + +
Weapons carried by the Black Hawk
WEAPONTYPECOUNTAMMO BIN
ER Large LaserEnergy1
ER Medium LaserEnergy5
ER Small LaserEnergy2
SRM 6Missile2
+
+
+
+
+ Loki mission-review portrait +
Loki chassis · with Hellbringer, Mischief
+
+

Loki

+

loki · base chassis

+

2× ER MEDIUM LASER2× ER SMALL LASER2× AFC 50SRM 4

+

7 weapons3 ammo binstorso TWISTS

+
Tonnage
75 t
Armor points
2110
Reservoir
3800 L
Heat sinks
38
Torso
60°/s · 110°
0–100 kph
4.5 s
Top speed
143 kph
Super charged
182 kph
Gimped
40 kph
+

manual p. 25

+
+
+ + + + +
Weapons carried by the Loki
WEAPONTYPECOUNTAMMO BIN
ER Medium LaserEnergy2
ER Small LaserEnergy2
AFC 50Ballistic2
SRM 4Missile1
+
+
+
+
+ Nova mission-review portrait +
Black Hawk chassis · with Black Hawk
+
+

Nova

+

bhk1 · variant of Black Hawk

+

3× ER MEDIUM LASER2× PPC2× SRM 6

+

7 weapons2 ammo binstorso FIXED

+
Tonnage
Armor points
Reservoir
Heat sinks
Torso
FIXED
0–100 kph
Top speed
Super charged
Gimped
+

chassis sheet: see Black Hawk

+
+
+ + + + +
Weapons carried by the Nova
WEAPONTYPECOUNTAMMO BIN
ER Medium LaserEnergy3
PPCEnergy2
SRM 6Missile2
+
+
+
+
+ Mad Cat mission-review portrait +
Mad Cat chassis · with Timber Wolf, Zanin Neko
+
+

Mad Cat

+

madcat · base chassis

+

ER LARGE LASER2× ER SMALL LASERAFC 1002× LRM 15

+

6 weapons3 ammo binstorso TWISTS

+
Tonnage
75 t
Armor points
2195
Reservoir
2800 L
Heat sinks
28
Torso
80°/s · 90°
0–100 kph
4.2 s
Top speed
175 kph
Super charged
220 kph
Gimped
62 kph
+

manual p. 26

+
+
+ + + + +
Weapons carried by the Mad Cat
WEAPONTYPECOUNTAMMO BIN
ER Large LaserEnergy1
ER Small LaserEnergy2
AFC 100Ballistic1
LRM 15Missile2
+
+
+
+
+ Thor mission-review portrait +
Thor chassis · with Summoner
+
+

Thor

+

thor · base chassis

+

ER MEDIUM LASER2× ER PPC2× ER SMALL LASERLARGE LASERLRM 15

+

7 weapons1 ammo binstorso TWISTS

+
Tonnage
75 t
Armor points
2110
Reservoir
3800 L
Heat sinks
38
Torso
60°/s · 110°
0–100 kph
4.5 s
Top speed
143 kph
Super charged
182 kph
Gimped
40 kph
+

manual p. 25

+
+
+ + + + +
Weapons carried by the Thor
WEAPONTYPECOUNTAMMO BIN
ER Medium LaserEnergy1
ER PPCEnergy2
ER Small LaserEnergy2
Large LaserEnergy1
LRM 15Missile1
+
+
+
+
+ Owens mission-review portrait +
Owens chassis · with Kotori
+
+

Owens

+

owens · base chassis

+

2× ER MEDIUM LASER4× ER SMALL LASER2× SRM 6

+

8 weapons2 ammo binstorso FIXED

+
Tonnage
25 t
Armor points
760
Reservoir
1500 L
Heat sinks
15
Torso
FIXED
0–100 kph
4.2 s
Top speed
154 kph
Super charged
265 kph
Gimped
63 kph
+

manual p. 29

+
+
+ + + + +
Weapons carried by the Owens
WEAPONTYPECOUNTAMMO BIN
ER Medium LaserEnergy2
ER Small LaserEnergy4
SRM 6Missile2
+
+
+
+
+ Kotori mission-review portrait +
Owens chassis · with Owens
+
+

Kotori

+

own1 · variant of Owens

+

ER MEDIUM LASERER SMALL LASERAFC 252× NRK 5

+

5 weapons3 ammo binstorso FIXED

+
Tonnage
Armor points
Reservoir
Heat sinks
Torso
FIXED
0–100 kph
Top speed
Super charged
Gimped
+

chassis sheet: see Owens

+
+
+ + + + +
Weapons carried by the Kotori
WEAPONTYPECOUNTAMMO BIN
ER Medium LaserEnergy1
ER Small LaserEnergy1
AFC 25Ballistic1
NRK 5Ballistic2
+
+
+
+
+ Summoner mission-review portrait +
Thor chassis · with Thor
+
+

Summoner

+

thr1 · variant of Thor

+

4× ER SMALL LASER2× LARGE LASER2× AFC 25LRM 10

+

9 weapons3 ammo binstorso TWISTS

+
Tonnage
Armor points
Reservoir
Heat sinks
Torso
twists
0–100 kph
Top speed
Super charged
Gimped
+

chassis sheet: see Thor

+
+
+ + + + +
Weapons carried by the Summoner
WEAPONTYPECOUNTAMMO BIN
ER Small LaserEnergy4
Large LaserEnergy2
AFC 25Ballistic2
LRM 10Missile1
+
+
+
+
+ Hellbringer mission-review portrait +
Loki chassis · with Loki, Mischief
+
+

Hellbringer

+

lok1 · variant of Loki

+

2× LARGE LASER2× MEDIUM LASER2× PPC2× SMALL LASERSRM 4

+

9 weapons1 ammo binstorso TWISTS

+
Tonnage
Armor points
Reservoir
Heat sinks
Torso
twists
0–100 kph
Top speed
Super charged
Gimped
+

chassis sheet: see Loki

+
+
+ + + + +
Weapons carried by the Hellbringer
WEAPONTYPECOUNTAMMO BIN
Large LaserEnergy2
Medium LaserEnergy2
PPCEnergy2
Small LaserEnergy2
SRM 4Missile1
+
+
+
+
+ Timber Wolf mission-review portrait +
Mad Cat chassis · with Mad Cat, Zanin Neko
+
+

Timber Wolf

+

mad1 · variant of Mad Cat

+

4× MEDIUM LASER2× AFC 252× LRM 10

+

8 weapons4 ammo binstorso TWISTS

+
Tonnage
Armor points
Reservoir
Heat sinks
Torso
twists
0–100 kph
Top speed
Super charged
Gimped
+

chassis sheet: see Mad Cat

+
+
+ + + + +
Weapons carried by the Timber Wolf
WEAPONTYPECOUNTAMMO BIN
Medium LaserEnergy4
AFC 25Ballistic2
LRM 10Missile2
+
+
+
+
+ Avatar mission-review portrait +
Avatar chassis · with Satyr
+
+

Avatar

+

avatar · base chassis

+

2× ER LARGE LASER4× ER MEDIUM LASERAFC 502× LRM 10

+

9 weapons3 ammo binstorso TWISTS

+
Tonnage
Armor points
Reservoir
Heat sinks
Torso
twists
0–100 kph
Top speed
Super charged
Gimped
+

no manual sheet (4.10 addition)

+
+
+ + + + +
Weapons carried by the Avatar
WEAPONTYPECOUNTAMMO BIN
ER Large LaserEnergy2
ER Medium LaserEnergy4
AFC 50Ballistic1
LRM 10Missile2
+
+
+
+
+ Satyr mission-review portrait +
Avatar chassis · with Avatar
+
+

Satyr

+

ava1 · variant of Avatar

+

2× ER MEDIUM LASERPPCAFC 100LRM 5SRM 2

+

6 weapons3 ammo binstorso TWISTS

+
Tonnage
Armor points
Reservoir
Heat sinks
Torso
twists
0–100 kph
Top speed
Super charged
Gimped
+

no manual sheet (4.10 addition)

+
+
+ + + + +
Weapons carried by the Satyr
WEAPONTYPECOUNTAMMO BIN
ER Medium LaserEnergy2
PPCEnergy1
AFC 100Ballistic1
LRM 5Missile1
SRM 2Missile1
+
+
+
+
+ Sunder mission-review portrait +
Sunder chassis · with Denkou
+
+

Sunder

+

sunder · base chassis

+

2× ER MEDIUM LASER2× ER SMALL LASER2× MEDIUM LASERAFC 100AFC 25LRM 10

+

9 weapons3 ammo binstorso TWISTS

+
Tonnage
Armor points
Reservoir
Heat sinks
Torso
twists
0–100 kph
Top speed
Super charged
Gimped
+

no manual sheet (4.10 addition)

+
+
+ + + + +
Weapons carried by the Sunder
WEAPONTYPECOUNTAMMO BIN
ER Medium LaserEnergy2
ER Small LaserEnergy2
Medium LaserEnergy2
AFC 100Ballistic1
AFC 25Ballistic1
LRM 10Missile1
+
+
+
+
+ Denkou mission-review portrait +
Sunder chassis · with Sunder
+
+

Denkou

+

snd1 · variant of Sunder

+

ER SMALL LASER3× PPCAFC 25LRM 5

+

6 weapons2 ammo binstorso TWISTS

+
Tonnage
Armor points
Reservoir
Heat sinks
Torso
twists
0–100 kph
Top speed
Super charged
Gimped
+

no manual sheet (4.10 addition)

+
+
+ + + + +
Weapons carried by the Denkou
WEAPONTYPECOUNTAMMO BIN
ER Small LaserEnergy1
PPCEnergy3
AFC 25Ballistic1
LRM 5Missile1
+
+
+
+
+ Vulture mission-review portrait +
Vulture chassis · with Mad Dog
+
+

Vulture

+

vulture · base chassis

+

2× ER MEDIUM LASER2× ER SMALL LASER2× LARGE LASER2× LRM 20

+

8 weapons2 ammo binstorso TWISTS

+
Tonnage
75 t
Armor points
2025
Reservoir
2400 L
Heat sinks
24
Torso
50°/s · 130°
0–100 kph
4.7 s
Top speed
175 kph
Super charged
235 kph
Gimped
62 kph
+

manual p. 26

+
+
+ + + + +
Weapons carried by the Vulture
WEAPONTYPECOUNTAMMO BIN
ER Medium LaserEnergy2
ER Small LaserEnergy2
Large LaserEnergy2
LRM 20Missile2
+
+
+
+
+ Mad Dog mission-review portrait +
Vulture chassis · with Vulture
+
+

Mad Dog

+

vul1 · variant of Vulture

+

4× ER SMALL LASER2× PPC2× LRM 15

+

8 weapons2 ammo binstorso TWISTS

+
Tonnage
Armor points
Reservoir
Heat sinks
Torso
twists
0–100 kph
Top speed
Super charged
Gimped
+

chassis sheet: see Vulture

+
+
+ + + + +
Weapons carried by the Mad Dog
WEAPONTYPECOUNTAMMO BIN
ER Small LaserEnergy4
PPCEnergy2
LRM 15Missile2
+
+
+
+
+ Mischief mission-review portrait +
Loki chassis · with Loki, Hellbringer
+
+

Mischief

+

lok2 · variant of Loki

+

3× MEDIUM LASERPPC2× SMALL LASERAFC 25GAUSSSRM 4

+

9 weapons3 ammo binstorso TWISTS

+
Tonnage
Armor points
Reservoir
Heat sinks
Torso
twists
0–100 kph
Top speed
Super charged
Gimped
+

chassis sheet: see Loki

+
+
+ + + + +
Weapons carried by the Mischief
WEAPONTYPECOUNTAMMO BIN
Medium LaserEnergy3
PPCEnergy1
Small LaserEnergy2
AFC 25Ballistic1
GaussBallistic1
SRM 4Missile1
+
+
+
+
+ Zanin Neko mission-review portrait +
Mad Cat chassis · with Mad Cat, Timber Wolf
+
+

Zanin Neko

+

mad2 · variant of Mad Cat

+

2× ER MEDIUM LASERER PPCAFC 50LRM 152× SRM 6

+

7 weapons4 ammo binstorso TWISTS

+
Tonnage
Armor points
Reservoir
Heat sinks
Torso
twists
0–100 kph
Top speed
Super charged
Gimped
+

chassis sheet: see Mad Cat

+
+
+ + + + +
Weapons carried by the Zanin Neko
WEAPONTYPECOUNTAMMO BIN
ER Medium LaserEnergy2
ER PPCEnergy1
AFC 50Ballistic1
LRM 15Missile1
SRM 6Missile2
+
+ + +

The roster is kVehicles[] in game/glass/btl4fe.cpp + — the exact catalog the in-game menu offers, in menu order. Each mech's weapons and + ammo bins are its cmCrit(...) lines in content/GAUGE/L4GAUGE.CFG, + the critical-damage schematic's authored subsystem roster (independently confirmed against + the subsystem records in BTL4.RES). Nothing is transcribed by hand.

+

The portraits are each mech's mission-review image + (GAUGE/<stem>_MR.PCC) resolved through the review screen's own palette. + In play, its zone indexes are live damage slots painted green→orange→red by the + ColorMapper gauges; this page shows every zone at the undamaged ramp entry — the + same green the armor doll idles at. Variants without their own portrait share the base's, + exactly as the resource file does.

+

Mech stats are the original player's manual stat sheets (pp. 25, 26, 29). + The manual documents the six 4.0 hulls; Avatar and Sunder arrived with 4.10 and have no + sheet, so their rows show a dash rather than an invented number. FIXED vs twisting torso + is read from the shipped resource file: a mech twists only if its subsystem record carries + the jointtorso/jointtshadow joints — the four fixed mechs + match the manual's Torso 0/0 rows exactly.

+

Weapon notes: ER lasers fire red beams, PPCs blue, standard lasers yellow. + Authored ranges where the game states them: PPCs 900 m, missiles 800 m, the + Blackhawk's lasers 500 m, the AFC 50 750 m. The Blackhawk's SRM 6 + racks fire Streak ammunition. LRM tube counts are the salvo size; each launcher's ammo + bin is listed beside it.

+
+ + + + diff --git a/tools/build_mechs.py b/tools/build_mechs.py new file mode 100644 index 0000000..7aee491 --- /dev/null +++ b/tools/build_mechs.py @@ -0,0 +1,260 @@ +"""Render the mech roster the way the game knows it. + +Data is drawn from the shipped files, not transcribed: + + * The ROSTER is `kVehicles[]` in game/glass/btl4fe.cpp -- the exact + 18-entry catalog the in-game menu offers (key + display name, menu + order). Nothing is filtered, so a menu change flows through. + * Each mech's WEAPONS and AMMO BINS are its `cmCrit(...)` lines in + content/GAUGE/L4GAUGE.CFG -- the critical-damage schematic's authored + subsystem roster. (Independently confirmed against the rtype-17 + subsystem records in BTL4.RES, 2026-08-12.) + * The PORTRAIT is the mech's own mission-review image + (GAUGE/_MR.PCC, shown by the cameraInit review context through + mrpal.pcc). Its zone indexes 32..63 are runtime ColorMapper slots -- + the review screen paints damage per zone -- so the page shows the + HEALTHY state: every zone slot at adpal.pcc entry 0, the same green + the armor doll idles at. PCC is PCX; the palette is the file tail. + * MECH STATS come from the original player's manual stat sheets + (reference/manual/Tesla40_BT_manual.pdf pp. 25/26/29, transcribed + from page renders 2026-08-12). The manual documents the six 4.0 + hulls only; the 4.10 additions (Avatar, Sunder) and all variants have + no sheet, and this page shows a dash rather than an invented number. + * FIXED vs TWISTING torso is derived from the shipped BTL4.RES: a mech + twists only if its subsystem record carries the jointtorso + + jointtshadow skeleton joints (Torso resolves them only when + torsoHorizontalEnabled, game/reconstructed/torso.cpp:270). The four + fixed mechs match the manual's Torso 0/0 rows exactly. + +Usage: python tools/build_mechs.py [out.html] +""" +import base64, html, io, os, re, sys + +ROOT = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) +GAUGE = os.path.join(ROOT, 'content', 'GAUGE') +OUT = sys.argv[1] if len(sys.argv) > 1 else os.path.join(ROOT, 'docs', 'MECHS.html') + +# --------------------------------------------------------------- roster +src = open(os.path.join(ROOT, 'game', 'glass', 'btl4fe.cpp'), + encoding='utf-8', errors='replace').read() +block = re.search(r'kVehicles\[\]\s*=\s*\{(.*?)\};', src, re.S).group(1) +ROSTER = re.findall(r'\{\s*"(\w+)"\s*,\s*"([^"]+)"\s*\}', block) +if len(ROSTER) < 18: + sys.exit('roster parse found only %d entries' % len(ROSTER)) + +# Variant -> base chassis (kVehicles order groups them; the stems below agree). +VARIANT_OF = {'bhk1': 'blkhawk', 'thr1': 'thor', 'lok1': 'loki', + 'lok2': 'loki', 'mad1': 'madcat', 'mad2': 'madcat', + 'own1': 'owens', 'ava1': 'avatar', 'snd1': 'sunder', + 'vul1': 'vulture'} + +# Mission-review portrait stem per key (GAUGE/_MR.PCC; variants with no +# portrait of their own share the base's, as the RES does). +MR_STEM = {'blkhawk': 'BLH', 'bhk1': 'BLH', 'loki': 'LOKI', 'lok1': 'LOK1', + 'lok2': 'LOKI', 'madcat': 'MAD', 'mad1': 'MAD1', 'mad2': 'MAD2', + 'thor': 'THOR', 'thr1': 'THR1', 'owens': 'OWEN', 'own1': 'OWEN', + 'avatar': 'AVA', 'ava1': 'AVA', 'sunder': 'SUN', 'snd1': 'SUN', + 'vulture': 'VULT', 'vul1': 'VUL1'} + +# Fixed-torso set, derived from BTL4.RES joint tables (see module docstring). +FIXED_TORSO = {'blkhawk', 'bhk1', 'owens', 'own1'} + +# The manual stat sheets (pp. 25 Loki/Thor, 26 Vulture/MadCat, 29 Owens/ +# Blackhawk). Keys: t tons, ap armor points, res reservoir liters, hs heat +# sinks, ts torso deg/s, tl torso limit deg, a100 0-100s, b100 100-0s, +# vn/vs/vg top speed normal / super charged / gimped kph. +MANUAL = { + 'loki': dict(t=75, ap=2110, res=3800, hs=38, ts=60, tl=110, + a100=4.5, b100=4.5, vn=143, vs=182, vg=40, page=25), + 'thor': dict(t=75, ap=2110, res=3800, hs=38, ts=60, tl=110, + a100=4.5, b100=4.5, vn=143, vs=182, vg=40, page=25), + 'vulture': dict(t=75, ap=2025, res=2400, hs=24, ts=50, tl=130, + a100=4.7, b100=3, vn=175, vs=235, vg=62, page=26), + 'madcat': dict(t=75, ap=2195, res=2800, hs=28, ts=80, tl=90, + a100=4.2, b100=4, vn=175, vs=220, vg=62, page=26), + 'owens': dict(t=25, ap=760, res=1500, hs=15, ts=0, tl=0, + a100=4.2, b100=5, vn=154, vs=265, vg=63, page=29), + 'blkhawk': dict(t=50, ap=1362, res=1600, hs=16, ts=0, tl=0, + a100=5.1, b100=4.6, vn=190, vs=280, vg=60, page=29), +} + +# ------------------------------------------------------------- weapons +CFG = open(os.path.join(GAUGE, 'L4GAUGE.CFG'), + encoding='utf-8', errors='replace').read() + +INFRA = {'HUD', 'Avionics', 'Gyroscope', 'Torso', 'Myomers'} + + +def init_block(key): + name = key.capitalize() + 'Init' + m = re.search(r'^%s\b' % re.escape(name), CFG, re.M) + if not m: + sys.exit('no %s block in L4GAUGE.CFG' % name) + n = re.search(r'^\w+Init\b', CFG[m.end():], re.M) + return CFG[m.start(): m.end() + n.start() if n else len(CFG)] + + +def family(sub): + """ERPPC_2 -> ERPPC, MLaser1 -> MLaser; AFC100/LRM15/NRK5 keep their digits + (they are family names, and they are in FAM already).""" + fam = re.sub(r'_\d+$', '', sub) + if fam not in FAM: + stripped = re.sub(r'\d+$', '', fam) + if stripped in FAM: + fam = stripped + return fam + + +def loadout(key): + weapons, bins = {}, {} + for sub in re.findall(r'cmCrit\([^,]+,[^,]+,\d+,[^,]+,[^,]+,(\w+)\)', + init_block(key)): + if sub.startswith('AmmoBin'): + fam = family(sub[len('AmmoBin'):]) + bins[fam] = bins.get(fam, 0) + 1 + elif not (sub in INFRA + or sub.startswith(('Generator', 'Condenser', 'Myomers'))): + fam = family(sub) + weapons[fam] = weapons.get(fam, 0) + 1 + return weapons, bins + + +# Family -> (display name, class). Classes: e energy, b ballistic, m missile. +FAM = { + 'PPC': ('PPC', 'e'), 'ERPPC': ('ER PPC', 'e'), + 'LLaser': ('Large Laser', 'e'), 'MLaser': ('Medium Laser', 'e'), + 'SLaser': ('Small Laser', 'e'), 'ERLLaser': ('ER Large Laser', 'e'), + 'ERMLaser': ('ER Medium Laser', 'e'), 'ERSLaser': ('ER Small Laser', 'e'), + 'AFC25': ('AFC 25', 'b'), 'AFC50': ('AFC 50', 'b'), + 'AFC100': ('AFC 100', 'b'), 'GAUSS': ('Gauss', 'b'), 'NRK5': ('NRK 5', 'b'), + 'LRM5': ('LRM 5', 'm'), 'LRM10': ('LRM 10', 'm'), 'LRM15': ('LRM 15', 'm'), + 'LRM20': ('LRM 20', 'm'), 'SRM2': ('SRM 2', 'm'), 'SRM4': ('SRM 4', 'm'), + 'SRM6': ('SRM 6', 'm'), +} +CLASS_NAME = {'e': 'Energy', 'b': 'Ballistic', 'm': 'Missile'} +CLASS_ORDER = {'e': 0, 'b': 1, 'm': 2} + +# ------------------------------------------------------------- portraits +from PIL import Image + +mrpal = open(os.path.join(GAUGE, 'MRPAL.PCC'), 'rb').read() +if mrpal[-769] != 0x0C: + sys.exit('MRPAL.PCC has no VGA palette where PCX keeps one') +BASEPAL = list(mrpal[-768:]) +adpal = open(os.path.join(GAUGE, 'ADPAL.PCC'), 'rb').read() +HEALTHY = list(adpal[-768:][0:3]) # ramp entry 0 = undamaged green + +_portraits = {} + + +def portrait(stem): + if stem not in _portraits: + im = Image.open(os.path.join(GAUGE, stem + '_MR.PCC')) + im.load() + flat = BASEPAL[:] + for s in range(32, 64): # zone slots -> healthy state + flat[s * 3:s * 3 + 3] = HEALTHY + im.putpalette(flat) + buf = io.BytesIO() + im.save(buf, 'PNG', optimize=True) + _portraits[stem] = ('data:image/png;base64,' + + base64.b64encode(buf.getvalue()).decode(), + im.width, im.height) + return _portraits[stem] + + +# ----------------------------------------------------------------- page +def dash(v, unit=''): + return '—' if v is None else '%s%s' % (v, unit) + + +NAMES = dict(ROSTER) +cards = [] +for key, name in ROSTER: + weapons, bins = loadout(key) + base = VARIANT_OF.get(key) + man = MANUAL.get(key) + uri, w, h = portrait(MR_STEM[key]) + + fams = sorted(weapons, key=lambda f: (CLASS_ORDER[FAM[f][1]], FAM[f][0])) + chips = ''.join( + '%s%s' % ( + FAM[f][1], + '%d× ' % weapons[f] if weapons[f] > 1 else '', + html.escape(FAM[f][0].upper())) + for f in fams) + + rows = ''.join( + '%s%s' + '%d%s' % ( + html.escape(FAM[f][0]), CLASS_NAME[FAM[f][1]], weapons[f], + '%d×' % bins[f] if f in bins else '—') + for f in fams) + + torso = ('FIXED' if key in FIXED_TORSO + else '%s°/s · %s°' % (man['ts'], man['tl']) + if man else 'twists') + spec = ''.join('
%s
%s
' % kv for kv in ( + ('Tonnage', dash(man and man['t'], ' t')), + ('Armor points', dash(man and man['ap'])), + ('Reservoir', dash(man and man['res'], ' L')), + ('Heat sinks', dash(man and man['hs'])), + ('Torso', torso), + ('0–100 kph', dash(man and man['a100'], ' s')), + ('Top speed', dash(man and man['vn'], ' kph')), + ('Super charged', dash(man and man['vs'], ' kph')), + ('Gimped', dash(man and man['vg'], ' kph')), + )) + sheet = ('manual p. %d' % man['page'] if man else + 'chassis sheet: see %s' % html.escape(NAMES[base]) if base in MANUAL + else 'no manual sheet (4.10 addition)') + + fam_base = base or key + kin = ([NAMES[fam_base]] if base else []) + \ + [NAMES[v] for v, b in VARIANT_OF.items() if b == fam_base and v != key] + cap = ('%s chassis · with %s' % ( + html.escape(NAMES.get(base, name)), html.escape(', '.join(kin))) + if kin else '%s chassis' % html.escape(name)) + + search = ' '.join([key, name.lower()] + + [FAM[f][0].lower() for f in fams] + fams).lower() + cards.append(""" +
+
+
+ {name} mission-review portrait +
{cap}
+
+

{name}

+

{key} · {kind}

+

{chips}

+

{nw} weapons{nb} ammo binstorso {torsoshort}

+
{spec}
+

{sheet}

+
+
+ + + + {rows} +
Weapons carried by the {name}
WEAPONTYPECOUNTAMMO BIN
+
""".format( + tags='variant' if base else 'base', search=html.escape(search), + uri=uri, w=w, h=h, name=html.escape(name), key=key, + kind='variant of %s' % html.escape(NAMES[base]) if base else 'base chassis', + cap=cap, chips=chips, nw=sum(weapons.values()), nb=sum(bins.values()), + torsoshort='FIXED' if key in FIXED_TORSO else 'TWISTS', + spec=spec, sheet=sheet, rows=rows)) + print(' %-8s %-12s %2d weapons, %d bins%s' % ( + key, name, sum(weapons.values()), sum(bins.values()), + ' [manual]' if man else ''), file=sys.stderr) + +PAGE = open(os.path.join(os.path.dirname(os.path.abspath(__file__)), + 'mechs.tpl'), encoding='utf-8').read() +os.makedirs(os.path.dirname(OUT), exist_ok=True) +open(OUT, 'w', encoding='utf-8').write(PAGE.format( + cards=''.join(cards), n=len(ROSTER), + nbase=sum(1 for k, _ in ROSTER if k not in VARIANT_OF), + nvar=sum(1 for k, _ in ROSTER if k in VARIANT_OF))) +print('wrote %s (%d mechs)' % (OUT, len(ROSTER)), file=sys.stderr) diff --git a/tools/mechs.tpl b/tools/mechs.tpl new file mode 100644 index 0000000..cf5a970 --- /dev/null +++ b/tools/mechs.tpl @@ -0,0 +1,260 @@ + + + + + +BattleTech 4.11 — the mech roster + + + + +
+
+

BattleTech 4.11 · from btl4fe.cpp, L4GAUGE.CFG and the player's manual

+

Every mech,
and what it carries

+

All {n} mechs the menu offers — {nbase} base chassis + and {nvar} variants — each with its authored weapons roster, ammo bins and the + stat sheet from the original player's manual. The portraits are the game's own + mission-review images, shown in their undamaged state.

+
    +
  • Variants share the chassis, not the loadout
  • +
  • Blackhawk, Nova, Owens, Kotori have a fixed torso
  • +
  • The manual sheets cover the six 4.0 hulls only
  • +
+
+
+ +
+
+
+ + + +
+ + {n} / {n} mechs +
+
+ +
+
+ Energy + Ballistic + Missile +
+ +
{cards}
+ + +

The roster is kVehicles[] in game/glass/btl4fe.cpp + — the exact catalog the in-game menu offers, in menu order. Each mech's weapons and + ammo bins are its cmCrit(...) lines in content/GAUGE/L4GAUGE.CFG, + the critical-damage schematic's authored subsystem roster (independently confirmed against + the subsystem records in BTL4.RES). Nothing is transcribed by hand.

+

The portraits are each mech's mission-review image + (GAUGE/<stem>_MR.PCC) resolved through the review screen's own palette. + In play, its zone indexes are live damage slots painted green→orange→red by the + ColorMapper gauges; this page shows every zone at the undamaged ramp entry — the + same green the armor doll idles at. Variants without their own portrait share the base's, + exactly as the resource file does.

+

Mech stats are the original player's manual stat sheets (pp. 25, 26, 29). + The manual documents the six 4.0 hulls; Avatar and Sunder arrived with 4.10 and have no + sheet, so their rows show a dash rather than an invented number. FIXED vs twisting torso + is read from the shipped resource file: a mech twists only if its subsystem record carries + the jointtorso/jointtshadow joints — the four fixed mechs + match the manual's Torso 0/0 rows exactly.

+

Weapon notes: ER lasers fire red beams, PPCs blue, standard lasers yellow. + Authored ranges where the game states them: PPCs 900 m, missiles 800 m, the + Blackhawk's lasers 500 m, the AFC 50 750 m. The Blackhawk's SRM 6 + racks fire Streak ammunition. LRM tube counts are the salvo size; each launcher's ammo + bin is listed beside it.

+
+ + + +