From 9a4a93e72ee77a06bcff49d66498607c6e9e4792 Mon Sep 17 00:00:00 2001 From: prosolis <5590409+prosolis@users.noreply.github.com> Date: Fri, 15 May 2026 10:45:40 -0700 Subject: [PATCH] Phase 2c (roster gate): dilute single-boss elite pools MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Each zone's elite pool was a single SpawnWeight=1 over-tier boss, so InterruptElite bracket rolls auto-picked that boss 100% of the time. The post-2b tier-lethality trace named these one-shots (Warchief, Hag, Roper, Young Red Dragon) as the dominant remaining death source. Promotes one mid-tier alt per zone to IsElite (underforge gets two since fire_elemental was itself a non-elite killer). Boss SW=1 stays; alt SW 3-4 gives the boss ~17-25% elite-roll share. pickZoneEnemy also excludes IsElite from the standard pool, so promotion softens standard encounters by one mid-difficulty entry — each zone still has 3-4 standard entries left. Crypt-Valdris already dual-elite, untouched. Promotions: worg, owlbear, aboleth_thrall, vampire_spawn, salamander+fire_elemental, drow_elite_warrior, night_hag, dragonborn_cultist, hezrou. Phase 1 matrix delta (200 trials/cell, Fighter, centerline): goblin_warrens: 0% → 3.0% completion (first non-zero T1 reading) sunken_temple: 0% → 0.5% dragons_lair: death 100% → 60% (40% starve — different failure) underdark: death 100% → 90% (10% starve) feywild: death 100% → 92% (8% starve) T3 cells still 100% death — next pass is global supply/threat levers. Tier-lethality trace shows Drow Elite Warrior + Dragonborn Cultist spawning and being winnable, with arcs stretching to 7-10 encounters instead of fresh-entry one-shots. Co-Authored-By: Claude Opus 4.7 (1M context) --- gogobee_expedition_difficulty.md | 48 ++++++++++++++++++++++++++------ internal/plugin/dnd_zone.go | 20 ++++++------- 2 files changed, 50 insertions(+), 18 deletions(-) diff --git a/gogobee_expedition_difficulty.md b/gogobee_expedition_difficulty.md index 4747b59..469c066 100644 --- a/gogobee_expedition_difficulty.md +++ b/gogobee_expedition_difficulty.md @@ -156,15 +156,47 @@ target the cascade path that's now mostly resolved; they have no remaining death-fraction to convert. Phase 2c (roster dilution) is justified rather than premature. -### Phase 2c — roster gate (next) +### Phase 2c — roster gate (shipped) -Promote softer mid-tier monsters to `IsElite: true` in zones whose -elite pool is a single tier-disproportionate boss (warchief / hag / -roper / dragon are all SpawnWeight=1 alone in their elite pool, so -an InterruptElite bracket roll = 100% pick of the over-tier boss). -Diluting the elite pool with one or two softer alternates at higher -SpawnWeight lets the fighter sometimes face a winnable elite, -without removing the over-tier boss as a possible spawn. +Promoted one mid-tier alt to `IsElite: true` in every zone whose elite +pool was a single SpawnWeight=1 boss (`internal/plugin/dnd_zone.go`). +The boss stays in the pool; weighted dilution means the InterruptElite +bracket no longer auto-picks the over-tier boss. `pickZoneEnemy` also +excludes the promoted entry from the standard pool, lowering standard +encounter difficulty by removing one mid-difficulty option from +non-elite brackets (acceptable: each zone still has 3-4 standard +entries left). Crypt-Valdris was already dual-elite (wight + flameskull) +and was left alone. + +| zone | promoted alt | boss (untouched) | +|--------------------|-----------------------|--------------------| +| goblin_warrens | worg (SW=3) | hobgoblin_warchief | +| forest_shadows | owlbear (SW=4) | green_hag | +| sunken_temple | aboleth_thrall (SW=3) | water_elemental | +| manor_blackspire | vampire_spawn (SW=3) | revenant | +| underforge | salamander (SW=3) + fire_elemental (SW=3) | helmed_horror | +| underdark | drow_elite_warrior (SW=4) | roper | +| feywild_crossing | night_hag (SW=3) | fomorian | +| dragons_lair | dragonborn_cultist (SW=3) | young_red_dragon | +| abyss_portal | hezrou (SW=4) | marilith | + +**Phase 1 matrix delta (200 trials/cell, Fighter, tier centerline):** +goblin_warrens 0% → **3.0%** completion (first non-zero T1 reading +since Phase 0); sunken_temple 0% → 0.5%; dragons_lair death% **100% → +60%** with 40% now starve (fighter survives the elite-spawn path long +enough to run out of supplies — different failure mode); underdark +death% 100% → 90% (10% starve); feywild_crossing 100% → 92% death +(8% starve). T3 manor_blackspire / underforge still 100% death — the +remaining death pressure there is the post-2b chained-standard path, +not the elite roll. + +Tier-lethality trace cross-check (`Phase2_TierLethality`) shows the +new alt-elites actually spawning and being winnable: underdark trial +1 now opens with `Drow Elite Warrior` (won), reaches the Roper at +turn 6, retreats, then dies on a Hook Horror nick — a substantively +longer arc than the pre-2c fresh-entry Roper one-shot. Dragons_lair +trials similarly show `Dragonborn Cultist` as a winnable elite stop +before the dragon roll lands. Stat-block tuning of the bosses themselves is off-limits per the Phase 3 constraint (bestiary is shared across systems). diff --git a/internal/plugin/dnd_zone.go b/internal/plugin/dnd_zone.go index 31a4cc3..0902ed4 100644 --- a/internal/plugin/dnd_zone.go +++ b/internal/plugin/dnd_zone.go @@ -220,7 +220,7 @@ func zoneGoblinWarrens() ZoneDefinition { {BestiaryID: "goblin_sneak", SpawnWeight: 7}, {BestiaryID: "goblin_archer", SpawnWeight: 6}, {BestiaryID: "hobgoblin_grunt", SpawnWeight: 5}, - {BestiaryID: "worg", SpawnWeight: 3}, + {BestiaryID: "worg", SpawnWeight: 3, IsElite: true}, {BestiaryID: "goblin_shaman", SpawnWeight: 2}, {BestiaryID: "hobgoblin_warchief", SpawnWeight: 1, IsElite: true}, }, @@ -310,7 +310,7 @@ func zoneForestShadows() ZoneDefinition { Enemies: []ZoneEnemy{ {BestiaryID: "dire_wolf", SpawnWeight: 6}, {BestiaryID: "bandit_captain", SpawnWeight: 4}, - {BestiaryID: "owlbear", SpawnWeight: 4}, + {BestiaryID: "owlbear", SpawnWeight: 4, IsElite: true}, {BestiaryID: "dryad_corrupted", SpawnWeight: 3}, {BestiaryID: "displacer_beast", SpawnWeight: 3}, {BestiaryID: "green_hag", SpawnWeight: 1, IsElite: true}, @@ -356,7 +356,7 @@ func zoneSunkenTemple() ZoneDefinition { {BestiaryID: "kuo_toa", SpawnWeight: 7}, {BestiaryID: "kuo_toa_whip", SpawnWeight: 4}, {BestiaryID: "merrow", SpawnWeight: 4}, - {BestiaryID: "aboleth_thrall", SpawnWeight: 3}, + {BestiaryID: "aboleth_thrall", SpawnWeight: 3, IsElite: true}, {BestiaryID: "water_elemental", SpawnWeight: 1, IsElite: true}, }, Boss: ZoneBoss{ @@ -403,7 +403,7 @@ func zoneManorBlackspire() ZoneDefinition { {BestiaryID: "poltergeist", SpawnWeight: 5}, {BestiaryID: "banshee", SpawnWeight: 3}, {BestiaryID: "wraith", SpawnWeight: 3}, - {BestiaryID: "vampire_spawn", SpawnWeight: 3}, + {BestiaryID: "vampire_spawn", SpawnWeight: 3, IsElite: true}, {BestiaryID: "revenant", SpawnWeight: 1, IsElite: true}, }, Boss: ZoneBoss{ @@ -449,8 +449,8 @@ func zoneUnderforge() ZoneDefinition { {BestiaryID: "magmin", SpawnWeight: 6}, {BestiaryID: "azer", SpawnWeight: 5}, {BestiaryID: "flameskull", SpawnWeight: 4}, - {BestiaryID: "salamander", SpawnWeight: 3}, - {BestiaryID: "fire_elemental", SpawnWeight: 3}, + {BestiaryID: "salamander", SpawnWeight: 3, IsElite: true}, + {BestiaryID: "fire_elemental", SpawnWeight: 3, IsElite: true}, {BestiaryID: "helmed_horror", SpawnWeight: 1, IsElite: true}, }, Boss: ZoneBoss{ @@ -495,7 +495,7 @@ func zoneUnderdark() ZoneDefinition { MaxRooms: 10, Enemies: []ZoneEnemy{ {BestiaryID: "drow", SpawnWeight: 7}, - {BestiaryID: "drow_elite_warrior", SpawnWeight: 4}, + {BestiaryID: "drow_elite_warrior", SpawnWeight: 4, IsElite: true}, {BestiaryID: "drow_mage", SpawnWeight: 3}, {BestiaryID: "mind_flayer", SpawnWeight: 2}, {BestiaryID: "hook_horror", SpawnWeight: 4}, @@ -545,7 +545,7 @@ func zoneFeywildCrossing() ZoneDefinition { {BestiaryID: "will_o_wisp", SpawnWeight: 5}, {BestiaryID: "quickling", SpawnWeight: 5}, {BestiaryID: "green_hag", SpawnWeight: 4}, - {BestiaryID: "night_hag", SpawnWeight: 3}, + {BestiaryID: "night_hag", SpawnWeight: 3, IsElite: true}, {BestiaryID: "fomorian", SpawnWeight: 1, IsElite: true}, }, Boss: ZoneBoss{ @@ -590,7 +590,7 @@ func zoneDragonsLair() ZoneDefinition { {BestiaryID: "kobold", SpawnWeight: 7}, {BestiaryID: "guard_drake", SpawnWeight: 5}, {BestiaryID: "kobold_scale_sorcerer", SpawnWeight: 4}, - {BestiaryID: "dragonborn_cultist", SpawnWeight: 3}, + {BestiaryID: "dragonborn_cultist", SpawnWeight: 3, IsElite: true}, {BestiaryID: "young_red_dragon", SpawnWeight: 1, IsElite: true}, }, Boss: ZoneBoss{ @@ -637,7 +637,7 @@ func zoneAbyssPortal() ZoneDefinition { Enemies: []ZoneEnemy{ {BestiaryID: "quasit", SpawnWeight: 6}, {BestiaryID: "vrock", SpawnWeight: 5}, - {BestiaryID: "hezrou", SpawnWeight: 4}, + {BestiaryID: "hezrou", SpawnWeight: 4, IsElite: true}, {BestiaryID: "nalfeshnee", SpawnWeight: 2}, {BestiaryID: "marilith", SpawnWeight: 1, IsElite: true}, },