Combines all uncommitted D&D work into one checkpoint: Phases 1-8 (per gogobee_dnd_session_summary.md): - Race/class/stats system, !setup flow, !sheet, !respec - d20-vs-AC combat with race/class passives, auto-migration - XP/level-up, skill checks, NPC refund hooks - Equipment slot mapping, rarity, !rest short/long - Pre-arm active abilities, resource pools - Bestiary, !roll/!stats/!level, onboarding DM - Audit fixes A-I, flavor wiring under internal/flavor/ - Phase 8 weapon dice + armor AC tables (gogobee_equipment_appendix) Phase 9 SP1 — spell system foundations: - 79 SpellDefinitions (76 in-scope + 3 reaction-deferred) - dnd_known_spells, dnd_spell_slots tables - pending_cast / concentration_* columns on dnd_character - Slot tables for Mage/Cleric/Ranger, DC + attack-bonus math - Long-rest refreshes slots; respec wipes spell state - Auto-grant default known list on !setup confirm and auto-migration Phase 9 SP2 — !cast / !spells / !prepare commands: - Out-of-combat HEAL and UTILITY resolve immediately - Damage/control/buff queue as pending_cast for next combat - Audit-style save-then-debit, slot refund on save failure - !cast --drop, concentration supersession, prep-cap enforcement - Reaction spells refused with Phase 11 note SP3 (combat-time resolution of pending_cast) and SP4 (full prep/learn tests) are next. Build clean, full test suite green. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
22 KiB
GogoBee — D&D Integration Design Document (v1.1, annotated)
Version: 1.1 — integration revision Status: Draft, supersedes v1.0 for implementation purposes Predecessor:
gogobee_dnd_design_doc.md(v1.0) — kept as the vision document Scope: Same as v1.0, reconciled against the existinginternal/plugin/adventure_*.goandinternal/db/db.gocodebase See also:gogobee_equipment_appendix.md
⚠️ Protected Files — DO NOT MODIFY
Unchanged from v1.0. All *_flavor.go / *_flavor.txt files, files containing the DO NOT REWRITE header, and NPC spec files (Thom Krooke, Misty, Arina) are immutable. New D&D flavor lives in new files (dnd_flavor_*.go), never as edits to existing flavor.
0. Why v1.1 exists
v1.0 was written without auditing the live adventure system. A literal implementation would destroy working features and player progress. This revision:
- Treats the existing adventure systems as ground truth. The D&D layer is additive, not a replacement.
adventure_charactersand friends keep their columns and semantics; D&D adds nullable columns and new tables alongside. - Preserves all player progress. Every column in
adventure_characters,adventure_equipment,adventure_inventory,adventure_treasures,adventure_buffs,user_archetypes,arena_stats,adventure_rival_records,adventure_babysit_log,holdem_scores,euro_balances, etc. is preserved unchanged. Migrations are column-adds with defaults only — no drops, no renames. - Gates D&D content on opt-in. A
pending_setupflag means non-opted-in players continue with the current adventure system unchanged. D&D-flavored output (!sheet, combat resolution narration) is only shown to players who have completed!setup. - Re-uses what already exists rather than reinventing it:
combat_levelbecomes D&D level,adventure_treasuresbecomes the attunement substrate,adventure_equipmentslots map forward,user_archetypesdrives class/race inference (already designed for this).
Wherever this revision diverges from v1.0, the divergence is annotated with [REVISED] and a one-line rationale.
1. Overview & Goals
Unchanged from v1.0 except for one added principle:
- Layered, not replaced. D&D mechanics sit on top of the existing adventure systems. The world layer (skills, encounters, loot, babysit, rivals, housing) keeps running; the character layer (race/class/HP/AC/abilities) is a new lens over it.
2. Existing System Inventory — actual state
[REVISED — v1.0's table was aspirational. This is what's actually in internal/db/db.go and internal/plugin/:]
2.1 Player tables (preserve every column)
| Table | Key columns | Status |
|---|---|---|
adventure_characters |
user_id (PK), display_name, combat_level, combat_xp, mining_skill/mining_xp, foraging_skill/foraging_xp, fishing_skill/fishing_xp, alive, dead_until, action_taken_today, holiday_action_taken, current_streak, best_streak, arena_wins, arena_losses, invasion_score, pet_*, house_*, babysit_*, auto_babysit, misty_buff_expires, misty_debuff_expires, arina_buff_expires |
Preserve all. D&D columns added nullable. |
adventure_equipment |
(user_id, slot) PK, tier, condition, name, actions_used, masterwork, skill_source |
Preserve. Add nullable D&D columns: rarity, stat_bonus_json, attuned. |
adventure_inventory |
id (PK), user_id, name, item_type, tier, value, slot, skill_source |
Preserve. Add nullable rarity, stat_bonus_json. |
adventure_treasures |
(user_id, treasure_key, bonus_type) UNIQUE, bonus_value (REAL) |
Preserve and re-use as attunement substrate (Section 7.3). |
adventure_buffs |
user_id, buff_type, buff_name, modifier, expires_at |
Preserve. Used for D&D conditions. |
user_archetypes |
(user_id, archetype) PK, category, signal_score, flavor, assigned_at |
Preserve. Drives migration inference (Section 11). |
arena_runs, arena_history, arena_stats |
streaks, win/loss, history | Preserve. Combat resolution swaps under the hood; records stay. |
adventure_rival_challenges, adventure_rival_records |
challenge state, head-to-head records | Preserve. RPS resolver replaced; tables untouched. |
adventure_babysit_log |
activity, outcome, gold, XP, items_dropped per day | Preserve. Babysit stays independent. |
euro_balances |
coin balance | Preserve. Coins are euros; no separate D&D gold. |
hangman_scores, blackjack_scores, holdem_scores |
per-game scores | Preserve. Independent of D&D layer. |
2.2 New tables for D&D layer
| Table | Purpose |
|---|---|
dnd_character |
Per-player D&D state: race, class, hp_current, hp_max, temp_hp, ac, str/dex/con/int/wis/cha, dnd_level, pending_setup, created_at, updated_at. One row per player after !setup; absent before. |
dnd_abilities |
(user_id, ability_id) — known abilities and uses-remaining of the relevant resource. |
dnd_resources |
(user_id, resource_type) — current Stamina/Focus/Mana/DivineFavor; reset on rest. |
dnd_combat_state |
Active combat encounter (round, turn, conditions JSON, log JSON). Cleared on combat end. |
adventure_characters_pre_dnd |
One-shot mirror of adventure_characters taken at deploy time. Rollback safety net. |
2.3 Things that don't yet exist anywhere
- HP, AC, ability scores, conditions in any persistent form
- Initiative, attack rolls, saving throws — current arena/rival are RPS or level-comparison
- Global player XP separate from skill XP
These are genuinely new and require fresh implementation; everything else is layering.
3. Character System
3.1 Races, 3.2 Classes, 3.3 Ability Scores
Tables unchanged from v1.0. The race/class tables and stat-modifier formula stand.
[REVISED] Class ↔ archetype inference is now keyed to the real archetype names from archetype.go, not the abstract categories in v1.0:
| Archetype (real) | Suggested Class | Suggested Race |
|---|---|---|
| Arena Champion / Dungeon Crawler | Fighter | Orc / Human |
| The Merchant / Whale | Rogue | Halfling / Human |
| Novelist / Philosopher / Wordsmith / Linkmaster | Mage | Elf / Tiefling |
| Cheerleader / Hype Machine / Patron / Reactor | Cleric | Dwarf / Half-Elf |
| The Angler / The Forager / The Adventurer | Ranger | Human / Elf |
| Fallback (Regular, Wildcard, no clear signal) | Human Fighter | (presented as suggestion only) |
When a player has multiple archetypes, the highest signal_score wins. Ties broken by archetype priority list defined in code.
3.4 Go data model
[REVISED] Drop the v1.0 CharacterSheet struct in favor of a model that mirrors the actual table layout and keeps adventure_characters as the source of truth for everything that already exists there.
// DnDCharacter is the new persistent layer. Joined with adventure_characters at read time.
type DnDCharacter struct {
UserID string
Race Race
Class Class
DnDLevel int // derived from combat_level at migration; advances independently after
HP HPBlock
AC int
Stats BaseStats // STR/DEX/CON/INT/WIS/CHA
PendingSetup bool // true until !setup completes
CreatedAt time.Time
UpdatedAt time.Time
}
// CharacterView is a read-only join used by !sheet and combat.
// Always construct via repository.LoadCharacterView(userID) — never instantiate directly.
type CharacterView struct {
Adv AdventureCharacter // existing struct from adventure_character.go
DnD *DnDCharacter // nil when player hasn't run !setup
Eq []EquipmentRow // existing
Inv []InventoryRow // existing
Treas []TreasureRow // existing — surfaces as attunements when DnD != nil
}
Race, Class, BaseStats, HPBlock constants and types follow v1.0 exactly.
4. Leveling System
[REVISED — this is the largest change from v1.0.]
v1.0 specifies a fresh XP curve (300, 900, 2700…) with no relationship to existing skill XP. That throws away hours of player progress. Instead:
4.1 Initial mapping (one-time, at !setup completion)
dnd_level = max(1, combat_level) // direct adoption — combat_level is literally a combat level
xp_carryover = 0 // dnd has its own XP track going forward
Skill levels (mining/foraging/fishing) and their XP pools are untouched. They keep advancing on their own from gathering activities.
4.2 New XP sources for D&D level
D&D level advances from:
- Combat encounters (arena wins, rival duels, monster kills) — primary source
- Quest/event completions
- NPC skill-check successes (small amounts)
Not from gathering. Mining XP keeps going to mining; that channel is unchanged.
4.3 XP curve from level N onward
The cumulative table from v1.0 (L2=300, L3=900, L5=2700, L10=14000, L20=85000) applies, but as XP earned past initial level, not from zero. A player migrated in at combat_level=8 starts D&D Level 8 with 0/required-for-9 XP.
4.4 Level-up flow
Same as v1.0 (5 steps, including stat point allocation and subclass prompt at L5). Level-up flavor must be class-specific and lives in a new dnd_flavor_levelup.go (new file, not editing existing flavor).
5. Combat Engine — staged rollout
[REVISED] v1.0 specifies the full D&D combat flow as if combat were greenfield. It isn't — arena and rival have semantics today, plus history. Stage the rollout:
5.1 Stage A — Arena conversion (do first)
- Replace the level-comparison + 50/50 winner logic with full D&D resolution (initiative → attack rolls vs. AC → damage → conditions).
- Preserve:
arena_stats,arena_history,current_streak,best_streak,arena_wins,arena_lossesrows. New combat writes to the same tables. - Streak bonuses (+5%/3-streak, etc.) become combat modifiers in the new resolver.
- Non-opted-in players (no
dnd_characterrow) still hit the legacy resolver. The arena gracefully runs both.
5.2 Stage B — Rival conversion (do second)
- Replace RPS in
adventure_rival.gowith D&D combat. adventure_rival_recordsandadventure_rival_challengesschemas unchanged. New resolver writes the same rows.- Stake calculation (
(combatLevel/5)*1000euros) preserved.
5.3 Stage C — Encounter combat (new)
- New monsters / dungeon encounters use D&D combat from day one. No legacy path.
5.4 Combat resolution flow, AC, conditions, data model
Sections 5.1, 5.2, 5.3, 5.4 of v1.0 stand as the spec for how combat works. Apply at the resolver layer; persist via dnd_combat_state (new table).
6. Abilities & Spells
Unchanged from v1.0. Resources persist in dnd_resources (new table). Reset triggered by !rest short/!rest long (Section 10 below — note the rename).
7. Equipment & Item System
7.1, 7.2 Rarity & Slots
Tables stand from v1.0.
7.3 Slot mapping — additive, not replacement
[REVISED] Existing adventure_equipment has 5 slots. Map them forward instead of orphaning gear:
| Existing slot | D&D slot |
|---|---|
weapon |
main_hand |
armor |
chest |
helmet |
head |
boots |
feet |
tool |
off_hand (or hands, by item type) |
Old gear keeps tier, condition, masterwork. Inferred rarity is computed from tier at migration (e.g., tier 1-2 → Common, 3-4 → Uncommon, 5-6 → Rare, 7+ → Epic). New rarity column is nullable; legacy items render fine without it.
D&D adds the new slots (legs, hands if not already mapped, ring_1, ring_2, amulet) — these start empty for migrated players.
7.4 Attunement = adventure_treasures
[REVISED] v1.0 invents a parallel attunement system. Don't. adventure_treasures already encodes named bonuses with stat modifiers per player — that's exactly an attunement record.
- The 3-item attunement cap = a row-count constraint on
adventure_treasuresperuser_id. bonus_typeandbonus_value(REAL) feed directly into stat resolution.- New magic items granted post-D&D-launch insert rows into the same table.
- Legacy treasures are automatically "attuned" — no migration step required.
7.5 Go data model
Use a thin wrapper that joins adventure_equipment + adventure_inventory + adventure_treasures at read time. Don't introduce a new Inventory/EquipmentSlots struct that duplicates state.
8. Monster Bestiary
Unchanged from v1.0. New tables, new flavor file (dnd_flavor_monsters.go).
9. Skill Check System
Unchanged from v1.0. NPC wiring (Thom Krooke / Misty / Arina) is purely new logic; no schema change.
One nuance: the existing Misty/Arina buff/debuff timestamp columns (misty_buff_expires, misty_debuff_expires, arina_buff_expires) stay as-is and become the persistence layer for skill-check-granted buffs. Don't add parallel buff tracking.
10. Rest System — naming collision resolved
[REVISED]
!adventure rest already exists as a daily-action narrative activity. It's not the same thing as a D&D short/long rest.
Rename and split:
!adventure camp— what!adventure restis today. Daily-action narrative day-skip. (Old command remains as an alias for one release for backwards compat.)!rest short— D&D short rest. No daily-action cost. 1-hour cooldown. Recovers 1d6+CON HP; resets short-rest resources (Fighter Stamina, Rogue/Ranger Focus).!rest long— D&D long rest. Requires housing or paid inn use (Thom Krooke). 24-hour cooldown. Full reset.
Babysit interaction: babysitting is independent of rest. A player on auto-babysit can still !rest short. !rest long while babysitting is allowed and does not interrupt the babysit log.
11. Player Onboarding & Migration
11.1 New user flow
Unchanged from v1.0. A new player runs !setup and gets the 4-step race/class/stats/welcome flow. This creates their adventure_characters row (if absent) and their dnd_character row in one transaction.
11.2 Existing user migration
[REVISED] Migration is opt-in via pending_setup. No data is mutated until the player runs !setup.
At deploy:
- Snapshot
adventure_characters→adventure_characters_pre_dnd(rollback safety). - No row changes. No
dnd_characterrows created. Every existing player is implicitlypending_setup = truebecause the row simply doesn't exist yet. - Bot DMs each active player once with the v1.0 migration message (suggested race/class from archetype, "Yes / No, let me choose / Skip for now"). Reminder cadence per v1.0 (every 7 days, auto-assign at 30 days).
While pending_setup is true:
- All existing
!adventure ...commands work exactly as before. - D&D-only commands (
!sheet,!stats,!use,!rest short/long,!check) prompt for setup. - Arena/rival use the legacy resolver.
After !setup:
dnd_characterrow is created.dnd_level = combat_level(Section 4.1).- HP_max computed from class HP die + CON modifier × level. Current HP set to max.
- AC computed from equipped armor + DEX. (Old armor maps via Section 7.3.)
- Arena/rival flip to D&D resolver for this user.
11.3 Auto-assign
After 30 days pending_setup and at least one prior interaction, auto-create dnd_character using inferred race/class from archetype. Player notified once: "We started a sheet for you — !setup to change it."
11.4 Data preservation guarantees
| Existing data | Guarantee |
|---|---|
euro_balances |
Untouched. Coins do not convert. |
Skill levels & XP (mining_*, foraging_*, fishing_*) |
Untouched. Skill grind continues independently. |
combat_level |
Read once at !setup to seed dnd_level. After that, both fields exist and advance independently (combat_level keeps incrementing on legacy paths if any remain; dnd_level is the canonical character level for D&D). |
combat_xp |
Untouched. Used as legacy display. |
Pets (pet_*) |
Untouched. Ranger gets passive bonus on top. |
arena_wins/losses/current_streak/best_streak |
Untouched. New combats append to the same counters. |
adventure_inventory |
Untouched. Items render with inferred rarity until D&D fields populated by new drops. |
adventure_equipment |
Untouched. Slot mapping is read-time, not a migration. |
adventure_treasures |
Untouched. Becomes attunement display source. |
adventure_buffs |
Untouched. Used for new condition tracking too. |
user_archetypes |
Untouched. Drives inference; retained for flavor post-setup. |
house_tier, house_loan_* |
Untouched. Drives long-rest eligibility. |
adventure_babysit_log and babysit fields |
Untouched. Babysit independent of D&D. |
holdem_scores, hangman_scores, blackjack_scores |
Untouched. Out of D&D scope entirely. |
Rollback plan: drop the new D&D tables and the nullable D&D columns. adventure_characters_pre_dnd is the integrity check that nothing was clobbered. If anything in adventure_characters differs from the pre-DnD snapshot at rollback time, that's a bug — restore the affected rows from the snapshot.
12. Cross-System Integration
Substantively unchanged from v1.0, with these additions:
- Babysit is independent of D&D. Stays as-is.
- Forex / lottery / coop dungeon / holdem are out of D&D scope and unchanged.
- Skill XP from gathering does not feed D&D level. Two distinct progression tracks (skill grind vs. D&D character level) coexist.
13. Commands Reference
v1.0's table stands, with these additions/clarifications:
| Command | Note |
|---|---|
!adventure camp |
Renamed from !adventure rest. Old name kept as alias for one release. |
!rest short / !rest long |
New D&D rests, gated on dnd_character existing. |
!equip <item> |
Subsumes !adventure equip. Routes to legacy masterwork-equip path when item is masterwork; otherwise D&D equip. |
!inventory |
Extends !adventure inventory with rarity/attunement display. Legacy !adventure inventory continues to work. |
!sheet, !stats, !level, !abilities, !use, !check, !roll, !respec, !attune, !unequip, !setup |
All new, no current implementation. |
14. Implementation Phases — revised
[REVISED — replaces v1.0 Section 14 in full.]
Phase 1 — Layering proof (smallest viable change)
Goal: prove D&D layers cleanly on existing data without changing any behavior for existing players.
- Schema: add
dnd_character,dnd_abilities,dnd_resources,dnd_combat_statetables. Add nullable D&D columns toadventure_equipment/adventure_inventory. - One-shot snapshot
adventure_characters_pre_dndat deploy. combat_level→ D&D level mapping function (read-only).!setupflow (4-step) with archetype inference.!sheetrendering — read-only join over existing data +dnd_character. No behavior change.pending_setupgating on D&D-only commands.
Exit criteria: opted-in player sees correct !sheet. Non-opted-in player notices nothing different.
Phase 2 — Combat engine + arena conversion (Stage A)
- Initiative, attack rolls vs. AC, crit/fumble, damage, conditions, saving throws.
- HP/AC computation on
!setupand on level-up. - Arena resolver swap for opted-in players. Legacy resolver kept for non-opted-in.
dnd_combat_statepersistence and combat log.
Phase 3 — Abilities, resources, leveling
- XP tracking (D&D-level XP separate from skill XP).
- Level-up flow with class-specific flavor (new
dnd_flavor_levelup.go). - Starter abilities per class.
!use,!abilitiescommands.- Resource tracking and short/long rest reset.
Phase 4 — Equipment expansion + attunement re-use
- Equipment slot mapping (Section 7.3).
- Rarity inference for legacy gear at read time.
adventure_treasures-as-attunement (Section 7.4).!equip,!unequip,!attune,!inventorysubsuming legacy commands.- Thom Krooke shop additions (Common/Uncommon equipment, potions).
Phase 5 — Skill checks + NPC integration
- Skill check resolver, DC table.
- Wire Thom Krooke (Persuasion), Misty (Insight), Arina (Arcana) using existing buff timestamp columns.
!checkcommand.
Phase 6 — Rest system
!rest short/!rest longwith housing gating.- Inn cost at Thom Krooke.
- Rename
!adventure rest→!adventure campwith alias.
Phase 7 — Monsters, rival conversion (Stage B), encounter combat (Stage C)
- Starter bestiary (Section 8.2 minimum) in new files.
- Rival RPS → D&D combat swap.
- Encounter-driven combat for new content.
- Cross-system polish (Ranger pet/fishing bonuses on top of existing bonuses).
15. Configuration Constants
Unchanged from v1.0. Add:
const (
DnDLevelFromCombatLevel = true // initial mapping at !setup
PendingSetupReminderDays = 7
PendingSetupAutoAssignDays = 30
LegacyArenaResolverEnabled = true // until 100% of active players opted in
)
16. Out of Scope
Same as v1.0. Plus:
- Forex, lottery, coop dungeon, holdem, blackjack, hangman, tarot, uno — stay out of D&D.
- Skill grind XP feeding D&D level — explicitly rejected. Two tracks.
- Coin → gold conversion — euros stay euros.
17. Open questions (must be resolved before Phase 1 ships)
- Stat generation method at
!setup: point-buy (27 points, standard array) or 4d6-drop-lowest? (v1.0 left TBD.) - Respec cost / cooldown. (v1.0 TBD.)
- Inn cost for long rest at Thom Krooke. (v1.0 TBD.)
combat_levelpost-setup: does it keep advancing on legacy paths, or freeze at setup time and onlydnd_levelmoves forward? Recommend freeze.- Subclass content for L5 prompt. v1.0 defers; need at least placeholder choices to not block the level-up flow.
End of v1.1. Differences from v1.0 are tagged [REVISED]. Where this document is silent, v1.0 is authoritative. Where they conflict, v1.1 wins for implementation purposes.