mirror of
https://github.com/prosolis/gogobee.git
synced 2026-07-15 08:32:41 +00:00
Adv 2.0 D&D Phase 11 D9: !zone lore subcommand
Wires the existing GMLore narration pool (zone-specific LoreLines* + generic LoreLines fallback, all prewritten) into a !zone lore command. Deterministic per (run, room) — re-asking in the same room yields the same line; cross-room calls vary. No mood or state side-effects. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -60,6 +60,8 @@ func (p *AdventurePlugin) handleDnDZoneCmd(ctx MessageContext, args string) erro
|
||||
return p.zoneCmdTaunt(ctx)
|
||||
case "compliment":
|
||||
return p.zoneCmdCompliment(ctx)
|
||||
case "lore", "history":
|
||||
return p.zoneCmdLore(ctx)
|
||||
default:
|
||||
return p.SendDM(ctx.Sender, zoneHelpText())
|
||||
}
|
||||
@@ -75,7 +77,8 @@ func zoneHelpText() string {
|
||||
b.WriteString("`!zone advance` — resolve the current room and move on\n")
|
||||
b.WriteString("`!zone abandon` — end the active run (no rewards)\n")
|
||||
b.WriteString("`!zone taunt` — poke TwinBee (mood −10)\n")
|
||||
b.WriteString("`!zone compliment` — flatter TwinBee (mood +5)")
|
||||
b.WriteString("`!zone compliment` — flatter TwinBee (mood +5)\n")
|
||||
b.WriteString("`!zone lore` — TwinBee shares zone history")
|
||||
return b.String()
|
||||
}
|
||||
|
||||
@@ -541,6 +544,30 @@ func (p *AdventurePlugin) zoneMoodInteraction(
|
||||
return p.SendDM(ctx.Sender, b.String())
|
||||
}
|
||||
|
||||
// ── lore ────────────────────────────────────────────────────────────────────
|
||||
|
||||
// zoneCmdLore renders a deterministic TwinBee lore line for the active
|
||||
// run's current room. Pulls from the zone-specific LoreLines* pool when
|
||||
// one exists (Tier 1–5 ship dedicated lore), falls back to the generic
|
||||
// LoreLines pool otherwise. roomIdx is folded into the selector so
|
||||
// repeated `!zone lore` in the same room returns the same prose, but
|
||||
// cross-room calls vary.
|
||||
func (p *AdventurePlugin) zoneCmdLore(ctx MessageContext) error {
|
||||
run, err := getActiveZoneRun(ctx.Sender)
|
||||
if err != nil {
|
||||
return p.SendDM(ctx.Sender, "Couldn't read run state: "+err.Error())
|
||||
}
|
||||
if run == nil {
|
||||
return p.SendDM(ctx.Sender, "No active zone run. Use `!zone enter <id>`.")
|
||||
}
|
||||
zone, _ := getZone(run.ZoneID)
|
||||
line := twinBeeLine(zone.ID, GMLore, run.RunID, run.CurrentRoom)
|
||||
if line == "" {
|
||||
return p.SendDM(ctx.Sender, "TwinBee has nothing to say about this place.")
|
||||
}
|
||||
return p.SendDM(ctx.Sender, fmt.Sprintf("📖 **%s — Lore**\n\n%s", zone.Display, line))
|
||||
}
|
||||
|
||||
// ── abandon ─────────────────────────────────────────────────────────────────
|
||||
|
||||
func (p *AdventurePlugin) zoneCmdAbandon(ctx MessageContext) error {
|
||||
|
||||
@@ -318,6 +318,47 @@ func TestZoneCmd_TauntWithoutRunNoCrash(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
// Phase 11 D9 — !zone lore.
|
||||
|
||||
func TestZoneCmd_LoreWithoutRunNoCrash(t *testing.T) {
|
||||
setupAuditTestDB(t)
|
||||
uid := id.UserID("@zone-cmd-lore-norun:example")
|
||||
zoneCmdTestCharacter(t, uid, 1)
|
||||
defer cleanupZoneRuns(uid)
|
||||
p := &AdventurePlugin{}
|
||||
if err := p.handleDnDZoneCmd(MessageContext{Sender: uid}, "lore"); err != nil {
|
||||
t.Fatalf("lore no-run: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestZoneCmd_LoreWithActiveRunNoSideEffects(t *testing.T) {
|
||||
setupAuditTestDB(t)
|
||||
uid := id.UserID("@zone-cmd-lore-run:example")
|
||||
zoneCmdTestCharacter(t, uid, 1)
|
||||
defer cleanupZoneRuns(uid)
|
||||
p := &AdventurePlugin{}
|
||||
if err := p.handleDnDZoneCmd(MessageContext{Sender: uid}, "enter goblin_warrens"); err != nil {
|
||||
t.Fatalf("enter: %v", err)
|
||||
}
|
||||
before, err := getActiveZoneRun(uid)
|
||||
if err != nil || before == nil {
|
||||
t.Fatalf("active run after enter: %v", err)
|
||||
}
|
||||
if err := p.handleDnDZoneCmd(MessageContext{Sender: uid}, "lore"); err != nil {
|
||||
t.Fatalf("lore: %v", err)
|
||||
}
|
||||
after, err := getActiveZoneRun(uid)
|
||||
if err != nil || after == nil {
|
||||
t.Fatalf("active run after lore: %v", err)
|
||||
}
|
||||
if after.GMMood != before.GMMood {
|
||||
t.Errorf("lore should not move mood: before %d, after %d", before.GMMood, after.GMMood)
|
||||
}
|
||||
if after.CurrentRoom != before.CurrentRoom {
|
||||
t.Errorf("lore should not advance room: before %d, after %d", before.CurrentRoom, after.CurrentRoom)
|
||||
}
|
||||
}
|
||||
|
||||
func TestTauntComplimentResponseLines_Deterministic(t *testing.T) {
|
||||
const runID = "run-d7-test"
|
||||
t1 := tauntResponseLine(runID, 0)
|
||||
|
||||
Reference in New Issue
Block a user