Companion page to MECHS.html: every map in BTL4.RES drawn the way the cockpit draws it (tools/build_maps.py + tools/maps.tpl -> docs/MAPS.html). Each plan is rendered from the map's own Entity::MakeMessage stream -- every placement, the rtype-18 GaugeImage outline its Model List carries, in the game's own btspal.pcc palette. Nothing is traced or redrawn. The eight playable maps lead; supporting streams (arena geometry, drop points, wind emitters) are labeled and filterable. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
148 lines
6.3 KiB
Smarty
148 lines
6.3 KiB
Smarty
<!doctype html>
|
|
<html lang="en">
|
|
<head>
|
|
<meta charset="utf-8">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
<title>BattleTech 4.11 — every map from above</title>
|
|
<style>
|
|
*, *::before, *::after {{ box-sizing: border-box; }}
|
|
:root {{
|
|
--ground: #0e0f11; --panel: #16181b; --rule: #2a2e33;
|
|
--ink: #e8e6e2; --ink-mid: #a3a8ae; --ink-low: #71777e;
|
|
--hot: #f39313; /* palette 6, the map's own amber */
|
|
--mono: ui-monospace, "Cascadia Mono", Consolas, Menlo, monospace;
|
|
--sans: ui-sans-serif, system-ui, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
|
|
}}
|
|
@media (prefers-color-scheme: light) {{
|
|
:root {{
|
|
--ground: #f4f2ee; --panel: #fbfaf8; --rule: #ddd8d0;
|
|
--ink: #14161a; --ink-mid: #565c63; --ink-low: #7d838a; --hot: #a35f00;
|
|
}}
|
|
}}
|
|
body {{
|
|
margin: 0; background: var(--ground); color: var(--ink);
|
|
font: 400 15px/1.6 var(--sans);
|
|
}}
|
|
.wrap {{ max-width: 78rem; margin: 0 auto; padding: 0 clamp(1rem, 4vw, 2.5rem); }}
|
|
header.top {{ border-bottom: 1px solid var(--rule); padding: clamp(2.5rem,6vw,4rem) 0 1.75rem; }}
|
|
.eyebrow {{
|
|
font: 500 12px/1 var(--mono); letter-spacing: .2em; text-transform: uppercase;
|
|
color: var(--ink-low); margin: 0 0 1rem;
|
|
}}
|
|
h1 {{
|
|
font: 700 clamp(1.9rem,1.4rem+2.2vw,3rem)/1.05 var(--mono);
|
|
letter-spacing: -.02em; text-transform: uppercase; margin: 0 0 .9rem;
|
|
}}
|
|
h1 em {{ font-style: normal; color: var(--hot); }}
|
|
.lede {{ max-width: 62ch; color: var(--ink-mid); margin: 0; font-size: 1.05rem; }}
|
|
.lede strong {{ color: var(--ink); font-weight: 600; }}
|
|
|
|
.bar {{ border-bottom: 1px solid var(--rule); padding: .8rem 0; }}
|
|
.seg {{ display: inline-flex; border: 1px solid var(--rule); }}
|
|
.seg button {{
|
|
font: 500 12px/1 var(--mono); letter-spacing: .12em; text-transform: uppercase;
|
|
background: none; border: 0; color: var(--ink-mid); padding: .55rem .9rem; cursor: pointer;
|
|
}}
|
|
.seg button[aria-pressed="true"] {{ background: var(--hot); color: var(--ground); }}
|
|
|
|
.grid {{
|
|
display: grid; gap: 1px; background: var(--rule);
|
|
border: 1px solid var(--rule); margin: 1.75rem 0 3rem;
|
|
grid-template-columns: repeat(auto-fill, minmax(19rem, 1fr));
|
|
}}
|
|
.map {{ background: var(--panel); padding: 1.1rem 1.25rem 1.35rem; }}
|
|
.map[hidden] {{ display: none; }}
|
|
.fig {{ margin: 0 0 .9rem; display: flex; justify-content: center; }}
|
|
/* The game's own palette on the display's own black, so it reads the same
|
|
in either theme. */
|
|
.plan {{
|
|
display: block; max-width: 100%; height: auto; max-height: 20rem;
|
|
background: #000; border: 1px solid var(--rule); image-rendering: pixelated;
|
|
}}
|
|
.plan--none {{
|
|
margin: 0; padding: 2rem 1rem; text-align: center; color: var(--ink-low);
|
|
font: 400 12px var(--mono); border: 1px dashed var(--rule); width: 100%;
|
|
}}
|
|
h2 {{ font: 700 1.3rem/1.1 var(--mono); margin: 0 0 .25rem; text-transform: uppercase; }}
|
|
.tag {{
|
|
font: 500 11px/1 var(--mono); letter-spacing: .14em; color: var(--ink-low);
|
|
margin: 0 0 .8rem;
|
|
}}
|
|
.stat {{ margin: 0; display: grid; grid-template-columns: 1fr auto; gap: .2rem .8rem; }}
|
|
.stat div {{ display: contents; }}
|
|
.stat dt {{ font: 500 12px var(--mono); letter-spacing: .08em; color: var(--ink-low); }}
|
|
.stat dd {{
|
|
margin: 0; text-align: right; font: 500 12px var(--mono); color: var(--ink);
|
|
font-variant-numeric: tabular-nums;
|
|
}}
|
|
.models {{
|
|
margin: .75rem 0 0; font: 400 11px/1.6 var(--mono); color: var(--ink-low);
|
|
word-break: break-word;
|
|
}}
|
|
.foot {{
|
|
border-top: 1px solid var(--rule); padding: 1.5rem 0 4rem; max-width: 76ch;
|
|
color: var(--ink-low); font-size: 13px;
|
|
}}
|
|
.foot code {{ font-family: var(--mono); color: var(--ink-mid); }}
|
|
</style>
|
|
</head>
|
|
<body>
|
|
|
|
<header class="top">
|
|
<div class="wrap">
|
|
<p class="eyebrow">BattleTech 4.11 · drawn from BTL4.RES</p>
|
|
<h1>Every map,<br><em>seen from above</em></h1>
|
|
<p class="lede">Each plan is drawn the way the cockpit draws it: every placement in
|
|
the map's own stream, the outline its model carries, in the game's own palette.
|
|
<strong>Nothing here is traced or redrawn</strong> — the buttes are circles
|
|
because the game draws them as circles.</p>
|
|
</div>
|
|
</header>
|
|
|
|
<div class="bar">
|
|
<div class="wrap">
|
|
<div class="seg" role="group" aria-label="Filter">
|
|
<button type="button" data-filter="all" aria-pressed="true">All {n}</button>
|
|
<button type="button" data-filter="playable" aria-pressed="false">Playable {playable}</button>
|
|
<button type="button" data-filter="aux" aria-pressed="false">Supporting</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<main class="wrap">
|
|
<div class="grid">{cards}</div>
|
|
|
|
<p class="foot">A map stream is a run of <code>Entity::MakeMessage</code> records. Each
|
|
carries its own length at +0, its class at +28, the resource it names at +40, its
|
|
instance flags at +44 and its origin at +48 — and BT pads each record to the
|
|
next four bytes, which Red Planet does not. The resource named is a <em>Model List</em>;
|
|
the outline the display draws is the GaugeImage inside that list, so the join is direct
|
|
rather than by name. A model with no GaugeImage is not drawn, which is why several
|
|
streams place far more than they draw.</p>
|
|
<p class="foot">Colours are palette indices resolved through <code>btspal.pcc</code>, the
|
|
palette <code>L4GAUGE.CFG</code> configures the secondary port with:
|
|
<code>configure(0,sec,270,0x003F,clut0,rgb,btspal.pcc)</code>. Unlike Red Planet,
|
|
every primitive here carries an explicit colour — nothing falls back to a display
|
|
default. Seen from above, +X runs right and +Z up.</p>
|
|
<p class="foot">Two of the eight playable maps, <code>arena1</code> and
|
|
<code>arena2</code>, place almost nothing: a sky and a pair of records too short to
|
|
carry an origin. Their arena geometry is <code>arenall</code>, which is a stream of its
|
|
own. <code>adrop</code> and <code>pol4sfx</code> are likewise supporting streams
|
|
— drop points and wind emitters — rather than places you fight in.</p>
|
|
</main>
|
|
|
|
<script>
|
|
const cards = [...document.querySelectorAll('.map')];
|
|
for (const b of document.querySelectorAll('[data-filter]')) {{
|
|
b.addEventListener('click', () => {{
|
|
const f = b.dataset.filter;
|
|
for (const o of document.querySelectorAll('[data-filter]'))
|
|
o.setAttribute('aria-pressed', String(o === b));
|
|
for (const c of cards)
|
|
c.hidden = f !== 'all' && !c.dataset.tags.split(' ').includes(f);
|
|
}});
|
|
}}
|
|
</script>
|
|
</body>
|
|
</html>
|