N5/D1b: boss epilogues + TwinBee's journal reactions

- Boss epilogues: a 2-3 sentence campaign capstone per zone boss, tying
  each kill to the Hollow King arc. Appended to the boss-down moment in
  both close-out paths (finishCombatSession solo, finishPartyWin party),
  gated on the boss room (!elite) so it fires for any boss kill —
  expedition or legacy !zone — and never for elites or the arena (which
  has no ZoneID entry). Forest of Shadows is the King himself; its
  epilogue frames the fall as a shed shell, leaving the arc for the finale.
- TwinBee digest reactions: a journal page found mid-expedition writes a
  "journal" log beat; the end-of-day digest emits one first-person,
  deterministically-picked TwinBee line reacting to the day's pages. No
  net-new DM — it rides the existing night-camp digest.

Golden byte-identical; go test ./... green.

Claude-Session: https://claude.ai/code/session_017mEwUmmS7aQTP2NQXj6rUa
This commit is contained in:
prosolis
2026-07-10 15:26:20 -07:00
parent fd7803b13c
commit aab7a7bad0
5 changed files with 108 additions and 0 deletions

View File

@@ -44,11 +44,14 @@ func renderEndOfDayDigest(expID string, prevDay int) string {
threatLines []string
milestoneLine []string
narrativeBits []string
journalPages int
)
for _, e := range entries {
switch e.Type {
case "walk":
walks++
case "journal":
journalPages++
case "harvest":
// Only count successful gathers — failed rolls / errors are noise.
if strings.Contains(e.Summary, "success") {
@@ -115,6 +118,12 @@ func renderEndOfDayDigest(expID string, prevDay int) string {
b.WriteString("\n")
bulleted = true
}
if react := twinBeeJournalReaction(prevDay, journalPages); react != "" {
b.WriteString("• ")
b.WriteString(react)
b.WriteString("\n")
bulleted = true
}
if !bulleted {
// All entries were filtered out — fall back to the bare camp block.
return ""