mirror of
https://github.com/prosolis/gogobee.git
synced 2026-07-15 08:32:41 +00:00
Adv 2.0 D&D Phase 11 D2b: Tier 1 zone flavor files
New additive flavor files (zone_goblin_warrens_flavor.go, zone_crypt_valdris_flavor.go) with elite-room intros, boss ability callouts (Grol: Surprise Attack / Heart of Hruggek / Terrifying Roar; Valdris: Corrupting Touch / Legendary Resistance / Call of the Grave / Phase Two), and zone-specific lore deep-dives. Existing twinbee_gm_flavor.go is untouched per the protected-files contract. Wires three narration helpers in dnd_zone_narration.go: composeBossEntry — boss-entry render plus a one-line ability callout eliteRoomEntryLine — elite-room atmospheric prefix zoneLorePool — zone-specific !lore pool with generic fallback Boss-entry callsite in dnd_zone_cmd.go now uses composeBossEntry; the elite branch of resolveCombatRoom prefixes with the zone's elite line. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
86
internal/flavor/zone_crypt_valdris_flavor.go
Normal file
86
internal/flavor/zone_crypt_valdris_flavor.go
Normal file
@@ -0,0 +1,86 @@
|
||||
// DO NOT REWRITE, SUMMARIZE, OR SHORTEN ANY ENTRIES IN THIS FILE
|
||||
// zone_crypt_valdris_flavor.go
|
||||
// Tier 1 zone flavor — The Crypt of Valdris. Additive only. Pools sampled
|
||||
// by internal/plugin via deterministic per-run, per-room hashing.
|
||||
//
|
||||
// Voice rules (from gogobee_dungeon_zones.md §3.3):
|
||||
// • Third person for description; second person for outcomes.
|
||||
// • Boss callouts get a beat of cinema. Don't overrun.
|
||||
// • TwinBee references the right era — NES, SNES, arcade. Not modern.
|
||||
|
||||
package flavor
|
||||
|
||||
// ─────────────────────────────────────────────────────────────────────────────
|
||||
// ELITE ROOM ENTRY — Crypt of Valdris (Wight / Flameskull)
|
||||
// ─────────────────────────────────────────────────────────────────────────────
|
||||
|
||||
var EliteRoomEntryCrypt = []string{
|
||||
"The room is colder than the last one. Not by feeling — by measurement. TwinBee can tell. There is a presence here that does not believe in the ambient temperature of stone.",
|
||||
"A figure sits in the cathedra at the chamber's far end. Robes intact. Skin not. The eyes open as you enter and they were already looking at the door. TwinBee draws breath despite not strictly needing to.",
|
||||
"Floating above the altar: a skull, lit from within in a color that pretends to be fire. TwinBee recognizes the pretense. The skull is doing math. The math is about where you are.",
|
||||
"The torches in this room are out, but the room is lit anyway. TwinBee identifies this as a problem worth naming aloud: 'That light has a source. The source is the encounter.'",
|
||||
"You step into a chapel. Pews. Altar. A figure rising from the front pew with the unhurried grace of something that has been waiting in this exact pew for a very long time. TwinBee respects the patience and refuses to be impressed by it.",
|
||||
"The mosaics on the walls show a procession. The procession leads to a king. The king is here. TwinBee notes that the mosaics are still being added to in real time — one tile per visitor — and you have not been added yet.",
|
||||
}
|
||||
|
||||
// ─────────────────────────────────────────────────────────────────────────────
|
||||
// BOSS ABILITY CALLOUTS — Valdris the Unburied
|
||||
// Used as a one-line cinematic suffix to BossEntryValdris when combat starts.
|
||||
// ─────────────────────────────────────────────────────────────────────────────
|
||||
|
||||
// Corrupting Touch: +4d6 necrotic; target max HP reduced by damage dealt.
|
||||
var ValdrisCorruptingTouchLines = []string{
|
||||
"His hand passes through your chestplate without touching it. The damage isn't to the plate. TwinBee watches your max HP tick down and quietly stops watching.",
|
||||
"Necrotic damage lands and lingers. The wound doesn't bleed — it forgets how. Your HP ceiling drops with it. TwinBee notes: long rest restores. Survive to long rest.",
|
||||
"Where Valdris touches, the body takes a piece of permanent. Not permanent-permanent. Long-rest-permanent. TwinBee considers this distinction the only good news in the sentence.",
|
||||
}
|
||||
|
||||
// Legendary Resistance: 2/combat; auto-succeed one failed save.
|
||||
var ValdrisLegendaryResistanceLines = []string{
|
||||
"Your save would have landed. Valdris decides otherwise. The roll resets to a success on his side of the table. TwinBee notes one charge spent, one remaining.",
|
||||
"The spell hits cleanly and Valdris ignores it on principle. TwinBee marks the Legendary Resistance and reminds you: he has two of these. After two, the math changes.",
|
||||
"You rolled the number. The number was correct. Valdris waves it away with a gesture that costs him something but not enough. TwinBee keeps count. Keep rolling.",
|
||||
}
|
||||
|
||||
// Call of the Grave: recharge 5–6; summons 1d4 skeletons.
|
||||
var ValdrisCallOfTheGraveLines = []string{
|
||||
"Valdris speaks a word that is not for the living. Bones in the chamber walls remember they were once attached to people. TwinBee counts the new combatants and recommends crowd control.",
|
||||
"From the alcoves: the dry rattle of skeletons reassembling on demand. TwinBee notes 1d4 new bodies on the field and quietly hopes for the lower end of that range.",
|
||||
"The skeletons stand up like a Castlevania stage hazard — same animation, same timing, same exact bad news. TwinBee has memories of this and they are not warm ones.",
|
||||
}
|
||||
|
||||
// Phase 2 (<50% HP): gains Fly speed; spells deal +1d6 necrotic.
|
||||
var ValdrisPhaseTwoLines = []string{
|
||||
"Valdris drops to half HP and stops walking. Not because he's tired — because he doesn't need to anymore. He rises a foot off the floor and TwinBee files this under 'phase shift.'",
|
||||
"The fight changes shape. Valdris hangs in the air now, robes still, very calm, very lethal. His spells gain a necrotic edge. TwinBee says, simply: 'Phase two. Adjust.'",
|
||||
"Half-HP is the line. You crossed it and Valdris crossed something else — gravity, mostly. The boss music gets a third instrument. TwinBee braces.",
|
||||
"Like Castlevania's Death revealing his real attack pattern at half HP — the fight you started is not the fight you're finishing. TwinBee respects the pivot and dislikes it intensely.",
|
||||
}
|
||||
|
||||
// ValdrisSignatureCallouts — combined pool the boss-entry composer samples
|
||||
// from at the start of the boss fight. Phase-two lines are surfaced via
|
||||
// the dedicated phase-two helper rather than the entry suffix.
|
||||
var ValdrisSignatureCallouts = func() []string {
|
||||
out := make([]string, 0,
|
||||
len(ValdrisCorruptingTouchLines)+
|
||||
len(ValdrisLegendaryResistanceLines)+
|
||||
len(ValdrisCallOfTheGraveLines))
|
||||
out = append(out, ValdrisCorruptingTouchLines...)
|
||||
out = append(out, ValdrisLegendaryResistanceLines...)
|
||||
out = append(out, ValdrisCallOfTheGraveLines...)
|
||||
return out
|
||||
}()
|
||||
|
||||
// ─────────────────────────────────────────────────────────────────────────────
|
||||
// LORE — Crypt of Valdris
|
||||
// Sampled by !lore inside this zone (zone-specific pool, generic fallback).
|
||||
// ─────────────────────────────────────────────────────────────────────────────
|
||||
|
||||
var LoreLinesCrypt = []string{
|
||||
"Valdris was a scholar. Then he was an aspirant. Then he was a failed aspirant. The failure is the part that mattered — the lich ritual completed but completed wrong, and the wrongness has had three centuries to compound. TwinBee has read the contemporaneous accounts and finds the original scholar likable, which makes the rest harder.",
|
||||
"The phylactery shard you'll find here is one of seven. The other six are not in this crypt. TwinBee will not say where they are because TwinBee doesn't fully know, and the partial knowledge TwinBee has is the kind that gets people followed by things that prefer not to be looked for.",
|
||||
"The candles in the crypt do not consume wax. They do not consume time, either, in the strict sense. They were lit on the day Valdris was interred and they have been lit ever since. TwinBee respects this kind of consistency in a way that does not extend to approval.",
|
||||
"The skeletons here are not all enemies. Some of them are former students, posed in the alcoves where they died, marked with the texts they were translating. TwinBee suggests you don't disturb the marked ones unless you mean to. Some lessons end and some lessons keep going.",
|
||||
"The iron gate at the entrance has been opened from the inside three times in the last decade, and from the outside zero times. TwinBee finds the asymmetry instructive. It also finds the pattern instructive: you are walking into the open door, not opening it.",
|
||||
"In life, Valdris was patient. In undeath, Valdris is also patient — which is unfair, mathematically, because the same trait scales differently across mortality conditions. TwinBee dislikes the math but respects the consistency.",
|
||||
}
|
||||
76
internal/flavor/zone_goblin_warrens_flavor.go
Normal file
76
internal/flavor/zone_goblin_warrens_flavor.go
Normal file
@@ -0,0 +1,76 @@
|
||||
// DO NOT REWRITE, SUMMARIZE, OR SHORTEN ANY ENTRIES IN THIS FILE
|
||||
// zone_goblin_warrens_flavor.go
|
||||
// Tier 1 zone flavor — Goblin Warrens. Additive only. Pools sampled by
|
||||
// internal/plugin via deterministic per-run, per-room hashing.
|
||||
//
|
||||
// Voice rules (from gogobee_dungeon_zones.md §3.3):
|
||||
// • Third person for description; second person for outcomes.
|
||||
// • Boss callouts get a beat of cinema. Don't overrun.
|
||||
// • TwinBee references the right era — NES, SNES, arcade. Not modern.
|
||||
|
||||
package flavor
|
||||
|
||||
// ─────────────────────────────────────────────────────────────────────────────
|
||||
// ELITE ROOM ENTRY — Goblin Warrens (Hobgoblin Warchief)
|
||||
// ─────────────────────────────────────────────────────────────────────────────
|
||||
|
||||
var EliteRoomEntryWarrens = []string{
|
||||
"The chamber widens. A hobgoblin in lacquered scale stands at the center, arms folded, watching the door. The lesser goblins go quiet. TwinBee notes the silence is the part you should be paying attention to.",
|
||||
"A war-banner hangs from the ceiling — three clans stitched together with rough thread. Beneath it, a Warchief turns to face you with the slow patience of someone who has done this part a hundred times. TwinBee straightens up out of habit.",
|
||||
"The corridor opens into a drilling ground. Goblins in formation. A Hobgoblin barking orders that stop the moment your boot hits the threshold. TwinBee has seen this exact composition in Shining Force and finds the parallel unhelpful.",
|
||||
"You smell the polish before you see the armor. The Warchief's blade is oiled, his straps are tight, his stance is correct. TwinBee acknowledges, with reluctance, that this one was trained.",
|
||||
"A circle of torches. A throne of stacked shields. The hobgoblin seated on it does not stand. He gestures, single-finger, in a way TwinBee universally translates as 'come here.' You go there.",
|
||||
"The room has been cleared for combat. Rugs rolled, braziers spaced evenly, sand on the floor for grip. TwinBee respects the preparation and is professionally annoyed by it.",
|
||||
}
|
||||
|
||||
// ─────────────────────────────────────────────────────────────────────────────
|
||||
// BOSS ABILITY CALLOUTS — Grol the Unbroken
|
||||
// Used as a one-line cinematic suffix to BossEntryGrol when combat starts.
|
||||
// ─────────────────────────────────────────────────────────────────────────────
|
||||
|
||||
// Surprise Attack: +2d6 if player has not acted this combat.
|
||||
var GrolSurpriseAttackLines = []string{
|
||||
"Grol moves before you do. He always moves before you do. TwinBee notes — too late — that the first hit in this fight is his.",
|
||||
"The cleaver comes around in an arc that started before you were in the room. TwinBee winces in advance.",
|
||||
"He's not waiting for the fight to start. The fight starts when he says it does. TwinBee marks the lesson and files it under 'next time.'",
|
||||
}
|
||||
|
||||
// Heart of Hruggek: crits deal max damage (no roll).
|
||||
var GrolHeartOfHruggekLines = []string{
|
||||
"Grol crits and the dice don't roll. TwinBee has seen this Bugbear blessing once before. The number is the maximum number, every time, no negotiation.",
|
||||
"His critical lands flat-max. No spread, no luck — just Hruggek's blessing collecting on a long-overdue debt. TwinBee notes the damage with grim respect.",
|
||||
"The crit hits like a Final Fantasy 'Berserk' status — capped, deterministic, unkind. TwinBee skips the roll and writes the maximum.",
|
||||
}
|
||||
|
||||
// Terrifying Roar: 1/combat; allies +2 to hit for 2 turns; player WIS DC 13 or Frightened.
|
||||
var GrolTerrifyingRoarLines = []string{
|
||||
"Grol throws his head back and roars. The room shakes. The goblins around him stand straighter. TwinBee says: 'WIS save. Now.'",
|
||||
"The roar isn't a sound — it's a pressure change. Your knees know about it before your ears do. TwinBee respects the technique and asks you to roll Wisdom.",
|
||||
"He bellows once. The torchlight bends. The goblins answer with cheers that sound rehearsed. TwinBee notes the buff is up; you have two turns to outlast it.",
|
||||
}
|
||||
|
||||
// GrolSignatureCallouts — combined pool the boss-entry composer samples
|
||||
// from. Concrete ability pools above are kept distinct so future per-turn
|
||||
// ability hooks (D6) can wire to a specific trigger.
|
||||
var GrolSignatureCallouts = func() []string {
|
||||
out := make([]string, 0,
|
||||
len(GrolSurpriseAttackLines)+len(GrolHeartOfHruggekLines)+len(GrolTerrifyingRoarLines))
|
||||
out = append(out, GrolSurpriseAttackLines...)
|
||||
out = append(out, GrolHeartOfHruggekLines...)
|
||||
out = append(out, GrolTerrifyingRoarLines...)
|
||||
return out
|
||||
}()
|
||||
|
||||
// ─────────────────────────────────────────────────────────────────────────────
|
||||
// LORE — Goblin Warrens
|
||||
// Sampled by !lore inside this zone (zone-specific pool, generic fallback).
|
||||
// ─────────────────────────────────────────────────────────────────────────────
|
||||
|
||||
var LoreLinesWarrens = []string{
|
||||
"The Warrens are old. Not goblin-old — older. The tunnels predate the goblins and the goblins know it. They've widened doorways meant for something taller and braced ceilings meant for something heavier. TwinBee has theories about what was here first. None of them are reassuring.",
|
||||
"Grol united the three clans by killing each of their war-chiefs in single combat, in order, in one afternoon. The fourth clan declined to send a chief and pledged loyalty by letter. TwinBee finds the letter, professionally, very funny.",
|
||||
"The graffiti on the walls dates the occupation. Goblins date by leaders and the names go back six generations. TwinBee can read goblin script when pressed and notes that the third-oldest name is one a paladin order would still recognize.",
|
||||
"The Merchant's Road above doesn't know about the Warrens. The Merchant's Road above used to know about the Warrens. TwinBee was here when it stopped knowing, and notes that the people in charge of Knowing About Things were the first to disappear.",
|
||||
"Hobgoblins hold formation; goblins hold grudges; bugbears hold pretty much anything they pick up. TwinBee offers this not as a joke but as a tactical primer that will save you a lot of HP if you remember it.",
|
||||
"The belt Grol wears is not a trophy. It is a contract. Each tooth on it is a debt some troll forgave when the wearing of the belt began, and the debts run in both directions. TwinBee strongly suggests not breaking the belt unless you mean to.",
|
||||
}
|
||||
Reference in New Issue
Block a user