mirror of
https://github.com/prosolis/gogobee.git
synced 2026-07-18 01:42:42 +00:00
adventure: T6 Inversion Stitch (Seamstress) + boss re-strengthen (P8)
Second in-combat Layer-2 mechanic, reusing Amendment's round-end seam. In the Seamstress's phase 2 (<=35% HP) the room sews inside-out in a repeating warn(1)->sting(2) cadence, telegraphed one round ahead: during a pulse player heals (self + ally) invert to damage, floored at 1 HP. State inversionActive/inversionTelegraph round-trips through CombatStatuses so a suspend/resume can't drop or double a pulse. Sim surfaced that unplace is reach-bound (only ~37% reach the boss, then cleared her ~98%), so the mechanic alone is sub-noise. Re-strengthened the Seamstress, the weakest T6 boss (over-softened by P7 for a zone lift that never came): HP 385->460, Atk 39->45, Needle Rain proc 0.40->0.45. Sim-validated at fighter zone 37.5% (in range), and a real boss fight now instead of a victory lap. Claude-Session: https://claude.ai/code/session_0156WqjgsbmSY2U8eQ3Kkb1s
This commit is contained in:
@@ -228,6 +228,8 @@ func applyBossInCombatRoundEnd(st *combatState, bossID string, enemyMaxHP int) {
|
||||
switch bossID {
|
||||
case "boss_custodian":
|
||||
applyAmendment(st, enemyMaxHP)
|
||||
case "boss_seamstress":
|
||||
applyInversionStitch(st, enemyMaxHP)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -261,3 +263,72 @@ func applyAmendment(st *combatState, enemyMaxHP int) {
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// ── Inversion Stitch — The Seamstress (The Unplace) ──────────────────────────
|
||||
//
|
||||
// The Seamstress is sewing the tear shut from the inside, and once she's far
|
||||
// enough into the work (phase 2) she starts turning the room inside-out around
|
||||
// the party: for a two-round pulse, healing runs the wrong direction — every
|
||||
// cure lands as a wound (gated in stepPlayerActionEffect, floored at 1 HP so a
|
||||
// player is never killed by their own healer, only softened for the Seamstress's
|
||||
// own blows to finish). The catch is that she can't invert the room without a
|
||||
// visible tell: each pulse is telegraphed one full round ahead, so a player who
|
||||
// reads it holds their heals and waits it out. The autopilot that drives the sim
|
||||
// does not read tells — so the headless sweep sees the mechanic at its harshest,
|
||||
// the way an undisciplined party would, and a real player who respects the
|
||||
// warning fares better. That gap IS the difficulty lever, the same way the Greed
|
||||
// Tax and the Phylactery Verses are prod-only player-agency levers.
|
||||
//
|
||||
// It is the second in-combat Layer-2 mechanic, so it rides the same round-end
|
||||
// seam Amendment opened. Its state (inversionActive countdown + inversionTelegraph
|
||||
// warning) round-trips through CombatStatuses so a suspend/resume can't drop or
|
||||
// double a pulse. A no-op outside the Seamstress's phase 2.
|
||||
const (
|
||||
// seamstressPhaseTwoFrac must track The Seamstress's PhaseTwoAt in
|
||||
// postgame_zone_defs.go (0.35): the inversion only starts once she is sewn
|
||||
// deep enough into the tear. Kept local for the same reason as
|
||||
// custodianPhaseTwoFrac — the round-end hook resolves off the session, not the
|
||||
// ZoneDefinition, so the threshold isn't otherwise in reach here.
|
||||
seamstressPhaseTwoFrac = 0.35
|
||||
|
||||
// inversionPulseRounds is how many rounds each inside-out pulse lasts once it
|
||||
// activates (heals sting for this many player-rounds).
|
||||
inversionPulseRounds = 2
|
||||
)
|
||||
|
||||
// applyInversionStitch drives the Seamstress's phase-2 inversion cadence at round
|
||||
// end: telegraph a pulse one round ahead, activate it for inversionPulseRounds,
|
||||
// then re-telegraph the next — giving a repeating warn(1) → sting(2) rhythm the
|
||||
// player can play around. No-op until the boss is in phase 2.
|
||||
func applyInversionStitch(st *combatState, enemyMaxHP int) {
|
||||
// Layer-1 fight until the Seamstress is sewn into her own phase 2.
|
||||
phaseTwo := int(seamstressPhaseTwoFrac * float64(enemyMaxHP))
|
||||
if st.enemyHP > phaseTwo {
|
||||
return
|
||||
}
|
||||
// An active pulse counts down one round per round end. While it stays above
|
||||
// zero the next round's heals still sting; when it lapses this round, fall
|
||||
// through so a fresh telegraph is scheduled immediately.
|
||||
if st.inversionActive > 0 {
|
||||
st.inversionActive--
|
||||
if st.inversionActive > 0 {
|
||||
return
|
||||
}
|
||||
}
|
||||
// A telegraphed pulse activates: the room turns inside-out for the pulse.
|
||||
if st.inversionTelegraph {
|
||||
st.inversionActive = inversionPulseRounds
|
||||
st.inversionTelegraph = false
|
||||
st.events = append(st.events, CombatEvent{
|
||||
Round: st.round, Phase: CombatPhaseRoundEnd, Actor: "enemy", Action: "inversion_stitch",
|
||||
PlayerHP: st.playerHP, EnemyHP: st.enemyHP,
|
||||
})
|
||||
return
|
||||
}
|
||||
// Otherwise warn: the next round's pulse is one round out.
|
||||
st.inversionTelegraph = true
|
||||
st.events = append(st.events, CombatEvent{
|
||||
Round: st.round, Phase: CombatPhaseRoundEnd, Actor: "enemy", Action: "inversion_telegraph",
|
||||
PlayerHP: st.playerHP, EnemyHP: st.enemyHP,
|
||||
})
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user