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>
83
LORE.md
@ -95,6 +95,89 @@ replaced by a receipt.
|
|||||||
| `datacentre` | Edge Node | power/build-radius creep | humming white monolith with a single blue status LED |
|
| `datacentre` | Edge Node | power/build-radius creep | humming white monolith with a single blue status LED |
|
||||||
| `transcoder` | Transcoder | refinery | white cube that swallows records whole; only receipts come out |
|
| `transcoder` | Transcoder | refinery | white cube that swallows records whole; only receipts come out |
|
||||||
|
|
||||||
|
## Heroes
|
||||||
|
|
||||||
|
Each side fields exactly one hero. They cost a fortune, they cannot be replaced
|
||||||
|
while alive, and losing one is a story beat, not a statistic.
|
||||||
|
|
||||||
|
### THE SELECTOR (MRP, `selector`)
|
||||||
|
|
||||||
|
Nobody built the Selector. It assembled itself in the sub-basement of a flooded
|
||||||
|
pressing plant out of a coat rack, a broken mastering lathe, and the contents of
|
||||||
|
a collection somebody spent forty years building and one afternoon losing.
|
||||||
|
|
||||||
|
It carries a crate of **one-of-one dubplates** — acetates cut before the
|
||||||
|
Compression, of songs that exist nowhere else. Each one it throws is gone
|
||||||
|
forever. That is the Selector's whole tragedy and its whole tactic: it wins
|
||||||
|
fights by destroying the last copies of the things it is fighting for.
|
||||||
|
|
||||||
|
It does not speak. It nods, and something in the distance falls over.
|
||||||
|
|
||||||
|
- Slow, absurdly tough for infantry, huge splash damage, long reload.
|
||||||
|
- Voice lines are just the needle-drop crackle of a record starting.
|
||||||
|
|
||||||
|
### THE CURATOR (Stream, `curator`)
|
||||||
|
|
||||||
|
The Algorithm's only physical opinion. A white sphere ringed with lenses that
|
||||||
|
hovers three feet off the ground and *watches*, and the watching is the weapon —
|
||||||
|
everything it looks at is being scored, ranked, and found wanting.
|
||||||
|
|
||||||
|
It is unfailingly polite. It refers to units it is destroying as "underperforming
|
||||||
|
content." It refers to the Selector as "a legacy account."
|
||||||
|
|
||||||
|
- Fast, fragile for a hero, continuous beam that melts armour.
|
||||||
|
- Cannot capture or hold ground. It only ever passes through, sampling.
|
||||||
|
|
||||||
|
## Air
|
||||||
|
|
||||||
|
Late-war escalation. Both sides looked up at the same time.
|
||||||
|
|
||||||
|
- **45 Flyer** (`flyer45`, MRP): a 7-inch single with tonearm rotor blades and a
|
||||||
|
scavenged engine pod bolted through the spindle hole. Loud, fast, made of
|
||||||
|
rubbish, held together by belief.
|
||||||
|
- **Compression Drone** (`compressor`, Stream): from the original Stream roster —
|
||||||
|
projects a shrinking blue field; things inside get smaller and worse.
|
||||||
|
- Launch pads: **Launch Ramp** (`launchramp`) and **Drone Port** (`droneport`).
|
||||||
|
|
||||||
|
## Scouts
|
||||||
|
|
||||||
|
- **Boom Bike** (`boombike`, MRP): a trike with two speaker cones where the
|
||||||
|
pillion should be. Nothing outruns it. Nothing wants to be near it either.
|
||||||
|
- **Crawler** (`crawler`, Stream): a flat white rover that maps your base and
|
||||||
|
files a report. Unarmed, silent, already gone by the time you shoot at it.
|
||||||
|
|
||||||
|
## Wax seeps
|
||||||
|
|
||||||
|
Wax fields are not deposits, they are **wounds**. Each field grows from a
|
||||||
|
**seep point** — a crack over a buried pressing plant, a landfill vent, a
|
||||||
|
flooded archive — and as long as the seep is open, the field regrows. Kill the
|
||||||
|
economy of a map and it will heal; the Black Wax has all the time in the world.
|
||||||
|
|
||||||
|
## The campaign: SIDE A
|
||||||
|
|
||||||
|
Three missions. The MRP origin story, told from the landfill up.
|
||||||
|
|
||||||
|
### 1. FIRST PRESSING
|
||||||
|
The Party wakes up. A pop-up van and a single digger in a wax field at the edge
|
||||||
|
of the old industrial estate. Get a pressing plant running and press the first
|
||||||
|
records of the new world — before the Stream's survey drones finish counting
|
||||||
|
what's down here.
|
||||||
|
*Objectives: build a Pressing Plant, bank 2000 records, survive the first probe.*
|
||||||
|
|
||||||
|
### 2. CRATE DIGGERS
|
||||||
|
A Stream transcoder outpost has found something under the hill: a **master
|
||||||
|
lacquer**, the original of an original. In six minutes it will be a receipt.
|
||||||
|
Take the outpost apart and take back the master.
|
||||||
|
*Objectives: destroy the Transcoder before the timer, keep the Selector alive.*
|
||||||
|
|
||||||
|
### 3. THE DROP
|
||||||
|
The Algorithm has surfaced. Build the Mastering Studio, charge the orbital
|
||||||
|
tonearm, and put the needle through it.
|
||||||
|
*Objectives: build a Mastering Studio, fire THE DROP at the Algorithm, survive
|
||||||
|
the counterattack.*
|
||||||
|
|
||||||
|
*(SIDE B — the Stream campaign, in which you are the polite one — is unwritten.)*
|
||||||
|
|
||||||
## Tone
|
## Tone
|
||||||
|
|
||||||
Saturday-morning-cartoon apocalypse. The stakes are real (music is being deleted
|
Saturday-morning-cartoon apocalypse. The stakes are real (music is being deleted
|
||||||
|
|||||||
@ -31,3 +31,7 @@ All images generated locally on MODELBEAST (`flux_local`) via `tools/mbgen.py`.
|
|||||||
| renders/scraper.png | 2026-07-20 | glossy seamless white tech aesthetic, soft blue ring lights, smooth rounded minimal design, autonomous white street sweeper vehicle inhaling black vinyl through a glowing blue intake, isometric three-quarter view from above, single object centered, video game asset, plain flat grey background, no text |
|
| renders/scraper.png | 2026-07-20 | glossy seamless white tech aesthetic, soft blue ring lights, smooth rounded minimal design, autonomous white street sweeper vehicle inhaling black vinyl through a glowing blue intake, isometric three-quarter view from above, single object centered, video game asset, plain flat grey background, no text |
|
||||||
| renders/bufferbot.png | 2026-07-20 | glossy seamless white tech aesthetic, soft blue ring lights, smooth rounded minimal design, knee-high white sphere robot with a loading spinner face, isometric three-quarter view from above, single object centered, video game asset, plain flat grey background, no text |
|
| renders/bufferbot.png | 2026-07-20 | glossy seamless white tech aesthetic, soft blue ring lights, smooth rounded minimal design, knee-high white sphere robot with a loading spinner face, isometric three-quarter view from above, single object centered, video game asset, plain flat grey background, no text |
|
||||||
| renders/drmwalker.png | 2026-07-20 | glossy seamless white tech aesthetic, soft blue ring lights, smooth rounded minimal design, tall faceless white mech with one blue ring-light eye and a glowing paywall screen chest, isometric three-quarter view from above, single object centered, video game asset, plain flat grey background, no text |
|
| renders/drmwalker.png | 2026-07-20 | glossy seamless white tech aesthetic, soft blue ring lights, smooth rounded minimal design, tall faceless white mech with one blue ring-light eye and a glowing paywall screen chest, isometric three-quarter view from above, single object centered, video game asset, plain flat grey background, no text |
|
||||||
|
| renders/selector.png | 2026-07-25 | rusty junkyard robot aesthetic, rust metal with hot pink trim, analog dials and speaker parts, legendary hero DJ robot in a long coat with a crate of glowing gold dubplates under one arm and a tonearm staff, isometric three-quarter view from above, single object centered, video game asset, plain flat grey background, no text |
|
||||||
|
| renders/curator.png | 2026-07-25 | glossy seamless white tech aesthetic, soft blue ring lights, smooth rounded minimal design, hovering white sphere ringed with many camera lenses, a single blue eye at the front, faint halo, isometric three-quarter view from above, single object centered, video game asset, plain flat grey background, no text |
|
||||||
|
| renders/launchramp.png | 2026-07-25 | rusty junkyard robot aesthetic, rust metal with hot pink trim, analog dials and speaker parts, scrap metal launch ramp pad with painted pink chevrons, floodlights and a parked flying vinyl disc, isometric three-quarter view from above, single object centered, video game asset, plain flat grey background, no text |
|
||||||
|
| renders/droneport.png | 2026-07-25 | glossy seamless white tech aesthetic, soft blue ring lights, smooth rounded minimal design, white circular drone landing pad building with recessed blue guide lights and folded launch arms, isometric three-quarter view from above, single object centered, video game asset, plain flat grey background, no text |
|
||||||
|
|||||||
BIN
assets_src/renders/curator.png
Normal file
|
After Width: | Height: | Size: 928 KiB |
BIN
assets_src/renders/curator_raw.png
Normal file
|
After Width: | Height: | Size: 819 KiB |
BIN
assets_src/renders/droneport.png
Normal file
|
After Width: | Height: | Size: 935 KiB |
BIN
assets_src/renders/droneport_raw.png
Normal file
|
After Width: | Height: | Size: 832 KiB |
BIN
assets_src/renders/launchramp.png
Normal file
|
After Width: | Height: | Size: 895 KiB |
BIN
assets_src/renders/launchramp_raw.png
Normal file
|
After Width: | Height: | Size: 772 KiB |
BIN
assets_src/renders/selector.png
Normal file
|
After Width: | Height: | Size: 937 KiB |
BIN
assets_src/renders/selector_raw.png
Normal file
|
After Width: | Height: | Size: 805 KiB |
BIN
assets_src/renders_topdown/boombike.png
Normal file
|
After Width: | Height: | Size: 547 KiB |
BIN
assets_src/renders_topdown/boombike_raw.png
Normal file
|
After Width: | Height: | Size: 471 KiB |
BIN
assets_src/renders_topdown/compressor.png
Normal file
|
After Width: | Height: | Size: 969 KiB |
BIN
assets_src/renders_topdown/compressor_raw.png
Normal file
|
After Width: | Height: | Size: 850 KiB |
BIN
assets_src/renders_topdown/crawler.png
Normal file
|
After Width: | Height: | Size: 813 KiB |
BIN
assets_src/renders_topdown/crawler_raw.png
Normal file
|
After Width: | Height: | Size: 720 KiB |
BIN
assets_src/renders_topdown/flyer45.png
Normal file
|
After Width: | Height: | Size: 553 KiB |
BIN
assets_src/renders_topdown/flyer45_raw.png
Normal file
|
After Width: | Height: | Size: 484 KiB |
BIN
assets_src/renders_topdown/waxseed.png
Normal file
|
After Width: | Height: | Size: 774 KiB |
BIN
assets_src/renders_topdown/waxseed_raw.png
Normal file
|
After Width: | Height: | Size: 687 KiB |
|
Before Width: | Height: | Size: 305 B After Width: | Height: | Size: 527 B |
@ -403,3 +403,6 @@ production-icons:
|
|||||||
vehicle: 0, 32, 16, 16
|
vehicle: 0, 32, 16, 16
|
||||||
vehicle-disabled: 16, 32, 16, 16
|
vehicle-disabled: 16, 32, 16, 16
|
||||||
vehicle-alert: 32, 32, 16, 16
|
vehicle-alert: 32, 32, 16, 16
|
||||||
|
aircraft: 0, 48, 16, 16
|
||||||
|
aircraft-disabled: 16, 48, 16, 16
|
||||||
|
aircraft-alert: 32, 48, 16, 16
|
||||||
|
|||||||
@ -93,3 +93,14 @@ Container@PLAYER_WIDGETS:
|
|||||||
X: 7
|
X: 7
|
||||||
Y: 7
|
Y: 7
|
||||||
ImageCollection: production-icons
|
ImageCollection: production-icons
|
||||||
|
ProductionTypeButton@AIRCRAFT:
|
||||||
|
Y: 99
|
||||||
|
Width: 30
|
||||||
|
Height: 30
|
||||||
|
Background: button
|
||||||
|
ProductionGroup: Aircraft
|
||||||
|
Children:
|
||||||
|
Image@ICON:
|
||||||
|
X: 7
|
||||||
|
Y: 7
|
||||||
|
ImageCollection: production-icons
|
||||||
|
|||||||
@ -87,3 +87,23 @@ power-thedrop =
|
|||||||
power-theshuffle =
|
power-theshuffle =
|
||||||
.name = THE SHUFFLE
|
.name = THE SHUFFLE
|
||||||
.description = Reality-compression strike. Terms of service apply.
|
.description = Reality-compression strike. Terms of service apply.
|
||||||
|
|
||||||
|
## round 5: heroes, scouts, air
|
||||||
|
actor-selector =
|
||||||
|
.name = The Selector
|
||||||
|
actor-curator =
|
||||||
|
.name = The Curator
|
||||||
|
actor-boombike =
|
||||||
|
.name = Boom Bike
|
||||||
|
actor-crawler =
|
||||||
|
.name = Crawler
|
||||||
|
actor-flyer45 =
|
||||||
|
.name = 45 Flyer
|
||||||
|
actor-compressor =
|
||||||
|
.name = Compression Drone
|
||||||
|
actor-launchramp =
|
||||||
|
.name = Launch Ramp
|
||||||
|
actor-droneport =
|
||||||
|
.name = Drone Port
|
||||||
|
actor-waxseed =
|
||||||
|
.name = Wax Seep
|
||||||
|
|||||||
|
Before Width: | Height: | Size: 86 B After Width: | Height: | Size: 86 B |
@ -58,5 +58,11 @@ Actors:
|
|||||||
Actor4: scraper
|
Actor4: scraper
|
||||||
Owner: BotB
|
Owner: BotB
|
||||||
Location: 24,25
|
Location: 24,25
|
||||||
|
waxseed0: waxseed
|
||||||
|
Owner: Neutral
|
||||||
|
Location: 8,20
|
||||||
|
waxseed1: waxseed
|
||||||
|
Owner: Neutral
|
||||||
|
Location: 18,10
|
||||||
|
|
||||||
Rules: rules.yaml
|
Rules: rules.yaml
|
||||||
|
|||||||
|
Before Width: | Height: | Size: 1.3 KiB After Width: | Height: | Size: 113 B |
@ -76,3 +76,30 @@ Actors:
|
|||||||
Actor5: mpspawn
|
Actor5: mpspawn
|
||||||
Owner: Multi5
|
Owner: Multi5
|
||||||
Location: 45,84
|
Location: 45,84
|
||||||
|
waxseed0: waxseed
|
||||||
|
Owner: Neutral
|
||||||
|
Location: 12,45
|
||||||
|
waxseed1: waxseed
|
||||||
|
Owner: Neutral
|
||||||
|
Location: 20,20
|
||||||
|
waxseed2: waxseed
|
||||||
|
Owner: Neutral
|
||||||
|
Location: 20,71
|
||||||
|
waxseed3: waxseed
|
||||||
|
Owner: Neutral
|
||||||
|
Location: 45,45
|
||||||
|
waxseed4: waxseed
|
||||||
|
Owner: Neutral
|
||||||
|
Location: 45,25
|
||||||
|
waxseed5: waxseed
|
||||||
|
Owner: Neutral
|
||||||
|
Location: 45,66
|
||||||
|
waxseed6: waxseed
|
||||||
|
Owner: Neutral
|
||||||
|
Location: 71,20
|
||||||
|
waxseed7: waxseed
|
||||||
|
Owner: Neutral
|
||||||
|
Location: 71,71
|
||||||
|
waxseed8: waxseed
|
||||||
|
Owner: Neutral
|
||||||
|
Location: 79,45
|
||||||
|
|||||||
|
Before Width: | Height: | Size: 937 B After Width: | Height: | Size: 99 B |
@ -60,3 +60,30 @@ Actors:
|
|||||||
Actor3: mpspawn
|
Actor3: mpspawn
|
||||||
Owner: Multi3
|
Owner: Multi3
|
||||||
Location: 57,57
|
Location: 57,57
|
||||||
|
waxseed0: waxseed
|
||||||
|
Owner: Neutral
|
||||||
|
Location: 10,32
|
||||||
|
waxseed1: waxseed
|
||||||
|
Owner: Neutral
|
||||||
|
Location: 16,16
|
||||||
|
waxseed2: waxseed
|
||||||
|
Owner: Neutral
|
||||||
|
Location: 16,49
|
||||||
|
waxseed3: waxseed
|
||||||
|
Owner: Neutral
|
||||||
|
Location: 32,32
|
||||||
|
waxseed4: waxseed
|
||||||
|
Owner: Neutral
|
||||||
|
Location: 32,10
|
||||||
|
waxseed5: waxseed
|
||||||
|
Owner: Neutral
|
||||||
|
Location: 32,55
|
||||||
|
waxseed6: waxseed
|
||||||
|
Owner: Neutral
|
||||||
|
Location: 49,16
|
||||||
|
waxseed7: waxseed
|
||||||
|
Owner: Neutral
|
||||||
|
Location: 49,49
|
||||||
|
waxseed8: waxseed
|
||||||
|
Owner: Neutral
|
||||||
|
Location: 55,32
|
||||||
|
|||||||
|
Before Width: | Height: | Size: 517 B After Width: | Height: | Size: 89 B |
@ -44,3 +44,18 @@ Actors:
|
|||||||
Actor1: mpspawn
|
Actor1: mpspawn
|
||||||
Owner: Multi1
|
Owner: Multi1
|
||||||
Location: 34,20
|
Location: 34,20
|
||||||
|
waxseed0: waxseed
|
||||||
|
Owner: Neutral
|
||||||
|
Location: 7,7
|
||||||
|
waxseed1: waxseed
|
||||||
|
Owner: Neutral
|
||||||
|
Location: 7,34
|
||||||
|
waxseed2: waxseed
|
||||||
|
Owner: Neutral
|
||||||
|
Location: 20,20
|
||||||
|
waxseed3: waxseed
|
||||||
|
Owner: Neutral
|
||||||
|
Location: 34,7
|
||||||
|
waxseed4: waxseed
|
||||||
|
Owner: Neutral
|
||||||
|
Location: 34,34
|
||||||
|
|||||||
|
Before Width: | Height: | Size: 86 B After Width: | Height: | Size: 86 B |
@ -52,3 +52,9 @@ Actors:
|
|||||||
Actor8: adblocker
|
Actor8: adblocker
|
||||||
Owner: Creeps
|
Owner: Creeps
|
||||||
Location: 25,22
|
Location: 25,22
|
||||||
|
waxseed0: waxseed
|
||||||
|
Owner: Neutral
|
||||||
|
Location: 8,20
|
||||||
|
waxseed1: waxseed
|
||||||
|
Owner: Neutral
|
||||||
|
Location: 18,10
|
||||||
|
|||||||
|
Before Width: | Height: | Size: 86 B After Width: | Height: | Size: 86 B |
@ -36,3 +36,9 @@ Actors:
|
|||||||
Actor0: mpspawn
|
Actor0: mpspawn
|
||||||
Owner: Multi0
|
Owner: Multi0
|
||||||
Location: 16,16
|
Location: 16,16
|
||||||
|
waxseed0: waxseed
|
||||||
|
Owner: Neutral
|
||||||
|
Location: 10,10
|
||||||
|
waxseed1: waxseed
|
||||||
|
Owner: Neutral
|
||||||
|
Location: 24,23
|
||||||
|
|||||||
@ -215,3 +215,152 @@ algorithm:
|
|||||||
DisplayRadarPing: true
|
DisplayRadarPing: true
|
||||||
SupportPowerPaletteOrder: 10
|
SupportPowerPaletteOrder: 10
|
||||||
SupportPowerChargeBar:
|
SupportPowerChargeBar:
|
||||||
|
|
||||||
|
# --- round 5: MRP hero + scout ---
|
||||||
|
|
||||||
|
selector:
|
||||||
|
Inherits: ^ArmedUnit
|
||||||
|
Voiced:
|
||||||
|
VoiceSet: MrpVoice
|
||||||
|
Buildable:
|
||||||
|
Queue: Infantry
|
||||||
|
BuildPaletteOrder: 30
|
||||||
|
Prerequisites: mastering
|
||||||
|
BuildLimit: 1
|
||||||
|
Valued:
|
||||||
|
Cost: 2000
|
||||||
|
Tooltip:
|
||||||
|
Name: actor-selector.name
|
||||||
|
Health:
|
||||||
|
HP: 40000
|
||||||
|
Armor:
|
||||||
|
Type: None
|
||||||
|
Mobile:
|
||||||
|
Locomotor: foot
|
||||||
|
Speed: 42
|
||||||
|
Armament:
|
||||||
|
Weapon: dubplate
|
||||||
|
RevealsShroud:
|
||||||
|
Range: 7c0
|
||||||
|
SelectionDecorations:
|
||||||
|
|
||||||
|
boombike:
|
||||||
|
Inherits: ^ArmedUnit
|
||||||
|
Voiced:
|
||||||
|
VoiceSet: MrpVoice
|
||||||
|
-WithSpriteBody:
|
||||||
|
WithFacingSpriteBody:
|
||||||
|
Buildable:
|
||||||
|
Queue: Vehicle
|
||||||
|
BuildPaletteOrder: 35
|
||||||
|
Prerequisites: garage
|
||||||
|
Valued:
|
||||||
|
Cost: 400
|
||||||
|
Tooltip:
|
||||||
|
Name: actor-boombike.name
|
||||||
|
Health:
|
||||||
|
HP: 15000
|
||||||
|
Armor:
|
||||||
|
Type: Light
|
||||||
|
Mobile:
|
||||||
|
Locomotor: wheeled
|
||||||
|
Speed: 140
|
||||||
|
Armament:
|
||||||
|
Weapon: bike_horn
|
||||||
|
RevealsShroud:
|
||||||
|
Range: 8c0
|
||||||
|
|
||||||
|
# --- round 5: air ---
|
||||||
|
# ponytail: aircraft are Targetable as GroundActor too, so existing weapons can
|
||||||
|
# hit them. Upgrade path: dedicated AA armaments + AirborneActor-only targeting.
|
||||||
|
|
||||||
|
^AirUnit:
|
||||||
|
BodyOrientation:
|
||||||
|
QuantizeFacingsFromSequence:
|
||||||
|
RenderSprites:
|
||||||
|
WithFacingSpriteBody:
|
||||||
|
SelectionDecorations:
|
||||||
|
AppearsOnRadar:
|
||||||
|
UseLocation: true
|
||||||
|
HitShape:
|
||||||
|
HiddenUnderFog:
|
||||||
|
Type: GroundPosition
|
||||||
|
Selectable:
|
||||||
|
Bounds: 1024, 1024
|
||||||
|
Targetable:
|
||||||
|
TargetTypes: GroundActor, AirborneActor
|
||||||
|
MustBeDestroyed:
|
||||||
|
FireWarheadsOnDeath:
|
||||||
|
Weapon: UnitExplode
|
||||||
|
Aircraft:
|
||||||
|
CanHover: True
|
||||||
|
CanSlide: True
|
||||||
|
VTOL: True
|
||||||
|
IdleBehavior: Land
|
||||||
|
LandableTerrainTypes: Clear, Wax
|
||||||
|
AirborneCondition: airborne
|
||||||
|
CruisingCondition: cruising
|
||||||
|
Hovers@CRUISING:
|
||||||
|
RequiresCondition: cruising
|
||||||
|
AttackMove:
|
||||||
|
Guard:
|
||||||
|
Guardable:
|
||||||
|
AutoTarget:
|
||||||
|
AutoTargetPriority@DEFAULT:
|
||||||
|
ValidTargets: GroundActor, Structure
|
||||||
|
RevealsShroud:
|
||||||
|
Range: 7c0
|
||||||
|
Type: CenterPosition
|
||||||
|
MapEditorData:
|
||||||
|
Categories: Aircraft
|
||||||
|
|
||||||
|
flyer45:
|
||||||
|
Inherits: ^AirUnit
|
||||||
|
Voiced:
|
||||||
|
VoiceSet: MrpVoice
|
||||||
|
Buildable:
|
||||||
|
Queue: Aircraft
|
||||||
|
BuildPaletteOrder: 10
|
||||||
|
Prerequisites: launchramp
|
||||||
|
Valued:
|
||||||
|
Cost: 900
|
||||||
|
Tooltip:
|
||||||
|
Name: actor-flyer45.name
|
||||||
|
Health:
|
||||||
|
HP: 22000
|
||||||
|
Armor:
|
||||||
|
Type: Light
|
||||||
|
Aircraft:
|
||||||
|
Speed: 149
|
||||||
|
Armament:
|
||||||
|
Weapon: rotor_blade
|
||||||
|
PauseOnCondition: !ammo
|
||||||
|
AttackAircraft:
|
||||||
|
AttackType: Hover
|
||||||
|
FacingTolerance: 90
|
||||||
|
AmmoPool:
|
||||||
|
Ammo: 12
|
||||||
|
ReloadDelay: 24
|
||||||
|
AmmoCondition: ammo
|
||||||
|
|
||||||
|
launchramp:
|
||||||
|
Inherits: ^EconBuilding
|
||||||
|
Inherits@shape: ^Buildable2x2
|
||||||
|
Buildable:
|
||||||
|
Queue: Building
|
||||||
|
BuildPaletteOrder: 55
|
||||||
|
Prerequisites: garage
|
||||||
|
Valued:
|
||||||
|
Cost: 800
|
||||||
|
Tooltip:
|
||||||
|
Name: actor-launchramp.name
|
||||||
|
Health:
|
||||||
|
HP: 70000
|
||||||
|
Production:
|
||||||
|
Produces: Aircraft
|
||||||
|
Exit@1:
|
||||||
|
SpawnOffset: 0,-256,0
|
||||||
|
ExitCell: 0,0
|
||||||
|
Reservable:
|
||||||
|
Power:
|
||||||
|
Amount: -20
|
||||||
|
|||||||
@ -263,3 +263,27 @@ garage:
|
|||||||
ExitCell: 0, 2
|
ExitCell: 0, 2
|
||||||
Power:
|
Power:
|
||||||
Amount: -20
|
Amount: -20
|
||||||
|
|
||||||
|
# --- round 5: wax seep points (regrow the fields; see LORE.md "Wax seeps") ---
|
||||||
|
|
||||||
|
waxseed:
|
||||||
|
BodyOrientation:
|
||||||
|
RenderSprites:
|
||||||
|
WithSpriteBody:
|
||||||
|
Interactable:
|
||||||
|
HiddenUnderShroud:
|
||||||
|
Building:
|
||||||
|
Footprint: x
|
||||||
|
Dimensions: 1,1
|
||||||
|
TerrainTypes: Clear, Wax
|
||||||
|
AppearsOnRadar:
|
||||||
|
RadarColorFromTerrain:
|
||||||
|
Terrain: Wax
|
||||||
|
AppearsOnMapPreview:
|
||||||
|
Terrain: Wax
|
||||||
|
SeedsResource:
|
||||||
|
ResourceType: Wax
|
||||||
|
Interval: 90
|
||||||
|
MaxRange: 60
|
||||||
|
MapEditorData:
|
||||||
|
Categories: Resource spawn
|
||||||
|
|||||||
@ -26,6 +26,10 @@ player:
|
|||||||
Type: Infantry
|
Type: Infantry
|
||||||
Group: Infantry
|
Group: Infantry
|
||||||
ReadyAudio: UnitReady
|
ReadyAudio: UnitReady
|
||||||
|
ClassicProductionQueue@Aircraft:
|
||||||
|
Type: Aircraft
|
||||||
|
Group: Aircraft
|
||||||
|
ReadyAudio: UnitReady
|
||||||
ConquestVictoryConditions:
|
ConquestVictoryConditions:
|
||||||
MissionObjectives:
|
MissionObjectives:
|
||||||
WinNotification: Win
|
WinNotification: Win
|
||||||
|
|||||||
@ -202,3 +202,108 @@ drmwalker:
|
|||||||
Speed: 42
|
Speed: 42
|
||||||
Armament:
|
Armament:
|
||||||
Weapon: feedback_burst
|
Weapon: feedback_burst
|
||||||
|
|
||||||
|
# --- round 5: Stream hero + scout ---
|
||||||
|
|
||||||
|
curator:
|
||||||
|
Inherits: ^ArmedUnit
|
||||||
|
Voiced:
|
||||||
|
VoiceSet: StreamVoice
|
||||||
|
Buildable:
|
||||||
|
Queue: Infantry
|
||||||
|
BuildPaletteOrder: 30
|
||||||
|
Prerequisites: algorithm
|
||||||
|
BuildLimit: 1
|
||||||
|
Valued:
|
||||||
|
Cost: 2000
|
||||||
|
Tooltip:
|
||||||
|
Name: actor-curator.name
|
||||||
|
Health:
|
||||||
|
HP: 25000
|
||||||
|
Armor:
|
||||||
|
Type: Light
|
||||||
|
Mobile:
|
||||||
|
Locomotor: foot
|
||||||
|
Speed: 95
|
||||||
|
Armament:
|
||||||
|
Weapon: curator_beam
|
||||||
|
RevealsShroud:
|
||||||
|
Range: 8c0
|
||||||
|
SelectionDecorations:
|
||||||
|
|
||||||
|
crawler:
|
||||||
|
Inherits: ^Unit
|
||||||
|
Voiced:
|
||||||
|
VoiceSet: StreamVoice
|
||||||
|
-WithSpriteBody:
|
||||||
|
WithFacingSpriteBody:
|
||||||
|
Buildable:
|
||||||
|
Queue: Vehicle
|
||||||
|
BuildPaletteOrder: 15
|
||||||
|
Prerequisites: transcoder
|
||||||
|
Valued:
|
||||||
|
Cost: 300
|
||||||
|
Tooltip:
|
||||||
|
Name: actor-crawler.name
|
||||||
|
Health:
|
||||||
|
HP: 10000
|
||||||
|
Armor:
|
||||||
|
Type: Light
|
||||||
|
Mobile:
|
||||||
|
Locomotor: wheeled
|
||||||
|
Speed: 155
|
||||||
|
RevealsShroud:
|
||||||
|
Range: 10c0
|
||||||
|
|
||||||
|
# --- round 5: air ---
|
||||||
|
|
||||||
|
compressor:
|
||||||
|
Inherits: ^AirUnit
|
||||||
|
Voiced:
|
||||||
|
VoiceSet: StreamVoice
|
||||||
|
Buildable:
|
||||||
|
Queue: Aircraft
|
||||||
|
BuildPaletteOrder: 11
|
||||||
|
Prerequisites: droneport
|
||||||
|
Valued:
|
||||||
|
Cost: 700
|
||||||
|
Tooltip:
|
||||||
|
Name: actor-compressor.name
|
||||||
|
Health:
|
||||||
|
HP: 16000
|
||||||
|
Armor:
|
||||||
|
Type: Light
|
||||||
|
Aircraft:
|
||||||
|
Speed: 170
|
||||||
|
Armament:
|
||||||
|
Weapon: compress_field
|
||||||
|
PauseOnCondition: !ammo
|
||||||
|
AttackAircraft:
|
||||||
|
AttackType: Hover
|
||||||
|
FacingTolerance: 90
|
||||||
|
AmmoPool:
|
||||||
|
Ammo: 10
|
||||||
|
ReloadDelay: 20
|
||||||
|
AmmoCondition: ammo
|
||||||
|
|
||||||
|
droneport:
|
||||||
|
Inherits: ^EconBuilding
|
||||||
|
Inherits@shape: ^Buildable2x2
|
||||||
|
Buildable:
|
||||||
|
Queue: Building
|
||||||
|
BuildPaletteOrder: 56
|
||||||
|
Prerequisites: printfarm
|
||||||
|
Valued:
|
||||||
|
Cost: 800
|
||||||
|
Tooltip:
|
||||||
|
Name: actor-droneport.name
|
||||||
|
Health:
|
||||||
|
HP: 60000
|
||||||
|
Production:
|
||||||
|
Produces: Aircraft
|
||||||
|
Exit@1:
|
||||||
|
SpawnOffset: 0,-256,0
|
||||||
|
ExitCell: 0,0
|
||||||
|
Reservable:
|
||||||
|
Power:
|
||||||
|
Amount: -20
|
||||||
|
|||||||
BIN
mods/vinylgod/sequences/assets/boombike.png
Normal file
|
After Width: | Height: | Size: 8.6 KiB |
BIN
mods/vinylgod/sequences/assets/compressor.png
Normal file
|
After Width: | Height: | Size: 17 KiB |
BIN
mods/vinylgod/sequences/assets/crawler.png
Normal file
|
After Width: | Height: | Size: 14 KiB |
BIN
mods/vinylgod/sequences/assets/curator.png
Normal file
|
After Width: | Height: | Size: 1.6 KiB |
BIN
mods/vinylgod/sequences/assets/droneport.png
Normal file
|
After Width: | Height: | Size: 6.0 KiB |
BIN
mods/vinylgod/sequences/assets/flyer45.png
Normal file
|
After Width: | Height: | Size: 14 KiB |
BIN
mods/vinylgod/sequences/assets/icon_curator.png
Normal file
|
After Width: | Height: | Size: 4.3 KiB |
BIN
mods/vinylgod/sequences/assets/icon_droneport.png
Normal file
|
After Width: | Height: | Size: 4.7 KiB |
BIN
mods/vinylgod/sequences/assets/icon_launchramp.png
Normal file
|
After Width: | Height: | Size: 4.1 KiB |
BIN
mods/vinylgod/sequences/assets/icon_selector.png
Normal file
|
After Width: | Height: | Size: 3.4 KiB |
BIN
mods/vinylgod/sequences/assets/launchramp.png
Normal file
|
After Width: | Height: | Size: 8.0 KiB |
BIN
mods/vinylgod/sequences/assets/selector.png
Normal file
|
After Width: | Height: | Size: 1.3 KiB |
BIN
mods/vinylgod/sequences/assets/waxseed.png
Normal file
|
After Width: | Height: | Size: 2.0 KiB |
@ -213,3 +213,59 @@ smoke_m:
|
|||||||
Filename: sequences/assets/smoke.png
|
Filename: sequences/assets/smoke.png
|
||||||
Start: 6
|
Start: 6
|
||||||
Length: 2
|
Length: 2
|
||||||
|
|
||||||
|
selector:
|
||||||
|
idle:
|
||||||
|
Filename: sequences/assets/selector.png
|
||||||
|
icon:
|
||||||
|
Filename: sequences/assets/icon_selector.png
|
||||||
|
|
||||||
|
curator:
|
||||||
|
idle:
|
||||||
|
Filename: sequences/assets/curator.png
|
||||||
|
icon:
|
||||||
|
Filename: sequences/assets/icon_curator.png
|
||||||
|
|
||||||
|
launchramp:
|
||||||
|
idle:
|
||||||
|
Filename: sequences/assets/launchramp.png
|
||||||
|
icon:
|
||||||
|
Filename: sequences/assets/icon_launchramp.png
|
||||||
|
|
||||||
|
droneport:
|
||||||
|
idle:
|
||||||
|
Filename: sequences/assets/droneport.png
|
||||||
|
icon:
|
||||||
|
Filename: sequences/assets/icon_droneport.png
|
||||||
|
|
||||||
|
boombike:
|
||||||
|
idle:
|
||||||
|
Filename: sequences/assets/boombike.png
|
||||||
|
Facings: 16
|
||||||
|
icon:
|
||||||
|
Filename: sequences/assets/icon_boombike.png
|
||||||
|
|
||||||
|
crawler:
|
||||||
|
idle:
|
||||||
|
Filename: sequences/assets/crawler.png
|
||||||
|
Facings: 16
|
||||||
|
icon:
|
||||||
|
Filename: sequences/assets/icon_crawler.png
|
||||||
|
|
||||||
|
flyer45:
|
||||||
|
idle:
|
||||||
|
Filename: sequences/assets/flyer45.png
|
||||||
|
Facings: 16
|
||||||
|
icon:
|
||||||
|
Filename: sequences/assets/icon_flyer45.png
|
||||||
|
|
||||||
|
compressor:
|
||||||
|
idle:
|
||||||
|
Filename: sequences/assets/compressor.png
|
||||||
|
Facings: 16
|
||||||
|
icon:
|
||||||
|
Filename: sequences/assets/icon_compressor.png
|
||||||
|
|
||||||
|
waxseed:
|
||||||
|
idle:
|
||||||
|
Filename: sequences/assets/waxseed.png
|
||||||
|
|||||||
@ -153,3 +153,104 @@ theshuffle_impact:
|
|||||||
Explosions: bigboom
|
Explosions: bigboom
|
||||||
ImpactSounds: audio/sfx_boom.wav
|
ImpactSounds: audio/sfx_boom.wav
|
||||||
ValidTargets: Ground, GroundActor
|
ValidTargets: Ground, GroundActor
|
||||||
|
|
||||||
|
# --- round 5: heroes, scouts, air ---
|
||||||
|
|
||||||
|
dubplate:
|
||||||
|
Inherits: ^GroundWeapon
|
||||||
|
Report: audio/sfx_throw.wav
|
||||||
|
ReloadDelay: 90
|
||||||
|
Range: 5c512
|
||||||
|
Projectile: Bullet
|
||||||
|
Speed: 448
|
||||||
|
LaunchAngle: 40
|
||||||
|
Image: seven_inch_proj
|
||||||
|
Sequences: idle
|
||||||
|
Warhead@1Dam: SpreadDamage
|
||||||
|
Spread: 426
|
||||||
|
Damage: 9000
|
||||||
|
ValidTargets: GroundActor
|
||||||
|
Versus:
|
||||||
|
None: 100
|
||||||
|
Wood: 90
|
||||||
|
Light: 85
|
||||||
|
Heavy: 65
|
||||||
|
Warhead@2Eff: CreateEffect
|
||||||
|
Explosions: bigboom
|
||||||
|
ImpactSounds: audio/sfx_boom.wav
|
||||||
|
ValidTargets: Ground, GroundActor
|
||||||
|
|
||||||
|
curator_beam:
|
||||||
|
Inherits: ^GroundWeapon
|
||||||
|
Report: audio/sfx_zap.wav
|
||||||
|
ReloadDelay: 8
|
||||||
|
Range: 4c512
|
||||||
|
Warhead@1Dam: SpreadDamage
|
||||||
|
Spread: 42
|
||||||
|
Damage: 1100
|
||||||
|
ValidTargets: GroundActor
|
||||||
|
Versus:
|
||||||
|
None: 70
|
||||||
|
Wood: 80
|
||||||
|
Light: 110
|
||||||
|
Heavy: 120
|
||||||
|
Warhead@2Eff: CreateEffect
|
||||||
|
Explosions: pop
|
||||||
|
ValidTargets: Ground, GroundActor
|
||||||
|
|
||||||
|
bike_horn:
|
||||||
|
Inherits: ^GroundWeapon
|
||||||
|
Report: audio/sfx_bass.wav
|
||||||
|
ReloadDelay: 35
|
||||||
|
Range: 2c512
|
||||||
|
Warhead@1Dam: SpreadDamage
|
||||||
|
Spread: 128
|
||||||
|
Damage: 1400
|
||||||
|
ValidTargets: GroundActor
|
||||||
|
Versus:
|
||||||
|
None: 120
|
||||||
|
Wood: 30
|
||||||
|
Light: 40
|
||||||
|
Heavy: 10
|
||||||
|
Warhead@2Eff: CreateEffect
|
||||||
|
Explosions: pop
|
||||||
|
ImpactSounds: audio/sfx_pop.wav
|
||||||
|
ValidTargets: Ground, GroundActor
|
||||||
|
|
||||||
|
rotor_blade:
|
||||||
|
Inherits: ^GroundWeapon
|
||||||
|
Report: audio/sfx_throw.wav
|
||||||
|
ReloadDelay: 22
|
||||||
|
Range: 3c512
|
||||||
|
Warhead@1Dam: SpreadDamage
|
||||||
|
Spread: 96
|
||||||
|
Damage: 2600
|
||||||
|
ValidTargets: GroundActor
|
||||||
|
Versus:
|
||||||
|
None: 95
|
||||||
|
Wood: 60
|
||||||
|
Light: 90
|
||||||
|
Heavy: 55
|
||||||
|
Warhead@2Eff: CreateEffect
|
||||||
|
Explosions: pop
|
||||||
|
ImpactSounds: audio/sfx_pop.wav
|
||||||
|
ValidTargets: Ground, GroundActor
|
||||||
|
|
||||||
|
compress_field:
|
||||||
|
Inherits: ^GroundWeapon
|
||||||
|
Report: audio/sfx_zap.wav
|
||||||
|
ReloadDelay: 28
|
||||||
|
Range: 3c256
|
||||||
|
Warhead@1Dam: SpreadDamage
|
||||||
|
Spread: 213
|
||||||
|
Damage: 1900
|
||||||
|
ValidTargets: GroundActor
|
||||||
|
Versus:
|
||||||
|
None: 110
|
||||||
|
Wood: 70
|
||||||
|
Light: 80
|
||||||
|
Heavy: 45
|
||||||
|
Warhead@2Eff: CreateEffect
|
||||||
|
Explosions: pop
|
||||||
|
ImpactSounds: audio/sfx_pop.wav
|
||||||
|
ValidTargets: Ground, GroundActor
|
||||||
|
|||||||
@ -30,6 +30,11 @@ VEHICLES = [
|
|||||||
('streamvan', 26, STR + 'sleek white autonomous delivery van with blue play-button roof logo'),
|
('streamvan', 26, STR + 'sleek white autonomous delivery van with blue play-button roof logo'),
|
||||||
('scraper', 24, STR + 'white autonomous street sweeper vehicle with glowing blue front intake'),
|
('scraper', 24, STR + 'white autonomous street sweeper vehicle with glowing blue front intake'),
|
||||||
('drmwalker', 30, STR + 'white quad-legged mech with one blue ring light, seen from above'),
|
('drmwalker', 30, STR + 'white quad-legged mech with one blue ring light, seen from above'),
|
||||||
|
# round 5: scouts + aircraft
|
||||||
|
('boombike', 20, MRP + 'small fast motorbike trike with two loudspeaker cones mounted on the back'),
|
||||||
|
('crawler', 18, STR + 'small flat white six-wheeled scout rover with a blue sensor dome'),
|
||||||
|
('flyer45', 22, MRP + 'flying machine built from a black vinyl record with spinning tonearm rotor blades and a small rusty engine pod'),
|
||||||
|
('compressor', 22, STR + 'white quadcopter drone with four rotors and a glowing blue lens underneath'),
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
@ -47,7 +52,12 @@ def sheet16(im, size, out):
|
|||||||
print(f'[facings] {out}', flush=True)
|
print(f'[facings] {out}', flush=True)
|
||||||
|
|
||||||
|
|
||||||
|
only = [a for a in sys.argv[1:] if not a.startswith('-')]
|
||||||
|
skip_world = '--units-only' in sys.argv
|
||||||
|
|
||||||
for name, size, prompt in VEHICLES:
|
for name, size, prompt in VEHICLES:
|
||||||
|
if only and name not in only:
|
||||||
|
continue
|
||||||
raw = os.path.join(RENDERS, f'{name}_raw.png')
|
raw = os.path.join(RENDERS, f'{name}_raw.png')
|
||||||
cut = os.path.join(RENDERS, f'{name}.png')
|
cut = os.path.join(RENDERS, f'{name}.png')
|
||||||
if not os.path.exists(cut):
|
if not os.path.exists(cut):
|
||||||
@ -55,6 +65,10 @@ for name, size, prompt in VEHICLES:
|
|||||||
run('bg_remove_local', {}, cut, asset_id=upload(raw))
|
run('bg_remove_local', {}, cut, asset_id=upload(raw))
|
||||||
sheet16(Image.open(cut).convert('RGBA'), size, os.path.join(ASSETS, f'{name}.png'))
|
sheet16(Image.open(cut).convert('RGBA'), size, os.path.join(ASSETS, f'{name}.png'))
|
||||||
|
|
||||||
|
if skip_world or only:
|
||||||
|
print('ALL DONE (units only)')
|
||||||
|
sys.exit(0)
|
||||||
|
|
||||||
# terrain tile: seamless ground texture -> 32x32
|
# terrain tile: seamless ground texture -> 32x32
|
||||||
traw = os.path.join(RENDERS, 'terrain_raw.png')
|
traw = os.path.join(RENDERS, 'terrain_raw.png')
|
||||||
if not os.path.exists(traw):
|
if not os.path.exists(traw):
|
||||||
|
|||||||
@ -43,6 +43,11 @@ ACTORS = [
|
|||||||
('scraper', 22, STR + 'autonomous white street sweeper vehicle inhaling black vinyl through a glowing blue intake'),
|
('scraper', 22, STR + 'autonomous white street sweeper vehicle inhaling black vinyl through a glowing blue intake'),
|
||||||
('bufferbot', 14, STR + 'knee-high white sphere robot with a loading spinner face'),
|
('bufferbot', 14, STR + 'knee-high white sphere robot with a loading spinner face'),
|
||||||
('drmwalker', 28, STR + 'tall faceless white mech with one blue ring-light eye and a glowing paywall screen chest'),
|
('drmwalker', 28, STR + 'tall faceless white mech with one blue ring-light eye and a glowing paywall screen chest'),
|
||||||
|
# round 5: heroes + air bases
|
||||||
|
('selector', 22, MRP + 'legendary hero DJ robot in a long coat with a crate of glowing gold dubplates under one arm and a tonearm staff'),
|
||||||
|
('curator', 22, STR + 'hovering white sphere ringed with many camera lenses, a single blue eye at the front, faint halo'),
|
||||||
|
('launchramp', 64, MRP + 'scrap metal launch ramp pad with painted pink chevrons, floodlights and a parked flying vinyl disc'),
|
||||||
|
('droneport', 64, STR + 'white circular drone landing pad building with recessed blue guide lights and folded launch arms'),
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
68
tools/place_seeds.py
Normal file
@ -0,0 +1,68 @@
|
|||||||
|
#!/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}')
|
||||||