The banter moves to its own book, and learns new verses

BOT_LINES leaves the server internals for banter.ts, keyed by
semantic trigger instead of raw event type, so editing the clockwork's
voice takes no knowledge of the event stream. The repertoire grows
from fourteen lines to fifty across twelve occasions — grabbing and
delivering gold, dealing and taking pain, killing and dying,
summoning, walling, escaping, springing traps, dodging, and winning.

Bots also now speak when things happen TO them: the actor remarks on
its deeds, bystanders on their suffering — a berserker taking a hit
answers "I FELT THAT. DO IT AGAIN." even on your turn. Still at most
one voice per step, still half the time, menace over chatter.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
Eric Wagoner
2026-08-16 22:38:45 -04:00
co-authored by Claude Fable 5
parent d4565006bc
commit b01e27c644
2 changed files with 157 additions and 41 deletions
+119
View File
@@ -0,0 +1,119 @@
// The automatons' table talk, one voice per temperament. Edit freely — the
// server picks from these pools at random, sparingly (menace over chatter).
//
// Triggers: grabGold (picked up a treasure), deliverGold (dropped one on a
// home base), dealPain (hurt somebody), takePain (got hurt), kill, die,
// summon (created a creature), buildWall, escape (self-teleported away),
// springTrap (drew a TRAP card), dodge (an attack missed them), win.
import type { AutomatonStyle } from "@wizwar/engine";
export type BanterTrigger =
| "grabGold" | "deliverGold" | "dealPain" | "takePain" | "kill" | "die"
| "summon" | "buildWall" | "escape" | "springTrap" | "dodge" | "win";
export const BOT_LINES: Record<AutomatonStyle, Partial<Record<BanterTrigger, string[]>>> = {
hunter: {
grabGold: [
"ACQUISITION COMPLETE.",
"YOUR GOLD HAS BEEN REALLOCATED.",
"ASSET SECURED.",
"APPRAISAL: ADEQUATE. TAKING IT ANYWAY.",
],
deliverGold: [
"DELIVERY CONFIRMED. PLEASURE DOING BUSINESS.",
"LOGISTICS IS MY LOVE LANGUAGE.",
"RECEIPT AVAILABLE UPON REQUEST.",
],
dealPain: [
"AN INEFFICIENT USE OF YOUR TURN.",
"COSTS HAVE BEEN PASSED TO THE CONSUMER.",
"THIS IS BILLABLE.",
],
takePain: [
"DAMAGE NOTED. INVOICE PENDING.",
"THAT COMES OUT OF YOUR ESTATE.",
],
kill: [
"INVENTORY TRANSFERRED. CONDOLENCES.",
"ACCOUNT CLOSED.",
],
die: [
"FILING FOR BANKRUPTCY.",
"THE MARKET HAS CORRECTED.",
],
summon: ["A SUBCONTRACTOR HAS BEEN RETAINED."],
buildWall: ["ZONING APPROVED."],
escape: ["RELOCATION EXPENSES: JUSTIFIED."],
springTrap: ["AN UNFORESEEN LIABILITY."],
dodge: ["PROJECTIONS SAID YOU WOULD MISS."],
win: ["PLEASURE DOING BUSINESS WITH ALL OF YOU."],
},
berserker: {
grabGold: [
"GOLD IS MERELY BAIT.",
"SHINY. IRRELEVANT.",
],
dealPain: [
"YES. AGAIN.",
"PAIN RECEIPT PRINTED.",
"HOLD STILL. THIS IS THE FUN PART.",
"THE MAZE PROVIDES.",
],
takePain: [
"GOOD. NOW IT IS INTERESTING.",
"I FELT THAT. DO IT AGAIN.",
],
kill: [
"SCHEDULED DEMISE: DELIVERED.",
"NEXT.",
"THE PILE GROWS.",
],
die: [
"SAVE MY SEAT.",
"I WILL BE BACK FOR THE REMATCH.",
],
summon: [
"I HAVE MADE YOU A FRIEND. IT IS NOT FRIENDLY.",
"IT EATS WHAT I TELL IT TO EAT.",
],
buildWall: ["MORE CORNERS TO TRAP YOU IN."],
escape: ["A TACTICAL LEAP. NOT A RETREAT."],
springTrap: ["WHO PUT THAT THERE. RESPECT."],
dodge: ["SWING HARDER."],
win: ["LAST ONE STANDING. AS FORETOLD."],
},
worrier: {
grabGold: [
"taking this. sorry. sorry.",
"borrowing it. permanently. sorry.",
],
deliverGold: ["home. safe. breathe."],
dealPain: [
"ow. logged.",
"unnecessary!",
"that looked like it hurt. it was supposed to. i think.",
],
takePain: [
"rude.",
"i wrote it down. the list is long.",
],
kill: [
"oh no. oh no. it worked?",
"i'm not proud. mostly.",
],
die: [
"called it.",
"this is fine. this is fine. this is not fine.",
],
summon: ["please be nice to it. actually don't."],
buildWall: [
"good wall. safe wall.",
"one more wall between me and everything.",
],
escape: ["nope nope nope."],
springTrap: ["i knew the floor was suspicious."],
dodge: ["missed me. oh thank goodness. i mean: ha."],
win: ["wait. me? check again."],
},
};