mirror of
https://github.com/prosolis/gogobee.git
synced 2026-07-16 00:52:40 +00:00
Adv 2.0 D&D Phase 12 E3a: Sunken Temple tidal event
Adds the §7.1 tidal event hook: warnings on Days 4 and 5, peak event on Day 6 with forced 2× supply burn (overrides tier-2 HarshMod 1.5×), silenced if the boss has been defeated. Wires zone-temporal events into deliverBriefing as two new hook points — pre-burn (mutates burn multiplier) and post-rollover (appends flavor-bearing log entries). Future E3b–E3f layer onto the same hooks. Reuses the prewritten flavor.SunkenTempleTidalWarning / TidalEvent pools per feedback_reuse_existing_flavor. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
97
internal/plugin/dnd_expedition_temporal.go
Normal file
97
internal/plugin/dnd_expedition_temporal.go
Normal file
@@ -0,0 +1,97 @@
|
||||
package plugin
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"gogobee/internal/flavor"
|
||||
)
|
||||
|
||||
// Phase 12 E3 — Zone-specific Temporal Events.
|
||||
// Spec: gogobee_expedition_system.md §7.
|
||||
//
|
||||
// Temporal events fire at briefing rollover and produce two outputs:
|
||||
// - extraHarsh: forces double supply burn for the burn fired by THIS
|
||||
// briefing (overrides the §4.1 zone HarshMod when the multiplier
|
||||
// should be 2× regardless of tier — e.g. tidal flooding §7.1).
|
||||
// - one or more flavor-bearing log entries (warnings, event narration).
|
||||
//
|
||||
// applyZoneTemporalPreBurn runs BEFORE applyDailyBurn so the burn
|
||||
// reflects the temporal effect for the day being entered. State that
|
||||
// persists across days (Heat stacks, Portal instability) is mutated
|
||||
// here as well — the per-day increment is the temporal event.
|
||||
//
|
||||
// Combat-side knobs (tidal +1d6 cold, Underforge +1d4 fire, etc.) are
|
||||
// exposed via ZoneTemporalEffects for the combat engine to read; the
|
||||
// engine hook lands with the combat-link phase.
|
||||
|
||||
// ZoneTemporalEffects bundles the per-zone, per-day combat-side
|
||||
// modifications produced by temporal events. Combat code reads this
|
||||
// from the active expedition; nothing reads it yet (combat-link phase).
|
||||
type ZoneTemporalEffects struct {
|
||||
// TidalActive — Sunken Temple Day 6 only. Combat: +1d6 cold per
|
||||
// turn while wading; kuo-toa +2 AC, +1d4 attack rolls.
|
||||
TidalActive bool
|
||||
}
|
||||
|
||||
// applyZoneTemporalPreBurn runs at the top of deliverBriefing, before
|
||||
// applyDailyBurn. It mutates e (state increments, in-memory only —
|
||||
// caller persists the relevant fields) and returns whether this
|
||||
// briefing's burn should be force-doubled regardless of HarshMod.
|
||||
//
|
||||
// nextDay is the day-number we're rolling INTO (i.e. e.CurrentDay+1
|
||||
// at call site, since the briefing increments after burn).
|
||||
func applyZoneTemporalPreBurn(e *Expedition, nextDay int) (extraHarsh bool) {
|
||||
switch e.ZoneID {
|
||||
case ZoneSunkenTemple:
|
||||
extraHarsh = sunkenTempleTemporalPreBurn(e, nextDay)
|
||||
}
|
||||
return extraHarsh
|
||||
}
|
||||
|
||||
// applyZoneTemporalPostRollover runs AFTER advance + threat drift.
|
||||
// It appends per-zone narration log entries for the day that just
|
||||
// became current. Returns lines to append to the briefing body.
|
||||
func applyZoneTemporalPostRollover(e *Expedition) []string {
|
||||
switch e.ZoneID {
|
||||
case ZoneSunkenTemple:
|
||||
return sunkenTempleTemporalPostRollover(e)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// ─────────────────────────────────────────────────────────────────────
|
||||
// §7.1 — Sunken Temple, Tidal Event (Day 6)
|
||||
// ─────────────────────────────────────────────────────────────────────
|
||||
|
||||
// sunkenTempleTemporalPreBurn doubles burn on Day 6 (tidal peak). Skips
|
||||
// entirely if the boss has been defeated — the spec's no-op clause.
|
||||
func sunkenTempleTemporalPreBurn(e *Expedition, nextDay int) bool {
|
||||
if e.BossDefeated {
|
||||
return false
|
||||
}
|
||||
return nextDay == 6
|
||||
}
|
||||
|
||||
// sunkenTempleTemporalPostRollover writes warnings on Day 4/5 and the
|
||||
// event narration on Day 6. Boss-kill before Day 6 silences all of it.
|
||||
func sunkenTempleTemporalPostRollover(e *Expedition) []string {
|
||||
if e.BossDefeated {
|
||||
return nil
|
||||
}
|
||||
day := e.CurrentDay
|
||||
switch day {
|
||||
case 4, 5:
|
||||
line := flavor.Pick(flavor.SunkenTempleTidalWarning)
|
||||
line = strings.ReplaceAll(line, "[N]", fmt.Sprintf("%d", day))
|
||||
summary := fmt.Sprintf("tidal warning — peak in %d day(s)", 6-day)
|
||||
_ = appendExpeditionLog(e.ID, day, "temporal", summary, line)
|
||||
return []string{line}
|
||||
case 6:
|
||||
line := flavor.Pick(flavor.SunkenTempleTidalEvent)
|
||||
_ = appendExpeditionLog(e.ID, day, "temporal",
|
||||
"tidal peak — flooded rooms hostile, supply burn doubled", line)
|
||||
return []string{line}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
Reference in New Issue
Block a user