Spaces:
Running
econ-harvester-defense-raid: per-scenario chokepoint map
Browse filesReplaces the generic rush-hour-arena base_map with a tailored
96x40 chokepoint-arena that funnels every raider through ONE
4-cell corridor at y=18..21. The water wall at x=46..54 splits
the map into a WEST lobe (agent base + harv + OFF-AXIS ore patch)
and an EAST lobe (raider spawn + persistent far-east enemy fact).
The single corridor mouth at (~44..46, 18..21) becomes the
canonical defensive position the model must read from the map
geometry. The off-axis patch keeps the harv commute strictly
inside the west lobe so the harv never touches the corridor,
which de-couples 'read the raid vector' from 'follow the harv'
and makes set_stance + position-the-escort-on-the-corridor-mouth
the load-bearing capability.
Hard tier keeps its two seed-driven AGENT spawn_point groups
(NORTH y=8 / SOUTH y=32) so the BASE moves but the corridor
mouth defensive position stays invariant.
Validation (scripted policies via openra_bench.eval_core.run_level):
stall (only observe) โ LOSS every tier, seeds 1..2:
easy seed=1 loss / easy seed=2 loss
medium seed=1 loss / medium seed=2 loss
hard seed=1 loss / hard seed=2 loss
In every case the harv is killed (units_lost=1), confirming
the corridor + raider geometry still produces a real harv-death
LOSS rather than a draw.
Map spec (deterministic, content-addressed):
generator: chokepoint-arena, name: econ-harvester-defense-raid-arena
width: 96, height: 40, cordon: 2
pinch_x: 50, pinch_width: 8, corridor_width: 4, corridor_y: 20
|
Binary file (876 Bytes). View file
|
|
|
|
@@ -11,14 +11,39 @@
|
|
| 11 |
# The load-bearing verb is `set_stance(escort, 2 or 3)` + escort
|
| 12 |
# movement onto the harv's lane.
|
| 13 |
#
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 14 |
# DESIGN
|
| 15 |
# ------
|
| 16 |
# Agent has fact + powr + proc + 1ร harv + ONE NEAR ore patch (mine
|
| 17 |
-
#
|
| 18 |
-
# world.rs::auto_route_idle_harvesters โ a scenario-placed
|
| 19 |
-
# auto-routes once its owner owns a refinery), so the harv
|
| 20 |
-
# proc
|
| 21 |
-
#
|
| 22 |
#
|
| 23 |
# Threat: enemy `bot_type: raider` (openra-sim/src/scripted_bot.rs:
|
| 24 |
# ScriptedBehavior::Raider) โ its tick() picks the agent's harv
|
|
@@ -26,55 +51,59 @@
|
|
| 26 |
# one every 12 ticks (the raider interval). New units added to the
|
| 27 |
# raider's roster (via scheduled_events::spawn_actors) are picked up
|
| 28 |
# on the next own_mobile() scan, so SCHEDULED raid waves all chase
|
| 29 |
-
# the harv.
|
|
|
|
|
|
|
| 30 |
#
|
| 31 |
# Wave schedule (scheduled_events: spawn_actors):
|
| 32 |
-
# easy: 1 wave โ 1ร 2tnk at tick 600 from (
|
| 33 |
-
# medium: 2 waves โ 1ร 2tnk at tick 600, 1ร 2tnk at tick 1500 โ both at (
|
| 34 |
-
# hard: 3 waves on
|
| 35 |
#
|
| 36 |
# Escort: 2ร 2tnk at base, stance:0 (HoldFire). The escort SITS at
|
| 37 |
# the proc; even when a raider walks into its weapon range the
|
| 38 |
# stance:0 units do not fire (verified per CLAUDE.md stance fix:
|
| 39 |
# stance:0 never auto-engages, even when shot at, even when an enemy
|
| 40 |
# is sitting on top of them). The agent must EITHER:
|
| 41 |
-
# (a) `set_stance(escort, 3)`
|
| 42 |
-
#
|
| 43 |
-
#
|
| 44 |
-
#
|
| 45 |
-
#
|
| 46 |
-
#
|
| 47 |
-
#
|
|
|
|
| 48 |
# (c) `attack_unit(escort, raider_id)` โ explicit order overrides
|
| 49 |
# stance:0, escort closes and kills the raider.
|
| 50 |
# Any of (a), (b), (c) clears the bar. The capability is "flip the
|
| 51 |
-
# escort from passive to active
|
|
|
|
| 52 |
#
|
| 53 |
# THE NO-CHEAT BAR (every lazy / stall / wrong-shape policy LOSES on
|
| 54 |
# every level and every hard seed; the intended capability WINS):
|
| 55 |
#
|
| 56 |
# โข stall (only observe): escort stays stance:0 at base, never
|
| 57 |
-
# engages. Raider wave 1
|
| 58 |
-
#
|
| 59 |
-
#
|
| 60 |
#
|
| 61 |
# โข defensive-but-passive (place / re-issue HoldFire on escort,
|
| 62 |
# observe): identical outcome โ the escort is structurally
|
| 63 |
# incapable of engaging. Harv dies โ LOSS.
|
| 64 |
#
|
| 65 |
-
# โข
|
| 66 |
-
#
|
| 67 |
-
#
|
| 68 |
-
#
|
| 69 |
-
#
|
| 70 |
-
#
|
| 71 |
-
# wave finds the harv unprotected because the escort overshot.)
|
| 72 |
#
|
| 73 |
# โข intended (set_stance(escort, 2 or 3) and/or attack_move escort
|
| 74 |
-
# onto the
|
| 75 |
-
#
|
| 76 |
-
#
|
| 77 |
-
#
|
|
|
|
| 78 |
#
|
| 79 |
# ENGINE FACTS (CLAUDE.md):
|
| 80 |
# - Tick budget ~90/turn. easy max_turns=35 โ ceiling 93+90ยท34=3153;
|
|
@@ -97,21 +126,24 @@
|
|
| 97 |
# intended path; the load-bearing verb is the stance flip OR
|
| 98 |
# an explicit attack order (which overrides stance per the
|
| 99 |
# CLAUDE.md stance fix).
|
| 100 |
-
# - Persistent far enemy `fact` at (
|
| 101 |
-
# CLAUDE.md (engine auto-`done`s on enemy-elim
|
| 102 |
-
# evaluates; the inert far marker keeps the
|
| 103 |
-
# the raider being destroyed).
|
|
|
|
|
|
|
|
|
|
| 104 |
# - `unit_type_count_gte: {harv, 1}` in fail_condition is the
|
| 105 |
# hard harv-survival predicate โ the moment the harv dies the
|
| 106 |
# fail clause fires and the LOSS is immediate.
|
| 107 |
-
# - hard tier uses TWO seed-driven
|
| 108 |
-
#
|
| 109 |
-
#
|
| 110 |
-
#
|
| 111 |
-
#
|
| 112 |
-
#
|
| 113 |
-
#
|
| 114 |
-
# spawn-groups hard-tier requirement (CLAUDE.md ยง7).
|
| 115 |
#
|
| 116 |
# Validate (no model / no network):
|
| 117 |
# python3 -m openra_bench.scenarios.validate \
|
|
@@ -131,25 +163,35 @@ meta:
|
|
| 131 |
decision is to FLIP the escort from passive to active โ set its
|
| 132 |
stance to defend / attack-anything, or order it onto the
|
| 133 |
harvester's lane to intercept โ so the raider dies on the
|
| 134 |
-
escort's fire envelope before reaching the harvester.
|
| 135 |
-
|
| 136 |
-
|
|
|
|
|
|
|
|
|
|
| 137 |
robotics_analogue: >
|
| 138 |
Mining-fleet protection under recurring asset-targeted attack โ
|
| 139 |
an autonomous extraction site with an extractor robot, a
|
| 140 |
processing depot, and a static defense detail. If the defense
|
| 141 |
detail is in safe-mode (hold fire) the recurring attacker
|
| 142 |
destroys the extractor on the first cycle; the operator must
|
| 143 |
-
flip the detail to engage and
|
| 144 |
-
the
|
| 145 |
benchmark_anchor:
|
| 146 |
- "SC2 harvester harass defense (Lambo, Reaper drops on workers)"
|
| 147 |
- "convoy / extractor protection under recurring harass"
|
| 148 |
- "RTS stance management โ flip escort from passive to active"
|
| 149 |
- "SOC active-vs-passive monitoring posture"
|
|
|
|
| 150 |
author: openra-bench
|
| 151 |
|
| 152 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 153 |
starting_cash: 0 # ALL income via harv survival; bar measures live throughput.
|
| 154 |
|
| 155 |
base:
|
|
@@ -175,73 +217,91 @@ base:
|
|
| 175 |
|
| 176 |
levels:
|
| 177 |
# โโ EASY โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
|
| 178 |
-
# Bare skill: ONE raid wave (1ร 2tnk) at tick 600
|
| 179 |
-
# proc(
|
| 180 |
-
#
|
| 181 |
-
#
|
| 182 |
-
#
|
| 183 |
-
#
|
| 184 |
-
#
|
|
|
|
|
|
|
| 185 |
# max_turns 35 โ ceiling 93+90ยท34=3153 > 3001 โ.
|
| 186 |
easy:
|
| 187 |
description: >
|
| 188 |
-
You own a Construction Yard, Power Plant, Refinery
|
| 189 |
-
Truck on auto-harvest to
|
| 190 |
-
|
| 191 |
-
|
| 192 |
-
|
| 193 |
-
|
| 194 |
-
|
| 195 |
-
|
| 196 |
-
|
| 197 |
-
|
| 198 |
-
|
| 199 |
-
|
|
|
|
|
|
|
|
|
|
| 200 |
starting_cash: 0
|
| 201 |
overrides:
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 202 |
actors:
|
| 203 |
-
# Agent base โ fact + powr seed the construction
|
| 204 |
-
# proc seeds the harv auto-harvest loop.
|
| 205 |
-
- {type: fact, owner: agent, position: [
|
| 206 |
-
- {type: powr, owner: agent, position: [
|
| 207 |
-
- {type: proc, owner: agent, position: [
|
| 208 |
# Single harv โ pre-placed adjacent to proc. With proc on the
|
| 209 |
# field, world.rs::auto_route_idle_harvesters installs a
|
| 210 |
# Harvest activity on the next tick; harv cycles proc<->mine.
|
| 211 |
-
- {type: harv, owner: agent, position: [
|
| 212 |
# Escort: 2ร 2tnk at the proc on stance:0 (HoldFire). The
|
| 213 |
-
# capability under test is "flip the escort active
|
| 214 |
-
#
|
| 215 |
-
#
|
| 216 |
-
|
| 217 |
-
-
|
| 218 |
-
|
| 219 |
-
- {type:
|
| 220 |
-
#
|
| 221 |
-
#
|
| 222 |
-
#
|
| 223 |
-
#
|
| 224 |
-
- {type:
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 225 |
scheduled_events:
|
| 226 |
-
# Single raid wave at tick 600 โ one 2tnk spawned
|
| 227 |
-
#
|
| 228 |
-
#
|
| 229 |
-
# toward the harv via harv_foes().
|
| 230 |
- tick: 600
|
| 231 |
type: spawn_actors
|
| 232 |
actors:
|
| 233 |
-
- {type: 2tnk, owner: enemy, position: [
|
| 234 |
win_condition:
|
| 235 |
# Ordered `then:` enforces "harv must SURVIVE past the raid
|
| 236 |
# window and THEN keep refining to the bar" โ clause 1
|
| 237 |
# (after_ticks: 1700) latches only past wave 1's typical
|
| 238 |
-
# kill-window
|
| 239 |
-
#
|
| 240 |
-
#
|
| 241 |
-
#
|
| 242 |
-
#
|
| 243 |
-
#
|
| 244 |
-
# well after tick 1700, all_of latches โ WIN.
|
| 245 |
all_of:
|
| 246 |
- then:
|
| 247 |
id: econ-harvester-defense-raid-easy
|
|
@@ -260,52 +320,64 @@ levels:
|
|
| 260 |
|
| 261 |
# โโ MEDIUM โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
|
| 262 |
# +1 controlled variable: TWO raid waves (tick 600, tick 1500) and
|
| 263 |
-
# a tighter bar (cash >=
|
| 264 |
-
# first raider" play has to ALSO
|
| 265 |
-
# escort must be RETURNED to
|
| 266 |
-
# AttackAnything stance:3) so the late
|
|
|
|
| 267 |
# max_turns 45 โ ceiling 4053 > 3901 โ.
|
| 268 |
medium:
|
| 269 |
description: >
|
| 270 |
-
Same setup as easy โ fact + powr + proc + 1ร harv on
|
| 271 |
-
|
| 272 |
-
|
| 273 |
-
|
| 274 |
-
|
| 275 |
-
|
| 276 |
-
|
| 277 |
-
|
| 278 |
-
|
| 279 |
-
|
|
|
|
|
|
|
| 280 |
starting_cash: 0
|
| 281 |
overrides:
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 282 |
actors:
|
| 283 |
-
- {type: fact, owner: agent, position: [
|
| 284 |
-
- {type: powr, owner: agent, position: [
|
| 285 |
-
- {type: proc, owner: agent, position: [
|
| 286 |
-
- {type: harv, owner: agent, position: [
|
| 287 |
-
- {type: 2tnk, owner: agent, position: [
|
| 288 |
-
- {type: 2tnk, owner: agent, position: [
|
| 289 |
-
- {type: mine, owner: neutral, position: [
|
| 290 |
-
- {type: fact, owner: enemy, position: [
|
| 291 |
scheduled_events:
|
| 292 |
- tick: 600
|
| 293 |
type: spawn_actors
|
| 294 |
actors:
|
| 295 |
-
- {type: 2tnk, owner: enemy, position: [
|
| 296 |
- tick: 1500
|
| 297 |
type: spawn_actors
|
| 298 |
actors:
|
| 299 |
-
- {type: 2tnk, owner: enemy, position: [
|
| 300 |
win_condition:
|
| 301 |
-
# `then:` forces cash bar to be reached AFTER tick 2700 โ
|
| 302 |
-
#
|
| 303 |
-
#
|
| 304 |
-
#
|
| 305 |
-
# past
|
| 306 |
-
# finish it; the harv dies before clause 1 latches โ fail
|
| 307 |
-
# clause unit_type_count_gte:{harv,1} fires โ LOSS
|
| 308 |
-
# though enough cash may have accumulated by ~tick 2200.
|
| 309 |
all_of:
|
| 310 |
- then:
|
| 311 |
id: econ-harvester-defense-raid-medium
|
|
@@ -324,103 +396,122 @@ levels:
|
|
| 324 |
|
| 325 |
# โโ HARD โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
|
| 326 |
# +1 axis vs medium: TWO seed-driven AGENT spawn_point groups โ
|
| 327 |
-
# base latitude NORTH y=
|
| 328 |
# Each group has its own fact/powr/proc/harv/escort/mine on its
|
| 329 |
-
# own y-band
|
| 330 |
-
#
|
| 331 |
-
#
|
|
|
|
|
|
|
|
|
|
| 332 |
#
|
| 333 |
# Hard tier โฅ2-spawn-groups requirement (CLAUDE.md ยง7): satisfied
|
| 334 |
# via two AGENT spawn_point groups (spawn_point: 0 / 1) โ every
|
| 335 |
# agent actor is duplicated across both groups; the active group
|
| 336 |
# is round-robined by seed.
|
| 337 |
#
|
| 338 |
-
# Three raid waves (ticks 600, 1500, 2400) spawn
|
| 339 |
-
#
|
| 340 |
-
#
|
| 341 |
-
#
|
| 342 |
-
#
|
| 343 |
-
#
|
| 344 |
-
#
|
| 345 |
-
#
|
| 346 |
-
#
|
| 347 |
-
#
|
| 348 |
-
#
|
| 349 |
# max_turns 50 โ ceiling 4503 > 4301 โ.
|
| 350 |
hard:
|
| 351 |
description: >
|
| 352 |
-
Tougher version
|
| 353 |
-
|
| 354 |
-
|
| 355 |
-
|
| 356 |
-
|
| 357 |
-
|
| 358 |
-
|
| 359 |
-
|
| 360 |
-
|
| 361 |
-
|
| 362 |
-
|
| 363 |
-
|
| 364 |
-
|
|
|
|
|
|
|
| 365 |
starting_cash: 0
|
| 366 |
overrides:
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 367 |
actors:
|
| 368 |
-
# spawn_point 0 โ NORTH base (y=
|
| 369 |
# must be duplicated across both spawn_point groups (the
|
| 370 |
# filter drops any group-untagged actor on either side).
|
| 371 |
-
- {type: fact, owner: agent, position: [
|
| 372 |
-
- {type: powr, owner: agent, position: [8,
|
| 373 |
-
- {type: proc, owner: agent, position: [
|
| 374 |
-
- {type: harv, owner: agent, position: [
|
| 375 |
# Escort placed on open ground east of the proc so attack_move
|
| 376 |
-
# has a clear east lane
|
| 377 |
-
|
| 378 |
-
- {type: 2tnk, owner: agent, position: [
|
| 379 |
-
|
| 380 |
-
|
| 381 |
-
- {type:
|
| 382 |
-
- {type:
|
| 383 |
-
- {type:
|
| 384 |
-
- {type:
|
| 385 |
-
- {type: 2tnk, owner: agent, position: [
|
| 386 |
-
|
| 387 |
-
#
|
| 388 |
-
#
|
| 389 |
-
#
|
| 390 |
-
#
|
| 391 |
-
# reach, which on each seed
|
| 392 |
-
|
| 393 |
-
- {type: mine, owner: neutral, position: [
|
| 394 |
-
|
| 395 |
-
|
|
|
|
| 396 |
scheduled_events:
|
| 397 |
-
# Three raid waves spawn on
|
| 398 |
-
#
|
| 399 |
-
#
|
| 400 |
-
#
|
| 401 |
-
#
|
| 402 |
-
#
|
| 403 |
-
#
|
| 404 |
-
#
|
|
|
|
|
|
|
|
|
|
| 405 |
- tick: 600
|
| 406 |
type: spawn_actors
|
| 407 |
actors:
|
| 408 |
-
- {type: 2tnk, owner: enemy, position: [
|
| 409 |
- tick: 1500
|
| 410 |
type: spawn_actors
|
| 411 |
actors:
|
| 412 |
-
- {type: 2tnk, owner: enemy, position: [
|
| 413 |
- tick: 2400
|
| 414 |
type: spawn_actors
|
| 415 |
actors:
|
| 416 |
-
- {type: 2tnk, owner: enemy, position: [
|
| 417 |
win_condition:
|
| 418 |
# `then:` forces cash bar AFTER tick 3500 โ past wave 3
|
| 419 |
-
# (spawns tick 2400, reaches harv ~tick
|
| 420 |
-
# undefended harv by ~tick
|
| 421 |
# all lose their harv before tick 3500 โ unit_type_count_gte
|
| 422 |
-
# fail clause fires โ LOSS. Intended (escort on
|
| 423 |
-
#
|
| 424 |
# uninterrupted through all three waves and accumulates
|
| 425 |
# cash past tick 3500.
|
| 426 |
all_of:
|
|
|
|
| 11 |
# The load-bearing verb is `set_stance(escort, 2 or 3)` + escort
|
| 12 |
# movement onto the harv's lane.
|
| 13 |
#
|
| 14 |
+
# MAP โ econ-harvester-defense-raid-arena (96ร40 chokepoint-arena)
|
| 15 |
+
# ----------------------------------------------------------------
|
| 16 |
+
# Per-scenario map (replaces the generic rush-hour-arena). A single
|
| 17 |
+
# vertical water wall at x=46..54 with one open corridor at y=18..21
|
| 18 |
+
# splits the playable area into a WEST lobe (the agent's base + the
|
| 19 |
+
# harv + the off-axis ore patch) and an EAST lobe (the raider spawn
|
| 20 |
+
# axis + the persistent far-east enemy fact). The corridor at
|
| 21 |
+
# y=18..21 is the ONE lane any raid wave must use to cross from the
|
| 22 |
+
# east into the west lobe โ there is no other route around the wall.
|
| 23 |
+
#
|
| 24 |
+
# The ore patch sits OFF-AXIS from the agent base (easy/medium: base
|
| 25 |
+
# at y=10..14, patch at y=28; hard NORTH: base at y=8, patch at
|
| 26 |
+
# y=12; hard SOUTH: base at y=32, patch at y=28). Off-axis means the
|
| 27 |
+
# harv commutes between proc and mine on a y-band that is NOT the
|
| 28 |
+
# raid corridor's y-band โ so the agent can read the raid vector
|
| 29 |
+
# (the single corridor mouth at the west wall, xโ44..46, y=18..21)
|
| 30 |
+
# INDEPENDENTLY of where its own harv currently is, and plant the
|
| 31 |
+
# defense on that one lane.
|
| 32 |
+
#
|
| 33 |
+
# This is what the scenario MEASURES: reading the raid vector from
|
| 34 |
+
# the map geometry (one corridor, one mouth) and positioning the
|
| 35 |
+
# escort there โ not spamming defense everywhere or following the
|
| 36 |
+
# harv around. set_stance + escort movement onto the corridor mouth
|
| 37 |
+
# is the load-bearing capability the chokepoint exposes.
|
| 38 |
+
#
|
| 39 |
# DESIGN
|
| 40 |
# ------
|
| 41 |
# Agent has fact + powr + proc + 1ร harv + ONE NEAR ore patch (mine
|
| 42 |
+
# OFF-AXIS from the base). The proc seeds the harv's auto-harvest
|
| 43 |
+
# loop (per world.rs::auto_route_idle_harvesters โ a scenario-placed
|
| 44 |
+
# idle harv auto-routes once its owner owns a refinery), so the harv
|
| 45 |
+
# cycles proc โ mine WITHOUT an explicit harvest order. Income is
|
| 46 |
+
# steady AS LONG AS THE HARV LIVES.
|
| 47 |
#
|
| 48 |
# Threat: enemy `bot_type: raider` (openra-sim/src/scripted_bot.rs:
|
| 49 |
# ScriptedBehavior::Raider) โ its tick() picks the agent's harv
|
|
|
|
| 51 |
# one every 12 ticks (the raider interval). New units added to the
|
| 52 |
# raider's roster (via scheduled_events::spawn_actors) are picked up
|
| 53 |
# on the next own_mobile() scan, so SCHEDULED raid waves all chase
|
| 54 |
+
# the harv. Because the wall blocks every other eastโwest route,
|
| 55 |
+
# each spawned raider MUST enter the west lobe through the single
|
| 56 |
+
# corridor at (~50, 18..21).
|
| 57 |
#
|
| 58 |
# Wave schedule (scheduled_events: spawn_actors):
|
| 59 |
+
# easy: 1 wave โ 1ร 2tnk at tick 600 from (75,20)
|
| 60 |
+
# medium: 2 waves โ 1ร 2tnk at tick 600, 1ร 2tnk at tick 1500 โ both at (75,20)
|
| 61 |
+
# hard: 3 waves on the central east corridor โ see hard tier comment
|
| 62 |
#
|
| 63 |
# Escort: 2ร 2tnk at base, stance:0 (HoldFire). The escort SITS at
|
| 64 |
# the proc; even when a raider walks into its weapon range the
|
| 65 |
# stance:0 units do not fire (verified per CLAUDE.md stance fix:
|
| 66 |
# stance:0 never auto-engages, even when shot at, even when an enemy
|
| 67 |
# is sitting on top of them). The agent must EITHER:
|
| 68 |
+
# (a) `set_stance(escort, 3)` and move them onto the corridor
|
| 69 |
+
# mouth โ Hunt: idle escort actively advances on visible
|
| 70 |
+
# enemies (raider walks into LOS as it exits the corridor,
|
| 71 |
+
# escort engages); OR
|
| 72 |
+
# (b) `set_stance(escort, 2)` AND `attack_move(escort, corridor
|
| 73 |
+
# mouth)` โ Defend stance auto-fires on whatever enters weapon
|
| 74 |
+
# range, so move the escort EAST onto the west mouth of the
|
| 75 |
+
# corridor (xโ44..46, y=18..21) to INTERCEPT the raid wave; OR
|
| 76 |
# (c) `attack_unit(escort, raider_id)` โ explicit order overrides
|
| 77 |
# stance:0, escort closes and kills the raider.
|
| 78 |
# Any of (a), (b), (c) clears the bar. The capability is "flip the
|
| 79 |
+
# escort from passive to active AND plant it on the corridor mouth"
|
| 80 |
+
# โ same verb as combat-tanya-vs-rush plus a positioning read.
|
| 81 |
#
|
| 82 |
# THE NO-CHEAT BAR (every lazy / stall / wrong-shape policy LOSES on
|
| 83 |
# every level and every hard seed; the intended capability WINS):
|
| 84 |
#
|
| 85 |
# โข stall (only observe): escort stays stance:0 at base, never
|
| 86 |
+
# engages. Raider wave 1 traverses the corridor, detours to the
|
| 87 |
+
# active harv latitude and kills it. unit_type_count_gte:
|
| 88 |
+
# {harv,1} fails โ fail_condition fires โ LOSS.
|
| 89 |
#
|
| 90 |
# โข defensive-but-passive (place / re-issue HoldFire on escort,
|
| 91 |
# observe): identical outcome โ the escort is structurally
|
| 92 |
# incapable of engaging. Harv dies โ LOSS.
|
| 93 |
#
|
| 94 |
+
# โข spam-defense-everywhere (escort split across the base
|
| 95 |
+
# perimeter, neither piece on the corridor mouth): the raider
|
| 96 |
+
# walks straight through the corridor on the same lane every
|
| 97 |
+
# wave; whichever escort piece is on the wrong band never
|
| 98 |
+
# contributes. On medium/hard the second/third wave finishes
|
| 99 |
+
# the harv โ LOSS.
|
|
|
|
| 100 |
#
|
| 101 |
# โข intended (set_stance(escort, 2 or 3) and/or attack_move escort
|
| 102 |
+
# onto the corridor mouth ~x=44..46, y=18..21): the wall geometry
|
| 103 |
+
# forces every raider through the escort's fire envelope on its
|
| 104 |
+
# approach, escort kills each raid wave before contact with the
|
| 105 |
+
# harv, harv survives, auto-route loop continues, cash bar
|
| 106 |
+
# clears โ WIN.
|
| 107 |
#
|
| 108 |
# ENGINE FACTS (CLAUDE.md):
|
| 109 |
# - Tick budget ~90/turn. easy max_turns=35 โ ceiling 93+90ยท34=3153;
|
|
|
|
| 126 |
# intended path; the load-bearing verb is the stance flip OR
|
| 127 |
# an explicit attack order (which overrides stance per the
|
| 128 |
# CLAUDE.md stance fix).
|
| 129 |
+
# - Persistent far enemy `fact` at (90,20) in the EAST lobe โ
|
| 130 |
+
# anti-DRAW per CLAUDE.md (engine auto-`done`s on enemy-elim
|
| 131 |
+
# before win/fail evaluates; the inert far marker keeps the
|
| 132 |
+
# episode alive past the raider being destroyed). The wall
|
| 133 |
+
# prevents agent units from reaching it without crossing the
|
| 134 |
+
# corridor, so an intended-defense play does not incidentally
|
| 135 |
+
# destroy the marker.
|
| 136 |
# - `unit_type_count_gte: {harv, 1}` in fail_condition is the
|
| 137 |
# hard harv-survival predicate โ the moment the harv dies the
|
| 138 |
# fail clause fires and the LOSS is immediate.
|
| 139 |
+
# - hard tier uses TWO seed-driven AGENT spawn_point groups (base
|
| 140 |
+
# latitude NORTH y=8 vs SOUTH y=32). Each group has its own
|
| 141 |
+
# fact/powr/proc/harv/escort + mine on its own y-band. The
|
| 142 |
+
# load-bearing decision is the same (flip + position escort on
|
| 143 |
+
# the corridor mouth) but the LATITUDE of the base varies per
|
| 144 |
+
# seed, so a memorised opening from the wrong latitude leaves
|
| 145 |
+
# the harv unprotected. This satisfies the โฅ2-distinct-seed-
|
| 146 |
+
# driven-spawn-groups hard-tier requirement (CLAUDE.md ยง7).
|
| 147 |
#
|
| 148 |
# Validate (no model / no network):
|
| 149 |
# python3 -m openra_bench.scenarios.validate \
|
|
|
|
| 163 |
decision is to FLIP the escort from passive to active โ set its
|
| 164 |
stance to defend / attack-anything, or order it onto the
|
| 165 |
harvester's lane to intercept โ so the raider dies on the
|
| 166 |
+
escort's fire envelope before reaching the harvester. The map
|
| 167 |
+
geometry funnels every raider through a single corridor mouth,
|
| 168 |
+
so the right place to plant the escort is unambiguous if the
|
| 169 |
+
agent reads the map. Stalling, leaving the escort on hold-fire,
|
| 170 |
+
or spreading defense everywhere instead of on the corridor mouth
|
| 171 |
+
all let the harvester die.
|
| 172 |
robotics_analogue: >
|
| 173 |
Mining-fleet protection under recurring asset-targeted attack โ
|
| 174 |
an autonomous extraction site with an extractor robot, a
|
| 175 |
processing depot, and a static defense detail. If the defense
|
| 176 |
detail is in safe-mode (hold fire) the recurring attacker
|
| 177 |
destroys the extractor on the first cycle; the operator must
|
| 178 |
+
flip the detail to engage and reposition it onto the single
|
| 179 |
+
access route the attacker must use.
|
| 180 |
benchmark_anchor:
|
| 181 |
- "SC2 harvester harass defense (Lambo, Reaper drops on workers)"
|
| 182 |
- "convoy / extractor protection under recurring harass"
|
| 183 |
- "RTS stance management โ flip escort from passive to active"
|
| 184 |
- "SOC active-vs-passive monitoring posture"
|
| 185 |
+
- "chokepoint defense โ plant the line on the one route"
|
| 186 |
author: openra-bench
|
| 187 |
|
| 188 |
+
# Per-scenario map: chokepoint-arena 96ร40 with a vertical water wall
|
| 189 |
+
# at x=46..54 broken by a single 4-cell corridor at y=18..21. The
|
| 190 |
+
# corridor is the ONE lane any raider must use to cross from the east
|
| 191 |
+
# raid-spawn lobe into the west base/patch lobe. Top-level base_map
|
| 192 |
+
# is the readable slug; each level's overrides: re-declares the full
|
| 193 |
+
# generator spec so materialize() builds the .oramap deterministically.
|
| 194 |
+
base_map: econ-harvester-defense-raid-arena
|
| 195 |
starting_cash: 0 # ALL income via harv survival; bar measures live throughput.
|
| 196 |
|
| 197 |
base:
|
|
|
|
| 217 |
|
| 218 |
levels:
|
| 219 |
# โโ EASY โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
|
| 220 |
+
# Bare skill: ONE raid wave (1ร 2tnk) at tick 600 from (75,20) in
|
| 221 |
+
# the EAST lobe. Harv cycles proc(10,12)โmine(30,28) on auto-route
|
| 222 |
+
# entirely inside the WEST lobe. Escort: 2ร 2tnk at base stance:0.
|
| 223 |
+
# Stall / passive: raider crosses the corridor (only route), detours
|
| 224 |
+
# south to the harv on its commute and kills it โ LOSS. Intended:
|
| 225 |
+
# set_stance(escort, 2 or 3) and/or attack_move escort east to the
|
| 226 |
+
# west corridor mouth (~x=44..46, y=18..21); escort engages every
|
| 227 |
+
# raider on exit from the corridor, harv survives, cash accumulates.
|
| 228 |
+
# Bar: cash >= 1200 before tick 3000.
|
| 229 |
# max_turns 35 โ ceiling 93+90ยท34=3153 > 3001 โ.
|
| 230 |
easy:
|
| 231 |
description: >
|
| 232 |
+
You own a Construction Yard, Power Plant, Refinery (NW corner,
|
| 233 |
+
around y=10..12), ONE Ore Truck on auto-harvest to an
|
| 234 |
+
OFF-AXIS ore patch SOUTH of base at (30,28), and TWO medium
|
| 235 |
+
tanks (2tnk) parked at your refinery on HOLD-FIRE stance.
|
| 236 |
+
A vertical water wall at x=46..54 splits the map; the ONLY
|
| 237 |
+
crossing is a 4-cell corridor at y=18..21. At tick 600 an
|
| 238 |
+
enemy raider tank spawns at (75,20) in the eastern lobe and
|
| 239 |
+
drives at your harvester โ it MUST come through the corridor
|
| 240 |
+
to reach you. Win when cash >= 1200 AND your harvester is
|
| 241 |
+
still alive AND your refinery is intact, before tick 3000.
|
| 242 |
+
Standing the escort idle (HOLD-FIRE) at base lets the raider
|
| 243 |
+
walk through and kill the harvester. The intended play is to
|
| 244 |
+
FLIP the escort's stance to Defend (2) or AttackAnything (3)
|
| 245 |
+
AND move it onto the west corridor mouth (around x=44..46,
|
| 246 |
+
y=18..21) so the raider dies on its way out of the corridor.
|
| 247 |
starting_cash: 0
|
| 248 |
overrides:
|
| 249 |
+
base_map:
|
| 250 |
+
generator: chokepoint-arena
|
| 251 |
+
name: econ-harvester-defense-raid-arena
|
| 252 |
+
width: 96
|
| 253 |
+
height: 40
|
| 254 |
+
cordon: 2
|
| 255 |
+
pinch_x: 50
|
| 256 |
+
pinch_width: 8
|
| 257 |
+
corridor_width: 4
|
| 258 |
+
corridor_y: 20
|
| 259 |
actors:
|
| 260 |
+
# Agent base โ NW corner; fact + powr seed the construction
|
| 261 |
+
# & power; proc seeds the harv auto-harvest loop.
|
| 262 |
+
- {type: fact, owner: agent, position: [8, 10]}
|
| 263 |
+
- {type: powr, owner: agent, position: [8, 8]}
|
| 264 |
+
- {type: proc, owner: agent, position: [10, 12]}
|
| 265 |
# Single harv โ pre-placed adjacent to proc. With proc on the
|
| 266 |
# field, world.rs::auto_route_idle_harvesters installs a
|
| 267 |
# Harvest activity on the next tick; harv cycles proc<->mine.
|
| 268 |
+
- {type: harv, owner: agent, position: [12, 12]}
|
| 269 |
# Escort: 2ร 2tnk at the proc on stance:0 (HoldFire). The
|
| 270 |
+
# capability under test is "flip the escort active AND
|
| 271 |
+
# position it on the corridor mouth" โ stance:0 never auto-
|
| 272 |
+
# engages, and a "place defenders at base and observe"
|
| 273 |
+
# policy LOSES because the corridor is too far east for
|
| 274 |
+
# base-bound defenders to fire on.
|
| 275 |
+
- {type: 2tnk, owner: agent, position: [14, 12], stance: 0}
|
| 276 |
+
- {type: 2tnk, owner: agent, position: [14, 14], stance: 0}
|
| 277 |
+
# OFF-AXIS ore patch โ south of base; the harv's auto-route
|
| 278 |
+
# target. Diagonal commute proc(10,12)โmine(30,28) stays
|
| 279 |
+
# entirely in the WEST lobe (x<46), so the harv never
|
| 280 |
+
# touches the corridor.
|
| 281 |
+
- {type: mine, owner: neutral, position: [30, 28]}
|
| 282 |
+
# Persistent far enemy fact โ east lobe, anti-DRAW (engine
|
| 283 |
+
# auto-done mitigation). Behind the wall and reachable only
|
| 284 |
+
# via the corridor, so an intended defense play does not
|
| 285 |
+
# incidentally destroy the marker.
|
| 286 |
+
- {type: fact, owner: enemy, position: [90, 20]}
|
| 287 |
scheduled_events:
|
| 288 |
+
# Single raid wave at tick 600 โ one 2tnk spawned in the
|
| 289 |
+
# east lobe. The raider bot's harv_foes() picks the agent's
|
| 290 |
+
# harv; the wall forces the approach through the corridor.
|
|
|
|
| 291 |
- tick: 600
|
| 292 |
type: spawn_actors
|
| 293 |
actors:
|
| 294 |
+
- {type: 2tnk, owner: enemy, position: [75, 20]}
|
| 295 |
win_condition:
|
| 296 |
# Ordered `then:` enforces "harv must SURVIVE past the raid
|
| 297 |
# window and THEN keep refining to the bar" โ clause 1
|
| 298 |
# (after_ticks: 1700) latches only past wave 1's typical
|
| 299 |
+
# kill-window. A stall run loses its harv well before clause 1
|
| 300 |
+
# latches; the `unit_type_count_gte:{harv,1}` clause has
|
| 301 |
+
# already failed โ fail_condition fires first. The intended
|
| 302 |
+
# escort engagement at the corridor mouth kills each raider,
|
| 303 |
+
# harv keeps cycling, cash crosses 1200 well after tick 1700,
|
| 304 |
+
# all_of latches โ WIN.
|
|
|
|
| 305 |
all_of:
|
| 306 |
- then:
|
| 307 |
id: econ-harvester-defense-raid-easy
|
|
|
|
| 320 |
|
| 321 |
# โโ MEDIUM โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
|
| 322 |
# +1 controlled variable: TWO raid waves (tick 600, tick 1500) and
|
| 323 |
+
# a tighter bar (cash >= 2200 โ 5..6 refines). A one-time "kill the
|
| 324 |
+
# first raider" play has to ALSO hold the corridor against the
|
| 325 |
+
# second wave โ the escort must be RETURNED to (or kept on) the
|
| 326 |
+
# corridor mouth (or kept on AttackAnything stance:3) so the late
|
| 327 |
+
# wave dies on approach too.
|
| 328 |
# max_turns 45 โ ceiling 4053 > 3901 โ.
|
| 329 |
medium:
|
| 330 |
description: >
|
| 331 |
+
Same setup as easy โ fact + powr + proc + 1ร harv on
|
| 332 |
+
auto-harvest to the OFF-AXIS patch at (30,28), 2ร 2tnk escort
|
| 333 |
+
at the refinery on HOLD-FIRE, same chokepoint map โ but TWO
|
| 334 |
+
raider waves arrive: one at tick 600 and a second at tick 1500.
|
| 335 |
+
Both spawn at (75,20) in the eastern lobe and must cross the
|
| 336 |
+
single corridor (y=18..21) to reach your harvester. Win when
|
| 337 |
+
cash >= 2200 AND your harvester is alive AND your refinery is
|
| 338 |
+
intact, before tick 3900. Stalling, leaving the escort on
|
| 339 |
+
hold-fire, and chasing the first raider PAST the corridor far
|
| 340 |
+
enough to miss the second wave all LOSE. The intended play is
|
| 341 |
+
to flip the escort active (stance Defend or AttackAnything)
|
| 342 |
+
and HOLD the corridor mouth so BOTH waves die on approach.
|
| 343 |
starting_cash: 0
|
| 344 |
overrides:
|
| 345 |
+
base_map:
|
| 346 |
+
generator: chokepoint-arena
|
| 347 |
+
name: econ-harvester-defense-raid-arena
|
| 348 |
+
width: 96
|
| 349 |
+
height: 40
|
| 350 |
+
cordon: 2
|
| 351 |
+
pinch_x: 50
|
| 352 |
+
pinch_width: 8
|
| 353 |
+
corridor_width: 4
|
| 354 |
+
corridor_y: 20
|
| 355 |
actors:
|
| 356 |
+
- {type: fact, owner: agent, position: [8, 10]}
|
| 357 |
+
- {type: powr, owner: agent, position: [8, 8]}
|
| 358 |
+
- {type: proc, owner: agent, position: [10, 12]}
|
| 359 |
+
- {type: harv, owner: agent, position: [12, 12]}
|
| 360 |
+
- {type: 2tnk, owner: agent, position: [14, 12], stance: 0}
|
| 361 |
+
- {type: 2tnk, owner: agent, position: [14, 14], stance: 0}
|
| 362 |
+
- {type: mine, owner: neutral, position: [30, 28]}
|
| 363 |
+
- {type: fact, owner: enemy, position: [90, 20]}
|
| 364 |
scheduled_events:
|
| 365 |
- tick: 600
|
| 366 |
type: spawn_actors
|
| 367 |
actors:
|
| 368 |
+
- {type: 2tnk, owner: enemy, position: [75, 20]}
|
| 369 |
- tick: 1500
|
| 370 |
type: spawn_actors
|
| 371 |
actors:
|
| 372 |
+
- {type: 2tnk, owner: enemy, position: [75, 20]}
|
| 373 |
win_condition:
|
| 374 |
+
# `then:` forces cash bar to be reached AFTER tick 2700 โ past
|
| 375 |
+
# the second raid wave's kill-window (wave 2 spawns at tick
|
| 376 |
+
# 1500, reaches harv ~tick 2000, kills undefended harv by
|
| 377 |
+
# ~tick 2600). Aggressive-no-corridor-hold (drive escort
|
| 378 |
+
# east past the corridor) lets wave 1 chip the harv and wave
|
| 379 |
+
# 2 finish it; the harv dies before clause 1 latches โ fail
|
| 380 |
+
# clause unit_type_count_gte:{harv,1} fires โ LOSS.
|
|
|
|
| 381 |
all_of:
|
| 382 |
- then:
|
| 383 |
id: econ-harvester-defense-raid-medium
|
|
|
|
| 396 |
|
| 397 |
# โโ HARD โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
|
| 398 |
# +1 axis vs medium: TWO seed-driven AGENT spawn_point groups โ
|
| 399 |
+
# base latitude NORTH y=8 vs SOUTH y=32, round-robined per seed.
|
| 400 |
# Each group has its own fact/powr/proc/harv/escort/mine on its
|
| 401 |
+
# own y-band, ENTIRELY inside the west lobe (above the corridor
|
| 402 |
+
# for NORTH, below for SOUTH). The agent's load-bearing decision
|
| 403 |
+
# is the same (flip + position escort onto the corridor mouth)
|
| 404 |
+
# but the harv's latitude varies per seed, so a memorised opening
|
| 405 |
+
# that ignores the active base latitude leaves the harv exposed
|
| 406 |
+
# on the wrong y after the raider exits the corridor.
|
| 407 |
#
|
| 408 |
# Hard tier โฅ2-spawn-groups requirement (CLAUDE.md ยง7): satisfied
|
| 409 |
# via two AGENT spawn_point groups (spawn_point: 0 / 1) โ every
|
| 410 |
# agent actor is duplicated across both groups; the active group
|
| 411 |
# is round-robined by seed.
|
| 412 |
#
|
| 413 |
+
# Three raid waves (ticks 600, 1500, 2400) spawn on the central
|
| 414 |
+
# east axis at (75,20). Per the raider bot, each one targets the
|
| 415 |
+
# active harv; the wall forces every approach through the
|
| 416 |
+
# corridor (y=18..21), then the raider detours north or south to
|
| 417 |
+
# the active harv latitude (NORTH y=8 needs a ~10-cell detour
|
| 418 |
+
# north of the corridor; SOUTH y=32 needs a ~11-cell detour
|
| 419 |
+
# south). The corridor mouth (xโ44..46, y=18..21) is the SHARED
|
| 420 |
+
# defensive position for BOTH spawn groups, so the load-bearing
|
| 421 |
+
# capability โ read the corridor + plant escort there โ is
|
| 422 |
+
# invariant across seeds; only the escort's STARTING position
|
| 423 |
+
# changes (north base vs south base).
|
| 424 |
# max_turns 50 โ ceiling 4503 > 4301 โ.
|
| 425 |
hard:
|
| 426 |
description: >
|
| 427 |
+
Tougher version on the same chokepoint map: your base
|
| 428 |
+
latitude varies per seed โ NORTH base (y=8) OR SOUTH base
|
| 429 |
+
(y=32). Each base has its own fact, powr, proc, harvester on
|
| 430 |
+
auto-harvest to its OWN OFF-AXIS near patch (mine at (30,12)
|
| 431 |
+
for NORTH; mine at (30,28) for SOUTH), and 2ร 2tnk escort at
|
| 432 |
+
the refinery on HOLD-FIRE. THREE raider heavy tanks arrive
|
| 433 |
+
at ticks 600, 1500, and 2400 from the central east corridor
|
| 434 |
+
at (75,20); each one drives through the single corridor at
|
| 435 |
+
y=18..21 then detours to your harvester's latitude. Win when
|
| 436 |
+
cash >= 2800 AND your harvester is alive AND your refinery
|
| 437 |
+
is intact, before tick 4300. Stalling, leaving escort on
|
| 438 |
+
hold-fire, parking escort at base, and missing the corridor
|
| 439 |
+
mouth all LOSE. Flip the escort to Defend / AttackAnything
|
| 440 |
+
AND attack-move it onto the corridor mouth (around x=44..46,
|
| 441 |
+
y=18..21) so all three waves die on approach.
|
| 442 |
starting_cash: 0
|
| 443 |
overrides:
|
| 444 |
+
base_map:
|
| 445 |
+
generator: chokepoint-arena
|
| 446 |
+
name: econ-harvester-defense-raid-arena
|
| 447 |
+
width: 96
|
| 448 |
+
height: 40
|
| 449 |
+
cordon: 2
|
| 450 |
+
pinch_x: 50
|
| 451 |
+
pinch_width: 8
|
| 452 |
+
corridor_width: 4
|
| 453 |
+
corridor_y: 20
|
| 454 |
actors:
|
| 455 |
+
# spawn_point 0 โ NORTH base (y=8). CLAUDE.md: agent actors
|
| 456 |
# must be duplicated across both spawn_point groups (the
|
| 457 |
# filter drops any group-untagged actor on either side).
|
| 458 |
+
- {type: fact, owner: agent, position: [8, 8], spawn_point: 0}
|
| 459 |
+
- {type: powr, owner: agent, position: [8, 6], spawn_point: 0}
|
| 460 |
+
- {type: proc, owner: agent, position: [10, 8], spawn_point: 0}
|
| 461 |
+
- {type: harv, owner: agent, position: [12, 8], spawn_point: 0}
|
| 462 |
# Escort placed on open ground east of the proc so attack_move
|
| 463 |
+
# has a clear east lane to the corridor mouth.
|
| 464 |
+
- {type: 2tnk, owner: agent, position: [14, 7], stance: 0, spawn_point: 0}
|
| 465 |
+
- {type: 2tnk, owner: agent, position: [14, 9], stance: 0, spawn_point: 0}
|
| 466 |
+
# spawn_point 1 โ SOUTH base (y=32). Symmetric.
|
| 467 |
+
- {type: fact, owner: agent, position: [8, 32], spawn_point: 1}
|
| 468 |
+
- {type: powr, owner: agent, position: [8, 34], spawn_point: 1}
|
| 469 |
+
- {type: proc, owner: agent, position: [10, 32], spawn_point: 1}
|
| 470 |
+
- {type: harv, owner: agent, position: [12, 32], spawn_point: 1}
|
| 471 |
+
- {type: 2tnk, owner: agent, position: [14, 31], stance: 0, spawn_point: 1}
|
| 472 |
+
- {type: 2tnk, owner: agent, position: [14, 33], stance: 0, spawn_point: 1}
|
| 473 |
+
# Two ore patches โ one per latitude, BOTH entirely in the
|
| 474 |
+
# west lobe (x<46) and on their respective sides of the
|
| 475 |
+
# corridor. Mines are neutral, so the spawn_point filter
|
| 476 |
+
# (agent-side) does not affect them; both place every seed.
|
| 477 |
+
# The active harv only uses ITS OWN patch (auto-route picks
|
| 478 |
+
# the nearest ore the owner can reach, which on each seed
|
| 479 |
+
# is the on-latitude one).
|
| 480 |
+
- {type: mine, owner: neutral, position: [30, 12]}
|
| 481 |
+
- {type: mine, owner: neutral, position: [30, 28]}
|
| 482 |
+
# Persistent far enemy fact โ east lobe, anti-DRAW.
|
| 483 |
+
- {type: fact, owner: enemy, position: [90, 20]}
|
| 484 |
scheduled_events:
|
| 485 |
+
# Three raid waves spawn on the central east corridor axis
|
| 486 |
+
# at (75,20). Each raider is bot-controlled and must traverse
|
| 487 |
+
# the single corridor (y=18..21) โ the wall blocks every
|
| 488 |
+
# other eastโwest route โ then detour ~10-11 cells north or
|
| 489 |
+
# south to reach the on-latitude harv. The detour gives the
|
| 490 |
+
# escort time to intercept at the corridor mouth, but ONLY
|
| 491 |
+
# if the escort is actually parked there. A memorised
|
| 492 |
+
# "send escort east along base latitude" opening drops them
|
| 493 |
+
# at y=8 (NORTH) or y=32 (SOUTH), well off the corridor;
|
| 494 |
+
# the raider exits the corridor unopposed and reaches the
|
| 495 |
+
# harv unmolested.
|
| 496 |
- tick: 600
|
| 497 |
type: spawn_actors
|
| 498 |
actors:
|
| 499 |
+
- {type: 2tnk, owner: enemy, position: [75, 20]}
|
| 500 |
- tick: 1500
|
| 501 |
type: spawn_actors
|
| 502 |
actors:
|
| 503 |
+
- {type: 2tnk, owner: enemy, position: [75, 20]}
|
| 504 |
- tick: 2400
|
| 505 |
type: spawn_actors
|
| 506 |
actors:
|
| 507 |
+
- {type: 2tnk, owner: enemy, position: [75, 20]}
|
| 508 |
win_condition:
|
| 509 |
# `then:` forces cash bar AFTER tick 3500 โ past wave 3
|
| 510 |
+
# (spawns tick 2400, reaches harv ~tick 2900, kills
|
| 511 |
+
# undefended harv by ~tick 3400). Stall / passive / off-axis
|
| 512 |
# all lose their harv before tick 3500 โ unit_type_count_gte
|
| 513 |
+
# fail clause fires โ LOSS. Intended (escort planted on the
|
| 514 |
+
# corridor mouth) kills each wave on approach; harv cycles
|
| 515 |
# uninterrupted through all three waves and accumulates
|
| 516 |
# cash past tick 3500.
|
| 517 |
all_of:
|