Feature 14: Dailies, Weeklies & Seasons
Overview
Recurring engagement systems: daily first-run bonus, 3 daily bounties with bonus chest, daily faction quests (Feature 12), weekly challenge dungeons, rotating seasonal events with free/premium reward tracks, and the rested XP bonus for offline players. Designed to reward regular play without punishing absence.
Dependencies
- Feature 07 (Quests & Runs) — daily bounties and weekly challenges are run types
- Feature 04 (Character Progression) — XP bonuses, rested bonus
- Feature 12 (Factions) — daily faction quests
Technical Tasks
1. Database Migrations
- Create migration
0013_create_dailies.sql:daily_tracking: character_id, date, first_run_bonus (bool), bounties_completed (smallint), bounty_chest_claimed (bool), faction_quests (JSONB) — PK: character_id + dateweekly_tracking: character_id, week_start (date), challenge_completed (bool), raid_tokens_earned (int) — PK: character_id + week_startseason_progress: character_id, season_id, track (‘free’/‘premium’), tier_reached (smallint), xp (int) — PK: character_id + season_idseasons: id, name, starts_at, ends_at, theme, is_active
2. Daily Reset Logic (crates/game)
- Create
src/dailies.rs:DAILY_FIRST_RUN_XP_BONUS: f64 = 0.50(50% bonus XP)DAILY_FIRST_RUN_GOLD_BONUS: f64 = 0.50(50% bonus gold)DAILY_BOUNTY_COUNT: u8 = 3generate_daily_bounties(character_level: u16, date: NaiveDate) -> Vec<DailyBounty>:- 3 short bounties, seeded by date for server-wide consistency
- Different content than the quest board
check_bounty_chest_eligible(bounties_completed: u8) -> bool: all 3 doneroll_bounty_chest(character_level: u16, rng: &mut impl Rng) -> Vec<GeneratedItem>:- Guaranteed Uncommon+ item, bonus materials, gold
3. Weekly Challenge Logic (crates/game)
- Create
src/weeklies.rs:generate_weekly_challenge(week_start: NaiveDate) -> WeeklyChallenge:- Rotating modifier dungeon (harder than normal, unique mechanic)
- Same challenge for all players (seeded by week)
- Duration: 1-2 hours
roll_weekly_chest(character_level: u16, rng: &mut impl Rng) -> Vec<GeneratedItem>:- Guaranteed Rare+ item, premium materials
4. Rested Bonus Logic (crates/game)
- Create
src/rested.rs:calculate_rested_bonus(last_active: DateTime, now: DateTime) -> f64:- +25% XP after 24 hours offline
- Caps at +50% after 3+ days
- Linear ramp: 0% at 0h, 25% at 24h, 50% at 72h
consume_rested_bonus(current: f64, xp_earned: u64) -> (f64, u64):- Apply bonus to earned XP
- Deplete rested pool proportionally
- Returns (remaining_bonus, bonus_xp_amount)
5. Seasonal Content Logic (crates/game)
- Create
src/seasons.rs:Season: id, name, starts_at, ends_at, theme, free_track (Vec), premium_track (Vec ) SeasonTier: tier_number, xp_required, rewards (Vec) - Free track: 15 tiers
- Premium track: 30 additional tiers (Patron only)
calculate_season_xp(activity: &str, difficulty: Difficulty) -> u32:- XP from seasonal dungeons, regular runs, PVP, daily completion
check_tier_up(current_xp: u32, current_tier: u16, track: &[SeasonTier]) -> Option<TierUpResult>- Seasonal challenge dungeons: unique encounter modifiers per season theme
6. Queries (crates/db)
- Create
src/queries/dailies.rs:get_or_create_daily_tracking(pool, character_id, date) -> DailyTrackingupdate_daily_tracking(pool, character_id, date, updates)get_or_create_weekly_tracking(pool, character_id, week_start) -> WeeklyTrackingupdate_weekly_tracking(pool, character_id, week_start, updates)get_season_progress(pool, character_id, season_id) -> Option<SeasonProgress>update_season_progress(pool, character_id, season_id, new_xp, new_tier)get_active_season(pool) -> Option<Season>
7. Scheduled Workers
- Update scheduler in
crates/workers:daily-reset(00:00 UTC): no DB mutation needed —daily_trackingrows are created per-day on first accessweekly-reset(Monday 00:00 UTC): same pattern forweekly_trackingrested-bonus-tick(every 1 hour): update rested_bonus for characters inactive > 24hseason-transition(manual or scheduled): end current season, archive progress, activate next season
8. Update Run Completion for Dailies
- In simulation worker, after resolving a run:
- If this is the character’s first run today: apply first-run XP/gold bonus
- If this was a daily bounty: increment bounties_completed, check for chest
- If this was the weekly challenge: mark challenge_completed, grant chest
- If season is active: add season XP, check for tier up
- Apply rested bonus to XP earned (if any rested bonus available)
9. API Routes (crates/api)
- Create
src/routes/dailies.rs:GET /api/characters/:id/dailies:- Return: first_run_bonus_available, daily_bounties (3 with completion status), bounty_chest_available, rested_bonus_percentage
GET /api/characters/:id/weeklies:- Return: weekly_challenge (details + completion status), raid_tokens (earned / cap)
GET /api/seasons/current:- Return: active season info, tracks, rewards per tier
GET /api/characters/:id/season-progress:- Return: current tier, XP, rewards claimed, next tier preview
10. Client — Dailies & Season UI
- Add daily/weekly panel to main game dashboard:
- Daily bounties: 3 checkboxes, bonus chest indicator
- First run bonus indicator
- Weekly challenge: name, completion status
- Rested bonus display
- Create
routes/(game)/season/+page.svelte:- Season theme banner
- Reward track visualization: horizontal progress bar with tier markers
- Free track on top, premium track below (greyed if not Patron)
- Claimed/unclaimed reward indicators
Tests
Unit Tests
generate_daily_bounties: returns 3 bountiesgenerate_daily_bounties: deterministic per datecheck_bounty_chest_eligible: true when 3/3, false otherwisegenerate_weekly_challenge: deterministic per weekgenerate_weekly_challenge: different each weekcalculate_rested_bonus: 0% at 0 hourscalculate_rested_bonus: 25% at 24 hourscalculate_rested_bonus: 50% at 72+ hourscalculate_rested_bonus: linear interpolation between thresholdsconsume_rested_bonus: depletes bonus proportionallycalculate_season_xp: returns correct XP per activity typecheck_tier_up: returns tier-up when XP sufficientcheck_tier_up: returns None when insufficient
Integration Tests
GET /api/characters/:id/dailiesreturns correct state for today- First run of the day applies 50% XP and gold bonus
- Second run of the day does NOT apply bonus
- Completing 3 daily bounties enables bonus chest claim
- Weekly challenge completion grants weekly chest
- Season XP accumulates across activities
- Season tier-up triggers notification
- Rested bonus applies to run XP after offline period
- Daily tracking resets per calendar day (UTC)
- Weekly tracking resets on Monday