mirror of
https://github.com/prosolis/gogobee.git
synced 2026-07-16 08:52:42 +00:00
N5/D1c: the finale — !expedition start epilogue
Closes the Hollow King arc with a solo one-shot boss fight, reached via
`!expedition start epilogue` (intercepted before the zone/loadout
machinery). Unlock: all 24 journal pages found + both Tier-5 zones cleared.
- Encounter: runZoneCombat + renderBossOutcome, the arena's own pattern —
no supplies, no walk, no party, no new mechanics. The stat block is
Belaxath's (the abyss boss whose gate "lets one thing come home")
re-dressed as the King returned in full, HP ×1.25 for a capstone; the
ability/AC/CR carry over unchanged.
- Reward-once: first clear grants a unique title ("Kingsbane") + one
Legendary + a games-room notice; later clears are a flavour-only
rematch. The flag is a dedicated player_meta.epilogue_cleared column,
latched by an atomic UPDATE (never the bulk save) so the monotonic
false→true can't be clobbered — same discipline as D1a's journal
bitmask. A loss costs a death, as any boss fight does.
- Title is written after a fresh character reload so runZoneCombat's
post-fight HP persist isn't overwritten (the survivalist-milestone
gotcha).
Golden byte-identical; go test ./... green.
Claude-Session: https://claude.ai/code/session_017mEwUmmS7aQTP2NQXj6rUa
This commit is contained in:
@@ -421,6 +421,33 @@ func grantJournalPageDB(userID id.UserID, page int) error {
|
||||
return err
|
||||
}
|
||||
|
||||
// loadEpilogueCleared reads the finale reward-once flag (N5/D1c).
|
||||
func loadEpilogueCleared(userID id.UserID) (bool, error) {
|
||||
var cleared int
|
||||
err := db.Get().QueryRow(
|
||||
`SELECT epilogue_cleared FROM player_meta WHERE user_id = ?`,
|
||||
string(userID),
|
||||
).Scan(&cleared)
|
||||
if err == sql.ErrNoRows {
|
||||
return false, nil
|
||||
}
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
return cleared != 0, nil
|
||||
}
|
||||
|
||||
// markEpilogueClearedDB latches the finale reward-once flag atomically, so the
|
||||
// monotonic false→true set survives any concurrent character save.
|
||||
func markEpilogueClearedDB(userID id.UserID) error {
|
||||
_, err := db.Get().Exec(
|
||||
`INSERT INTO player_meta (user_id, epilogue_cleared) VALUES (?, 1)
|
||||
ON CONFLICT(user_id) DO UPDATE SET epilogue_cleared = 1`,
|
||||
string(userID),
|
||||
)
|
||||
return err
|
||||
}
|
||||
|
||||
// HouseState is the in-memory mirror of player_meta's house_* columns. Phase
|
||||
// L4e ports housing/mortgage off AdvCharacter (gogobee_legacy_migration.md
|
||||
// §6.5). All six fields mutate together at known sites (purchase, payoff,
|
||||
@@ -1319,6 +1346,9 @@ func applyPlayerMetaOverlay(c *AdventureCharacter) {
|
||||
if mask, err := loadJournalPages(uid); err == nil {
|
||||
c.JournalPages = mask
|
||||
}
|
||||
if cleared, err := loadEpilogueCleared(uid); err == nil {
|
||||
c.EpilogueCleared = cleared
|
||||
}
|
||||
if s, err := loadHouseState(uid); err == nil {
|
||||
c.HouseTier = s.Tier
|
||||
c.HouseLoanBalance = s.LoanBalance
|
||||
|
||||
Reference in New Issue
Block a user