mirror of
https://github.com/prosolis/gogobee.git
synced 2026-07-16 17:02:42 +00:00
N5 review fixes: protect keys from Robbie, fire epilogue on autopilot, atomic finale reward
Five correctness fixes from a code review of the N5 branch: - Robbie no longer sweeps/sells cross-zone keys (Type "key"), which permanently broke the vault unlock they exist to open. - Robbie's gift tier now reads the canonical DnD level, not the frozen legacy CombatLevel that pegged every gift at tier 1. - Boss epilogue (D1b) now fires on the compact autopilot boss resolve — the primary long-expedition path — not just manual !fight. Deduped the two manual sites into a shared writeBossEpilogue helper. - Finale reward latches epilogue_cleared before granting the Legendary + title, so a failed/late write can't make the reward repeatable. - Misty arc beat's occupied-slot guard moved above the counter increment, so a contended pending slot defers the encounter instead of consuming a 5/15/30 beat forever. Claude-Session: https://claude.ai/code/session_017mEwUmmS7aQTP2NQXj6rUa
This commit is contained in:
@@ -269,6 +269,17 @@ func bossEpilogueLine(zoneID ZoneID) string {
|
||||
return bossEpilogues[zoneID]
|
||||
}
|
||||
|
||||
// writeBossEpilogue appends a zone's campaign capstone (if any) to a
|
||||
// victory narration. Shared by every boss-down render path — the manual
|
||||
// turn-based finishes (finishCombatSession, finishPartyWin) and the compact
|
||||
// autopilot boss resolve — so the D1b epilogue fires no matter how the boss
|
||||
// was cleared. Caller gates on "this was a boss, not an elite".
|
||||
func writeBossEpilogue(b *strings.Builder, zoneID ZoneID) {
|
||||
if ep := bossEpilogueLine(zoneID); ep != "" {
|
||||
b.WriteString("\n" + ep + "\n")
|
||||
}
|
||||
}
|
||||
|
||||
// twinBeeJournalReactions are TwinBee's morning/digest reactions to pages found
|
||||
// during the day — first-person, implicit subject, he/him, one line, curious,
|
||||
// never expository (feedback_twinbee_voice, feedback_twinbee_is_male). Picked
|
||||
@@ -463,6 +474,15 @@ func (p *AdventurePlugin) finishEpilogueWin(userID id.UserID, alreadyCleared boo
|
||||
return "_The throne stays empty. You came to be sure. You are sure._"
|
||||
}
|
||||
|
||||
// Latch the once-only flag BEFORE handing out the Legendary + title, so a
|
||||
// failed write (or a crash) can never leave the reward repeatable. If the
|
||||
// latch fails, skip the grant entirely — the player re-enters uncleared and
|
||||
// can try again, rather than pocketing a second Legendary on the retry.
|
||||
if err := markEpilogueClearedDB(userID); err != nil {
|
||||
slog.Error("epilogue: mark cleared failed", "user", userID, "err", err)
|
||||
return "_The account won't quite close — the ledger jams. Try `!expedition start epilogue` again._"
|
||||
}
|
||||
|
||||
var b strings.Builder
|
||||
b.WriteString("🎖️ **The account is closed.** You are named **" + finaleTitle + "** — the one who unhoused the Hollow King.\n")
|
||||
if mi, ok := pickMagicItemForRarity(RarityLegendary, nil); ok {
|
||||
@@ -481,9 +501,6 @@ func (p *AdventurePlugin) finishEpilogueWin(userID id.UserID, alreadyCleared boo
|
||||
}
|
||||
}
|
||||
}
|
||||
if err := markEpilogueClearedDB(userID); err != nil {
|
||||
slog.Error("epilogue: mark cleared failed", "user", userID, "err", err)
|
||||
}
|
||||
|
||||
if gr := gamesRoom(); gr != "" {
|
||||
if dn, _ := loadDisplayName(userID); dn != "" {
|
||||
|
||||
Reference in New Issue
Block a user