RECORDANDRONCO/tools/gen_mission3.py
type-two ef432e4182 Mission 03: THE DROP — campaign finale
Full base-building map against a live Stream bot holding The Algorithm behind a
defended base. Building the Mastering Studio triggers a scripted all-in
counterattack; silencing The Algorithm wins. Tick scan throttled to 1Hz.

SIDE A is now three missions.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-07-25 23:19:43 +10:00

125 lines
3.7 KiB
Python

#!/usr/bin/env python3
"""Generate campaign mission 03 — THE DROP (finale: full base vs a live Stream base)."""
import os, struct
from PIL import Image
SIZE = 64
W = H = SIZE + 2
MAP = os.path.join(os.path.dirname(__file__), '..', 'mods', 'vinylgod', 'maps', 'm03')
os.makedirs(MAP, exist_ok=True)
WAX = [(14, 50, 6), (24, 40, 5), (32, 32, 6), (40, 24, 5), (50, 14, 6), (12, 30, 4), (52, 34, 4)]
data = bytearray()
data += struct.pack('<BHH', 2, W, H)
data += struct.pack('<III', 17, 0, 3 * W * H + 17)
data += b'\xff\x00\x00' * (W * H)
res = bytearray(2 * W * H)
for cx, cy, r in WAX:
for x in range(cx - r, cx + r + 1):
for y in range(cy - r, cy + r + 1):
d2 = (x - cx) ** 2 + (y - cy) ** 2
if d2 <= r * r and 0 < x < W - 1 and 0 < y < H - 1:
o = 2 * (x * H + y)
res[o], res[o + 1] = 1, max(2, round(12 * (1 - (d2 ** 0.5) / (r + 1))))
data += res
open(os.path.join(MAP, 'map.bin'), 'wb').write(data)
ACTORS = [
('spawn0', 'mpspawn', 'Neutral', 10, 54),
# the Party
('TheVan', 'popupvan', 'Player', 10, 54),
('dig1', 'digger', 'Player', 13, 54),
('dig2', 'digger', 'Player', 12, 56),
('guard1', 'stacktank', 'Player', 15, 52),
('guard2', 'spinner', 'Player', 16, 55),
('guard3', 'djgrunt', 'Player', 14, 57),
('guard4', 'djgrunt', 'Player', 15, 57),
# the Algorithm's seat
('TheAlgorithm', 'algorithm', 'Enemy', 52, 8),
('ehub', 'streamhub', 'Enemy', 48, 10),
('eproc1', 'transcoder', 'Enemy', 44, 8),
('eproc2', 'transcoder', 'Enemy', 55, 14),
('enode1', 'datacentre', 'Enemy', 50, 13),
('enode2', 'datacentre', 'Enemy', 54, 11),
('epods', 'podfarm', 'Enemy', 45, 13),
('eprint', 'printfarm', 'Enemy', 49, 16),
('eport', 'droneport', 'Enemy', 56, 18),
('etur1', 'adblocker', 'Enemy', 46, 17),
('etur2', 'adblocker', 'Enemy', 52, 18),
('etur3', 'adblocker', 'Enemy', 43, 11),
('escrap1', 'scraper', 'Enemy', 47, 20),
('escrap2', 'scraper', 'Enemy', 50, 20),
('emob1', 'drmwalker', 'Enemy', 44, 20),
('emob2', 'drmwalker', 'Enemy', 53, 22),
('emob3', 'bufferbot', 'Enemy', 46, 22),
('emob4', 'bufferbot', 'Enemy', 47, 22),
('emob5', 'bufferbot', 'Enemy', 48, 22),
# forward picket in the middle
('mid1', 'adblocker', 'Enemy', 34, 28),
('mid2', 'bufferbot', 'Enemy', 33, 30),
('mid3', 'bufferbot', 'Enemy', 35, 30),
]
actors = '\n'.join(f'\t{n}: {t}\n\t\tOwner: {o}\n\t\tLocation: {x},{y}' for n, t, o, x, y in ACTORS)
open(os.path.join(MAP, 'map.yaml'), 'w').write(f"""MapFormat: 12
RequiresMod: vinylgod
Title: 03 - The Drop
Author: Monster Robot Party
Tileset: VINYLGOD
MapSize: {W},{H}
Bounds: 1,1,{SIZE},{SIZE}
Visibility: MissionSelector
Categories: Campaign
LockPreview: True
Players:
PlayerReference@Neutral:
Name: Neutral
OwnsWorld: True
NonCombatant: True
Faction: vinylgod
PlayerReference@Player:
Name: Player
Playable: True
Required: True
AllowBots: False
LockFaction: True
Faction: vinylgod
LockSpawn: True
LockTeam: True
Enemies: Enemy
PlayerReference@Enemy:
Name: Enemy
Faction: stream
Bot: wax
Enemies: Player
Actors:
{actors}
Rules: vinylgod|rules/campaign.yaml, rules.yaml
FluentMessages: vinylgod|fluent/lua.ftl
""")
im = Image.new('RGB', (W, H), (55, 50, 52))
for cx, cy, r in WAX:
for x in range(cx - r, cx + r + 1):
for y in range(cy - r, cy + r + 1):
if (x - cx) ** 2 + (y - cy) ** 2 <= r * r and 0 <= x < W and 0 <= y < H:
im.putpixel((x, y), (255, 45, 150))
for _, _, o, x, y in ACTORS:
im.putpixel((x, y), (255, 255, 255) if o == 'Player' else (80, 150, 255) if o == 'Enemy' else (240, 210, 90))
im.resize((W * 3, H * 3), Image.NEAREST).save(os.path.join(MAP, 'map.png'))
print('m03 written')