mirror of
https://github.com/prosolis/gogobee.git
synced 2026-07-15 08:32:41 +00:00
Adv 2.0 D&D Phase 10 SUB2b: Mage subclasses (Evocation/Abjuration/Necromancy)
Evocation L7 Empowered Evocation adds INT mod (min +1) to Mage evocation spell damage. Abjuration L5 Arcane Ward grants a 2×level HP buffer absorbed before player HP, +prof at L7. Necromancy L5 Grim Harvest heals 2× spell level on spell-kill (3× necrotic) via post-combat hook. Sculpt Spells / Potent Cantrip / Inured to Undeath skipped — no allies, save-half is already uniform, and no necrotic enemy damage to resist. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -82,6 +82,17 @@ type CombatModifiers struct {
|
||||
AssassinateAdvantage bool
|
||||
AssassinateBonusDmg int
|
||||
|
||||
// Phase 10 SUB2b — Mage subclasses.
|
||||
// ArcaneWardHP: flat HP buffer absorbed before player HP. Refilled at the
|
||||
// start of each combat by Abjuration L5+ (2× Mage level, +prof at L7).
|
||||
// Persists across rounds within a single combat; not refunded between fights.
|
||||
// GrimHarvestSlot/Necrotic: snapshot of the queued spell stashed by
|
||||
// applyPendingCast for the post-combat Grim Harvest hook (Necromancy L5+).
|
||||
// Heal fires only if the spell event is what dropped the enemy to 0.
|
||||
ArcaneWardHP int
|
||||
GrimHarvestSlot int
|
||||
GrimHarvestNecrotic bool
|
||||
|
||||
// Phase 9 — pending spell resolution. Set by applyPendingCast in
|
||||
// dnd_spell_combat.go before SimulateCombat runs. SpellPreDamage is
|
||||
// dealt as a pre-combat event with SpellPreDamageDesc as the narrative
|
||||
@@ -204,6 +215,9 @@ type combatState struct {
|
||||
assassinateRerollUsed bool
|
||||
assassinateBonusUsed bool
|
||||
|
||||
// Phase 10 SUB2b — Abjuration Arcane Ward HP buffer.
|
||||
arcaneWardHP int
|
||||
|
||||
round int
|
||||
events []CombatEvent
|
||||
}
|
||||
@@ -217,6 +231,7 @@ func SimulateCombat(player, enemy Combatant, phases []CombatPhase) CombatResult
|
||||
reflectFrac: player.Mods.ReflectNext,
|
||||
autoCrit: player.Mods.AutoCritFirst,
|
||||
enemySkipFirst: player.Mods.SpellEnemySkipFirst,
|
||||
arcaneWardHP: player.Mods.ArcaneWardHP,
|
||||
}
|
||||
|
||||
result := CombatResult{
|
||||
@@ -723,6 +738,25 @@ func resolveEnemyAttack(st *combatState, player, enemy *Combatant, phase *Combat
|
||||
action = "block"
|
||||
}
|
||||
|
||||
// Phase 10 SUB2b — Abjuration Arcane Ward absorbs incoming damage before
|
||||
// it hits player HP. Only wired into the standard enemy attack path; tick
|
||||
// effects (poison, environment, lifesteal, cleave) bypass the ward in this
|
||||
// model — those represent damage-over-time / tactical hits where the
|
||||
// abstraction "magical aegis" reads thinner narratively.
|
||||
if st.arcaneWardHP > 0 && dmg > 0 {
|
||||
absorbed := dmg
|
||||
if absorbed > st.arcaneWardHP {
|
||||
absorbed = st.arcaneWardHP
|
||||
}
|
||||
st.arcaneWardHP -= absorbed
|
||||
dmg -= absorbed
|
||||
st.events = append(st.events, CombatEvent{
|
||||
Round: st.round, Phase: phaseName, Actor: "player", Action: "arcane_ward",
|
||||
Damage: absorbed, PlayerHP: st.playerHP, EnemyHP: st.enemyHP,
|
||||
Desc: "Arcane Ward",
|
||||
})
|
||||
}
|
||||
|
||||
st.playerHP = max(0, st.playerHP-dmg)
|
||||
st.events = append(st.events, CombatEvent{
|
||||
Round: st.round, Phase: phaseName, Actor: "enemy", Action: action,
|
||||
|
||||
Reference in New Issue
Block a user