RECORDANDRONCO/tools/make_anims.py
type-two 8e4d13b72b Decree two: construction buildup anims, Boombox Crates, real faction flags, character portraits
* All 17 buildings now RISE out of the ground behind a pink scan line when
  built (tools/make_anims.py generates 7-frame make sequences; WithMakeAnimation
  on the building template).
* Boombox Crates: neutral pickups spawn on a timer (max 4). 500 records usually,
  1500 jackpot sometimes, bass_ring feedback trap rarely. Locomotors crush
  crates to collect, classic style.
* Lobby faction flags are real now: MRP record, Stream play button, split '?'.
* MC 8-TRACK and ASSISTANT portraits generated for briefings/press kit.
* Balance ledger updated: first aura-era match went to Stream (runaway flag);
  full ledger M M M | S S | M | S — boundary variance, no knee-jerk tune.

Smoke-tested PASS on arena and m01 with everything live.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-26 19:53:36 +10:00

62 lines
2.4 KiB
Python

#!/usr/bin/env python3
"""Generate construction 'make' animations for every building.
7 frames per building: the structure rises out of the ground behind a hot pink
scan line, classic buildup feel without hand-drawn scaffolding. Source frames
are the static frame-0 backups maintained by animate_sprites.py.
Writes <name>_make.png sheets and appends `make:` sequences.
"""
import os
from PIL import Image, ImageDraw
from PIL.PngImagePlugin import PngInfo
ROOT = os.path.join(os.path.dirname(__file__), '..')
ASSETS = os.path.join(ROOT, 'mods', 'vinylgod', 'sequences', 'assets')
BACKUP = os.path.join(ROOT, 'assets_src', 'static_frames')
SEQ = os.path.join(ROOT, 'mods', 'vinylgod', 'sequences', 'economy.yaml')
FRAMES = 7
PINK = (255, 45, 150, 255)
BUILDINGS = ['popupshop', 'pressplant', 'ampstack', 'vault', 'merchtable', 'garage',
'mastering', 'hornpit', 'streamhub', 'datacentre', 'transcoder', 'podfarm',
'printfarm', 'adblocker', 'algorithm', 'launchramp', 'droneport']
seq = open(SEQ).read()
made = []
for name in BUILDINGS:
src = os.path.join(BACKUP, f'{name}.png')
if not os.path.exists(src):
continue
base = Image.open(src).convert('RGBA')
w, h = base.size
sheet = Image.new('RGBA', (w * FRAMES, h), (0, 0, 0, 0))
for i in range(FRAMES):
t = (i + 1) / FRAMES
reveal = int(h * t) # rows revealed, bottom-up
rise = int((1 - t) * h * 0.25) # slight rise from the ground
frame = Image.new('RGBA', (w, h), (0, 0, 0, 0))
part = base.crop((0, h - reveal, w, h))
frame.paste(part, (0, h - reveal + rise), part)
d = ImageDraw.Draw(frame)
if i < FRAMES - 1:
y = h - reveal + rise
if 0 <= y < h:
d.line([0, y, w, y], fill=PINK, width=2)
sheet.paste(frame, (i * w, 0))
meta = PngInfo()
meta.add_text('FrameSize', f'{w},{h}')
sheet.save(os.path.join(ASSETS, f'{name}_make.png'), pnginfo=meta)
block = f'{name}:\n\tidle:'
if block in seq and f'{name}:\n\tidle:' in seq and f'sequences/assets/{name}_make.png' not in seq:
seq = seq.replace(f'{name}:\n\tidle:',
f'{name}:\n\tmake:\n\t\tFilename: sequences/assets/{name}_make.png\n'
f'\t\tLength: {FRAMES}\n\t\tTick: 70\n\tidle:', 1)
made.append(name)
print(f'make anim: {name}')
open(SEQ, 'w').write(seq)
print(f'{len(made)} buildup animations written')