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