adventure: T6 Phylactery Verses + stackable-rebirth engine primitive (P8)

The second Layer-2 postgame boss mechanic, and the first stateful in-combat one.
Valdris ("boss_valdris_ascendant", the Ossuary Ascendant) is bound to three
Verses hidden on the zone's secret nodes: every Verse the player finds and walks
before the fight unbinds one rebirth, every Verse they skip leaves it armed. A
full-clear explorer strips all three and fights a mortal lich; a speedrunner who
blows past the secrets fights a god who will not stay down.

New engine primitive: stackable rebirth. The stock survive_at_1 is a one-shot
1-HP stay; Valdris needs several rebirths that each restore a real pool.
combatState/CombatStatuses gain EnemyReviveCharges/EnemyReviveHP (round-tripped
through the turn engine so a suspend/resume keeps the live count), and enemyDown
consumes a charge after the survive_at_1 check, reviving to 25% of the
party-scaled max and emitting a phylactery_rebirth event. Zero for every
non-Valdris fight.

Unlike Greed Tax (a pure per-round recompute in applyBossRunModifiers), rebirths
are spent mid-fight, so the charge count is seeded ONCE at session creation
(seedBossRunStatuses, from unvisited secret Verses) and never re-derived on the
per-round enemy rebuild. Seeded from handleFightCmd after startPartyCombatSession.

Sim A/B (millenia, n=120 L20 party+Pete+pets, same binary, control neuters the
dispatch): mortal end (verses found) fighter 42.5% -- reproduces the deployed P7
ossuary baseline, confirming the mechanic doesn't touch the validated full-clear
path -- and the god end (0 verses) fighter 12.5%, a deadly-but-beatable flex arm.
The sim walks 0 verses (autopilot takes the first unlocked fork; Verses are
behind Perception locks), so the A/B brackets the whole player-agency gradient.

Claude-Session: https://claude.ai/code/session_0156WqjgsbmSY2U8eQ3Kkb1s
This commit is contained in:
prosolis
2026-07-16 08:04:19 -07:00
parent fc9e055083
commit 686434f8e3
7 changed files with 239 additions and 0 deletions

View File

@@ -428,6 +428,14 @@ type combatState struct {
enemyRegen int // regenerate: enemy heals this much each round end
enemySurviveArmed bool // survive_at_1: enemy cheats death once, dropping to 1 HP
// Phylactery Verses (T6 Valdris) — stackable rebirth. enemyReviveCharges is
// how many times the boss still cheats death; each revives it to
// enemyReviveHP. Seeded once at fight start from unfound Verses, round-tripped
// through CombatStatuses. Distinct from enemySurviveArmed (a one-shot 1-HP
// proc): a rebirth restores a meaningful pool, and there can be several.
enemyReviveCharges int
enemyReviveHP int
// Phase 13 bestiary slice 4 — the former flavor-only placeholders, now
// backed by real state.
enemySpellResist bool // spell_resist: player spell damage against this enemy is halved
@@ -1308,6 +1316,19 @@ func enemyDown(st *combatState, phaseName string) bool {
})
return false
}
// Phylactery Verses (T6 Valdris): a stackable rebirth. Each unfound Verse
// left one of these charges, and each restores a real pool rather than the
// 1-HP stay above — a full-clear explorer stripped them all and fights a
// mortal, a skip-route fights a god who keeps getting back up.
if st.enemyReviveCharges > 0 {
st.enemyReviveCharges--
st.enemyHP = max(1, st.enemyReviveHP)
st.events = append(st.events, CombatEvent{
Round: st.round, Phase: phaseName, Actor: "enemy", Action: "phylactery_rebirth",
PlayerHP: st.playerHP, EnemyHP: st.enemyHP,
})
return false
}
return true
}