mirror of
https://github.com/prosolis/gogobee.git
synced 2026-07-15 08:32:41 +00:00
Tedium-removal pass driven by live play feedback. Three big threads: Expedition autopilot Phase 4 — background auto-run + harvest-until-dry: - New expeditionAutoRunTicker walks active expeditions every 15min (5min tick, per-expedition CAS on new last_autorun_at column). Skips combat sessions, briefing/recap quiet windows, expeditions <30min old. - Walks up to 3 rooms/tick with compact narration; suppresses DMs when 0 rooms walked or just hitting the per-tick cap (no "stretch complete" filler). Player only hears from the bot when a real decision is needed. - Compact mode: one-line combat narration for trash/elite, auto-resolves elite doorways via the forward-sim engine (boss still pauses). Threaded via new advanceOnceWithOpts → resolveRoom → resolveCombatRoom. - Auto-harvest now grinds each Common/Uncommon node until dry (cap at 8 attempts/visit), mirroring manual !scavenge retries. Rare+ still pauses. - Ambient ticker: anti-repeat by Kind via new last_ambient_kind column (avoids two pack_rat DMs in a row when the pool only has 6 lines). - !expedition go <n> now routes to the fork-choice handler when active + numeric; fork footer rewritten to suggest !expedition go instead of !zone go. Boss/Elite doorway: formatNextRoomMessage routes the action hint by next room type and autopilot loop breaks via new nextRoomType field so "Room X/Y — Boss" doesn't double-print with contradictory hints (!zone advance vs !fight). - runAutopilotWalk extracted from expeditionCmdRun so foreground and background share the loop body. Rogue Sneak Attack actually exists now: - Audit found the rogue's "Sneak Attack" passive was AutoCritFirst + 5% damage rider. No Nd6, ever. Phase 2 Monte Carlo masked this with a small flat buff; the class's defining mechanic never matched its tooltip or 5e identity. - Added SneakAttackDie int to CombatModifiers, per-hit Nd6 in combat_primitives.go (same lane as DivineStrikePerHit). Scales with level: 1d6 at L1-2 ... 4d6 at L7-8 ... capped at 10d6 at L19-20. - AutoCritFirst + 5% rider retained as bonuses on top of working sneak attack — preserves the opener-burst feel. - L7 rogue expected per-hit ~8 → ~22 damage. Valdris fight math goes from "16 rounds to kill, die in 8" to winnable. TwinBee voice sweep (Phase B3): - ~530 line changes across 24 files replacing third-person "TwinBee notes/files/tracks/respects/..." constructions with first-person inside flavor string literals. Code identifiers (TwinBeeLine, twinBeeLine, etc.), chat-prefix labels (🎭 **TwinBee:**), item names (TwinBee's Bell), achievements, and game-title references in fun.go (Konami TwinBee ship) left intact. - Catches a real bug: Valdris fight rendered "TwinBee marks the Legendary Resistance" mid-combat in third person, contradicting the Phase B2 convention. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
240 lines
20 KiB
Go
240 lines
20 KiB
Go
// twinbee_resource_flavor.go
|
|
// TwinBee GM Dialogue — Resource gathering, combat interrupts,
|
|
// zone-specific loot descriptions, and harvest narration.
|
|
//
|
|
// Voice convention (Phase B2): TwinBee speaks in first-person or implicit
|
|
// subject. No third-person "TwinBee [verb]" lines. Add freely.
|
|
// Don't shorten existing entries.
|
|
|
|
package flavor
|
|
|
|
// ─────────────────────────────────────────────────────────────────────────────
|
|
// HARVEST SUCCESS — Generic by Action Type
|
|
// ─────────────────────────────────────────────────────────────────────────────
|
|
|
|
var HarvestForageSuccess = []string{
|
|
"The land gives something up. I watch you identify it with the quiet satisfaction of someone watching a skill be used correctly.",
|
|
"There — growing in a place that suggests it knows exactly what it's good for and has been waiting. You found it. I approve of the finding.",
|
|
"A Ranger's eye in a non-Ranger would have missed that entirely. I note the distinction.",
|
|
"Like finding the hidden item block in a Mario level — you knew to look, you looked in the right place, and the thing that was always there is now yours.",
|
|
"The plant comes away cleanly. Good root structure, good potency. Mentally catalogued. Moving on.",
|
|
}
|
|
|
|
var HarvestMineSuccess = []string{
|
|
"The stone yields. I listen to the sound of it — the specific tone of rock giving up something it's been holding for a very long time.",
|
|
"Solid work. The ore comes out in a piece worth taking. I check the vein depth. There's more. There's always more if you're willing to dig.",
|
|
"Like the mining minigame in Stardew Valley, but with real consequences and no save file. I watch you extract the material with professional appreciation.",
|
|
"The wall gives up its contents without drama. I appreciate materials that cooperate.",
|
|
"Good strike. Clean extraction. I note the weight and the quality simultaneously.",
|
|
}
|
|
|
|
var HarvestScavengeSuccess = []string{
|
|
"There it is. Among the debris, the decay, the things that were left behind — something worth taking. I knew it was there. You found it. Pleased.",
|
|
"The room held something after all. I had estimated 60% odds and am updating the estimate to 'correct.'",
|
|
"Like finding the secret item in a dungeon chest that looked empty — you checked anyway. That's the habit. That's the discipline. I note both.",
|
|
"Scavenged. The word has a bad reputation it doesn't deserve. You found value in the discarded. I respect that entirely.",
|
|
"A Rogue's eye in a non-Rogue would have walked past this. I note the distinction.",
|
|
}
|
|
|
|
var HarvestEssenceSuccess = []string{
|
|
"The essence coalesces. I watch the process with the reverence it deserves — magic condensing from ambient to held is not nothing.",
|
|
"Drawn out cleanly. The Arcana check held and the essence responds to the knowledge behind it. I'm appropriately impressed.",
|
|
"Like tapping into a power source in Metroid — you knew the energy was there, you had the tool to reach it, you reached it. The vial fills.",
|
|
"The room releases something it didn't know it was holding. I watch the transfer and mark the yield in the ledger.",
|
|
"Essence harvested. Quality above average for this zone, below average for what you'd need to know to appreciate that distinction. I appreciate it on your behalf.",
|
|
}
|
|
|
|
var HarvestCommuneSuccess = []string{
|
|
"The spiritual resonance here responds to you. I observe this with something adjacent to wonder — not everything in a dungeon wants to fight, and this one chose to offer instead.",
|
|
"A Cleric reaching into the bones of a place and finding something willing to be found. I've watched this fewer times than I've watched combat and value it proportionally.",
|
|
"The commune holds. The material comes. I say nothing and let the moment be what it is.",
|
|
"Like finding a save point that also tells you something true about the world. The dungeon has given you something. I note the gift.",
|
|
}
|
|
|
|
var HarvestFishSuccess = []string{
|
|
"The line goes taut and I straighten up. Whatever's on the end of it, it came from somewhere deep and dark and it's yours now.",
|
|
"A catch. I identify it before you finish pulling it in — the coloring, the depth-marks, the specific opacity of its eyes. 'Good one,' I say, meaning it.",
|
|
"Fishing in a dungeon. I have opinions about fishing in dungeons and all of them are positive. The fish is landed. The opinions remain.",
|
|
"Like the fishing minigame in every RPG that ever had one — the moment the indicator hits perfect and everything pays off. Quiet delight, on my end.",
|
|
"The water gives up its catch with minimal argument. I respect fish that don't make it personal.",
|
|
}
|
|
|
|
// ─────────────────────────────────────────────────────────────────────────────
|
|
// HARVEST FAILURE — Generic
|
|
// ─────────────────────────────────────────────────────────────────────────────
|
|
|
|
var HarvestFail = []string{
|
|
"Nothing. The node had nothing to offer, or you didn't ask the right way, or both. No judgment from me. Try elsewhere.",
|
|
"The attempt fails to produce anything useful. I mark the node and move on. Some rooms are stingier than others.",
|
|
"Not everything that looks like a resource is one. Filed under 'learned' and considered worth the attempt.",
|
|
"Empty-handed. I've seen this before and will see it again. The dungeon doesn't owe you anything. You ask anyway. That's the deal.",
|
|
}
|
|
|
|
// ─────────────────────────────────────────────────────────────────────────────
|
|
// HARVEST INTERRUPT — Combat Triggered
|
|
// ─────────────────────────────────────────────────────────────────────────────
|
|
|
|
var HarvestInterrupt = []string{
|
|
"I see it before you do — movement at the edge of the room, something that was waiting for you to be distracted. 'Company,' I say, which is the politest word for it.",
|
|
"The harvest is interrupted. You were focused on the node; something was focused on you. I note the tactical lesson without rubbing it in. Much.",
|
|
"Like the enemy ambush that fires when you open the treasure chest — the dungeon watched you commit to the harvest and introduced a complication. I did warn about this. Once. Earlier.",
|
|
"Something heard the mining. Sound travels in dungeons. I have mentioned this. The enemy emerging from the corridor has confirmed it.",
|
|
"A patrol. Bad timing, or very good timing from their perspective. I set aside the harvest log and open the combat log.",
|
|
"The forage was going well until it wasn't. I measure the distance between you and the enemy, between the enemy and the door, and start calculating options at speed.",
|
|
"Interrupted. The node is still there. The enemy is also still there, in a more immediate way. I suggest addressing the more immediate thing first.",
|
|
}
|
|
|
|
// ─────────────────────────────────────────────────────────────────────────────
|
|
// NODE DEPLETED
|
|
// ─────────────────────────────────────────────────────────────────────────────
|
|
|
|
var NodeDepleted = []string{
|
|
"The node is stripped. You've taken everything it had to give. Marked in the mental map as exhausted until the next rest.",
|
|
"Empty. The resource is gone. Something quietly melancholy about a depleted node and something practical about moving to the next one.",
|
|
"That's all it had. I confirm the node at zero and move on without ceremony.",
|
|
"Harvested clean. The room is now resource-dry until you rest and the dungeon replenishes. It will replenish. It always does.",
|
|
}
|
|
|
|
// ─────────────────────────────────────────────────────────────────────────────
|
|
// RICH YIELD
|
|
// ─────────────────────────────────────────────────────────────────────────────
|
|
|
|
var RichYield = []string{
|
|
"A rich vein. My assessment upgrades mid-harvest — more than expected, better quality than the zone average. This room was generous. Marked.",
|
|
"The node gives more than it should have. I note the anomaly with appreciation and decline to question it.",
|
|
"Like finding the rare item drop that you stopped expecting — the dungeon decided to be kind today, in this specific way, in this specific room. I take it. We take it. We do not look it in the mouth.",
|
|
"Exceptional yield. I catalog the bonus material with the efficiency of someone who's been waiting for exactly this and prepared for it anyway.",
|
|
"More than the DC promised. The dungeon overdelivered. Unusual. Also completely welcome.",
|
|
}
|
|
|
|
// ─────────────────────────────────────────────────────────────────────────────
|
|
// ZONE-SPECIFIC HARVEST LINES
|
|
// ─────────────────────────────────────────────────────────────────────────────
|
|
|
|
var HarvestGoblinWarrens = []string{
|
|
"The goblins had more than anyone gave them credit for. Crude, yes. Stolen, mostly. But present, and now yours. I'm pragmatic about origins.",
|
|
"Scavenged from a goblin stash that someone worked hard to hide and harder to accumulate. A moment of respect for the effort, then we move on.",
|
|
"The warrens are full of things the goblins took from people who'd take them back given the opportunity. I consider this a form of redistribution.",
|
|
}
|
|
|
|
var HarvestCryptValdris = []string{
|
|
"Grave goods. The weight of taking from a burial site, filed under: necessary. The dead have no use for these. You do.",
|
|
"The crypt gives up its materials with the reluctance of a place that considers itself permanent. I disagree with the premise. The materials are harvested.",
|
|
"Ancient things preserved by darkness and time. I handle the concept carefully even as you handle the material practically.",
|
|
}
|
|
|
|
var HarvestForestShadows = []string{
|
|
"The forest gives and the forest takes and right now it is giving, which I note as the correct direction for this interaction to go.",
|
|
"A plant that has no business being this healthy in a corrupted forest. Either very resilient or very clever. Either way, useful.",
|
|
"The woods here remember what they were before they went wrong. The resources carry that memory. I think this makes them better materials. I might be right.",
|
|
}
|
|
|
|
var HarvestSunkenTemple = []string{
|
|
"The temple held onto this longer than anything else. I extract it from the silt and the salt and the particular weight of a place that's been underwater for thirty years.",
|
|
"Ancient, preserved, and still potent. The deep cold does something to materials that nothing else replicates. I value the outcome even if I decline to romanticize the process.",
|
|
"The sea left something behind when it half-abandoned this place. Retrieved with appropriate care.",
|
|
}
|
|
|
|
var HarvestHauntedManor = []string{
|
|
"The manor keeps things. Has always kept things. I take this one out of the keeping and into the useful, which is a small act of defiance against the house's whole philosophy.",
|
|
"Found among the things that have been here since the last person stopped being here. Provenance noted, not dwelt on.",
|
|
"The house watches you take it. I watch the house watch you. A full triangle of observation — the house blinks first.",
|
|
}
|
|
|
|
var HarvestUnderforge = []string{
|
|
"The forge yields its material with the grudging respect of something built to produce and still producing, even now, for someone it didn't expect.",
|
|
"Dwarven craftsmanship even in the raw materials. I've always believed the quality is in the extraction, not just the finishing. This confirms it.",
|
|
"Hot, heavy, and exactly what the zone promised. I mark the vein depth. There is more. The Underforge does not run out of things to give.",
|
|
}
|
|
|
|
var HarvestUnderdark = []string{
|
|
"The Underdark produces everything the surface does, stranger, in the dark, and with fewer questions about why. I harvest without asking why.",
|
|
"Things grow down here that have no equivalent above. I catalog the material and the context it came from with equal precision.",
|
|
"A material that has never seen sunlight and is better for it. Noted without irony.",
|
|
}
|
|
|
|
var HarvestFeywild = []string{
|
|
"The Feywild gives things away. That's the problem — it gives things away and sometimes what it gives isn't what you thought you were taking. I check the material twice. It appears to be what it appears to be. Remaining alert.",
|
|
"Beautiful material from a zone that uses beauty as a weapon. I take it carefully, like picking up something that might be watching.",
|
|
"The fey made this place generous on purpose. I'm not going to complain about the generosity and I'm not going to stop watching for the catch.",
|
|
}
|
|
|
|
var HarvestDragonsLair = []string{
|
|
"Plucked from a hoard that has been accumulating since before your civilization named itself. Historical weight noted. Moving on.",
|
|
"The kobolds will notice something is missing. They count everything. I account for this and suggest moving with intent.",
|
|
"Dragon-adjacent materials carry something in them — a residual heat, a quality that doesn't exist anywhere the dragon hasn't been. I consider this a feature.",
|
|
}
|
|
|
|
var HarvestAbyssPortal = []string{
|
|
"Harvesting from the Abyss. Flatly delivered, because the line deserves flat delivery. The material is valuable. The context is permanent.",
|
|
"Reality left something behind when it tore here. I take the fragment and note: don't linger near the edges of what isn't stable.",
|
|
"Demon ichor. I say the words with the efficiency of someone who has moved past the part where the words were alarming.",
|
|
}
|
|
|
|
// ─────────────────────────────────────────────────────────────────────────────
|
|
// FISHING — Zone-Specific Lines
|
|
// ─────────────────────────────────────────────────────────────────────────────
|
|
|
|
var FishingForestShadows = []string{
|
|
"Fishing in a cursed forest stream. More peaceful than it has any right to be, and I refuse to let the shadow-things in the canopy ruin it.",
|
|
"The stream runs dark but the fish run silver. I watch the line and say nothing for a while, which is what fishing is for.",
|
|
"Like the fishing minigame before the hard dungeon in Ocarina of Time. I take the moment seriously.",
|
|
}
|
|
|
|
var FishingSunkenTemple = []string{
|
|
"Fishing in a flooded temple. The fish here have never seen the surface. They don't know what they're missing. I'm uncertain whether to pity them.",
|
|
"The line drops into water that hasn't moved in thirty years and immediately gets attention. Things down here are hungry. I watch the tension.",
|
|
"Deep water fishing in the ruins of something ancient. The builders would have found this either sacrilegious or practical. I land on practical.",
|
|
}
|
|
|
|
var FishingUnderdark = []string{
|
|
"The underground river is cold and fast and the fish in it have evolved past needing eyes, which I find both efficient and slightly unsettling.",
|
|
"Fishing in total darkness in a river that doesn't appear on any surface map. I narrate by sound: the cast, the current, the eventual tension on the line.",
|
|
"The Eyeless King is in here somewhere. I don't say this out loud but think it very clearly. The line goes deep.",
|
|
}
|
|
|
|
var FishingFeywild = []string{
|
|
"Fey fishing. I watch the line for signs of time distortion — the way the reflection moves wrong, the way the fish seem to arrive before they bite. The Feywild is like this about everything.",
|
|
"The stream catches light that shouldn't be here and the fish reflect it from below. I watch something luminous move toward the hook and try to stay professional about it.",
|
|
"Like fishing in a dream. I mean this literally — the mechanics are the same but the rules feel advisory.",
|
|
}
|
|
|
|
// ─────────────────────────────────────────────────────────────────────────────
|
|
// PATROL ENCOUNTER LINES
|
|
// ─────────────────────────────────────────────────────────────────────────────
|
|
|
|
var PatrolEncounter = []string{
|
|
"A patrol. Moving between the cleared rooms with the confidence of something that considers them still theirs. I disagree with this assessment and will help you express the disagreement.",
|
|
"They found you between rooms, which is exactly where patrols are supposed to find you. Threat Clock noted; I suggest dispatching this quickly and quietly.",
|
|
"The patrol isn't looking for a fight — it's doing its job, which happens to involve you being somewhere you aren't supposed to be. I'll help you redefine 'supposed to.'",
|
|
"Two of them. Moving together. The coordination suggests the zone is at Alert or higher. Confirmed: it is. Fight or fade.",
|
|
}
|
|
|
|
// ─────────────────────────────────────────────────────────────────────────────
|
|
// LOOT DROP LINES — Generic
|
|
// ─────────────────────────────────────────────────────────────────────────────
|
|
|
|
var LootDropCommon = []string{
|
|
"They had something on them. I check it over. Common rarity — useful in the way that common things are useful, which is often.",
|
|
"Standard loot. Nothing that rewrites the story, but everything that keeps it going.",
|
|
"A drop. I catalog it efficiently and note: this is the economy of dungeons. Enemies have things. You take them. The loop continues.",
|
|
}
|
|
|
|
var LootDropUncommon = []string{
|
|
"Better than expected. I examine the drop with slightly elevated interest. Uncommon rarity — someone made this with intent.",
|
|
"An uncommon drop from a common enemy. Anomaly noted with satisfaction. The dungeon was generous in this room.",
|
|
"Uncommon. I turn it over once and nod. 'Keeper,' I say — which in my vocabulary means: this changes your math.",
|
|
}
|
|
|
|
var LootDropRare = []string{
|
|
"I stop. Actually stop. 'That's rare,' I say, with the specific register of someone who uses the word correctly and use it seldom.",
|
|
"A rare drop. I examine it the way you examine something that doesn't appear often — thoroughly, quietly, with appropriate appreciation.",
|
|
"The loot table gave you something uncommon and then kept going. Rare rarity. Filed in the column I reserve for things worth remembering.",
|
|
}
|
|
|
|
var LootDropLegendary = []string{
|
|
"I go very still. The drop sits in the light and I process what I am seeing. 'Legendary,' I say eventually. One word. That's all it needs.",
|
|
"Legendary rarity. I've seen a few of these in a long career and each time — each time — there is a moment that is separate from everything else. This is that moment. Pick it up carefully.",
|
|
"The dungeon produced a legendary item. I note the zone, the enemy, the day of the expedition, the Threat Clock value, the precise conditions. Some things deserve to be recorded completely.",
|
|
}
|