mirror of
https://github.com/prosolis/gogobee.git
synced 2026-07-16 00:52:40 +00:00
Adv 2.0 D&D layer: Phases 1-8 + Phase 9 SP1+SP2
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>
This commit is contained in:
@@ -94,6 +94,8 @@ type AdventureCharacter struct {
|
||||
PetLevel10Date string
|
||||
PetMorningDefense bool
|
||||
AutoBabysit bool
|
||||
AutoBabysitFocus string // mining|fishing|foraging — preferred skill for auto-babysit; "" defaults to weakest
|
||||
TreasuresLocked bool // when true, treasure drops at cap are refused instead of auto-swapping
|
||||
StreakDecayed bool
|
||||
CraftsSucceeded int
|
||||
DeathSource string // "adventure" | "arena" | "" (legacy/unknown — treated as adventure)
|
||||
@@ -378,7 +380,17 @@ func xpToNextLevel(level int) int {
|
||||
|
||||
// checkAdvLevelUp checks if a character leveled up in the given skill and applies it.
|
||||
// Returns whether a level-up occurred and the new level.
|
||||
//
|
||||
// Combat is special-cased: once a player has confirmed a D&D character,
|
||||
// combat_level freezes. dnd_level (driven by dnd_xp via grantDnDXP) is
|
||||
// canonical going forward. Combat XP still accrues into combat_xp for
|
||||
// historical display, but never causes combat_level to advance.
|
||||
// Skill levels (mining/foraging/fishing) are unaffected and continue to
|
||||
// progress on their own track per v1.1 §4.
|
||||
func checkAdvLevelUp(char *AdventureCharacter, skill string) (bool, int) {
|
||||
if skill == "combat" && HasCompletedSetup(char.UserID) {
|
||||
return false, char.CombatLevel
|
||||
}
|
||||
var xp *int
|
||||
var level *int
|
||||
switch skill {
|
||||
@@ -426,7 +438,7 @@ func loadAdvCharacter(userID id.UserID) (*AdventureCharacter, error) {
|
||||
|
||||
var houseFrozen, houseAutopay int
|
||||
var petChasedAway, petReactivated, petArrived, thomAnimalLine, petSupplyUnlocked, petMorningDef int
|
||||
var autoBabysit, streakDecayed int
|
||||
var autoBabysit, streakDecayed, treasuresLocked int
|
||||
|
||||
err := d.QueryRow(`
|
||||
SELECT user_id, display_name,
|
||||
@@ -453,7 +465,7 @@ func loadAdvCharacter(userID id.UserID) (*AdventureCharacter, error) {
|
||||
misty_encounter_count, misty_donated_count,
|
||||
thom_animal_line_fired, pet_supply_shop_unlocked, pet_level10_date,
|
||||
pet_morning_defense, auto_babysit, streak_decayed, crafts_succeeded,
|
||||
death_source, death_location
|
||||
death_source, death_location, auto_babysit_focus, treasures_locked
|
||||
FROM adventure_characters WHERE user_id = ?`, string(userID)).Scan(
|
||||
&c.UserID, &c.DisplayName,
|
||||
&c.CombatLevel, &c.MiningSkill, &c.ForagingSkill, &c.FishingSkill,
|
||||
@@ -479,7 +491,7 @@ func loadAdvCharacter(userID id.UserID) (*AdventureCharacter, error) {
|
||||
&c.MistyEncounterCount, &c.MistyDonatedCount,
|
||||
&thomAnimalLine, &petSupplyUnlocked, &c.PetLevel10Date,
|
||||
&petMorningDef, &autoBabysit, &streakDecayed, &c.CraftsSucceeded,
|
||||
&c.DeathSource, &c.DeathLocation,
|
||||
&c.DeathSource, &c.DeathLocation, &c.AutoBabysitFocus, &treasuresLocked,
|
||||
)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -491,6 +503,7 @@ func loadAdvCharacter(userID id.UserID) (*AdventureCharacter, error) {
|
||||
c.BabysitActive = babysitAct == 1
|
||||
c.PetMorningDefense = petMorningDef == 1
|
||||
c.AutoBabysit = autoBabysit == 1
|
||||
c.TreasuresLocked = treasuresLocked == 1
|
||||
c.StreakDecayed = streakDecayed == 1
|
||||
if deadUntil.Valid {
|
||||
c.DeadUntil = &deadUntil.Time
|
||||
@@ -650,7 +663,9 @@ func saveAdvCharacter(char *AdventureCharacter) error {
|
||||
streak_decayed = ?,
|
||||
crafts_succeeded = ?,
|
||||
death_source = ?,
|
||||
death_location = ?
|
||||
death_location = ?,
|
||||
auto_babysit_focus = ?,
|
||||
treasures_locked = ?
|
||||
WHERE user_id = ?`,
|
||||
char.DisplayName, char.CombatLevel, char.MiningSkill, char.ForagingSkill, char.FishingSkill,
|
||||
char.CombatXP, char.MiningXP, char.ForagingXP, char.FishingXP,
|
||||
@@ -678,11 +693,20 @@ func saveAdvCharacter(char *AdventureCharacter) error {
|
||||
streakDecayed,
|
||||
char.CraftsSucceeded,
|
||||
char.DeathSource, char.DeathLocation,
|
||||
char.AutoBabysitFocus,
|
||||
boolToInt(char.TreasuresLocked),
|
||||
string(char.UserID),
|
||||
)
|
||||
return err
|
||||
}
|
||||
|
||||
func boolToInt(b bool) int {
|
||||
if b {
|
||||
return 1
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func loadAdvEquipment(userID id.UserID) (map[EquipmentSlot]*AdvEquipment, error) {
|
||||
d := db.Get()
|
||||
rows, err := d.Query(`
|
||||
@@ -809,7 +833,7 @@ func loadAllAdvCharacters() ([]AdventureCharacter, error) {
|
||||
misty_encounter_count, misty_donated_count,
|
||||
thom_animal_line_fired, pet_supply_shop_unlocked, pet_level10_date,
|
||||
pet_morning_defense, auto_babysit, streak_decayed, crafts_succeeded,
|
||||
death_source, death_location
|
||||
death_source, death_location, auto_babysit_focus, treasures_locked
|
||||
FROM adventure_characters`)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -824,7 +848,7 @@ func loadAllAdvCharacters() ([]AdventureCharacter, error) {
|
||||
var mistyLastSeen, arinaLastSeen, mistyBuffExp, mistyDebuffExp, arinaBuffExp sql.NullTime
|
||||
var houseFrozen, houseAutopay int
|
||||
var petChasedAway, petReactivated, petArrived, thomAnimalLine, petSupplyUnlocked, petMorningDef int
|
||||
var autoBabysit, streakDecayed int
|
||||
var autoBabysit, streakDecayed, treasuresLocked int
|
||||
if err := rows.Scan(
|
||||
&c.UserID, &c.DisplayName,
|
||||
&c.CombatLevel, &c.MiningSkill, &c.ForagingSkill, &c.FishingSkill,
|
||||
@@ -850,7 +874,7 @@ func loadAllAdvCharacters() ([]AdventureCharacter, error) {
|
||||
&c.MistyEncounterCount, &c.MistyDonatedCount,
|
||||
&thomAnimalLine, &petSupplyUnlocked, &c.PetLevel10Date,
|
||||
&petMorningDef, &autoBabysit, &streakDecayed, &c.CraftsSucceeded,
|
||||
&c.DeathSource, &c.DeathLocation,
|
||||
&c.DeathSource, &c.DeathLocation, &c.AutoBabysitFocus, &treasuresLocked,
|
||||
); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -861,6 +885,7 @@ func loadAllAdvCharacters() ([]AdventureCharacter, error) {
|
||||
c.BabysitActive = babysitAct == 1
|
||||
c.PetMorningDefense = petMorningDef == 1
|
||||
c.AutoBabysit = autoBabysit == 1
|
||||
c.TreasuresLocked = treasuresLocked == 1
|
||||
c.StreakDecayed = streakDecayed == 1
|
||||
c.HouseLoanFrozen = houseFrozen == 1
|
||||
c.HouseAutopay = houseAutopay == 1
|
||||
|
||||
Reference in New Issue
Block a user