mirror of
https://github.com/prosolis/gogobee.git
synced 2026-07-15 08:32:41 +00:00
Add rival duels, babysitting service, multilingual !define, economy tuning
Rival System: - RPS-based duels between combat level 5+ players (best of 3, ties re-prompt) - Stakes scale with level, split 50/50 between winner and community pot - 3-4 day randomized challenge interval, 7-day same-pair cooldown - 24h response window with auto-forfeit - Full flavor text pools, character sheet integration, !adventure rivals Babysitting Service: - Weekly/monthly auto-play service targeting weakest skill - Babysitter rerolls death, claims items, credits gold and XP - Rivals automatically declined during service - End-of-service summary with diaper report Revive fixes: - On-demand revive in handleMenu, parseAndResolveChoice, handleStatus - Morning DM respawn check now runs before babysit interception - Players no longer stuck dead after DeadUntil expires mid-day Other changes: - Multilingual !define searches all DreamDict languages by default - TwinBee empty haul now shows "jackshit" instead of blank - Wordle solve payouts increased (e.g. 1-guess: €100 -> €500) - Per-message euro payouts doubled across all tiers - Audit fixes: user locks on RPS/babysit handlers, TOCTOU on gold transfers, dead code removal, deprecated strings.Title replaced, error logging on silent failures Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -49,8 +49,13 @@ type AdventureCharacter struct {
|
||||
GrudgeLocation string
|
||||
CreatedAt time.Time
|
||||
LastActiveAt time.Time
|
||||
DeathReprieveLast *time.Time
|
||||
DeathReprieveLast *time.Time
|
||||
MasterworkDropsReceived int
|
||||
RivalPool int
|
||||
RivalUnlockedNotified bool
|
||||
BabysitActive bool
|
||||
BabysitExpiresAt *time.Time
|
||||
BabysitSkillFocus string
|
||||
}
|
||||
|
||||
type AdvEquipment struct {
|
||||
@@ -289,8 +294,8 @@ func checkAdvLevelUp(char *AdventureCharacter, skill string) (bool, int) {
|
||||
func loadAdvCharacter(userID id.UserID) (*AdventureCharacter, error) {
|
||||
d := db.Get()
|
||||
c := &AdventureCharacter{}
|
||||
var alive, actionTaken, holidayTaken int
|
||||
var deadUntil, reprieveLast sql.NullTime
|
||||
var alive, actionTaken, holidayTaken, rivalUnlocked, babysitAct int
|
||||
var deadUntil, reprieveLast, babysitExp sql.NullTime
|
||||
|
||||
err := d.QueryRow(`
|
||||
SELECT user_id, display_name,
|
||||
@@ -300,7 +305,9 @@ func loadAdvCharacter(userID id.UserID) (*AdventureCharacter, error) {
|
||||
arena_wins, arena_losses, invasion_score, title,
|
||||
current_streak, best_streak, last_action_date, grudge_location,
|
||||
created_at, last_active_at, death_reprieve_last,
|
||||
masterwork_drops_received
|
||||
masterwork_drops_received,
|
||||
rival_pool, rival_unlocked_notified,
|
||||
babysit_active, babysit_expires_at, babysit_skill_focus
|
||||
FROM adventure_characters WHERE user_id = ?`, string(userID)).Scan(
|
||||
&c.UserID, &c.DisplayName,
|
||||
&c.CombatLevel, &c.MiningSkill, &c.ForagingSkill, &c.FishingSkill,
|
||||
@@ -310,6 +317,8 @@ func loadAdvCharacter(userID id.UserID) (*AdventureCharacter, error) {
|
||||
&c.CurrentStreak, &c.BestStreak, &c.LastActionDate, &c.GrudgeLocation,
|
||||
&c.CreatedAt, &c.LastActiveAt, &reprieveLast,
|
||||
&c.MasterworkDropsReceived,
|
||||
&c.RivalPool, &rivalUnlocked,
|
||||
&babysitAct, &babysitExp, &c.BabysitSkillFocus,
|
||||
)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -317,12 +326,17 @@ func loadAdvCharacter(userID id.UserID) (*AdventureCharacter, error) {
|
||||
c.Alive = alive == 1
|
||||
c.ActionTakenToday = actionTaken == 1
|
||||
c.HolidayActionTaken = holidayTaken == 1
|
||||
c.RivalUnlockedNotified = rivalUnlocked == 1
|
||||
c.BabysitActive = babysitAct == 1
|
||||
if deadUntil.Valid {
|
||||
c.DeadUntil = &deadUntil.Time
|
||||
}
|
||||
if reprieveLast.Valid {
|
||||
c.DeathReprieveLast = &reprieveLast.Time
|
||||
}
|
||||
if babysitExp.Valid {
|
||||
c.BabysitExpiresAt = &babysitExp.Time
|
||||
}
|
||||
return c, nil
|
||||
}
|
||||
|
||||
@@ -369,6 +383,14 @@ func saveAdvCharacter(char *AdventureCharacter) error {
|
||||
if char.HolidayActionTaken {
|
||||
holidayTaken = 1
|
||||
}
|
||||
rivalUnlocked := 0
|
||||
if char.RivalUnlockedNotified {
|
||||
rivalUnlocked = 1
|
||||
}
|
||||
babysitAct := 0
|
||||
if char.BabysitActive {
|
||||
babysitAct = 1
|
||||
}
|
||||
|
||||
_, err := d.Exec(`
|
||||
UPDATE adventure_characters SET
|
||||
@@ -378,14 +400,19 @@ func saveAdvCharacter(char *AdventureCharacter) error {
|
||||
arena_wins = ?, arena_losses = ?, invasion_score = ?, title = ?,
|
||||
current_streak = ?, best_streak = ?, last_action_date = ?, grudge_location = ?,
|
||||
last_active_at = CURRENT_TIMESTAMP, death_reprieve_last = ?,
|
||||
masterwork_drops_received = ?
|
||||
masterwork_drops_received = ?,
|
||||
rival_pool = ?, rival_unlocked_notified = ?,
|
||||
babysit_active = ?, babysit_expires_at = ?, babysit_skill_focus = ?
|
||||
WHERE user_id = ?`,
|
||||
char.DisplayName, char.CombatLevel, char.MiningSkill, char.ForagingSkill, char.FishingSkill,
|
||||
char.CombatXP, char.MiningXP, char.ForagingXP, char.FishingXP,
|
||||
alive, char.DeadUntil, actionTaken, holidayTaken,
|
||||
char.ArenaWins, char.ArenaLosses, char.InvasionScore, char.Title,
|
||||
char.CurrentStreak, char.BestStreak, char.LastActionDate, char.GrudgeLocation,
|
||||
char.DeathReprieveLast, char.MasterworkDropsReceived, string(char.UserID),
|
||||
char.DeathReprieveLast, char.MasterworkDropsReceived,
|
||||
char.RivalPool, rivalUnlocked,
|
||||
babysitAct, char.BabysitExpiresAt, char.BabysitSkillFocus,
|
||||
string(char.UserID),
|
||||
)
|
||||
return err
|
||||
}
|
||||
@@ -499,7 +526,9 @@ func loadAllAdvCharacters() ([]AdventureCharacter, error) {
|
||||
arena_wins, arena_losses, invasion_score, title,
|
||||
current_streak, best_streak, last_action_date, grudge_location,
|
||||
created_at, last_active_at, death_reprieve_last,
|
||||
masterwork_drops_received
|
||||
masterwork_drops_received,
|
||||
rival_pool, rival_unlocked_notified,
|
||||
babysit_active, babysit_expires_at, babysit_skill_focus
|
||||
FROM adventure_characters`)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -509,8 +538,8 @@ func loadAllAdvCharacters() ([]AdventureCharacter, error) {
|
||||
var chars []AdventureCharacter
|
||||
for rows.Next() {
|
||||
c := AdventureCharacter{}
|
||||
var alive, actionTaken, holidayTaken int
|
||||
var deadUntil, reprieveLast sql.NullTime
|
||||
var alive, actionTaken, holidayTaken, rivalUnlocked, babysitAct int
|
||||
var deadUntil, reprieveLast, babysitExp sql.NullTime
|
||||
if err := rows.Scan(
|
||||
&c.UserID, &c.DisplayName,
|
||||
&c.CombatLevel, &c.MiningSkill, &c.ForagingSkill, &c.FishingSkill,
|
||||
@@ -520,18 +549,25 @@ func loadAllAdvCharacters() ([]AdventureCharacter, error) {
|
||||
&c.CurrentStreak, &c.BestStreak, &c.LastActionDate, &c.GrudgeLocation,
|
||||
&c.CreatedAt, &c.LastActiveAt, &reprieveLast,
|
||||
&c.MasterworkDropsReceived,
|
||||
&c.RivalPool, &rivalUnlocked,
|
||||
&babysitAct, &babysitExp, &c.BabysitSkillFocus,
|
||||
); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
c.Alive = alive == 1
|
||||
c.ActionTakenToday = actionTaken == 1
|
||||
c.HolidayActionTaken = holidayTaken == 1
|
||||
c.RivalUnlockedNotified = rivalUnlocked == 1
|
||||
c.BabysitActive = babysitAct == 1
|
||||
if deadUntil.Valid {
|
||||
c.DeadUntil = &deadUntil.Time
|
||||
}
|
||||
if reprieveLast.Valid {
|
||||
c.DeathReprieveLast = &reprieveLast.Time
|
||||
}
|
||||
if babysitExp.Valid {
|
||||
c.BabysitExpiresAt = &babysitExp.Time
|
||||
}
|
||||
chars = append(chars, c)
|
||||
}
|
||||
return chars, rows.Err()
|
||||
|
||||
Reference in New Issue
Block a user