RECORDANDRONCO/tools/place_seeds.py
type-two 5255aeeb1f Round 5a: heroes (The Selector, The Curator), air (45 Flyer, Compression Drone) with pads + Aircraft queue/tab, scouts (Boom Bike, Crawler), 5 weapons, wax seep regrowth on all maps
Wax seeps fix the economy flatline the arena telemetry exposed: both bots hit
cash=0/stored=0 from tick 6250 with no way to recover.

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

69 lines
2.6 KiB
Python

#!/usr/bin/env python3
"""Place a neutral `waxseed` actor at the centre of every wax blob on every map.
Reads the resource plane straight out of each map.bin, finds blob centroids by
flood fill, and appends the actors to map.yaml. Idempotent: strips previously
placed waxseed entries first.
"""
import os, re, struct, glob
MAPS = glob.glob(os.path.join(os.path.dirname(__file__), '..', 'mods', 'vinylgod', 'maps', '*'))
def resource_cells(path):
d = open(path, 'rb').read()
fmt, w, h = d[0], *struct.unpack_from('<HH', d, 1)
tiles_off, heights_off, res_off = struct.unpack_from('<III', d, 5)
assert fmt == 2 and heights_off == 0, path
cells = set()
for x in range(w):
for y in range(h):
if d[res_off + 2 * (x * h + y)] != 0:
cells.add((x, y))
return cells
def blobs(cells):
"""Flood-fill into connected blobs, return list of (cx, cy)."""
seen, out = set(), []
for start in sorted(cells):
if start in seen:
continue
stack, blob = [start], []
seen.add(start)
while stack:
x, y = stack.pop()
blob.append((x, y))
for n in ((x+1, y), (x-1, y), (x, y+1), (x, y-1)):
if n in cells and n not in seen:
seen.add(n)
stack.append(n)
if len(blob) >= 6: # ignore specks
out.append((round(sum(p[0] for p in blob) / len(blob)),
round(sum(p[1] for p in blob) / len(blob))))
return out
for mapdir in sorted(MAPS):
my, mb = os.path.join(mapdir, 'map.yaml'), os.path.join(mapdir, 'map.bin')
if not (os.path.exists(my) and os.path.exists(mb)):
continue
centres = blobs(resource_cells(mb))
s = open(my).read()
s = re.sub(r'\n\twaxseed\d+: waxseed\n\t\tOwner: Neutral\n\t\tLocation: \d+,\d+', '', s)
if 'Actors:' not in s:
s = s.rstrip() + '\n\nActors:\n'
block = ''.join(f'\n\twaxseed{i}: waxseed\n\t\tOwner: Neutral\n\t\tLocation: {x},{y}'
for i, (x, y) in enumerate(centres))
# append to the Actors section (it is the last block in our generated maps)
head, _, tail = s.partition('Actors:')
lines = tail.split('\n')
cut = len(lines)
for i, ln in enumerate(lines):
if ln and not ln.startswith('\t') and i > 0: # next top-level key
cut = i
break
tail = '\n'.join(lines[:cut]).rstrip() + block + '\n' + '\n'.join(lines[cut:])
open(my, 'w').write(head + 'Actors:' + tail)
print(f'{os.path.basename(mapdir)}: {len(centres)} seep(s) at {centres}')