Phase 7: boss fights with area attacks, guardians reviewed, End boss

Adrian (2026-11-02): every zone guardian gets area attacks (harder in
harder zones); a boss for the Basalt Furnace; a Pokémon replaces the
Ender Dragon; dying or leaving the arena loses; the Deep Dark gets a
legendary and every guardian should fit its zone. Groudon, Giratina and
Meloetta have no model in Cobblemon 1.8.4: Moltres, Eternatus and
Regigigas stand in.

- Guardians: Mudsdale, Flygon, Abomasnow, Regigigas (normal size), new
  Moltres for the Basalt Furnace; zone_spawns.py takes a guardian
  "scale".
- tools/zone_bosses.py writes bosses/<zone>.json and end.json from a
  tier table (circle, line, cone, rings; telegraph, damage, triggers,
  fire/ice/poison effects, arena).
- boss/: BossFights runs patterns during a guardian or End boss battle
  (particle telegraphs, hits players inside, stops on battle end),
  enforces the arena and death as a loss (battle ends, boss heals);
  EndBoss keeps the dragon out (allowlist emptied), spawns Eternatus on
  the main island with the dragon's boss bar, and on defeat opens the
  exit portal, gateway and egg via the vanilla dragon fight, plus XP.
- Self-tests: coverage (incl. Cobblemon models), shapes, landing and
  stopping, arena loss, End boss. Docs, balance, Phase 7 checklist.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
claudeandClaude Opus 5.5 committed 2026-11-02 16:22:10 +01:00
1 parent dc4568e023
commit cd232bdf6a
32 files changed
+1420 -24

No files matched your search

@@ -0,0 +1,69 @@
{
"_comment": "Generated by tools/zone_bosses.py; do not edit by hand. See docs/design.md (Phase 7) for the format.",
"guardian": "basalt",
"arena": 32,
"patterns": [
{
"shape": "circle",
"radius": 3.5,
"aim": "player",
"telegraph_ticks": 30,
"damage": 12,
"effect": "fire",
"trigger": {
"every_ticks": 112,
"offset": 40
}
},
{
"shape": "line",
"length": 14,
"width": 2,
"aim": "player",
"telegraph_ticks": 30,
"damage": 12,
"effect": "fire",
"trigger": {
"every_ticks": 160,
"offset": 100
}
},
{
"shape": "cone",
"length": 10,
"angle": 70,
"aim": "player",
"telegraph_ticks": 30,
"damage": 12,
"effect": "fire",
"trigger": {
"every_ticks": 200,
"offset": 160
}
},
{
"shape": "ring",
"inner": 3,
"outer": 9,
"aim": "boss",
"telegraph_ticks": 30,
"damage": 12,
"effect": "fire",
"trigger": {
"below_health": 0.5
}
},
{
"shape": "ring",
"inner": 2,
"outer": 12,
"aim": "boss",
"telegraph_ticks": 30,
"damage": 12,
"effect": "fire",
"trigger": {
"below_health": 0.25
}
}
]
}
@@ -0,0 +1,19 @@
{
"_comment": "Generated by tools/zone_bosses.py; do not edit by hand. See docs/design.md (Phase 7) for the format.",
"guardian": "button_isle",
"arena": 24,
"patterns": [
{
"shape": "circle",
"radius": 2.5,
"aim": "player",
"telegraph_ticks": 50,
"damage": 2,
"effect": "none",
"trigger": {
"every_ticks": 160,
"offset": 40
}
}
]
}
@@ -0,0 +1,57 @@
{
"_comment": "Generated by tools/zone_bosses.py; do not edit by hand. See docs/design.md (Phase 7) for the format.",
"guardian": "deep_dark",
"arena": 24,
"patterns": [
{
"shape": "circle",
"radius": 3.25,
"aim": "player",
"telegraph_ticks": 35,
"damage": 11,
"effect": "none",
"trigger": {
"every_ticks": 124,
"offset": 40
}
},
{
"shape": "line",
"length": 14,
"width": 2,
"aim": "player",
"telegraph_ticks": 35,
"damage": 11,
"effect": "none",
"trigger": {
"every_ticks": 175,
"offset": 100
}
},
{
"shape": "cone",
"length": 10,
"angle": 70,
"aim": "player",
"telegraph_ticks": 35,
"damage": 11,
"effect": "none",
"trigger": {
"every_ticks": 215,
"offset": 160
}
},
{
"shape": "ring",
"inner": 3,
"outer": 9,
"aim": "boss",
"telegraph_ticks": 35,
"damage": 11,
"effect": "none",
"trigger": {
"below_health": 0.5
}
}
]
}
@@ -0,0 +1,57 @@
{
"_comment": "Generated by tools/zone_bosses.py; do not edit by hand. See docs/design.md (Phase 7) for the format.",
"guardian": "deep_sea",
"arena": 24,
"patterns": [
{
"shape": "circle",
"radius": 3.25,
"aim": "player",
"telegraph_ticks": 35,
"damage": 9,
"effect": "none",
"trigger": {
"every_ticks": 124,
"offset": 40
}
},
{
"shape": "line",
"length": 14,
"width": 2,
"aim": "player",
"telegraph_ticks": 35,
"damage": 9,
"effect": "none",
"trigger": {
"every_ticks": 175,
"offset": 100
}
},
{
"shape": "cone",
"length": 10,
"angle": 70,
"aim": "player",
"telegraph_ticks": 35,
"damage": 9,
"effect": "none",
"trigger": {
"every_ticks": 215,
"offset": 160
}
},
{
"shape": "ring",
"inner": 3,
"outer": 9,
"aim": "boss",
"telegraph_ticks": 35,
"damage": 9,
"effect": "none",
"trigger": {
"below_health": 0.5
}
}
]
}
@@ -0,0 +1,76 @@
{
"_comment": "Generated by tools/zone_bosses.py; do not edit by hand. See docs/design.md (Phase 7) for the format.",
"end": {
"species": "eternatus",
"level": 80,
"scale": 0.2,
"respawn_hours": 5,
"xp_first_win": 12000,
"xp": 500
},
"arena": 40,
"patterns": [
{
"shape": "circle",
"radius": 3.5,
"aim": "player",
"telegraph_ticks": 30,
"damage": 13,
"effect": "poison",
"trigger": {
"every_ticks": 112,
"offset": 40
}
},
{
"shape": "line",
"length": 14,
"width": 2,
"aim": "player",
"telegraph_ticks": 30,
"damage": 13,
"effect": "poison",
"trigger": {
"every_ticks": 160,
"offset": 100
}
},
{
"shape": "cone",
"length": 10,
"angle": 70,
"aim": "player",
"telegraph_ticks": 30,
"damage": 13,
"effect": "poison",
"trigger": {
"every_ticks": 200,
"offset": 160
}
},
{
"shape": "ring",
"inner": 3,
"outer": 9,
"aim": "boss",
"telegraph_ticks": 30,
"damage": 13,
"effect": "poison",
"trigger": {
"below_health": 0.5
}
},
{
"shape": "ring",
"inner": 2,
"outer": 12,
"aim": "boss",
"telegraph_ticks": 30,
"damage": 13,
"effect": "poison",
"trigger": {
"below_health": 0.25
}
}
]
}
@@ -0,0 +1,57 @@
{
"_comment": "Generated by tools/zone_bosses.py; do not edit by hand. See docs/design.md (Phase 7) for the format.",
"guardian": "frostpeak",
"arena": 24,
"patterns": [
{
"shape": "circle",
"radius": 3.25,
"aim": "player",
"telegraph_ticks": 35,
"damage": 10,
"effect": "ice",
"trigger": {
"every_ticks": 124,
"offset": 40
}
},
{
"shape": "line",
"length": 14,
"width": 2,
"aim": "player",
"telegraph_ticks": 35,
"damage": 10,
"effect": "ice",
"trigger": {
"every_ticks": 175,
"offset": 100
}
},
{
"shape": "cone",
"length": 10,
"angle": 70,
"aim": "player",
"telegraph_ticks": 35,
"damage": 10,
"effect": "ice",
"trigger": {
"every_ticks": 215,
"offset": 160
}
},
{
"shape": "ring",
"inner": 3,
"outer": 9,
"aim": "boss",
"telegraph_ticks": 35,
"damage": 10,
"effect": "ice",
"trigger": {
"below_health": 0.5
}
}
]
}
@@ -0,0 +1,45 @@
{
"_comment": "Generated by tools/zone_bosses.py; do not edit by hand. See docs/design.md (Phase 7) for the format.",
"guardian": "highlands",
"arena": 24,
"patterns": [
{
"shape": "circle",
"radius": 3.0,
"aim": "player",
"telegraph_ticks": 40,
"damage": 7,
"effect": "none",
"trigger": {
"every_ticks": 136,
"offset": 40
}
},
{
"shape": "line",
"length": 14,
"width": 2,
"aim": "player",
"telegraph_ticks": 40,
"damage": 7,
"effect": "none",
"trigger": {
"every_ticks": 190,
"offset": 100
}
},
{
"shape": "cone",
"length": 10,
"angle": 70,
"aim": "player",
"telegraph_ticks": 40,
"damage": 7,
"effect": "none",
"trigger": {
"every_ticks": 230,
"offset": 160
}
}
]
}
@@ -0,0 +1,32 @@
{
"_comment": "Generated by tools/zone_bosses.py; do not edit by hand. See docs/design.md (Phase 7) for the format.",
"guardian": "jungle",
"arena": 24,
"patterns": [
{
"shape": "circle",
"radius": 2.75,
"aim": "player",
"telegraph_ticks": 45,
"damage": 6,
"effect": "none",
"trigger": {
"every_ticks": 148,
"offset": 40
}
},
{
"shape": "line",
"length": 14,
"width": 2,
"aim": "player",
"telegraph_ticks": 45,
"damage": 6,
"effect": "none",
"trigger": {
"every_ticks": 205,
"offset": 100
}
}
]
}
@@ -0,0 +1,45 @@
{
"_comment": "Generated by tools/zone_bosses.py; do not edit by hand. See docs/design.md (Phase 7) for the format.",
"guardian": "mire",
"arena": 24,
"patterns": [
{
"shape": "circle",
"radius": 3.0,
"aim": "player",
"telegraph_ticks": 40,
"damage": 7,
"effect": "none",
"trigger": {
"every_ticks": 136,
"offset": 40
}
},
{
"shape": "line",
"length": 14,
"width": 2,
"aim": "player",
"telegraph_ticks": 40,
"damage": 7,
"effect": "none",
"trigger": {
"every_ticks": 190,
"offset": 100
}
},
{
"shape": "cone",
"length": 10,
"angle": 70,
"aim": "player",
"telegraph_ticks": 40,
"damage": 7,
"effect": "none",
"trigger": {
"every_ticks": 230,
"offset": 160
}
}
]
}
@@ -0,0 +1,32 @@
{
"_comment": "Generated by tools/zone_bosses.py; do not edit by hand. See docs/design.md (Phase 7) for the format.",
"guardian": "southwold",
"arena": 24,
"patterns": [
{
"shape": "circle",
"radius": 2.75,
"aim": "player",
"telegraph_ticks": 45,
"damage": 4,
"effect": "none",
"trigger": {
"every_ticks": 148,
"offset": 40
}
},
{
"shape": "line",
"length": 14,
"width": 2,
"aim": "player",
"telegraph_ticks": 45,
"damage": 4,
"effect": "none",
"trigger": {
"every_ticks": 205,
"offset": 100
}
}
]
}
@@ -0,0 +1,45 @@
{
"_comment": "Generated by tools/zone_bosses.py; do not edit by hand. See docs/design.md (Phase 7) for the format.",
"guardian": "sunscorch",
"arena": 24,
"patterns": [
{
"shape": "circle",
"radius": 3.0,
"aim": "player",
"telegraph_ticks": 40,
"damage": 8,
"effect": "none",
"trigger": {
"every_ticks": 136,
"offset": 40
}
},
{
"shape": "line",
"length": 14,
"width": 2,
"aim": "player",
"telegraph_ticks": 40,
"damage": 8,
"effect": "none",
"trigger": {
"every_ticks": 190,
"offset": 100
}
},
{
"shape": "cone",
"length": 10,
"angle": 70,
"aim": "player",
"telegraph_ticks": 40,
"damage": 8,
"effect": "none",
"trigger": {
"every_ticks": 230,
"offset": 160
}
}
]
}
@@ -0,0 +1,32 @@
{
"_comment": "Generated by tools/zone_bosses.py; do not edit by hand. See docs/design.md (Phase 7) for the format.",
"guardian": "westmarch",
"arena": 24,
"patterns": [
{
"shape": "circle",
"radius": 2.75,
"aim": "player",
"telegraph_ticks": 45,
"damage": 5,
"effect": "none",
"trigger": {
"every_ticks": 148,
"offset": 40
}
},
{
"shape": "line",
"length": 14,
"width": 2,
"aim": "player",
"telegraph_ticks": 45,
"damage": 5,
"effect": "none",
"trigger": {
"every_ticks": 205,
"offset": 100
}
}
]
}