Spiritual Weapon: own channel + narration; rest blocked mid-zone

Spiritual Weapon used to ride the pet-attack channel, so a petless
cleric saw "🐾 Your faithful companion" each round and couldn't tell
the spell was firing. Split it to SpiritWeaponProc/Dmg with its own
 flavor; damage now scales with spell mod + upcast.

Rest also fired mid-dungeon — only the autorun honored RestingUntil,
the !rest commands themselves had no gate. Block both short and long
rest when an expedition or combat session is active.
This commit is contained in:
prosolis
2026-05-23 10:14:51 -07:00
parent 9eed921e4b
commit 2e6274c1b7
7 changed files with 102 additions and 5 deletions

View File

@@ -53,6 +53,11 @@ type CombatModifiers struct {
PetAttackDmg int
PetDeflectProc float64
PetWhiffProc float64 // pet distracts enemy → guaranteed miss
// Spiritual Weapon — separate channel from the pet so the spectral mace
// gets its own narration when a cleric without a companion casts it.
// Damage formula mirrors PetAttack (Dmg + d5), proc rolls per round.
SpiritWeaponProc float64
SpiritWeaponDmg int
SniperKillProc float64 // Arina instant-kill
MistyHealProc float64
MistyHealAmt int
@@ -645,6 +650,19 @@ func simulateRound(st *combatState, player, enemy *Combatant, phase *CombatPhase
}
}
// Spiritual Weapon strike
if player.Mods.SpiritWeaponProc > 0 && st.randFloat() < player.Mods.SpiritWeaponProc {
swDmg := player.Mods.SpiritWeaponDmg + st.roll(5)
st.enemyHP = max(0, st.enemyHP-swDmg)
st.events = append(st.events, CombatEvent{
Round: st.round, Phase: phaseName, Actor: "spirit_weapon", Action: "spirit_weapon_strike",
Damage: swDmg, PlayerHP: st.playerHP, EnemyHP: st.enemyHP,
})
if enemyDown(st, phaseName) {
return true
}
}
// Misty heal
if player.Mods.MistyHealProc > 0 && st.randFloat() < player.Mods.MistyHealProc {
healAmt := player.Mods.MistyHealAmt