mirror of
https://github.com/prosolis/gogobee.git
synced 2026-07-15 08:32:41 +00:00
Combat engine §6: the rooms get the small change, the boss keeps the big slots
The first cut let a caster cast in auto-resolved rooms and capped nothing but upcasting. The sweep said that was half a fix. Room deaths fell for every caster — mage 131 -> 105, sorcerer 118 -> 105 — and fleeing collapsed, which is what §6 predicted. But elite and boss deaths exploded behind it: mage 7 -> 38 and 19 -> 61, sorcerer 14 -> 51 and 15 -> 65. They were winning the trash rooms and arriving at the thing that matters with an empty pool. Net, mage and sorcerer came out of §6 worse than they went in (-34 and -37 runs cleared). "Never upcast" is not a reserve. A mage's native-level spells ARE its boss kit, so casting them at native level in a goblin room still spends the dragon's slots. Only a level cap reserves anything. So an ordinary room may reach for a 2nd-level slot and no higher. Every caster still owns a real spell down there — a cleric's inflict_wounds, everyone else's scorching_ray — but fireball, spirit_guardians, flame_strike and every slot the turn engine would upcast into stay in the caster's pocket until there is something worth spending them on. Claude-Session: https://claude.ai/code/session_01B2MwktU4RgfWkar8HM3zZn
This commit is contained in:
@@ -66,9 +66,27 @@ func (p *AdventurePlugin) autoCastForAutoResolve(
|
||||
return true
|
||||
}
|
||||
|
||||
// roomSlotCap is the highest slot level an ordinary room may spend. Cantrips are
|
||||
// free and always available; anything above this is reserved for the elite and
|
||||
// the boss.
|
||||
//
|
||||
// The first cut of §6 had no cap — "never upcast" was supposed to be enough. It
|
||||
// was not, and the sweep said so: room deaths fell for every caster (mage 131 →
|
||||
// 105) while elite and boss deaths exploded (mage 7 → 38 and 19 → 61, sorcerer
|
||||
// 14 → 51 and 15 → 65). Casters were winning the trash rooms and arriving at the
|
||||
// thing that matters with an empty pool. Native-level is not a reserve, because
|
||||
// a mage's native-level spells ARE its boss kit; only a level cap is.
|
||||
//
|
||||
// 2 is where the two demands stop overlapping. Every caster owns a damage spell
|
||||
// at or below it (a cleric's guiding_bolt and inflict_wounds are both 1st), so
|
||||
// the rooms still get a real spell — but a fireball, a spirit_guardians, a
|
||||
// flame_strike, and every slot the turn engine would upcast into stays in the
|
||||
// caster's pocket until there is something worth spending it on.
|
||||
const roomSlotCap = 2
|
||||
|
||||
// pickAutoResolveSpell is the best damage spell this caster can actually cast
|
||||
// right now: known, prepared, on their list, and backed by a slot they still
|
||||
// hold.
|
||||
// right now: known, prepared, on their list, at or under the room slot cap, and
|
||||
// backed by a slot they still hold.
|
||||
//
|
||||
// It casts at the spell's NATIVE level and never upcasts. simPickSpell upcasts
|
||||
// aggressively — correct there, because it runs in the turn engine at an elite
|
||||
@@ -115,8 +133,12 @@ func pickAutoResolveSpell(uid id.UserID, c *DnDCharacter) (SpellDefinition, int,
|
||||
if !onList {
|
||||
continue
|
||||
}
|
||||
// A cantrip is free; a leveled spell needs a slot still in hand.
|
||||
// A cantrip is free; a leveled spell needs a slot still in hand, and the
|
||||
// room only gets to reach for the small ones.
|
||||
if sp.Level > 0 {
|
||||
if sp.Level > roomSlotCap {
|
||||
continue
|
||||
}
|
||||
if pair, ok := slots[sp.Level]; !ok || pair[0]-pair[1] <= 0 {
|
||||
continue
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user