From 5ad55aa1ebfe8b371a3aec37d81a0381f773d448 Mon Sep 17 00:00:00 2001 From: Cyd Date: Fri, 7 Aug 2026 12:08:11 -0500 Subject: [PATCH] Nine tracks get the console's own map, and the projection is corrected RPConfig.xml has always named a picture for nine of the eighteen tracks. The pictures exist after all, so the page reads the mapping straight out of the config and uses them: score zones, drop zone, the chambers drawn properly and labelled. No reconstruction beats the real thing. The other nine keep the course traced from their gates, and each card now says which of the two it is showing. The pictures also check the reconstruction. Brewer's Bane is the one track shaped distinctively enough to be obviously wrong, and it matches the console picture turn for turn - long leg up one side to Score Zone 1, the corner, the run out to Score Zone 2, junction chambers spaced along it. It matched MIRRORED. Seen from above with +Z up the page the engine's +X runs to the left, and every plan here had been drawn the other way round. Fixed, so the nine tracks without a picture are drawn the same way round as the nine with one. --- docs/tracks.html | 71 ++++++++++++++++++++++------------- tools/pages/build_tracks.py | 74 ++++++++++++++++++++++++++++++++----- tools/pages/tracks.css | 15 +++++++- tools/pages/tracks.tpl | 20 +++++++--- 4 files changed, 136 insertions(+), 44 deletions(-) diff --git a/docs/tracks.html b/docs/tracks.html index cd0bd96..761baaa 100644 --- a/docs/tracks.html +++ b/docs/tracks.html @@ -108,9 +108,20 @@ h1 em { font-style: normal; color: var(--sys); } .trk { background: var(--panel); padding: 1.1rem 1.25rem 1.25rem; } .trk[hidden] { display: none; } -.plan { margin: 0 0 1rem; display: flex; justify-content: center; } +.plan { + margin: 0 0 1rem; display: flex; flex-direction: column; + align-items: center; gap: .5rem; +} +.plan__src { + font: 500 var(--step--1)/1 var(--mono); letter-spacing: .1em; + text-transform: uppercase; color: var(--ink-low); text-align: center; +} .plan__img { - display: block; width: 100%; max-width: 15rem; aspect-ratio: var(--ar); + /* The mask is drawn with contain, so clamping the box letterboxes the + art rather than stretching it - a portrait console map stays legible + beside a squat arena. */ + display: block; width: 100%; max-width: 15rem; max-height: 22rem; + aspect-ratio: var(--ar); background-color: var(--ink-mid); -webkit-mask-image: var(--art); mask-image: var(--art); -webkit-mask-size: contain; mask-size: contain; @@ -175,12 +186,12 @@ h1 em { font-style: normal; color: var(--sys); }

Red Planet 4.12 · plans drawn from RPL4.RES

Every track,
seen from above

-

There are no track maps in the game's files — the console had - pictures of them and those pictures did not survive. But the track itself knows - where it goes. Almost every one is built from a single piece repeated: a wall - thrown across the route with a gate in the middle. These plans are the - course those gates describe — every gate is a point the race passes - through, walked in the order the course visits them.

+

There are no track maps in the game's files. Nine of these are the + next best thing: the setup console's own pictures, score zones and + drop zone labelled, recovered and shown here as they were drawn. The other nine + never had one — so their plan comes from the track itself. Almost every track + is a single piece repeated, a wall thrown across the route with a gate in the + middle, and every gate is a point the race passes through.

@@ -209,7 +220,7 @@ h1 em { font-style: normal; color: var(--sys); }
-
+
The console’s own map

Paingod's Passage

pain

@@ -225,7 +236,7 @@ h1 em { font-style: normal; color: var(--sys); }
-
+
The console’s own map

Blade's Edge

blade

@@ -241,7 +252,7 @@ h1 em { font-style: normal; color: var(--sys); }
-
+
The console’s own map

Yip's Yahoorama

yip

@@ -257,7 +268,7 @@ h1 em { font-style: normal; color: var(--sys); }
-
+
The console’s own map

Berserker's Bahnzai

otto

@@ -273,7 +284,7 @@ h1 em { font-style: normal; color: var(--sys); }
-
+
The console’s own map

Firestorm's Fury

frstrm

@@ -289,7 +300,7 @@ h1 em { font-style: normal; color: var(--sys); }
-
+
The console’s own map

Wiseguy's Wake

wise

@@ -305,7 +316,7 @@ h1 em { font-style: normal; color: var(--sys); }
-
+
The console’s own map

Burnt Cookies

burnt

@@ -321,7 +332,7 @@ h1 em { font-style: normal; color: var(--sys); }
-
+
The console’s own map

Brewer's Bane

brewers

@@ -337,7 +348,7 @@ h1 em { font-style: normal; color: var(--sys); }
-
+
The console’s own map

Lyz's Lane

lyzlane

@@ -353,7 +364,7 @@ h1 em { font-style: normal; color: var(--sys); }
-
+
Course traced from the gates

Freezemoon's Freeway

headoff

@@ -369,7 +380,7 @@ h1 em { font-style: normal; color: var(--sys); }
-
+
Course traced from the gates

Freezemoon's Freeway (Football)

headmf

@@ -385,7 +396,7 @@ h1 em { font-style: normal; color: var(--sys); }
-
+
Course traced from the gates

-- Tour De Mars --

tourdemars

@@ -401,7 +412,7 @@ h1 em { font-style: normal; color: var(--sys); }
-
+
Course traced from the gates

-- Donut --

donut

@@ -417,7 +428,7 @@ h1 em { font-style: normal; color: var(--sys); }
-
+
Course traced from the gates

-- Ares' Armpits --

trough

@@ -433,7 +444,7 @@ h1 em { font-style: normal; color: var(--sys); }
-
+
Course traced from the gates

-- Zaxxis --

rpweekend2014

@@ -449,7 +460,7 @@ h1 em { font-style: normal; color: var(--sys); }
-
+
Course traced from the gates

-- Wiserguy's --

wiserguys

@@ -465,7 +476,7 @@ h1 em { font-style: normal; color: var(--sys); }
-
+
Wall blocks — no single course to trace

-- Arena (Large) --

demoderb

@@ -481,7 +492,7 @@ h1 em { font-style: normal; color: var(--sys); }
-
+
Course traced from the gates

-- Arena (Small) --

arena

@@ -525,6 +536,14 @@ h1 em { font-style: normal; color: var(--sys); } obstacles gives it four or more. Seventeen tracks score 1 or 2 and are drawn as a course. The large arena scores 8 on an exact 100 unit grid, so it keeps its wall blocks instead — and the small arena, which scores 2, really is the maze it looks like.

+

The console's nine pictures also check the other nine. Brewer's Bane is + the one track with a shape distinctive enough to be wrong in an obvious way, and the + reconstruction matches the picture turn for turn — long leg up one side to Score + Zone 1, the corner, the run out to Score Zone 2, junction chambers spaced along it. It + matched mirrored, which is how the projection came to be corrected: seen from above + with +Z up the page the engine's +X runs to the left, and every plan here had + been drawn the other way round. The tracks with no picture are now drawn the same way + round as the tracks with one.

There is still no driving surface anywhere in the file: the track is walls and gates, never tarmac. Extent and relief are the span of the placed geometry in world units, so a long thin plan is a point-to-point canyon run — most of the diff --git a/tools/pages/build_tracks.py b/tools/pages/build_tracks.py index 6e0e3c2..2a6c194 100644 --- a/tools/pages/build_tracks.py +++ b/tools/pages/build_tracks.py @@ -7,7 +7,7 @@ stride, so the scenery placements ARE the map, seen from above. Usage: build_tracks.py """ import base64, html, io, os, re, struct, sys -from PIL import Image, ImageDraw +from PIL import Image, ImageDraw, ImageOps sys.path.insert(0, os.path.dirname(os.path.abspath(__file__))) import navmap @@ -47,10 +47,16 @@ def resource_table(): TABLE = resource_table() # ------------------------------------------------------------ the console -CONSOLE = {} +CONSOLE, CONSOLE_ART = {}, {} xml = open(ROOT + '/tools/console-config/RPConfig.xml', encoding='utf-8-sig').read() -for m in re.finditer(r' box: + k = box / max(im.size) + im = im.resize((max(1, int(im.width * k)), max(1, int(im.height * k))), + Image.LANCZOS) + out = Image.merge('RGBA', (Image.new('L', im.size, 255),) * 3 + (im,)) + buf = io.BytesIO() + out.save(buf, 'PNG', optimize=True) + return ('data:image/png;base64,' + base64.b64encode(buf.getvalue()).decode(), + im.width, im.height) + + def plan_view(segs, box=520, flat=False): """The course, straight down, as an alpha mask. `flat` for the route chains, which are (x, z) pairs rather than (x, y, z) world points.""" @@ -99,8 +135,15 @@ def plan_view(segs, box=520, flat=False): ih = max(8, int(h * scale) + 20) img = Image.new('L', (iw, ih), 0) dr = ImageDraw.Draw(img) + # X runs left, not right. Seen from above with +Z up the page, the + # engine's +X goes to the LEFT - drawn the other way every plan came out + # mirrored. The console's own picture of Brewer's Bane settles it: its + # long leg runs up the right side to Score Zone 1, turns at the corner + # and runs left to Score Zone 2, which is this projection and not its + # mirror. The nine tracks the console never had a picture of are drawn + # the same way round as the nine it did. for seg in segs: - xy = [(10 + (p[0] - min(xs)) * scale, + xy = [(10 + (max(xs) - p[0]) * scale, ih - 10 - ((p[1] if flat else p[2]) - min(zs)) * scale) for p in seg] if len(xy) > 1: @@ -144,13 +187,17 @@ for key, t in tracks.items(): if pts: xs = [p[0] for p in pts]; ys = [p[1] for p in pts]; zs = [p[2] for p in pts] t['extent'] = (max(xs) - min(xs), max(ys) - min(ys), max(zs) - min(zs)) - if t['kind'] == 'route' and chains: - t['art'], t['aw'], t['ah'] = plan_view(chains, flat=True) - else: - t['art'], t['aw'], t['ah'] = plan_view(segs) + shown = console_plan(CONSOLE_ART[key]) if key in CONSOLE_ART else None + t['source'] = 'console' + if shown is None: + t['source'] = 'route' if (t['kind'] == 'route' and chains) else 'blocks' + shown = (plan_view(chains, flat=True) if t['source'] == 'route' + else plan_view(segs)) + t['art'], t['aw'], t['ah'] = shown else: t['extent'] = (0, 0, 0) t['art'] = None + t['source'] = 'none' # Tracks with identical footprints are almost certainly one built from the # other; say so rather than leaving the reader to notice. @@ -185,9 +232,16 @@ for key in ORDER: short = ('

%d of %d placements are drawn; the rest carry no ' 'map art or stand alone off the course

' % (t['drawn'], t['instances'])) if t['skipped'] else '' + SOURCE = { + 'console': 'The console’s own map', + 'route': 'Course traced from the gates', + 'blocks': 'Wall blocks — no single course to trace', + } + art = ('
%s
' % SOURCE[t['source']] + ) if t['art'] else '' art = ('' - % (html.escape(t['name']), t['art'], t['aw'], t['ah'])) if t['art'] else '' + 'style="--art:url(%s);--ar:%d/%d">%s' + % (html.escape(t['name']), t['art'], t['aw'], t['ah'], art)) if t['art'] else '' cards.append("""
{art}
diff --git a/tools/pages/tracks.css b/tools/pages/tracks.css index 833dacd..ef8e4d5 100644 --- a/tools/pages/tracks.css +++ b/tools/pages/tracks.css @@ -104,9 +104,20 @@ h1 em { font-style: normal; color: var(--sys); } .trk { background: var(--panel); padding: 1.1rem 1.25rem 1.25rem; } .trk[hidden] { display: none; } -.plan { margin: 0 0 1rem; display: flex; justify-content: center; } +.plan { + margin: 0 0 1rem; display: flex; flex-direction: column; + align-items: center; gap: .5rem; +} +.plan__src { + font: 500 var(--step--1)/1 var(--mono); letter-spacing: .1em; + text-transform: uppercase; color: var(--ink-low); text-align: center; +} .plan__img { - display: block; width: 100%; max-width: 15rem; aspect-ratio: var(--ar); + /* The mask is drawn with contain, so clamping the box letterboxes the + art rather than stretching it - a portrait console map stays legible + beside a squat arena. */ + display: block; width: 100%; max-width: 15rem; max-height: 22rem; + aspect-ratio: var(--ar); background-color: var(--ink-mid); -webkit-mask-image: var(--art); mask-image: var(--art); -webkit-mask-size: contain; mask-size: contain; diff --git a/tools/pages/tracks.tpl b/tools/pages/tracks.tpl index 48ac26b..907d726 100644 --- a/tools/pages/tracks.tpl +++ b/tools/pages/tracks.tpl @@ -8,12 +8,12 @@

Red Planet 4.12 · plans drawn from RPL4.RES

Every track,
seen from above

-

There are no track maps in the game's files — the console had - pictures of them and those pictures did not survive. But the track itself knows - where it goes. Almost every one is built from a single piece repeated: a wall - thrown across the route with a gate in the middle. These plans are the - course those gates describe — every gate is a point the race passes - through, walked in the order the course visits them.

+

There are no track maps in the game's files. Nine of these are the + next best thing: the setup console's own pictures, score zones and + drop zone labelled, recovered and shown here as they were drawn. The other nine + never had one — so their plan comes from the track itself. Almost every track + is a single piece repeated, a wall thrown across the route with a gate in the + middle, and every gate is a point the race passes through.

@@ -70,6 +70,14 @@ obstacles gives it four or more. Seventeen tracks score 1 or 2 and are drawn as a course. The large arena scores 8 on an exact 100 unit grid, so it keeps its wall blocks instead — and the small arena, which scores 2, really is the maze it looks like.

+

The console's nine pictures also check the other nine. Brewer's Bane is + the one track with a shape distinctive enough to be wrong in an obvious way, and the + reconstruction matches the picture turn for turn — long leg up one side to Score + Zone 1, the corner, the run out to Score Zone 2, junction chambers spaced along it. It + matched mirrored, which is how the projection came to be corrected: seen from above + with +Z up the page the engine's +X runs to the left, and every plan here had + been drawn the other way round. The tracks with no picture are now drawn the same way + round as the tracks with one.

There is still no driving surface anywhere in the file: the track is walls and gates, never tarmac. Extent and relief are the span of the placed geometry in world units, so a long thin plan is a point-to-point canyon run — most of the