Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Delve — Game Design Documents

Delve is an asynchronous idle MMO with synchronous multiplayer elements, an original fantasy RPG inspired by classic tabletop games. Players create characters, prepare them for dungeon runs, and send them into danger — reviewing detailed results when the run completes. The game is free-to-play with convenience monetization.

Document Index

#DocumentDescriptionStatus
01Game OverviewVision, core loop, design pillars, session flow, monetization philosophyDraft
02Character CreationSpecies, classes, attributes, backgrounds, starting equipmentDraft
03Character ProgressionLeveling (1-50), subclasses, feats, skills, Paragon/prestige systemDraft
04Combat Systemd100 percentile mechanics, skill queue configuration, conditions, death, combat log formatDraft
05Equipment and LootGear slots, rarity tiers, weapons, armor, consumables, loot tablesDraft
06Quests and DungeonsQuest board, quest types, encounter types, run timeline, failure analysis, suppliesDraft
07Crafting and GatheringGathering professions, crafting professions, recipes, material tiersDraft
08Economy and TradingCurrencies, marketplace, NPC vendors, gold sinks, inflation controlDraft
09Social and MMO SystemsGuilds, timed lobby parties, raids, friends, chat, mailDraft
10PVP SystemArena PVP, async resolution, seasons, guild wars, faction warfareDraft
11Factions and ReputationWorld factions, reputation tiers, faction conflicts, faction vendorsDraft
12World and SettingAethermere setting, regions, lore (The Sundering), key NPCsDraft
13Idle and Time MechanicsOffline progress, timers, notifications, anti-burnout designDraft
14Monetization$5/mo Patron subscription, permanent purchases, no premium currency, ethical principlesDraft
15Progression Hooks and RetentionDailies, weeklies, achievements, seasons, leaderboards, collectionsDraft

Key Design Decisions

  • Species & Classes: 9 original species and 9 classes with 6 custom attributes (Might, Logic, Speed, Presence, Fortitude, Luck)
  • Combat: d100 percentile dice system with skill queue combat, optimized for idle/async auto-resolution
  • Progression: Levels 1-50 with Paragon system beyond cap
  • Monetization: F2P + optional $5/mo Patron subscription (50% faster time-based activities). No premium currency, no cosmetic sales, no loot boxes.
  • Multiplayer: Timed lobby system — group content starts at scheduled times, players prepare async
  • Scope: Full sandbox — combat, crafting, gathering, economy, PVP, factions, social

How to Read These Docs

  • Start with 01-Game Overview for the big picture
  • 02-04 cover the character and combat core
  • 05-06 cover the loot and dungeon loop
  • 07-08 cover crafting and economy
  • 09-11 cover multiplayer and social systems
  • 12 covers the game world
  • 13-15 cover meta-systems (time, money, retention)

Each document is self-contained but cross-references related docs where systems interact.

Status

All documents are in Draft status — ready for review and iteration.

Game Overview

Game Pitch

Delve is an asynchronous idle MMO where players create characters inspired by classic tabletop RPG archetypes and send them into dangerous dungeons, questlines, and encounters that resolve over real-world time. Players don’t control combat in real-time — they prepare, strategize, and configure their characters’ behavior, then set them loose and review the results.

Think of it as managing an adventurer’s career. You’re the strategist behind the hero: picking quests, equipping gear, setting combat priorities, stocking supplies, and joining up with other players’ characters for raids. The dungeon happens while you’re at work. You come back, read the battle log, see where things went right or wrong, adapt, and send them out again.

Core Fantasy

You are the mind behind the adventurer. Every decision you make before the dungeon matters — what spells to prioritize, when to use potions, whether to bring extra rations or a second weapon. The dungeon run plays out like a story you get to read, with your preparation determining the outcome.

Core Gameplay Loop

LOGIN
  │
  ▼
REVIEW RESULTS ─── Read the timeline of your last dungeon run.
  │                 See each encounter: combat rolls, trap checks,
  │                 loot found, resources consumed.
  │                 Understand exactly why you succeeded or failed.
  │
  ▼
MANAGE INVENTORY ── Equip new gear, sell unwanted loot,
  │                  salvage materials, brew potions,
  │                  restock supplies (rations, torches, scrolls).
  │
  ▼
BROWSE QUESTS ───── View the quest board: bounties, questlines,
  │                  dungeon crawls, guild raids.
  │                  Each shows difficulty, estimated duration,
  │                  potential rewards, and recommended level.
  │
  ▼
PREPARE ─────────── Configure combat AI priorities.
  │                  Select spells to memorize.
  │                  Choose supplies to bring.
  │                  Set trap detection behavior.
  │                  Join a party lobby (if multiplayer quest).
  │
  ▼
COMMIT ──────────── Lock in and send your character on the quest.
  │                  The run resolves over real-world time.
  │
  ▼
IDLE ───────────── While waiting, you can:
  │                 • Manage other characters (if unlocked)
  │                 • Craft items or gather materials
  │                 • Browse the marketplace
  │                 • Chat with guild members
  │                 • Review leaderboards
  │                 • Log off entirely — the run continues
  │
  ▼
NOTIFICATION ────── "Your dungeon run is complete!"
  │
  └──► Return to REVIEW RESULTS

Session Flow

Quick Session (5-10 minutes)

  1. Review last run results
  2. Sell junk loot, equip upgrades
  3. Pick a new quest from the board
  4. Use default combat settings or make minor tweaks
  5. Commit and log off

Active Session (30-60 minutes)

  1. Review results in detail — study the combat log
  2. Reorganize inventory, craft consumables
  3. Browse marketplace for upgrades
  4. Fine-tune combat AI configuration
  5. Coordinate with guild for an upcoming raid
  6. Commit to a quest
  7. While waiting: gather materials, manage a second character, chat

Check-in Session (1-2 minutes)

  1. See notification that a run completed
  2. Glance at results (success/fail, notable loot)
  3. Quick-commit to another quest of similar difficulty
  4. Log off

Target Audience

  • Tabletop RPG fans who love character building and tactical decisions but don’t always have time for a full session
  • Idle game enthusiasts who want deeper progression and strategy than typical idle/incremental games
  • MMO players who want social features (guilds, raids, PVP) without demanding a fixed play schedule
  • Strategy gamers who enjoy optimizing builds, min-maxing gear, and solving the puzzle of dungeon preparation

Platform Considerations

  • Web-first — accessible from any browser, desktop or mobile
  • Mobile-friendly — the async nature makes it perfect for phone check-ins
  • No downloads required — low barrier to entry for F2P
  • Push notifications — run complete, raid starting, auction sold

Monetization Philosophy

Delve is free to play with an optional $5/month subscription and small permanent purchases. No premium currency. No loot boxes. No cosmetic microtransactions.

The Patron Subscription ($5/month)

  • 50% faster dungeon runs, crafting, and gathering
  • That’s it. No bonus XP, no bonus loot, no combat advantages. Subscribers wait less — they don’t hit harder.

Permanent Purchases

  • Additional character slots ($2 each, up to 5 extra)
  • Expanded bank/storage space ($1 per upgrade)
  • Name changes and appearance resets ($1 each)

What You CANNOT Buy

  • Gear, weapons, or items with stats
  • XP, gold, or loot boosts
  • Premium currency (doesn’t exist)
  • Loot boxes or randomized purchases (don’t exist)
  • Combat advantages of any kind
  • Cosmetics (earned through gameplay only)
  • Content access (all gameplay is free)

Why This Model

Players should never feel like they lost a dungeon run because someone else spent money. A subscriber and a free player in the same dungeon have the same chance of success. The game makes money by being good enough that players want to support it — not by creating friction that drives impulse purchases.

See 14-monetization.md for full details.

What Makes Delve Different

FeatureTypical Idle GameTypical MMODelve
Time investmentMinutes/dayHours/day5 min to 1 hour, your choice
Decision depthLow (upgrade numbers)High (real-time combat)High (preparation & strategy)
Social featuresMinimalExtensive but time-demandingAsync-friendly guilds, raids, PVP
Failure feedback“You died”Real-time awarenessDetailed post-run analysis
Character buildingSimple upgradesComplex but real-timeDeep builds resolved automatically

Design Pillars

  1. Preparation is gameplay. The decisions you make before a dungeon run ARE the game. Choosing the right spells, configuring smart combat behavior, bringing enough supplies — this is where skill lives.

  2. Failure is a teacher. When a run fails, the player should understand exactly why and what to change. The run timeline is the core feedback mechanism.

  3. Respect the player’s time. Whether you have 5 minutes or an hour, there’s something meaningful to do. You should never feel punished for not logging in.

  4. Social without synchronous. Guilds, raids, and PVP should be engaging without requiring everyone to be online at the same time. The timed lobby system makes group content accessible to all schedules.

  5. Earn, don’t buy, your power. Every piece of gear, every level, every achievement is earned through play. Money buys time savings, never power.

Character Creation

Overview

Character creation is the player’s first major decision point. Every option — species, class, attribute spread, background — should feel distinct and have a clear gameplay impact. The goal is meaningful choice without overwhelming new players.

Players start with one character slot for free. Additional slots can be purchased from the in-game shop (see 14-monetization.md).

Character Identity

Name

  • Must be unique server-wide
  • 3-20 characters, letters and spaces only
  • Filtered for inappropriate content
  • Can be changed for a small one-time purchase ($1 — see 14-monetization.md)

Appearance

  • Visual portrait selection from a curated set per species
  • Cosmetic armor skins overlay the portrait
  • Additional portraits earned through achievements, faction reputation, and seasonal events

Title

  • Displayed alongside the character name (e.g., “Korrin the Unyielding”)
  • Earned through achievements, faction reputation, PVP rank, or seasonal events
  • Players choose which earned title to display

Attributes

Delve uses six core attributes that affect every system in the game — combat, dungeon exploration, crafting, and social interactions.

The Six Attributes

AttributeAbbrevCombat RoleDungeon Role
MightMGTMelee damage, heavy weapon accuracy, physical skill powerForce doors, carry more supplies, resist grapples, move heavy objects
LogicLOGMagical damage, spell accuracy, mana pool sizeSolve puzzles, identify items, recall enemy lore, detect magical traps
SpeedSPDRanged accuracy, evasion rating, initiative tie-breakingDodge traps, avoid ambushes, act first, navigate hazards
PresencePRSSupport/healing skill power, debuff potency, social skillsNegotiate with NPCs, intimidate enemies, inspire allies, avoid encounters through diplomacy
FortitudeFRTMax HP, stamina/devotion pool, condition resistanceResist poison/disease, endure long dungeons, survive environmental hazards, recover more at rest
LuckLCKCritical hit threshold, critical miss reduction, loot qualityFind hidden treasure, better loot rolls, dodge random hazards, favorable decision outcomes

How Attributes Affect Combat

Might:

  • +2% melee skill accuracy per point above 10
  • +1.5% melee skill damage per point above 10
  • Determines Might-based resistance checks (grapples, knockdowns)

Logic:

  • +2% magical skill accuracy per point above 10
  • +1.5% magical skill damage per point above 10
  • +3 mana per point
  • Determines Logic-based resistance checks (illusions, puzzles)

Speed:

  • +1.5% ranged skill accuracy per point above 10
  • +1 evasion rating per point (makes you harder to hit)
  • Tie-breaking value for skill initiative
  • Determines Speed-based resistance checks (traps, AoE dodging)

Presence:

  • +2% healing/buff skill effectiveness per point above 10
  • +2% debuff potency per point above 10 (harder for enemies to resist)
  • Determines Presence-based resistance checks (fear, charm, intimidation)

Fortitude:

  • +5 max HP per point above 10
  • +2 stamina/devotion per point
  • +1.5% condition resistance per point above 10 (blanket bonus to resist poison, stun, etc.)
  • Determines Fortitude-based resistance checks (poison, disease, exhaustion)

Luck:

  • Critical hit threshold improved by 0.5% per point above 10 (base crit: ≤5 on d100; at 20 LCK: ≤10)
  • Critical miss threshold reduced by 0.5% per point above 10 (base crit miss: 96-100; at 20 LCK: 98-100 only)
  • +1% loot quality modifier per point above 10 (slightly better rolls on loot tables)
  • Once per dungeon run per 5 points of LCK: automatically re-roll one failed d100 check

Attribute Scale

Attributes range from 1 to 30 (soft cap), with a theoretical maximum of 40 through endgame gear and buffs.

RangeDescription
1-5Below average. Significant penalties in related activities.
6-9Average. No notable bonus or penalty.
10-14Above average. Noticeable edge in related activities.
15-19Exceptional. Clear strength in this area.
20-24Heroic. Among the best in the world.
25-30Legendary. Near the peak of mortal capability.
31-40Transcendent. Only achievable through endgame gear, buffs, and Paragon bonuses.

Attribute Point-Buy

At character creation, players distribute 40 points across the six attributes. All attributes start at 5 (baseline), and points raise them from there.

Attribute ValueTotal Points Spent (from 5)
50 (base)
61
72
83
94
105
117
129
1311
1414
1517

The escalating cost means players can build a well-rounded character (several 10-12s) or specialize heavily (one or two 14-15s with lower elsewhere). The maximum any single attribute can reach at creation is 15 before species bonuses.

Species bonus is applied AFTER point-buy and can push an attribute above 15 at creation.

Each class has a one-click “Recommended” button that sets a sensible point-buy for new players. Advanced players can customize freely.


Species

Delve features 9 playable species at launch. Each species has a distinct visual identity, cultural flavor, a primary attribute bonus, a secondary attribute bonus, and a unique species skill usable in the skill queue (see 04-combat-system.md).

No species is mandatory for any class — bonuses nudge, they don’t dictate.

Ironborn

  • Primary Attribute: +3 Fortitude
  • Secondary Attribute: +1 Might
  • Species Skill: Unyielding (Passive) — Once per dungeon run, when reduced below 20% HP, automatically gain Shielded (absorb damage equal to 15% max HP) and +10% damage for 2 rounds.
  • Appearance: Tall, broad, stone-gray skin with metalite veins running through their body. Dense, almost sculpted features. Hair ranges from iron-black to rust-red.
  • Lore: The Ironborn emerged from the deep mountains after the Sundering, their bodies permanently fused with the mineral-rich stone that sheltered them. They are naturally resilient and culturally stoic — they believe that to endure is to prevail. Ironborn communities are built around forges and mines, and they have a reputation as the finest blacksmiths in Aethermere.
  • Playstyle nudge: Tanky frontline characters. Great with heavy armor and shields. The Fortitude bonus means more HP and better condition resistance.

Verdani

  • Primary Attribute: +3 Logic
  • Secondary Attribute: +1 Presence
  • Species Skill: Aethersight (Active, Init 2) — Reveal all enemy weaknesses and resistances for 3 rounds. Allies gain +10% accuracy against revealed targets. 2 uses per dungeon run. Swift (doesn’t consume queue slot).
  • Appearance: Slender, elongated limbs with faintly luminous skin in pale green or soft blue. Eyes without pupils that glow faintly. Intricate natural patterns on their skin resembling circuitry or veins of a leaf.
  • Lore: The Verdani are an ancient species who claim to remember the world before the Sundering. They experience reality through a “second sense” — an innate ability to perceive magical currents. This makes them natural scholars and spellcasters, though their detached perspective sometimes puts them at odds with shorter-lived species. Their cities are grown from living crystal in the deep forests.
  • Playstyle nudge: Spellcasters and support characters. The Logic bonus boosts magical damage and mana pools.

Kharren

  • Primary Attribute: +3 Might
  • Secondary Attribute: +1 Fortitude
  • Species Skill: Blood Frenzy (Active, Init 1) — For 3 rounds, all melee skills deal +20% damage but you take 10% more damage from all sources. 2 uses per dungeon run.
  • Appearance: Powerfully built with thick, layered skin ranging from deep crimson to dark bronze. Prominent lower canines (tusks). Scarification patterns are a cultural tradition — each scar tells a story.
  • Lore: The Kharren are a proud warrior culture from the Ashlands, forged by generations of surviving volcanic wastelands and fighting for scarce resources. They value strength and honor in equal measure — a Kharren who wins through treachery is despised, but one who wins through might is celebrated. They were among the first to reclaim territory after the Sundering, and their holds are the most well-defended settlements in the harsh frontier.
  • Playstyle nudge: Melee damage dealers. The Might bonus amplifies physical skill damage. Blood Frenzy is a classic risk/reward damage steroid.

Sylphari

  • Primary Attribute: +3 Speed
  • Secondary Attribute: +1 Logic
  • Species Skill: Phase Step (Active, Init 0) — Become untargetable for 1 round. Your next offensive skill gains +15% accuracy and +15% damage. 2 uses per dungeon run.
  • Appearance: Lean and angular with semi-translucent skin that shifts color subtly with their emotional state. Hair like spun glass or fiber optics. They move with an unnatural fluidity, as if slightly out of phase with reality.
  • Lore: The Sylphari exist partially between dimensions — a side effect of the Sundering that affected their ancestors who lived near the epicenter. They flicker between planes of existence, making them appear to shimmer or blur at the edges. This gives them extraordinary reflexes and an uncanny ability to avoid danger. Their communities are nomadic, drifting along the ley lines that crisscross Aethermere.
  • Playstyle nudge: Rogues, ranged damage, and evasion-focused builds. The Speed bonus boosts evasion and ranged accuracy. Phase Step is an incredible defensive/offensive hybrid.

Thornkin

  • Primary Attribute: +3 Fortitude
  • Secondary Attribute: +1 Logic
  • Species Skill: Regenerative Bark (Active, Init 5) — Gain Regenerating condition (recover 5% max HP per round for 4 rounds). If already below 50% HP, the regeneration is doubled to 10%. 2 uses per dungeon run.
  • Appearance: Bark-like skin in shades of brown, green, and amber. Leaves, moss, or small flowering vines grow naturally from their shoulders, head, and arms. Their eyes are deep amber or emerald. They are stocky and grounded.
  • Lore: The Thornkin are a plant-humanoid species that arose when the Sundering’s magical fallout saturated the great forests. They are deeply connected to the natural world and grow stronger with age — elder Thornkin can be centuries old and massive in stature. They are patient, pragmatic, and difficult to kill. Thornkin communities grow their homes directly from living trees, and they have a symbiotic relationship with the forests they inhabit.
  • Playstyle nudge: Tanks and healers. The Fortitude bonus stacks HP and condition resistance. Regenerative Bark is a powerful self-sustain tool that makes them excellent at enduring long dungeon runs.

Ashenmere (Ash Folk)

  • Primary Attribute: +3 Presence
  • Secondary Attribute: +1 Speed
  • Species Skill: Soul Echo (Active, Init 3) — Target ally gains Inspired (+10% accuracy, +10% damage) for 3 rounds. If used on self, also gain +10% condition resistance. 3 uses per dungeon run.
  • Appearance: Pale, almost translucent skin with faint ember-like markings that glow softly in dim light. Their hair is white, silver, or ashen blonde, and their eyes are striking — vivid amber, gold, or pale violet. They have an ethereal, otherworldly beauty.
  • Lore: The Ashenmere are descendants of a civilization that was closest to the epicenter of the Sundering. Their ancestors should have been obliterated, but some survived by binding themselves to the lingering spirits of those who perished. Every Ashenmere carries an “echo” — a spiritual presence that enhances their force of personality and gives them an innate connection to others. They are natural diplomats, leaders, and healers. Their culture is built around community and memory — they honor the dead by living fully.
  • Playstyle nudge: Support, healing, and leadership builds. The Presence bonus amplifies buff/debuff/heal skills. Soul Echo is a versatile party buff.

Glimkin

  • Primary Attribute: +3 Luck
  • Secondary Attribute: +1 Speed
  • Species Skill: Fortune’s Favor (Passive) — Twice per dungeon run, when a skill would critically miss (96-100), downgrade it to a normal miss instead. Additionally, +5% to loot quality rolls on all encounters.
  • Appearance: Small (about 4 feet tall), with large expressive eyes and slightly oversized ears. Their skin has a faint metallic sheen — copper, silver, or gold tones. Wild, unruly hair in improbable colors. They always seem to be grinning.
  • Lore: No one is entirely sure where the Glimkin came from. They appeared shortly after the Sundering, cheerful and seemingly unbothered by the apocalypse. They have an inexplicable knack for being in the right place at the right time (and the wrong place at the wrong time, just as often). Glimkin claim this is “the Knack” — an innate connection to probability itself. Scholars suspect they were created by the Sundering’s chaotic magic. Glimkin communities are colorful, noisy, and organized only by accident.
  • Playstyle nudge: Any class works. The Luck bonus makes crits more frequent, crit misses rarer, and loot better. Fortune’s Favor protects against catastrophic bad rolls. Great for players who enjoy the gambling aspect of the d100 system.

Vexari

  • Primary Attribute: +3 Logic
  • Secondary Attribute: +1 Luck
  • Species Skill: Unravel (Active, Init 4) — Strip all buffs from target enemy. For each buff removed, deal moderate magical damage. If the target had no buffs, deal heavy magical damage instead. 2 uses per dungeon run.
  • Appearance: Dark skin in shades of deep indigo or black, with glowing sigil-like markings that pulse faintly. Horns curl back from the forehead in various shapes. A thin, prehensile tail. Eyes are solid colors — red, violet, gold, or white with no visible pupil.
  • Lore: The Vexari are touched by the chaotic energies that leaked through the Sundering’s dimensional tears. Their ancestors made pacts — willingly or not — with entities from beyond, and the mark persists in their bloodline. Other species are wary of them, but the Vexari have proven their loyalty to Aethermere time and again. They have an innate talent for manipulating magical energies, especially unweaving and disrupting spells. Vexari culture values self-determination above all — they refuse to be defined by their origins.
  • Playstyle nudge: Spellcasters, especially disruptors and debuffers. Unravel is a powerful anti-mage tool. The Logic bonus feeds magical builds, and the Luck secondary helps with crits.

Ferathi

  • Primary Attribute: +3 Speed
  • Secondary Attribute: +1 Might
  • Species Skill: Predator’s Instinct (Passive) — The first skill in your queue each encounter always executes before all enemies, regardless of initiative values. Additionally, if that first skill kills an enemy, your next skill gains +20% damage.
  • Appearance: Lean, athletic builds with animalistic features — slit-pupil eyes, elongated canines, clawed fingertips, and fine fur covering their forearms, shoulders, and calves. Fur and eye colors vary widely (tawny, spotted, striped, solid). Ears are pointed and mobile.
  • Lore: The Ferathi are beast-touched — their ancestors were hunters and trackers who bonded so deeply with the predators of the wild that the Sundering’s magic made the bond literal. They are fierce, territorial, and loyal to their pack (which, for adventuring Ferathi, means their party). Ferathi communities are clan-based, and each clan identifies with a different predator: wolf, hawk, panther, viper, bear. While they can seem feral to outsiders, Ferathi culture has a deep code of honor and surprisingly sophisticated oral traditions.
  • Playstyle nudge: Aggressive builds — rogues, rangers, melee DPS. Predator’s Instinct guarantees you strike first, which synergizes beautifully with high-damage opening skills. The Speed + Might bonuses support fast, hard-hitting play.

Species Comparison Table

SpeciesPrimary (+3)Secondary (+1)Species SkillArchetype
IronbornFortitudeMightUnyielding (auto-shield at low HP)Immovable tank
VerdaniLogicPresenceAethersight (reveal weaknesses)Analytical caster
KharrenMightFortitudeBlood Frenzy (damage boost at cost)Berserker
SylphariSpeedLogicPhase Step (untargetable + burst)Elusive striker
ThornkinFortitudeLogicRegenerative Bark (self-heal over time)Enduring survivor
AshenmerePresenceSpeedSoul Echo (ally buff)Inspiring leader
GlimkinLuckSpeedFortune’s Favor (prevent crit misses, loot bonus)Lucky wildcard
VexariLogicLuckUnravel (strip buffs, deal damage)Arcane disruptor
FerathiSpeedMightPredator’s Instinct (guaranteed first strike)Alpha predator

Classes

Each class defines the character’s combat role, resource system, and skill progression. Classes determine which class-specific skills unlock at which levels and how the character scales through the 1-50 level range.

Classes are archetypes — original to Delve but inspired by classic fantasy roles. Each class has 3 subclasses chosen at level 10.

Vanguard (Martial Frontline)

  • Role: Frontline tank and sustained damage
  • Resource: Stamina
  • Key Attributes: Might, Fortitude
  • Identity: The disciplined warrior. Vanguards are the backbone of any party — durable, reliable, and deadly with any weapon. They excel at staying in the fight longer than anyone else.
  • Skills per round: 2 (base), increases to 3 at level 25
  • Unique Mechanic: Battle Surge — Once per dungeon run (twice at level 30), execute 3 skills in a single round instead of the normal amount. Configured in queue with a conditional.
  • Starting Gear: Medium armor, martial weapon of choice, shield, explorer’s pack
  • Subclasses (Level 10):
    • Bulwark — Pure defense. Gains skills that redirect damage to self, buff party evasion, and create damage absorption shields. The immovable wall.
    • Warblade — Offense focus. Gains skills with higher damage multipliers, bleed effects, and execute-style finishers. The relentless attacker.
    • Tactician — Hybrid support. Gains skills that buff ally accuracy and damage, debuff enemy groups, and manipulate initiative order. The field commander.

Shade (Stealth & Precision)

  • Role: Burst damage, trap specialist, evasion
  • Resource: Momentum (starts at 0, builds +20 per round in combat. Retains 50% between encounters. Capped at 100. Spent on powerful skills.)
  • Key Attributes: Speed, Luck
  • Identity: The unseen blade. Shades strike from angles enemies don’t expect, exploit weaknesses, and specialize in ending fights before they become wars of attrition. Outside combat, they’re the best at detecting and disarming traps.
  • Skills per round: 2 (base)
  • Unique Mechanic: Exploit Weakness — When attacking an enemy affected by a debuff, all Shade skills deal +15% bonus damage. This makes debuffs from allies (or from the Shade’s own skills) extra valuable.
  • Momentum Carry-Over: Momentum retains 50% between encounters. A Shade ending a fight at 80 momentum enters the next fight at 40 — enough to immediately use mid-tier skills. By encounter 4-5, the Shade is entering fights at full power from round 1.
  • Trap Expertise: Shades have +25% to all trap detection and disarm checks. At level 20, traps that would deal damage deal 50% reduced damage even if triggered.
  • Starting Gear: Light armor, two daggers, shortbow, lockpicks, infiltrator’s pack
  • Subclasses (Level 10):
    • Assassin — Maximum burst. First-strike bonus damage, execute skills, and +1% damage per 5 momentum banked (at 80 momentum: +16% damage). Rewards building and holding momentum.
    • Phantom — Evasion focus. Skills that make you untargetable, redirect attacks, and let you skip past encounters entirely through stealth.
    • Saboteur — Trap and debuff specialist. Gains skills that apply DoTs, weaken enemies, and set up traps that damage enemies at the start of the next encounter.

Arcanist (Arcane Spellcaster)

  • Role: Versatile magical damage, AoE, and utility
  • Resource: Mana
  • Key Attributes: Logic, Fortitude (for concentration/durability)
  • Identity: The scholar of destruction. Arcanists command raw magical energy — they can burn down groups of enemies or surgically dismantle a single target. Their weakness is durability; they need protection or distance.
  • Skills per round: 2 (base)
  • Unique Mechanic: Spell Mastery — The Arcanist’s mana cost for any skill decreases by 1% for each time that skill is used in the dungeon run (cumulative). By the 10th use of Arcane Bolt, it costs 10% less. Rewards consistent skill use.
  • Starting Gear: Staff or wand, light armor, arcane focus, scholar’s pack
  • Subclasses (Level 10):
    • Evoker — Raw damage. Fire, ice, lightning AoE skills. Can shape AoE to avoid allies. The blaster.
    • Chronomancer — Time manipulation. Skills that slow enemies, haste allies, and manipulate initiative values. The controller.
    • Voidcaller — Dark magic. Drain effects, DoTs, and skills that get stronger the lower the Arcanist’s HP (risk/reward). The gambler.

Warden (Divine Healer & Protector)

  • Role: Healer, buffer, anti-undead, off-tank
  • Resource: Devotion
  • Key Attributes: Presence, Fortitude
  • Identity: The divine conduit. Wardens channel power from a higher source to mend wounds, shield allies, and purge corruption. In a party, they’re the difference between victory and a wipe. Solo, they outlast enemies through attrition.
  • Skills per round: 2 (base)
  • Unique Mechanic: Sanctify — Once per encounter, the Warden can Sanctify the battlefield (automatic, no queue slot). While Sanctified, all healing done by the Warden is increased by 20% and undead enemies take 10% more damage from all sources. Lasts 3 rounds.
  • Starting Gear: Medium armor, shield, mace, holy symbol, healer’s pack
  • Subclasses (Level 10):
    • Lifebinder — Pure healing. Enhanced heal skills, resurrection ability, and skills that prevent damage rather than heal it after the fact.
    • Crusader — Offensive healer. Radiant damage skills, smite-like burst damage, and heals that trigger when you deal damage. The fighting priest.
    • Oathkeeper — Protection focus. Skills that redirect damage, grant damage immunity, and create healing zones. The guardian.

Pathfinder (Ranged & Scouting)

  • Role: Ranged sustained damage, scouting, dungeon navigation
  • Resource: Focus (regenerates faster than other resources — 40% between encounters)
  • Key Attributes: Speed, Logic
  • Identity: The wayfinder. Pathfinders are ranged specialists who read terrain, spot dangers, and strike from a distance. They bring a unique dungeon utility: scouting ahead to reveal traps, finding shortcuts, and identifying enemy composition before engagement.
  • Skills per round: 2 (base)
  • Unique Mechanic: Terrain Mastery — Before a dungeon run, the Pathfinder selects a terrain type (cave, forest, ruins, etc.). If the dungeon matches, they gain: +10% accuracy on all skills, +15% trap detection, and 10% chance per encounter to find a shortcut (skip the encounter entirely).
  • Starting Gear: Light armor, bow, two short swords, explorer’s pack, scout’s kit
  • Subclasses (Level 10):
    • Marksman — Pure ranged damage. Gains skills with extreme accuracy, long-range bonuses, and multi-shot abilities.
    • Beastcaller — Companion specialist. Gains an animal companion that acts as a separate combatant with its own mini-queue (2 skills). The companion persists across encounters but shares the Pathfinder’s HP pool.
    • Trailblazer — Dungeon utility. Enhanced scouting, skills that reveal the entire dungeon layout, and abilities that let the party skip non-combat encounters. Reduces dungeon run duration by up to 15%.

Berserker (Aggressive Melee)

  • Role: High-risk, high-reward melee damage
  • Resource: Fury (starts at 0, builds from damage DEALT. Capped at 100. Retains 25% between encounters. Decays -5/round while Raging.)
  • Key Attributes: Might, Fortitude
  • Identity: The storm of violence. Berserkers get stronger the more damage they deal — hitting things fuels their rage. They trade defense for offense and thrive when they can stay aggressive.
  • Skills per round: 2 (base), 3 while in Rage state
  • Unique Mechanic: Rage — When Fury reaches 50+, the Berserker enters Rage (automatic). While Raging: +25% melee damage, -15% evasion, 3 skills per round instead of 2, and immune to Frightened. Fury decays -5/round while Raging — the Berserker must keep landing hits to sustain Rage. Rage ends if Fury drops below 25.
  • Fury Generation: +1 Fury per ~3% of target’s max HP dealt. A big hit against a boss generates more Fury than chip damage against minions. Front-loading the queue with fast, reliable hits builds Fury fastest.
  • Fury Carry-Over: Retains 25% between encounters. Ending a fight at 80 Fury means starting the next at 20 — not enough for Rage, but a head start.
  • Starting Gear: No armor (uses Fortitude for base evasion), two-handed weapon, berserker’s pack
  • Subclasses (Level 10):
    • Ravager — Maximum damage. Skills that deal more damage the lower your HP. A crit-focused build that thrives at death’s door.
    • Totemist — Spiritual warrior. Choose a spirit totem (Bear: +30% HP, Eagle: -1 initiative on all skills, Wolf: allies deal +10% damage). Provides party utility while raging.
    • Bloodletter — Vampiric berserker. Skills that heal self based on damage dealt. The self-sustaining bruiser who gets harder to kill the harder they hit.

Songweaver (Support & Versatility)

  • Role: Party buffer, debuffer, jack-of-all-trades
  • Resource: Resonance (starts at max, depletes as abilities are used. Recovers 15% between encounters — the slowest pool recovery in the game. Rest points restore 50%.)
  • Key Attributes: Presence, Speed
  • Identity: The force multiplier. Songweavers don’t deal the most damage or have the most HP — they make everyone around them better. A good Songweaver in a party turns a mediocre group into an unstoppable force. Solo, they’re versatile enough to handle anything, just slower.
  • Skills per round: 2 (base)
  • Unique Mechanic: Anthem — The Songweaver maintains a persistent Anthem that provides a free passive bonus to all allies (including self) — Anthems cost NO Resonance. Choose one Anthem before the run:
    • Anthem of Valor: +8% damage to all allies
    • Anthem of Grace: +8% evasion to all allies
    • Anthem of Mending: All allies regenerate 2% max HP per round
    • Anthem of Haste: -1 initiative value on all ally skills (act faster)
  • Resource Floor: Even at 0 Resonance, the Songweaver still provides value through the free Anthem and zero-cost basic weapon attacks. They decline over long dungeons but never become dead weight.
  • Starting Gear: Light armor, rapier, musical instrument (cosmetic), entertainer’s pack
  • Subclasses (Level 10):
    • Virtuoso — Enhanced anthems. Can maintain TWO anthems simultaneously. Anthem effects increased to 12%.
    • Dirge Singer — Offensive debuffer. Gains skills that weaken, slow, frighten, and disrupt enemy groups. The anti-support.
    • War Chanter — Hybrid fighter/support. Gains melee combat skills that also buff allies when they hit. Each successful attack grants an ally a small buff.

Oathblade (Holy Warrior)

  • Role: Durable melee fighter with healing and burst damage
  • Resource: Zeal (30% recovery between encounters. Moderate pool, but Smite burns extra on top of normal skill costs, making effective burn rate ~1.5-2x faster when Smiting.)
  • Key Attributes: Might, Presence
  • Identity: The righteous warrior. Oathblades are melee fighters who channel divine power through their weapon strikes. They can heal, they can tank, and they can deal devastating burst damage — but they can’t do all three in the same dungeon run without running dry. Resource management is their core challenge.
  • Skills per round: 2 (base)
  • Unique Mechanic: Smite — Any melee weapon skill in the queue can be “empowered” with a Smite modifier (set during queue configuration). Smiting costs extra Zeal but adds 50% bonus radiant damage to the skill and an additional 25% if the target is undead. Players choose which skills to Smite and which to leave normal — Smiting everything means running dry fast; Smiting only bosses means sustained power.
  • Starting Gear: Heavy armor, martial weapon, shield, holy symbol, crusader’s pack
  • Subclasses (Level 10):
    • Avenger — Offense focus. Smite costs reduced by 25%. Gains execute-style skills that deal bonus damage to low-HP enemies. The divine executioner.
    • Sentinel — Defense focus. Gains aura skills that grant allies condition immunity, damage reduction, and healing. The party protector.
    • Inquisitor — Anti-magic focus. Gains skills that silence enemy casters, strip magical buffs, and resist magical damage. The mage-hunter.

Hexbinder (Occult Caster)

  • Role: Consistent magical damage, drain effects, dark utility
  • Resource: Essence (unique: low base pool but recharges 50% between encounters — fast cycle, small bursts)
  • Key Attributes: Logic, Presence
  • Identity: The pact-maker. Hexbinders draw power from entities beyond the material world — not gods (that’s the Warden’s domain) but stranger, older things. Their magic is consistent and self-sustaining: many skills heal the caster or debuff enemies while dealing damage. They’re the magical equivalent of a war of attrition.
  • Skills per round: 2 (base)
  • Unique Mechanic: Soul Pact — Choose a pact entity at character creation. This determines the Hexbinder’s bonus skills and playstyle:
    • Pact of the Flame: Fire-themed. Bonus fire damage on all skills. Burning condition applied frequently.
    • Pact of the Void: Necrotic-themed. Drain effects heal the Hexbinder. Skills get stronger as the fight goes longer.
    • Pact of the Eye: Psychic-themed. Powerful debuffs, mind control, and information-gathering. Less damage, more control.
  • Starting Gear: Light armor, wand or rod, occult focus, hexer’s pack
  • Subclasses (Level 10):
    • Witch — Curse specialist. Gains powerful DoT and debuff skills that stack. Multiple curses on one enemy amplify each other.
    • Soulreaper — Drain specialist. All damage skills heal for a percentage of damage dealt. Gets stronger the closer to death.
    • Fateweaver — Luck manipulation. Gains skills that force enemies to re-roll successes, grant allies re-rolls on failures, and manipulate the d100 outcomes. The probability bender.

Class Comparison Table

ClassRoleResourceRecoveryKey AttributesSkills/RoundPower Curve
VanguardTank/Melee DPSStamina50%Might, Fortitude2→3Flat (consistent)
ShadeBurst DPS/TrapsMomentum50% carrySpeed, Luck2Rising (ramps up)
ArcanistMagic DPS/AoEMana25%Logic, Fortitude2Declining (front-loaded)
WardenHealer/SupportDevotion25%Presence, Fortitude2Declining (must ration)
PathfinderRanged DPS/ScoutFocus50%Speed, Logic2Flat (sustainable)
BerserkerMelee DPS (risky)Fury25% carryMight, Fortitude2→3 (Rage)Volatile (spikes)
SongweaverBuffer/DebufferResonance15%Presence, Speed2Declining (Anthem floor)
OathbladeTank/Burst/HealerZeal30%Might, Presence2Depends on Smite use
HexbinderMagic DPS/DrainEssence50%Logic, Presence2Flat (burst cycles)

Backgrounds

Backgrounds represent what the character did before becoming an adventurer. Each provides a passive perk that affects dungeon runs and an attribute bonus (+1 to a specific attribute).

BackgroundAttribute BonusPassive Perk
Soldier+1 Fortitude+10% HP recovery at rest points
Outlaw+1 SpeedChance to find hidden caches in dungeons
Scholar+1 LogicAutomatically identify item properties on pickup
Pilgrim+1 Presence+15% healing received from all sources
Merchant+1 Luck10% better prices at NPC vendors
Survivalist+1 FortitudeConsume 20% fewer rations during runs
Aristocrat+1 PresenceStart with bonus gold; +10% gold from quest rewards
Performer+1 Presence10% chance to avoid non-boss combat via performance
Artisan+1 Logic15% faster crafting times
Wanderer+1 Speed+10% chance to find shortcuts in dungeons

Starting Equipment

Beyond class-specific gear, all characters start with:

  • 50 gold
  • 5 rations
  • 2 basic healing salves
  • 1 torch bundle (5 torches)
  • Basic adventurer’s clothing

Character Slots

  • First character: Free
  • Additional slots: Purchased from the in-game shop
  • Each character is fully independent — separate inventory, separate quests, separate progression
  • Characters on the same account can mail items and gold to each other (with a small gold transfer fee as a gold sink)
  • Only one character can be on an active dungeon run at a time per slot (but crafting/gathering can run in parallel)

New Player Experience

  1. Name and appearance — Quick portrait selection per species
  2. Species selection — Each shown with a brief description, clear attribute bonus, and species skill preview
  3. Class selection — Presented with role description and playstyle summary
  4. Attribute points — Point-buy with one-click “Recommended” per class
  5. Background — Simple selection with clear perk description
  6. Tutorial quest — A short, guided dungeon run (2 encounters) that teaches the core loop: review results → equip → build queue → commit → wait → results

The entire creation process should take under 5 minutes. Players can respec attribute points later (for a gold cost) but species and class are permanent.

Character Progression

Overview

Progression in Delve is the long-term reward cycle that keeps players engaged. Characters grow stronger through leveling (1-50), weapon proficiency (0-100), subclass specialization, feat selection, and eventually Paragon ranks after the level cap. The curve is designed for an idle game — meaningful gains every session, but the cap should take months to reach.

Level System

Level Cap: 50

50 levels provides a long, satisfying progression arc with room for meaningful milestones and customization. Every level provides something — a stat boost, a new skill, a feat choice, or a subclass feature.

XP Sources

SourceXP AmountNotes
Dungeon run completionHighScales with difficulty tier
Quest completion (bonus)MediumOne-time per quest
Per-encounter killsLow-MediumPer enemy defeated
Trap disarmingLowBonus for Shades
Puzzle solvingLowBonus for high-Logic characters
Hidden discoveriesLowExploration reward
PVP matchesLow-MediumWin or lose, bonus for winning
First craft per recipeLowOne-time per recipe
Daily first-run bonusMediumEncourages daily engagement

XP on Failed Runs

Failed runs award partial XP based on progress. A character that cleared 8 of 10 encounters earns roughly 70-80% of the full run’s XP. Failure should sting but never feel like wasted time.

Leveling Curve

Level RangePhaseApproximate TimeDesign Intent
1-10Beginner1-2 weeksHook phase. Rapid progression, learn the core loop, unlock basic systems.
11-20Intermediate2-4 weeksSubclass chosen at 10, deeper content opens, multiplayer unlocks.
21-30Advanced1-2 monthsBuild identity solidifies. Endgame content begins. Feats create meaningful choices.
31-40Expert2-3 monthsPower growth slows but each level feels significant. Raid content, faction endgame.
41-50Endgame3-4 monthsEach level is a major achievement. Capstone abilities. Preparing for Paragon.

Total time to 50: Approximately 8-12 months of regular play (1-2 sessions per day). The journey IS the game.

What You Get Per Level

Every level provides:

  • +Max HP (based on class + Fortitude)
  • +Resource pool (Stamina, Mana, Devotion, etc. — class dependent)
  • +1 attribute point every 5 levels (10, 15, 20, 25, 30, 35, 40, 45, 50 — total of 9 bonus attribute points)

Level Milestone Table

LevelMilestone
1Starting class skills and species skill
3Class feature unlock
51st Feat selection
7Class skill unlock
10Subclass selection — major branching point
10+1 Attribute point
122nd Feat selection
15Subclass feature + skill unlock
15+1 Attribute point
18Class feature unlock
203rd Feat selection
20+1 Attribute point
22Subclass feature
25Class milestone: major power spike (e.g., Vanguard gets 3 skills/round)
25+1 Attribute point
284th Feat selection
30Subclass feature + skill unlock
30+1 Attribute point
33Class feature unlock
355th Feat selection + Attribute point
38Subclass feature
40Class milestone: second major power spike
40+1 Attribute point
426th Feat selection
45Subclass capstone (ultimate subclass ability)
45+1 Attribute point
487th Feat selection
50Class capstone — defining ultimate ability + Attribute point

Attribute Growth Summary

  • At creation: ~40 distributed points + species bonus (+3/+1) + background (+1)
  • Through leveling: +9 attribute points (one every 5 levels from 10-50)
  • From gear: Varies, typically +3-8 total across equipped items at endgame
  • Theoretical endgame total: A primary attribute can reach 25-30 through optimization, 30-40 with top-tier gear and Paragon bonuses

Subclasses

Subclass selection at level 10 is the biggest single progression choice after class selection. It defines the character’s specialization for the rest of their career.

Each class has 3 subclasses (detailed in 02-character-creation.md). Subclasses provide:

  • Level 10: Core subclass skill + passive
  • Level 15: Subclass skill upgrade or new skill
  • Level 22: Subclass feature (passive enhancement)
  • Level 30: Advanced subclass skill
  • Level 38: Subclass feature (passive enhancement)
  • Level 45: Subclass capstone — a powerful ultimate ability

Subclass Cannot Be Changed

Subclass is a permanent choice. This makes it feel meaningful and encourages players to roll new characters to try different paths. Combined with weapon proficiency (which takes months to level), each character becomes a unique investment.

Feats

At levels 5, 12, 20, 28, 35, 42, and 48, players select a Feat — a permanent passive or activated bonus that customizes the character beyond class and species.

7 total feat slots over 50 levels gives players significant build variety. Two characters of the same class and subclass can play very differently based on feat choices.

Feat List (Launch Set)

Combat Feats

FeatPrerequisiteEffect
Iron WillFRT 12++15% resistance to all conditions. Your resistance checks are rolled twice, take the better result.
Lethal PrecisionSPD 12+Critical hit threshold improved by an additional 3% (stacks with Luck).
Heavy HitterMGT 12+Power-type skills (init 6+) deal +15% damage.
Quick ReflexesSPD 12+Quick-type skills (init 1-3) gain +10% accuracy.
Weapon SpecialistAny weapon prof 30+Choose one weapon type: +5% accuracy, +5% damage, and weapon proficiency gains 25% faster with that type.
Dual FocusLOG 12+When casting a magical skill, 10% chance to cast it twice (second cast is free).
RelentlessFRT 14+When reduced to 0 HP, survive with 1 HP instead. Once per dungeon run.
Overwhelming ForceMGT 14+AoE skills hit one additional target beyond their normal range.
EvasiveSPD 14++5 flat evasion rating. Dodging an attack (miss against you) grants +5% damage on your next skill.
Blood MagicLOG 12+, FRT 12+You can spend HP instead of Mana/Devotion/Essence to fuel skills (at a 2:1 ratio — 2 HP per 1 resource). Dangerous but prevents running dry.

Dungeon Feats

FeatPrerequisiteEffect
Trap SenseNone+20% trap detection. Detected traps can be avoided automatically (no disarm roll needed).
Pack RatNone+5 inventory slots. Consumable stacks increased to 30 (from 20).
Efficient TravelerNoneConsume 25% fewer rations. Rest points restore 15% more HP.
Keen EyeLOG 10+Automatically identify all item properties on pickup (normally Scholar background only). Reveal hidden rooms 15% more often.
Pathfinder’s GiftNone+15% chance to find shortcuts. Dungeon run duration reduced by 5%.
Resilient ConstitutionFRT 12+Between encounters, HP regeneration increased from 5-10% to 15-20%. Recover from one condition between encounters for free.

Social/Economic Feats

FeatPrerequisiteEffect
Silver TonguePRS 12++15% chance to avoid combat through diplomacy. NPC vendor prices improved by 10%.
Guild CommanderLevel 20+While in a party, all allies gain +3% accuracy and +3% damage (stacks with other buffs).
Fortune SeekerLCK 12++10% gold from all sources. Loot quality modifier increased by an additional 5%.
Master ArtisanAny crafting skill 50+Crafting time reduced by 20%. Critical craft chance increased by 10%.

Luck Feats

FeatPrerequisiteEffect
LuckyNone3 times per dungeon run, force a re-roll on any d100 result (yours or an enemy’s). Take whichever result you prefer.
Fate’s ChosenLCK 14+Critical miss range eliminated entirely (96-100 becomes a normal miss, not a crit miss). Lucky feat re-rolls increased to 5.

Feat Synergies

Feats are designed to create interesting build decisions when combined:

  • Heavy Hitter + Weapon Specialist (axes) = Devastating power strikes with axes
  • Quick Reflexes + Lethal Precision = Fast skills that crit frequently
  • Blood Magic + Relentless = A desperation caster who trades HP for power with a safety net
  • Lucky + Fate’s Chosen = Maximum dice manipulation — the “luck build”

Skills (Non-Combat)

Skills represent trained abilities that affect dungeon outcomes outside of combat. Each character has proficiency in skills based on class, background, and species.

Skill List

SkillAttributeDungeon Use
AthleticsMightClimb, swim, force doors, resist grapples
AcrobaticsSpeedBalance, dodge physical hazards, squeeze through gaps
StealthSpeedAvoid encounters, ambush enemies, bypass patrols
PerceptionLogicDetect traps, spot ambushes, find hidden rooms
InvestigationLogicSolve puzzles, find secret mechanisms, analyze clues
ArcanaLogicIdentify magical traps/items, interact with magical mechanisms
SurvivalFortitudeNavigate, forage for supplies, endure harsh environments
MedicineLogicStabilize dying allies, identify poisons, improve rest recovery
IntimidationPresenceScare enemies into fleeing, prevent ambushes, force information
PersuasionPresenceNegotiate with NPCs, recruit allies, avoid encounters
DeceptionPresenceBluff past enemies, mislead pursuers, create distractions
CraftsmanshipLogicRepair items, improvise tools, interact with mechanical devices

Skill Checks in Dungeons

d100 roll vs. success chance
Success Chance = Skill Base (from proficiency) + Attribute Modifier + Gear Bonuses

Proficient skills have a significantly higher base than non-proficient ones. This makes class choice matter for dungeon utility, not just combat.

Paragon System (Post-Level-50)

After hitting level 50, XP continues accumulating toward Paragon Ranks — an endgame horizontal progression system that provides incremental, uncapped growth.

Paragon Ranks

  • Each Paragon Rank requires increasing XP (same curve as late levels)
  • Each rank grants a Paragon Point
  • Paragon Points are spent on a universal Paragon tree with minor but meaningful bonuses:

Paragon Tree Categories:

CategoryBonuses Available
Combat+0.5% accuracy, +0.5% damage, +0.5% crit chance (per point)
Durability+3 max HP, +0.5% evasion, +0.5% condition resistance (per point)
Resources+1% resource pool, +0.5% resource regeneration (per point)
Fortune+0.3% loot quality, +0.3% gold find, +0.2% crit chance (per point)
Mastery+0.5% weapon proficiency gain rate, +0.5% crafting/gathering speed (per point)

Diminishing Returns

  • Paragon Points are uncapped, but each subsequent point gives slightly less total impact
  • The difference between Paragon 0 and Paragon 20 is significant
  • The difference between Paragon 80 and Paragon 100 is barely noticeable
  • This gives endgame players continuous progression without making them unreachable for newer max-level characters

Paragon Milestones

  • Paragon 10: “Paragon” title + portrait frame
  • Paragon 25: “Champion” title + enhanced portrait frame
  • Paragon 50: “Legend” title + unique cosmetic armor effect
  • Paragon 100: “Eternal” title + animated portrait frame + character statue in guild hall

Weapon Proficiency as Progression

See 04-combat-system.md for full details. Key points:

  • Each weapon type (swords, axes, daggers, bows, etc.) has an independent 0-100 proficiency track
  • Using a weapon in combat increases proficiency → unlocks new skills and passives
  • This never ends. Even at level 50 with Paragon ranks, picking up a new weapon type means starting at proficiency 0 — a whole new progression journey
  • A veteran player might have swords at 100 and axes at 60, but daggers at 15. Trying daggers gives them months of fresh progression.

Respec Rules

WhatCan Respec?Cost
Attribute pointsYesGold (scales with level — more expensive at higher levels)
FeatsYes (one at a time)Gold (scales with level)
SubclassNo — permanent choiceRoll a new character
SpeciesNo — permanent choiceRoll a new character
ClassNo — permanent choiceRoll a new character
Weapon proficiencyCannot be reset — always retainedN/A

Respec costs act as a gold sink (see 08-economy-and-trading.md). The intent: attributes and feats are adaptable, but the core identity of the character (species, class, subclass) is permanent and meaningful.

Combat System

Overview

Combat in Delve is never witnessed in real-time. The player’s job is to build a skill queue — an ordered list of skills their character will execute — and the server resolves combat automatically. After the run, the player reads a detailed combat log showing every roll, every skill fired, and exactly what happened.

The core strategic loop: build your queue → run the dungeon → read the results → adjust your queue → run again.

Design Philosophy

  • The player is the coach, not the athlete. You draft the game plan. The character executes it. Your preparation determines the outcome.
  • Every failure is a lesson. The combat log must make it clear WHY something happened — which skill missed, which enemy acted first, where the queue fell apart.
  • Progression never ends. Between character level, weapon proficiency, skill unlocks, and gear, there’s always something to improve.

Core Dice System: d100 Percentile

Delve uses a d100 (percentile) system for all combat resolution. Every skill, attack, and effect rolls a number from 1-100 against a success threshold.

How It Works

Roll d100 → Compare to success chance → Determine outcome

Every skill has a base accuracy (e.g., 75%). This is modified by the attacker’s stats, the defender’s stats, conditions, and buffs/debuffs to produce a final success chance.

Success Chance = Skill Base Accuracy + Attacker Modifier - Defender Modifier + Buffs/Debuffs
  • Roll ≤ success chanceHit
  • Roll > success chanceMiss
  • Roll ≤ 5Critical Hit (bonus damage, usually 1.5x)
  • Roll 96-100Critical Miss (skill fails and may have a penalty — wasted resource, self-debuff, etc.)

Why d100?

  • Percentages are intuitive — “you have a 73% chance to hit” is immediately understood
  • Fine-grained balance — designers can tune in 1% increments
  • Critical hits and misses are always possible, creating dramatic “clutch” and “heartbreak” moments
  • Legally distinct from any existing tabletop system

Modifiers

Attacker Modifier is derived from:

  • Relevant attribute (Might for melee, Speed for ranged, Logic/Presence for magic)
  • Weapon proficiency level (0-100, grants +0 to +15)
  • Gear bonuses
  • Buff effects

Defender Modifier is derived from:

  • Evasion rating (derived from armor, Speed, shields, and class features)
  • Debuff effects
  • Terrain/positional modifiers

Example

Skill: Crushing Blow (base accuracy 80%)
Attacker Might modifier: +8
Weapon proficiency bonus: +6 (sword mastery at level 40)
Target Evasion modifier: -12 (plate armor + shield)
Buff: Precision Stance +5

Final success chance: 80 + 8 + 6 - 12 + 5 = 87%
Roll: 34 → HIT (34 ≤ 87)

Saving Throws

When a skill inflicts a condition or effect (poison, stun, fear), the target makes a resistance check:

Roll d100 vs. Resistance Chance
Resistance Chance = Base Resistance + Relevant Ability Modifier + Gear/Buff Bonuses
  • Roll ≤ resistance chance → effect is resisted (negated or halved)
  • Roll > resistance chance → effect lands

This means high-Fortitude characters resist poison more often, high-Presence characters resist fear, etc.


The Skill Queue

The skill queue is the player’s primary interaction with combat. Before a dungeon run, the player arranges their available skills into an ordered queue. During combat, skills execute from this queue based on their initiative values, interleaved with enemy skills.

How the Queue Works

  1. The player arranges their skills in a queue (ordered list, typically 4-8 skills)
  2. Each skill has an initiative value — a fixed speed rating that determines when it fires relative to other actions in the round
  3. Each round, ALL skills from ALL combatants are sorted by initiative (lowest = fastest)
  4. Skills execute in initiative order
  5. When the player’s queue reaches the end, it loops back to the beginning
  6. The queue resets to position 1 at the start of each new encounter (but resources carry over — see Encounter Reset)

Initiative and Turn Order

Every skill has a fixed initiative value representing how fast the skill executes. Lower initiative = acts first.

Think of initiative as “wind-up time” — a quick dagger stab (init 2) fires before a heavy overhead swing (init 8).

Each round, the system collects the “next queued skill” from every combatant and sorts them:

ROUND 1 — Turn Order (sorted by initiative, lowest first):

Player Queue:          Enemy (Dire Rat):
  Slot 1: Crushing Blow (init 5)    Slot 1: Bite (init 2)
  Slot 2: Strengthening Shout (init 7)  Slot 2: Squeal (init 6)

Execution order:
  1. [Init 2] Dire Rat → Bite
  2. [Init 5] Player → Crushing Blow
  3. [Init 6] Dire Rat → Squeal
  4. [Init 7] Player → Strengthening Shout

ROUND 2 — Queue loops:
Player Queue:          Enemy (Dire Rat):
  Slot 3: Quick Slash (init 3)     Slot 3: Bite (init 2)
  Slot 4: Healing Surge (init 9)    Slot 4: Flee Check (init 10)

Execution order:
  1. [Init 2] Dire Rat → Bite
  2. [Init 3] Player → Quick Slash
  3. [Init 9] Player → Healing Surge
  4. [Init 10] Dire Rat → Flee Check

Skills Per Round

Each combatant executes 2 skills per round by default. This can be modified by:

  • Class features (e.g., Fighter gets 3 skills per round at level 11)
  • Haste-type buffs (+1 skill per round for duration)
  • Exhaustion or debuffs (-1 skill per round)
  • Specific skills that are “swift” and don’t consume a slot

This means a queue of 6 skills takes 3 rounds to cycle through before looping.

Tie-Breaking

When two skills have the same initiative value:

  1. Player character breaks ties using their character initiative stat (derived from DEX + class bonuses + gear). Higher character initiative goes first.
  2. If still tied (e.g., two enemies), resolve randomly.

Queue Slots

  • Base queue size: 6 slots
  • Certain class features expand this (e.g., Bard gets +1 slot for a support skill, Wizard gets +1 slot at level 10)
  • Maximum queue size: 10 slots (with all bonuses)
  • Minimum queue size: 3 slots (must have at least 3 skills queued)

Light Conditionals

Each skill slot in the queue can have one optional condition attached. If the condition is not met when the skill’s turn comes up, the skill is skipped and the queue advances to the next skill.

Available Conditions

Self Conditions:

  • “Use if my HP is below X%” (e.g., only heal when hurt)
  • “Use if my HP is above X%” (e.g., only use risky skills when healthy)
  • “Skip if [condition] is active on me” (e.g., don’t buff if already buffed)
  • “Use if I have [resource] remaining” (e.g., only use mana skill if mana available)

Target Conditions:

  • “Use if enemy count is above/below X”
  • “Use if target HP is above/below X%”
  • “Use if target is [enemy type]” (undead, beast, humanoid, etc.)
  • “Skip if target has [condition]” (e.g., don’t re-poison a poisoned target)

Ally Conditions (party play):

  • “Use if any ally HP is below X%”
  • “Use if ally count is below X” (e.g., emergency heal when party is dying)

Conditional Behavior

  • A skill with no condition always fires when its turn comes
  • A skill with a failed condition is skipped — the queue advances and that round’s action is lost (the character hesitates)
  • This means poorly configured conditionals can waste turns — an intentional risk/reward for using them
  • New players should leave most conditions empty and add them as they learn

Example Queue with Conditions

Slot 1: Quick Slash (init 3) ............. [no condition — always fires]
Slot 2: Crushing Blow (init 5) ........... [no condition — always fires]
Slot 3: Healing Surge (init 9) ........... [IF my HP < 50%]
Slot 4: Power Strike (init 6) ............ [no condition — always fires]
Slot 5: War Cry (init 7) ................. [IF enemy count ≥ 3]
Slot 6: Defensive Stance (init 4) ........ [IF my HP < 25%]

In this queue:

  • Slots 1, 2, and 4 always fire — reliable damage core
  • Slot 3 heals only when needed — skips if healthy (preserving the action for next cycle? No — it’s lost. The player accepts this trade-off for not wasting a heal at full HP)
  • Slot 5 only War Cries against groups — skipped against single targets
  • Slot 6 is an emergency defensive stance — almost always skipped, but catches emergencies

Skill Targeting

Each skill in the queue has a target rule that determines who it affects. The player configures this per slot.

Target Rules

Offensive Skills:

RuleBehavior
NearestClosest enemy (default for melee)
Lowest HPEnemy with the fewest hit points (finish off wounded)
Highest HPEnemy with the most hit points (focus the biggest threat)
Highest ThreatEnemy dealing the most damage (shut down their DPS)
RandomRandom enemy (unpredictable but sometimes optimal for AoE setup)
Boss/ElitePrioritize boss or elite enemies if present, otherwise fallback to nearest

Defensive/Support Skills:

RuleBehavior
SelfTarget self (default for self-buffs)
Lowest HP AllyAlly with the fewest hit points (triage healing)
Highest Threat AllyAlly drawing the most enemy attacks (keep the tank alive)
Random AllyRandom party member

Area-of-Effect (AoE) Skills:

  • AoE skills automatically target the cluster with the most enemies
  • Player can set: “Prioritize damage” (hit max enemies) or “Prioritize safety” (avoid hitting allies in the blast)

Weapon Proficiency System

Every weapon type in the game has a proficiency track from 0 to 100. Using a weapon in combat increases proficiency with that weapon type, unlocking stronger skills and passive bonuses.

Weapon Types

Each weapon belongs to a type. Proficiency is tracked per type, not per individual weapon.

Weapon TypeExamplesPrimary Stat
SwordsShortsword, Longsword, GreatswordSTR or DEX
AxesHandaxe, Battleaxe, GreataxeSTR
Maces & HammersMace, Warhammer, MaulSTR
DaggersDagger, Stiletto, Ritual KnifeDEX
PolearmsSpear, Halberd, GlaiveSTR
BowsShortbow, Longbow, Composite BowDEX
CrossbowsHand Crossbow, Light Crossbow, Heavy CrossbowDEX
StavesQuarterstaff, Battle Staff, Arcane StaffSTR or INT
WandsWand, Rod, ScepterINT or WIS or CHA
ShieldsBuckler, Kite Shield, Tower ShieldCON
UnarmedFists, Claws, Natural WeaponsSTR or DEX

Proficiency Progression

Proficiency LevelTitleAccuracy BonusSkills Unlocked
0-9Novice+0Basic attack only
10-19Apprentice+21st weapon skill
20-29Journeyman+42nd weapon skill
30-39Adept+63rd weapon skill
40-49Skilled+84th weapon skill + passive bonus
50-59Expert+95th weapon skill
60-69Master+106th weapon skill + 2nd passive
70-79Grandmaster+117th weapon skill
80-89Legend+138th weapon skill + 3rd passive
90-99Mythic+149th weapon skill
100Transcendent+15Ultimate weapon skill + final passive

Proficiency XP Gain

  • Each combat encounter where the weapon is used grants weapon proficiency XP
  • XP scales with encounter difficulty (harder fights = faster weapon growth)
  • Proficiency slows down at higher levels (0→50 takes roughly the same time as 50→100)
  • Estimated time to 100: 3-4 months of regular play with one weapon type
  • Players can level multiple weapon types, but spreading focus means slower progress per type
  • Weapon proficiency is character-bound — each character tracks their own

Passive Bonuses

At proficiency milestones (40, 60, 80, 100), the weapon type grants a passive bonus that’s always active when wielding that weapon type:

Example — Swords:

  • Prof 40: +5% critical hit chance with swords
  • Prof 60: Sword skills cost 10% less resource (mana/stamina)
  • Prof 80: +10% damage with swords
  • Prof 100: Sword attacks have a 10% chance to strike twice

These passives are unique per weapon type, encouraging players to specialize.


Skill Sources

Skills come from four sources. A character’s total available skill pool is the union of all skills they’ve unlocked from each source.

1. Weapon Skills

Unlocked by weapon proficiency (see above). These are the bulk of a character’s offensive skills.

Example — Sword Skills (unlocked at proficiency milestones):

ProfSkillInitTypeDescription
0Basic Slash5PhysicalSimple sword attack. Base accuracy 80%. Deals weapon damage.
10Quick Thrust3PhysicalFast stab. Base accuracy 75%. Low damage but acts early.
20Crushing Blow7PhysicalHeavy overhead strike. Base accuracy 70%. 1.5x damage.
30Parrying Riposte4Physical/DefensiveDefensive strike. Base accuracy 85%. Reduces incoming damage from next attack by 30%, then counterattacks.
40Whirlwind Slash6Physical/AoESpin attack hitting all adjacent enemies. Base accuracy 65%. 0.8x damage to each.
50Bleeding Edge5Physical/DoTPrecise cut. Base accuracy 78%. Deals weapon damage + Bleeding condition (damage over 3 rounds).
60Executioner’s Strike8PhysicalDevastating blow. Base accuracy 60%. 2.5x damage. Best against low-HP targets.
70Steel Tempest3Physical/AoELightning-fast series of cuts. Hits 3 random enemies. Base accuracy 72%. 0.7x damage each.
80Vorpal Edge6PhysicalEmpowered strike. Base accuracy 75%. Critical hit threshold expanded to ≤10 (double crit chance).
90Blade Cascade4PhysicalRapid combo. Base accuracy 70%. Hits same target 3 times at 0.6x damage each.
100Sword Saint’s Judgment9Physical/UltimateMassive single strike. Base accuracy 85%. 4x damage. Ignores 50% of target’s evasion. 5-encounter cooldown.

2. Class Skills

Granted by character class at specific levels. These define the class’s unique combat identity.

Example — Fighter Class Skills:

LevelSkillInitDescription
1Second Wind2Heal self for 15% max HP. 3 uses per dungeon run.
2Tactical Assessment1Swift skill (doesn’t use a queue slot). Reveals enemy weaknesses for 3 rounds (+10% accuracy for party).
3(Subclass skill)VariesDepends on subclass chosen
5Action Surge0This round, execute 3 skills instead of 2. 1 use per dungeon run.
7Intimidating Presence6Frightened condition on target (resistance check vs. CHA).
10IndomitablePassive: Once per encounter, automatically re-roll a failed resistance check.
14Veteran’s EndurancePassive: +15% max HP.
20Legendary Commander1All allies execute +1 skill this round. 1 use per dungeon run.

Example — Wizard Class Skills:

LevelSkillInitDescription
1Arcane Bolt4Basic magical attack. Uses INT. Base accuracy 80%. Scales with level.
1Mana Shield3Absorb next incoming hit, spending mana instead of HP.
2Elemental Burst6AoE damage. Choose element at queue time (fire/cold/lightning). Targets resist with relevant save.
3(Subclass skill)Varies
5Arcane Missiles23 bolts that auto-hit (no accuracy roll) for moderate damage each. High mana cost.
7Counterspell1Reactive: Negates next enemy magical skill. 2 uses per dungeon run.
10Spell WeavingPassive: 15% chance that a spell skill doesn’t consume mana.
14Meteor Strike10Massive AoE. Very high damage. Very high mana cost. Long wind-up (init 10).
20Time Stop0Execute your next 3 queued skills before anyone else acts. 1 use per dungeon run.

3. Species Skills

One skill granted by species (race). Always available from level 1.

SpeciesSkillInitDescription
HumanAdaptabilityPassive: Once per dungeon run, an action that misses by ≤5% automatically hits instead.
ElfKeen Focus2+15% accuracy on next skill. Swift (doesn’t use queue slot). 3 uses per dungeon run.
DwarfStone Endurance3Reduce incoming damage by 25% for 2 rounds. 2 uses per dungeon run.
HalflingLucky DodgePassive: When hit by a critical miss trigger (96-100), re-roll once.
OrcRelentless Fury1When reduced below 20% HP, automatically triggers: gain 10% HP back and +20% damage for 2 rounds. Once per dungeon run.
GnomeArcane ResistancePassive: +15% resistance to all magical effects.
TieflingInfernal Rebuke2When hit, automatically deal fire damage back to attacker. 3 uses per dungeon run.
DragonbornBreath Weapon7AoE elemental damage (type chosen at character creation). Base accuracy 75%. 2 uses per dungeon run.

4. Gear Skills

Some equipment grants bonus skills that can be placed in the queue. These are a major part of the loot chase — finding a weapon with a powerful attached skill is exciting.

Examples:

  • Flamebrand Longsword (Rare): Grants “Flame Burst” (init 5, AoE fire damage around the target)
  • Shield of the Sentinel (Very Rare): Grants “Guardian’s Wall” (init 1, absorb damage for lowest-HP ally for 1 round)
  • Cloak of Shadows (Uncommon): Grants “Vanish” (init 2, become untargetable for 1 round, next attack is a guaranteed critical)
  • Ring of Mending (Rare): Grants “Pulse Heal” (init 8, heal self and all allies for 10% max HP)

Gear skills follow the same rules as all other skills — they occupy a queue slot, have initiative values, and can have conditionals.


Resource System

Skills aren’t free. Most non-basic skills cost resources to use. Resource management across a multi-encounter dungeon is a core strategic concern. Each class has a unique resource with different pool sizes, recovery rates, and behaviors — this is what makes classes feel fundamentally different even when using the same weapons.

The Zero-Cost Rule

Every class has access to zero-cost basic weapon attacks. The basic attack for each weapon type (Basic Slash, Stab, Shoot, etc. at proficiency 0) costs NO resources. This ensures a character is never completely helpless when their resource runs dry — they just lose access to their powerful skills and fall back on basics. Running on empty is weak, but it’s not dead in the water.

Resource Types

ResourceUsed ByPool Size (Level 25)Between-Encounter RecoveryIn-Combat RecoveryBehavior
StaminaVanguard, Pathfinder~20050%NoneReliable workhorse. High pool, good recovery. Never flashy, never dry.
MomentumShade0-100 (capped)Retains 50% of current value+20 per roundBuilds during combat, partially carries over. Rewards aggression across encounters.
ManaArcanist~15025%NonePowerful but limited. Must ration across dungeon. Spell Mastery reduces costs over time.
DevotionWarden~14025%NonePrecious healing fuel. Running dry means the party loses its healer. Careful rationing essential.
FocusPathfinder~16050%NoneMost sustainable caster resource. Enables consistent ranged pressure across long dungeons.
FuryBerserker0-100 (capped)Retains 25% of current valueGain based on damage dealtDamage-driven. Hit things to power up. Partially carries over to reward aggressive play.
ResonanceSongweaver~18015%NoneStarts high, depletes slowly. Lowest recovery rate among pool resources. Must be managed carefully over full dungeon.
ZealOathblade~12030%NoneModerate pool. Smite burns extra on top of skill costs, so effective recovery is lower. The burst-vs-sustain tension.
EssenceHexbinder~8050%NoneSmallest pool but fastest recovery. Designed for short bursts each encounter. Never stockpiles, but never runs dry.
ChargesSpecies skills, gear skills, some class skillsFixed (varies)Do NOT recoverDo NOT recoverPowerful one-shots. Budget carefully across the whole dungeon run.

Pool sizes are approximate at level 25 with moderate attributes. Actual values scale with level + relevant attribute.

Resource Pool Formulas

ResourceFormula
Stamina60 + (Fortitude × 4) + (Level × 4)
MomentumFixed cap of 100 (not scaled by stats)
Mana30 + (Logic × 5) + (Level × 3)
Devotion30 + (Presence × 5) + (Level × 3)
Focus40 + (Logic × 4) + (Level × 3.5)
FuryFixed cap of 100 (not scaled by stats)
Resonance50 + (Presence × 4) + (Level × 4)
Zeal30 + (Presence × 3) + (Level × 3)
Essence20 + (Logic × 3) + (Level × 2)

Detailed Resource Behaviors

Stamina (Vanguard, Pathfinder)

The baseline “reliable” resource. High pool, 50% recovery between encounters. A Vanguard or Pathfinder should be able to use powered skills in every encounter of a 10-encounter dungeon without running dry — as long as they don’t exclusively spam their most expensive skills.

  • Dungeon curve: Flat. Consistent performance from encounter 1 to encounter 10.
  • Strategic tension: Low. Stamina users focus more on queue optimization than resource management.

Momentum (Shade)

Starts at 0 each dungeon. Builds +20 per round of combat. Retains 50% between encounters (rounded down).

  • Round 1: Momentum = 0 (or carry-over from last fight). Basic skills only.
  • Round 2: Momentum = 20+. Cheap powered skills available.
  • Round 3: Momentum = 40+. Mid-tier skills available.
  • Round 4+: Momentum = 60+. Premium skills available.
  • Between encounters: If ending a fight at 80 momentum → carry 40 into the next fight.
  • Dungeon curve: Ramps up. Early encounters are weaker; by encounter 3-4 the Shade enters each fight with 30-40 banked momentum and hits their power spike faster.
  • Strategic tension: Queue ordering matters enormously. Cheap skills early in the queue build momentum; expensive skills later in the queue spend it.
  • Assassin subclass bonus: Skills deal +1% damage per 5 momentum currently banked (at 80 momentum: +16% damage). Rewards banking momentum rather than spending it freely.

Mana (Arcanist)

Classic caster resource. 25% recovery is the second-lowest among pool resources (only Resonance is lower). The Arcanist must choose: go nuclear on early encounters (Fireball everything) and scrape by later, or conserve mana and deal moderate damage throughout.

  • Spell Mastery class feature reduces costs the more a skill is used in a dungeon, rewarding consistent skill selection over the full run.
  • Dungeon curve: Declining. Peak power in encounters 1-3, then gradually weaker as mana depletes. Strategic play extends the peak.
  • Strategic tension: High. Which encounters deserve your expensive spells? Can you clear this fight with cantrips and save mana for the boss?

Devotion (Warden)

Same 25% recovery as mana. But the stakes are higher: when the Warden runs dry, the party loses ALL healing. This makes Warden resource management the most consequential in the game for party play.

  • Sanctify (free, once per encounter) provides a 20% healing boost window — timing Sanctify with your biggest heals maximizes devotion efficiency.
  • Dungeon curve: Declining, with catastrophic failure state. Smart Wardens heal only when necessary and let natural regen handle minor damage.
  • Strategic tension: Highest of any class. Over-healing wastes devotion. Under-healing risks party death. The Warden is always making resource calls.

Focus (Pathfinder)

50% recovery — tied with Stamina for the best among pool resources. Combined with a moderate pool size, the Pathfinder is the most sustainable ranged class.

  • Dungeon curve: Nearly flat. Slight decline over very long dungeons but generally consistent.
  • Strategic tension: Low-medium. Pathfinders can afford to use powered skills most rounds.

Fury (Berserker)

Starts at 0. Builds based on damage dealt only (not damage taken). Each skill that hits grants Fury proportional to the damage dealt (roughly +1 Fury per 3% of target’s max HP dealt). Retains 25% between encounters.

  • Rage triggers at 50 Fury: +25% melee damage, -15% evasion, 3 skills per round, immune to Frightened.
  • Rage ends if Fury drops below 25 (Fury naturally decays -5/round while Raging, creating a timer — must keep hitting to sustain it).
  • Between encounters: If ending at 70 Fury → carry 17 into next fight. Not enough to start Raging, but a head start.
  • Dungeon curve: Volatile. Short easy fights may never trigger Rage. Long hard fights trigger Rage quickly. Boss encounters are where Berserkers shine.
  • Strategic tension: Medium. Queue should front-load fast, reliable hits to build Fury, then switch to heavy power skills once Raging.

Resonance (Songweaver)

Starts at max. 15% recovery between encounters — the lowest of any pool resource. The Songweaver’s arc is unique: they start as the strongest buffer in the game and gradually weaken.

  • Anthem is free — the passive Anthem effect costs no Resonance and is always active. The Songweaver is never useless.
  • Active skills (buffs, debuffs, heals) cost Resonance.
  • Dungeon curve: Declining, but with a floor. Even at 0 Resonance, the Anthem provides value and basic weapon attacks are free.
  • Strategic tension: Very high. Every active skill expenditure is a permanent investment. Is this encounter worth blowing a buff, or should you coast on the Anthem and basic attacks?
  • Rest points provide a significant Resonance boost (50%), making rest point decisions critical for Songweavers.

Zeal (Oathblade)

Moderate pool, 30% recovery. The catch: Smite costs Zeal ON TOP OF the skill’s normal cost. A Smited Crushing Blow costs the base Crushing Blow stamina/zeal PLUS the Smite surcharge. This makes Oathblades burn resources roughly 1.5-2x faster than other classes when Smiting.

  • Dungeon curve: Depends entirely on Smite usage. An Oathblade who Smites every skill is dry by encounter 5. One who only Smites bosses lasts the whole dungeon.
  • Strategic tension: High. Which skills to Smite is the core Oathblade decision. Smite the opening power strike for burst? Or save Smites for the boss?
  • Avenger subclass reduces Smite cost by 25%, making the burn rate much more sustainable.

Essence (Hexbinder)

Smallest pool but 50% recovery — the fast-cycle resource. A Hexbinder enters each encounter with a small burst window (3-4 powered skills), then falls back to basics or drain-style skills that are cheap/free.

  • Pact of the Void subpath makes drain skills cost 0 Essence but deal 15% less damage — the sustained option.
  • Dungeon curve: Flat but in a different way from Stamina. Each encounter is a mini-cycle: burst → conserve → burst → conserve.
  • Strategic tension: Medium. The question isn’t “will I run dry over the dungeon” but “how do I get maximum value out of my 3-4 powered skills per encounter.”

Resource Recovery at Rest Points

Rest points (see 06-quests-and-dungeons.md) provide enhanced recovery:

ResourceRest Point Recovery
Stamina100% (full)
MomentumSet to 50 (regardless of current value)
Mana50%
Devotion50%
Focus100% (full)
FurySet to 0 (rage subsides during rest)
Resonance50% (crucial for Songweavers)
Zeal50%
Essence100% (full)
ChargesDo NOT recover (even at rest)

Running Out of Resources

When a skill in the queue would fire but the character doesn’t have enough resources:

  • The skill is skipped (same as a failed conditional)
  • The queue advances to the next slot
  • The character does NOT lose the action — if the next slot has an affordable skill (or a zero-cost basic attack), it fires instead
  • If NO skills in the queue are affordable, the character performs a zero-cost basic weapon attack as a fallback

This means even depleted characters contribute damage. They’re significantly weaker, but never dead weight.

10-Encounter Dungeon Performance Summary

How each class performs across a full 10-encounter dungeon (no rest points):

ClassEnc 1-3Enc 4-6Enc 7-10Overall Arc
Vanguard★★★★★★★★★Flat — consistent all dungeon
Shade★★★★★★★★★Rising — builds momentum carry-over
Arcanist★★★★★★★★★Declining — front-loaded power
Warden★★★★★★★★Declining — must ration heals
Pathfinder★★★★★★★★★Flat — sustainable ranged
Berserker★★★★★★★★★Volatile — spikes on hard fights
Songweaver★★★★★★★★★Declining — Anthem sustains floor
Oathblade★★★★★★★★★Declining — if Smiting; Flat if conserving
Hexbinder★★★★★★★★★Flat — burst/recover cycle each encounter

This diversity of power curves is intentional. Parties benefit from mixing classes with different arcs — an Arcanist who goes nuclear early paired with a Shade who comes online later creates sustained total DPS across the dungeon.


Encounter Flow

1. Surprise Check

Attacker Stealth Rating vs. Defender Perception Rating → d100 roll
  • If the party’s scout (highest stealth) beats the enemies’ perception → party gets a surprise round (one full cycle of skills before enemies act)
  • If enemies beat the party’s perception → enemies get a surprise round
  • Shades and Pathfinders have class bonuses to stealth; Perception is a key defensive stat

2. Combat Rounds

Each round:

  1. Collect the next queued skill from each combatant
  2. Sort all skills by initiative value (lowest first)
  3. Execute skills in order, resolving hits/misses/effects
  4. Check for triggered reactive skills (species abilities, gear procs)
  5. Apply end-of-round effects (DoTs, condition timers, regeneration)
  6. Check for combat end conditions

3. Combat Ends When

  • All enemies reach 0 HP (victory)
  • The player character reaches 0 HP (defeat — see Death and Recovery)
  • A special condition is met (survive X rounds, destroy an object, etc.)
  • An enemy flees (some enemies flee at low HP)

4. Between Encounters (Partial Reset)

  • Queue resets to slot 1
  • HP does NOT fully recover — only natural regen (5-10% based on Fortitude) unless a healing skill or potion is available
  • Resource recovery varies by type (see Resource System above):
    • Stamina/Focus/Essence: 50%
    • Zeal: 30%
    • Mana/Devotion: 25%
    • Resonance: 15%
    • Momentum: retains 50% of current value
    • Fury: retains 25% of current value
    • Charges: do NOT recover
  • Conditions persist (poison, bleeding, etc. carry to next encounter unless cured)
  • Cooldowns tick down (a 5-encounter cooldown skill becomes available sooner)

This partial reset creates tension across a full dungeon run. A player who blows all their mana in encounter 1 will struggle by encounter 5.


Conditions and Effects

Conditions are status effects applied during combat by skills, traps, environmental hazards, and enemy abilities. They are central to strategy — applying the right debuffs and avoiding the wrong ones is as important as raw damage.

Conditions fall into three categories: Debuffs (harmful, applied to enemies), Buffs (beneficial, applied to self/allies), and Environmental (caused by dungeon hazards, affect everyone).

How Conditions Work

  • Application: A skill that inflicts a condition triggers a resistance check on the target (unless the condition is irresistible or a buff)
  • Resistance check: d100 roll vs. target's Resistance Chance for the relevant attribute. Roll ≤ resistance chance = resisted (condition doesn’t apply). Roll > resistance chance = condition lands.
  • Resistance Chance formula: Base Resistance (30%) + (Relevant Attribute × 2%) + Gear/Buff Bonuses + Fortitude Blanket Bonus
  • Fortitude blanket bonus: Every point of Fortitude above 10 adds +1.5% to ALL resistance checks, regardless of type. This makes Fortitude the universal defensive attribute for conditions.
  • Stacking: Most conditions do NOT stack with themselves. Reapplying a condition refreshes the duration instead. Exceptions are noted (Bleeding, Exhaustion).
  • Condition cap: A character can be affected by a maximum of 5 debuffs simultaneously. If a 6th is applied, the one with the shortest remaining duration is removed. This prevents debuff avalanches from making a character completely nonfunctional.
  • Cleansing: Conditions can be removed early by cleanse skills (Warden, Songweaver, some consumables), or by specific counters noted per condition.

Debuffs (Harmful Conditions)

Physical Debuffs

Bleeding

  • Effect: Lose 4% of max HP at the end of each round. Does not trigger resistance checks to end — runs its full duration.
  • Duration: 3 rounds
  • Resisted By: Fortitude
  • Stacking: YES — each application adds a separate Bleeding stack. 3 stacks of Bleeding = 12% max HP per round. Max 5 stacks.
  • Cured By: Healing skill (removes 1 stack per heal), Healer’s Kit consumable (removes all stacks), rest point (removes all stacks)
  • Strategic Notes: Bleeding is the primary sustained damage condition. Classes like the Shade (Saboteur) and weapons like daggers (Bleeding Edge) specialize in stacking bleeds. Against high-HP bosses, stacking bleeds can outdamage direct attacks. Fortitude-heavy builds resist the initial application but can’t stop it once it’s on.
  • Combat Log Display: ⚠ BLEEDING (×2) — Losing 8% max HP/round (14 damage/round). 2 rounds remaining.

Poisoned

  • Effect: -12% accuracy on all skills AND -12% damage dealt.
  • Duration: 4 rounds OR until cured
  • Resisted By: Fortitude
  • Stacking: No (refreshes duration)
  • Cured By: Antidote consumable (instant cure), Warden cleanse skill, rest point, or Fortitude resistance check at end of each round (separate roll — 50% of normal resistance chance, so it’s hard to shake off naturally)
  • Strategic Notes: Poison is a comprehensive debuff that makes the target worse at everything. It’s most effective against damage dealers (reducing their output) and against enemies with high accuracy (making them miss). The per-round resistance check means high-Fortitude characters can shrug it off naturally; low-Fortitude characters are stuck for the full duration.
  • Combat Log Display: ☠ POISONED — -12% accuracy, -12% damage. 3 rounds remaining. End-of-round Fortitude check: d100: 72 vs. 23% → FAILED to shake off.

Weakened

  • Effect: -20% damage dealt on all skills.
  • Duration: 3 rounds
  • Resisted By: Might
  • Stacking: No (refreshes duration)
  • Cured By: Buff skills that grant Empowered (overrides Weakened), cleanse, rest point
  • Strategic Notes: Pure damage reduction debuff. Most effective against enemies with few but powerful attacks (bosses). Less useful against swarm enemies. Resisted by Might, so casters and healers are more vulnerable to it.

Exhaustion

  • Effect: Cumulative debuff with escalating levels. Each level stacks on the previous:
    • Level 1: -5% accuracy, -5% damage, -5% evasion
    • Level 2: -10% all stats, resource recovery between encounters halved
    • Level 3: -20% all stats, only 1 skill per round
    • Level 4: Unconscious (effectively dead for the encounter; in party play, can be revived)
  • Duration: Until a rest point is reached OR the dungeon ends. Does NOT expire on its own.
  • Resisted By: Cannot be resisted. Exhaustion is a dungeon management mechanic, not a combat mechanic.
  • Stacking: YES — by levels. Each new source of exhaustion adds +1 level.
  • Caused By: Running out of rations, failing certain environmental hazards, Berserker’s Frenzy subclass abilities, some boss mechanics, consecutive fights without rest
  • Cured By: Rest points reduce exhaustion by 1 level. Some Warden skills can reduce by 1 level. Completing the dungeon fully removes exhaustion.
  • Strategic Notes: Exhaustion is the penalty for poor preparation — not bringing enough rations, skipping rest points, or pushing through content that’s too hard. It’s also a design tool for making dungeon length matter. A 15-encounter dungeon without rest points will exhaust characters who aren’t prepared.
  • Combat Log Display: ⚡ EXHAUSTION Level 2 — -10% all stats, resource recovery halved.

Elemental Debuffs

Burning

  • Effect: Lose 6% of max HP at the start of each round. If another Burning creature is adjacent, 25% chance to spread Burning to non-burning adjacent targets (enemies AND allies — friendly fire risk for AoE fire skills).
  • Duration: 2 rounds
  • Resisted By: Speed (dodge the initial source)
  • Stacking: No (refreshes duration)
  • Cured By: Using an action to extinguish (costs a queue slot — the “Extinguish” fallback action), water-based environmental effects, cold damage (removes Burning), cleanse
  • Strategic Notes: Burning is high damage-over-time but short duration and has a built-in counterplay (spend an action to extinguish). The spread mechanic makes Burning powerful against groups but dangerous in parties — an Arcanist (Evoker) who Burns an enemy adjacent to the party’s Vanguard may accidentally set the tank on fire. The Evoker subclass can shape AoE to avoid this.

Frozen

  • Effect: Initiative values on ALL skills increased by +4 (act significantly slower). -10% evasion (harder to dodge while frozen in place).
  • Duration: 2 rounds
  • Resisted By: Fortitude
  • Stacking: No (refreshes duration)
  • Cured By: Fire damage (removes Frozen), Burning condition (removes Frozen — fire and ice cancel), cleanse, natural expiration
  • Counter-Synergy with Burning: Frozen and Burning cancel each other. Applying Burning to a Frozen target removes Frozen (and vice versa). This creates tactical decisions — do you Freeze an enemy to slow them, knowing your Arcanist’s fire spells will unfreeze them?
  • Strategic Notes: Frozen is the premier “slow you down” debuff. In the skill queue system, +4 initiative is devastating — a Quick Thrust (init 3) becomes init 7, acting after most enemy skills. Frozen is best used against fast enemies to neutralize their speed advantage.

Shocked (Lightning)

  • Effect: 30% chance each round that the next queued skill fizzles (activates but automatically misses, still consuming resources). Additionally, -5% accuracy on all skills.
  • Duration: 2 rounds
  • Resisted By: Fortitude
  • Stacking: No (refreshes duration)
  • Cured By: Cleanse, natural expiration
  • Strategic Notes: Shocked is the most RNG-heavy debuff. The 30% fizzle chance creates dramatic moments in the combat log — the enemy boss’s devastating power strike fizzles harmlessly due to being Shocked. Unreliable but potentially game-changing.

Corroded (Acid)

  • Effect: -15% evasion (armor is dissolving) AND all incoming damage increased by 10%.
  • Duration: 3 rounds
  • Resisted By: Fortitude
  • Stacking: No (refreshes duration)
  • Cured By: Cleanse, natural expiration
  • Strategic Notes: Corroded is a “damage amplifier” debuff. It doesn’t deal damage directly but makes the target dramatically more vulnerable to everything else. Apply Corroded first, THEN hit with power strikes. Excellent in party play where one character applies Corroded and others exploit it.

Mental Debuffs

Frightened

  • Effect: -15% accuracy on all skills. Cannot target the source of fear (skills targeting the frightener are redirected to the next valid target per the target rule). If the source of fear is the ONLY enemy, -25% accuracy instead (nowhere to redirect).
  • Duration: 2 rounds
  • Resisted By: Presence
  • End-of-round check: At the end of each round, the Frightened character makes a Presence resistance check at 50% of normal resistance chance. Success removes Frightened early.
  • Cured By: Warden cleanse, Songweaver’s Anthem of Valor (provides immunity while active), Berserker’s Rage (grants immunity), natural end-of-round check
  • Strategic Notes: Frightened is the premiere “keep away” condition. A tank who Frightens enemies protects squishier allies. An enemy that Frightens the party’s damage dealer can stall a fight. Presence-focused classes (Warden, Songweaver, Oathblade) resist it easily; Logic/Speed classes are more vulnerable.

Charmed

  • Effect: Cannot target the charmer with any offensive skill. 25% chance each round that the Charmed character’s offensive skill targets a random ally instead of an enemy (in party play — solo characters target themselves for reduced damage). The Charmed character’s accuracy against non-charmer targets is unaffected.
  • Duration: 3 rounds OR until the Charmed character takes damage from any source (damage breaks the charm)
  • Resisted By: Presence
  • Stacking: No (refreshes duration and source)
  • Cured By: Taking any damage (including DoTs — a Bleeding character auto-breaks charm), cleanse, natural expiration
  • Strategic Notes: Charm is terrifying in party play — a Charmed Berserker might Crushing Blow their own Warden. The counterplay is immediate: ANY damage breaks it. This means Burning or Bleeding actually serves as charm protection. Clever parties ensure their high-damage members always have a minor DoT ticking to prevent charm disasters.
  • Combat Log Display: 💜 CHARMED by Siren — Cannot target Siren. Friendly fire risk: 25%. Damage will break charm.

Confused

  • Effect: Each round, 40% chance that the queued skill targets a random combatant (could be an ally, an enemy, or self) instead of the configured target. Remaining 60% of the time, skills execute normally.
  • Duration: 2 rounds
  • Resisted By: Logic
  • Stacking: No (refreshes duration)
  • Cured By: Cleanse, natural expiration
  • Strategic Notes: Confused is the “chaos” debuff. Unlike Charm (which has a clear source and clear counterplay), Confusion is just random disruption. It’s less severe than Charm (40% misdirection vs. guaranteed) but has no easy counterplay. Most dangerous on high-damage characters.

Silenced

  • Effect: Cannot use magical skills (any skill tagged as Magical type). Physical and weapon skills are unaffected. Resource-based class skills that require verbal/magical components are also blocked.
  • Duration: 2 rounds
  • Resisted By: Logic
  • Stacking: No (refreshes duration)
  • Cured By: Cleanse, natural expiration
  • Affected Classes: Arcanist (severely — most skills are magical), Warden (healing skills are magical), Hexbinder (most skills), Songweaver (active buffs are magical, but Anthem persists since it’s passive). Vanguard, Shade, Berserker, Pathfinder largely unaffected.
  • Strategic Notes: Silence is an anti-caster condition. The Oathblade (Inquisitor) subclass specializes in applying Silence. Against a party, Silencing the Warden shuts down healing. Against enemy casters, Silence is the best counter available.
  • Combat Log Display: 🔇 SILENCED — Cannot use magical skills. Physical skills unaffected. 2 rounds remaining.

Movement/Action Debuffs

Stunned

  • Effect: Skip the next queued skill entirely (lose 1 action). If a character would execute 2 skills this round, they only execute 1. If they would execute 1 (already Slowed), they execute 0.
  • Duration: 1 round (always — Stun is short but devastating)
  • Resisted By: Fortitude
  • Stacking: No. If already Stunned, reapplication has no effect (can’t double-stun).
  • Cured By: Automatic after 1 round. Cannot be cleansed early (it’s too fast — cleanse happens on your turn, but the stun already consumed your action).
  • Strategic Notes: Stun is the strongest single-round debuff in the game. Losing an entire action in a queue-based system is massive — it pushes back your entire queue by one slot, potentially desynchronizing combos. The Shield skill line (Shield Bash) is one of the most reliable Stun sources. Bosses typically have increased Stun resistance or are immune.

Slowed

  • Effect: Only execute 1 skill per round instead of 2 (or instead of 3 for Raging Berserkers / Vanguards at level 25+).
  • Duration: 2 rounds
  • Resisted By: Speed
  • Stacking: No (refreshes duration)
  • Cured By: Haste buff (overrides Slow — they cancel each other), cleanse, natural expiration
  • Counter-synergy with Haste: Slowed and Hasted cancel each other. Applying Haste to a Slowed character removes Slow. Applying Slow to a Hasted character removes Haste.
  • Strategic Notes: Slowed is Stun’s longer, milder cousin. Losing 1 skill per round for 2 rounds means losing 2 total skills — same as being Stunned twice. But Slowed is resistable, cleansable, and counterable with Haste. Most effective against Berserkers (drops them from 3 skills/round while Raging to 1 — devastating).

Blinded

  • Effect: -25% accuracy on all skills. Cannot detect traps (if Blinded during a trap encounter). Auto-fail sight-based skill checks.
  • Duration: 2 rounds
  • Resisted By: Speed (dodge the blinding effect)
  • Stacking: No (refreshes duration)
  • Cured By: Cleanse, Warden healing skill (some remove Blinded as a secondary effect), natural expiration
  • Strategic Notes: Blinded is the heaviest single accuracy penalty in the game. A Blinded character with 80% base accuracy drops to 55% — coin-flip territory. Most impactful on power-strike builds where every miss is a massive DPS loss. Less impactful on DoT/condition builds that don’t rely on accuracy as much.

Rooted

  • Effect: Cannot use skills tagged as “movement” or “repositioning.” Melee skills can only target adjacent enemies (can’t close distance). Ranged skills are unaffected. -10% evasion.
  • Duration: 2 rounds
  • Resisted By: Might (brute force to break free)
  • Stacking: No (refreshes duration)
  • Cured By: Might resistance check at end of each round (50% of normal chance), cleanse, fire damage (burns the roots)
  • Strategic Notes: Rooted is a positioning debuff. In a system without physical movement, its primary effect is preventing certain skills that involve repositioning (Shadow Step, dash-type abilities) and reducing evasion. Most impactful against Shades and other mobile classes.

Buffs (Beneficial Conditions)

Buffs are applied by support skills, self-buffs, consumables, and some class mechanics. They cannot be resisted (you don’t resist your own buffs). They CAN be dispelled by enemy skills that strip buffs (Vexari’s Unravel, Hexbinder’s Witch subclass).

Inspired

  • Effect: +10% accuracy and +10% damage on all skills.
  • Duration: 2 rounds
  • Source: Songweaver skills, Ashenmere species skill (Soul Echo), some gear
  • Dispellable: Yes
  • Strategic Notes: The bread-and-butter combat buff. Simple, universally useful, always worth applying. Best on high-damage allies (10% of a big number is a big bonus).

Empowered

  • Effect: +20% damage on all skills. Overrides Weakened (removes it if present).
  • Duration: 2 rounds
  • Source: Berserker self-buffs, Oathblade aura skills, Songweaver War Chanter skills
  • Dispellable: Yes
  • Strategic Notes: Stronger than Inspired’s damage component but doesn’t include accuracy. Best on characters who already have high accuracy and want to push their damage ceiling.

Shielded

  • Effect: Absorb the next X points of damage before HP is affected. Shield value varies by the skill that applied it (typically 10-30% of the caster’s max HP). Multiple Shielded effects stack their absorb values.
  • Duration: Until depleted OR 5 rounds (whichever comes first)
  • Source: Vanguard (Bulwark), Warden skills, Shield weapon skills, some gear
  • Dispellable: Yes (dispel removes the entire shield)
  • Strategic Notes: Shielded is the premier damage prevention buff. It’s more efficient than healing because it prevents damage before it happens (no HP lost, no healing needed). Stacking shields on a character before a boss encounter is a powerful preparation strategy.

Regenerating

  • Effect: Recover 4% of max HP at the start of each round.
  • Duration: 3 rounds
  • Source: Warden heal-over-time skills, Thornkin species skill (Regenerative Bark — enhanced version), some potions, Songweaver Anthem of Mending (weaker but free and permanent)
  • Dispellable: Yes
  • Strategic Notes: Efficient healing over time. 4% per round × 3 rounds = 12% total — often more than a direct heal for the same resource cost. Best applied proactively before damage is taken.

Hasted

  • Effect: Execute 3 skills per round instead of 2 (or 4 instead of 3 for Raging Berserkers). Overrides Slowed (removes it if present).
  • Duration: 2 rounds
  • Source: Arcanist (Chronomancer) skills, rare consumables (Potion of Speed), high-level Songweaver skills
  • Dispellable: Yes
  • Strategic Notes: Haste is one of the most powerful buffs in the game. An extra skill per round for 2 rounds means 2 extra actions total — effectively a free round of combat. Because the skill queue loops, Haste doesn’t just add actions, it accelerates your queue cycle, getting you back to your best skills faster. Extremely valuable on damage dealers.

Fortified

  • Effect: +15% evasion and +15% resistance to all conditions.
  • Duration: 3 rounds
  • Source: Vanguard defensive skills, Shield skills (Shield Wall), Oathblade (Sentinel) aura, some potions
  • Dispellable: Yes
  • Strategic Notes: The defensive counterpart to Inspired. Makes a character harder to hit and harder to debuff. Best applied to the character most likely to be targeted (the tank) or most vulnerable to conditions (the Arcanist with low Fortitude).

Focused

  • Effect: Critical hit threshold improved by +5% (e.g., base ≤5 becomes ≤10). Next critical hit deals 2x damage instead of the normal 1.5x.
  • Duration: 3 rounds OR until a critical hit is scored (whichever comes first)
  • Source: Shade self-buffs, Pathfinder (Eagle Eye), Assassin subclass skills, some gear
  • Dispellable: Yes
  • Strategic Notes: Focused turns the next critical hit into a devastating blow. Best applied before a high-accuracy, multi-hit skill (Viper’s Dance, Arrow Storm) to maximize the chance of triggering the enhanced crit.

Invisible

  • Effect: Cannot be targeted by single-target enemy skills for the duration. AoE skills still affect Invisible characters. First offensive skill used while Invisible gains +20% accuracy and +20% damage (the Invisible character then becomes visible).
  • Duration: 1 round OR until an offensive skill is used
  • Source: Shade (Phase Step, Shadow Step), Potion of Invisibility, Phantom subclass skills
  • Dispellable: No (it’s a physical state, not a magical effect)
  • Strategic Notes: Invisibility is a powerful burst setup — become invisible, then unleash a devastating skill at +20%. It’s also defensive in that enemies can’t target you for a round. The AoE vulnerability prevents it from being a complete immunity.

Taunted (Forced Targeting)

  • Effect: Affected enemy MUST target the Taunter with their next offensive skill. If the Taunter is untargetable (Invisible, dead), the Taunt breaks.
  • Duration: 2 rounds
  • Source: Vanguard skills (Guardian Stance, Bulwark subclass), Shield skills, Intimidation-based skills
  • Applied to: Enemies (it’s technically a debuff on the enemy, but listed here because it’s a tank BUFF mechanic)
  • Resisted By: Presence (the enemy resists being forced)
  • Strategic Notes: Taunt is the core tanking mechanic. A Vanguard who can reliably Taunt enemies protects the party’s squishier members. Taunt interacts with the enemy’s queue — the enemy’s next skill is forced to target the Taunter, which may waste a heal or buff on an offensive action. Bosses may have Taunt resistance or immunity on certain phases.

Environmental Conditions

These are applied by dungeon hazards, traps, and environmental effects — not by skills. They affect any character in the encounter.

Darkness

  • Effect: All characters without Darkvision: -15% accuracy, -25% trap detection, cannot detect hidden rooms. Characters WITH Darkvision (some species or gear) are unaffected.
  • Duration: Entire encounter (or until a torch is used)
  • Cured By: Using a torch (consumable), Light-producing skills, Darkvision gear
  • Strategic Notes: This is why you bring torches. A dark encounter without torches is a serious handicap, especially for trap detection. Some dungeon types (caves, crypts) are primarily dark.

Wet

  • Effect: +50% damage from Lightning/Shock effects. -50% damage from Fire effects. Burning condition is immediately removed.
  • Duration: Entire encounter OR 3 rounds after the water source is passed
  • Caused By: Flooded rooms, rain, water traps
  • Strategic Notes: Wet dramatically changes elemental combat math. An Arcanist (Evoker) should switch from fire to lightning spells in wet encounters. Enemies in a flooded room are extremely vulnerable to Chain Lightning.

Extreme Heat

  • Effect: All characters lose 2% max HP per round. Fire resistance reduces this to 1%. Fortitude resistance check each round — failure adds 1 Exhaustion level at the end of the encounter.
  • Duration: Entire encounter
  • Caused By: Volcanic areas, fire-themed dungeons, desert environments
  • Strategic Notes: Extreme Heat makes long fights dangerous. Quick kills are rewarded. Fire Resistance Potions become essential in fire-themed dungeons.

Extreme Cold

  • Effect: All characters have +2 initiative on all skills (act slower). Fortitude resistance check each round — failure adds 1 Exhaustion level at the end of the encounter. Fire-based skills deal +15% damage (the heat is welcome).
  • Duration: Entire encounter
  • Caused By: Frozen areas, ice-themed dungeons, mountain peaks
  • Strategic Notes: Extreme Cold slows everyone down and punishes long fights. The fire damage bonus makes fire-based builds situationally excellent in cold dungeons.

Cursed Ground

  • Effect: Healing effectiveness reduced by 50%. Regenerating condition ticks for half value. Necrotic damage increased by 25%.
  • Duration: Entire encounter
  • Caused By: Undead lairs, corrupted areas, necromantic rituals
  • Strategic Notes: Cursed Ground makes healer-dependent parties struggle and is the signature hazard of undead dungeons. Parties should bring extra healing potions for cursed encounters and avoid relying solely on the Warden.

Arcane Interference

  • Effect: All magical skills have -10% accuracy. Mana/Essence/Devotion costs increased by 25%. Physical skills are unaffected.
  • Duration: Entire encounter
  • Caused By: Anti-magic zones, Sundering scars, specific dungeon rooms
  • Strategic Notes: Arcane Interference punishes magic-heavy parties. Fights in these zones favor physical damage dealers (Vanguard, Shade, Berserker, Pathfinder with bows). Arcanists and Hexbinders should switch to weapon skills if they have proficiency.

Condition Interactions

Certain conditions interact with each other in specific ways. These interactions create tactical depth and reward players who understand the system.

Condition A+ Condition BInteraction
Burning+ FrozenCancel each other (both removed)
Burning+ WetBurning is immediately removed
Frozen+ Fire damageFrozen is removed; fire damage deals +25%
Wet+ ShockedShock duration doubled; fizzle chance increased to 50%
Wet+ Lightning damageLightning damage deals +50%
Hasted+ SlowedCancel each other (both removed)
Empowered+ WeakenedEmpowered removes Weakened
Charmed+ Any damageCharm is broken (removed)
Bleeding+ CharmedBleed tick breaks Charm immediately
Invisible+ BurningThe flames reveal the character — Invisible is removed
Rooted+ Fire damageRoots burn away — Rooted is removed
Poisoned+ RegeneratingBoth active simultaneously — regen heals, poison weakens. They don’t cancel.

Condition Immunity

Some abilities grant immunity to specific conditions:

  • Berserker Rage: Immune to Frightened
  • Ironborn (Unyielding): Immune to Rooted while Shielded
  • Fortified buff: Not immunity, but +15% resistance makes conditions much harder to land
  • Boss mechanics: Many bosses are immune to Stunned and Charmed (noted in their stat block). No boss is immune to Bleeding or Burning (DoTs always work, ensuring damage-over-time builds remain viable against all content).

Condition Priority in the Combat Log

The combat log displays active conditions prominently:

YOUR STATUS: HP 142/200 (71%) | Stamina 64/180
  Active: Inspired (1 round), Bleeding ×2 (2 rounds)
  Losing 8% HP/round from Bleeding

ENEMY STATUS: Goblin Boss HP 89/150 (59%)
  Active: Poisoned (3 rounds), Corroded (2 rounds)
  -12% accuracy, -12% damage, -15% evasion, +10% incoming damage

After each encounter, the log summarizes condition impact:

📊 CONDITION IMPACT:
  Your Bleeding stacks dealt 42 total damage to you (24% of damage taken)
  Your Poisoned debuff on Goblin Boss reduced its damage output by ~18 points
  Your Corroded debuff on Goblin Boss increased party damage to it by ~31 points
  💡 TIP: Bringing Antidotes would have prevented 42 Bleeding damage.
     The Goblin Shaman applied Bleeding twice — consider focusing it first.

Death and Recovery

Falling to 0 HP

When a character reaches 0 HP:

  • Solo play: The character is defeated. The encounter (and the run, if no revival items) ends in failure.
  • Party play: The character falls unconscious. Each round, roll d100:
    • ≤30: Stabilize (stop dying, remain unconscious at 1 HP)
    • 31-90: No change (still dying)
    • 91-100: Worsen (one step closer to death — 3 worsens = eliminated from the run)
    • Allies can use healing skills/items on unconscious characters to revive them

Revival Items

  • Revive Scroll (consumable): Immediately revive with 25% HP. Rare and valuable.
  • Certain class skills can revive (Warden’s “Breath of Life”, Oathblade’s “Lay on Hands” at high level)

Run Failure Penalties

  • Character returns to town
  • Partial XP awarded based on encounters completed (~70-80% of earned XP)
  • Consumables used during the run are lost (potions, rations, scrolls, charges)
  • Gear is NOT lost — no durability loss, no item destruction
  • Recovery timer before next run: 15 minutes to 2 hours (scales with dungeon depth)
  • Weapon proficiency XP is kept — even failed runs contribute to weapon mastery

Why No Permadeath

You can’t intervene in an idle game. Permadeath for something you couldn’t control would be rage-inducing. The penalty — lost time, lost consumables, recovery timer — is meaningful enough to make preparation matter without being devastating.


Skill Design Framework

Skills are categorized by role to ensure a wide variety of strategic options. Every weapon type and class should have skills across multiple categories.

Skill Categories

CategoryPurposeInit RangeResource Cost
Quick StrikeFast, reliable damage. Low risk.1-3Low
Power StrikeHeavy damage. Slow but impactful.6-9Medium-High
AoEHit multiple targets. Good vs. groups.5-8High
DoT (Damage over Time)Apply conditions that deal damage over rounds. Efficient vs. high-HP enemies.4-6Medium
BuffStrengthen self or allies. Front-load for later payoff.2-5Medium
DebuffWeaken enemies. Reduce their accuracy, damage, or speed.3-6Medium
HealRestore HP to self or allies.5-9Medium-High
DefensiveReduce incoming damage, raise evasion, absorb hits.1-4Medium
UltimateExtremely powerful, very limited use (1-2 per dungeon run). Game-changing.0-10Charges (fixed uses)
UtilityNon-damage effects: cleanse conditions, reveal weaknesses, reposition.2-5Low-Medium

Skill Design Rules

  1. Every skill must have a meaningful initiative value. Fast skills are weaker; slow skills are stronger. This is the core trade-off.
  2. No skill should be strictly better than another in all situations. Quick Thrust is faster but weaker than Crushing Blow — both have a place.
  3. Skills should combo. A debuff that lowers evasion makes the next power strike more likely to hit. A buff that increases damage makes the next AoE more devastating. Queue ordering matters.
  4. Resource costs create choices. A full queue of power strikes runs out of stamina fast. Mixing in basic attacks extends the run.
  5. Skills per weapon should feel thematically distinct. Sword skills feel different from axe skills — swords are precise and combo-oriented; axes are raw power and cleave.

Expanded Skill Lists by Weapon Type

Axes

ProfSkillInitTypeDescription
0Chop5PhysicalBasic axe attack. 80% accuracy. Weapon damage.
10Reckless Swing4PhysicalWild swing. 70% accuracy but 1.3x damage. If miss, self takes 5% HP.
20Cleave6Physical/AoESwing through. Hits primary target and one adjacent. 75% accuracy.
30Sunder Armor7DebuffHeavy strike that reduces target evasion by 10 for 3 rounds. 80% accuracy.
40Berserker Chop3PhysicalFast, frenzied attack. 75% accuracy. Damage increases by 10% for each missing 10% of max HP.
50Maiming Strike6Physical/DoTDeep wound. 72% accuracy. Weapon damage + heavy Bleeding (8% max HP/round, 3 rounds).
60Skull Splitter8PhysicalDevastating overhead. 65% accuracy. 2x damage. On crit: Stun.
70Whirlwind5Physical/AoESpin attack hitting ALL enemies. 68% accuracy. 0.9x damage each.
80Rampage4PhysicalEach kill with this skill grants +1 additional hit (chain kills). 73% accuracy.
90Deathblow7Physical60% accuracy. 3x damage. If this kills the target, fully refund stamina cost.
100Worldsplitter10UltimateMassive AoE. 90% accuracy. 3x damage to all enemies. Sunder Armor effect on all hit. 5-encounter cooldown.

Daggers

ProfSkillInitTypeDescription
0Stab3PhysicalQuick dagger attack. 85% accuracy. Low damage but fast.
10Poison Strike4Physical/DoTEnvenomed blade. 80% accuracy. Weapon damage + Poisoned condition.
20Backstab2PhysicalStrikes from the shadows. 75% accuracy. 2x damage if target hasn’t acted yet this round.
30Fan of Knives5Physical/AoEThrow daggers at up to 3 enemies. 70% accuracy each. 0.6x damage per target.
40Eviscerate6PhysicalPrecise disemboweling. 78% accuracy. 1.5x damage + heavy Bleeding.
50Shadow Step1Utility/BuffBecome untargetable until your next offensive skill. Swift (doesn’t consume queue slot). 2/dungeon.
60Assassinate7PhysicalFull power surprise attack. 70% accuracy. 3x damage. Double crit range (≤10).
70Lacerate3Physical/DoTRapid cuts. 82% accuracy. Low immediate damage but applies Bleeding + Weakened.
80Death Mark4DebuffMark a target: all attacks against them gain +15% accuracy and +15% damage for 3 rounds.
90Viper’s Dance2PhysicalStrike 4 times rapidly. 72% accuracy each. 0.5x damage per hit. Each hit applies a stack of poison.
100Coup de Grace0UltimateInstant kill attempt: 50% base accuracy, but +2% per 1% of target’s missing HP. At 50% target HP, this is 100% accuracy instant kill. 5-encounter cooldown.

Bows

ProfSkillInitTypeDescription
0Shoot4Physical/RangedBasic arrow shot. 80% accuracy. Weapon damage at range.
10Aimed Shot7Physical/RangedCareful aim. 90% accuracy. 1.3x damage.
20Rapid Shot2Physical/RangedQuick snap shot. 70% accuracy. 0.8x damage but very fast initiative.
30Pinning Shot5Physical/DebuffArrow to the leg. 78% accuracy. Weapon damage + Slowed condition.
40Volley8Physical/AoE/RangedRain of arrows on an area. 65% accuracy. Hits all enemies. 0.7x damage each.
50Piercing Arrow6Physical/RangedArmor-piercing shot. 75% accuracy. Ignores 50% of target evasion.
60Explosive Arrow7Physical/AoE/RangedArrow detonates on impact. 72% accuracy. 1.5x damage to target + 0.8x to adjacent. Burning condition.
70Eagle Eye3BuffNext 3 bow skills gain +20% accuracy. Swift. 2/dungeon.
80Heart Seeker5Physical/Ranged80% accuracy. Crit threshold expanded to ≤15. On crit: 3x damage.
90Arrow Storm6Physical/AoE/Ranged8 arrows at random enemies. 68% accuracy each. 0.5x damage.
100Skyfall9UltimateCall down a massive arrow barrage. 85% accuracy. 4x damage AoE to all enemies. Pinning + Bleeding. 5-encounter cooldown.

Staves (Melee/Hybrid)

ProfSkillInitTypeDescription
0Staff Strike5PhysicalBasic staff whack. 78% accuracy.
10Arcane Tap3MagicalChannel magic through the staff. 82% accuracy. INT-based damage.
20Sweeping Strike6Physical/AoEWide sweep. 72% accuracy. Hits up to 3 adjacent enemies. Prone on crit.
30Mana Siphon5Magical/Utility76% accuracy. Deals moderate damage and recovers 10% of damage dealt as mana.
40Barrier Pulse4Defensive/AoECreate a barrier granting Shielded to self and allies (absorb damage equal to 15% of your max HP).
50Elemental Conduit6Magical80% accuracy. Damage type matches target’s vulnerability (auto-detect). If no vulnerability, defaults to force damage.
60Thunderclap7Magical/AoESlam staff into ground. 70% accuracy. AoE damage + Stunned on targets that fail CON resistance.
70Spell Amplifier2BuffNext magical skill deals 50% more damage. Swift. 3/dungeon.
80Leyline Surge8Magical78% accuracy. Deals massive magical damage. Cost: 25% of current mana (percentage-based, always usable).
90Reality Fracture6Magical/Debuff72% accuracy. Deals damage and reduces target’s resistance to all conditions by 20% for 3 rounds.
100Cataclysm10UltimateChannel devastating magical energy. 88% accuracy. AoE. 5x INT-based damage. All enemies: Stunned + Weakened. 5-encounter cooldown.

Wands

ProfSkillInitTypeDescription
0Wand Bolt4Magical/RangedBasic magical bolt. 82% accuracy.
10Hex Shot5Magical/Debuff78% accuracy. Moderate damage + Weakened.
20Mana Dart2Magical/RangedQuick bolt. 80% accuracy. Low damage, low cost, very fast.
30Chain Lightning6Magical/AoE75% accuracy. Hits target then bounces to 2 more. 100%/70%/50% damage on each bounce.
40Life Drain5Magical76% accuracy. Deals necrotic damage. Heals self for 50% of damage dealt.
50Dispel3UtilityRemove one buff from target enemy OR one debuff from self/ally. Always succeeds.
60Soul Fire7Magical72% accuracy. Ignores evasion entirely (targets the soul). High damage.
70Curse of Agony4Magical/DoT80% accuracy. Low initial damage but applies stacking DoT: 3%/5%/8%/12% max HP over 4 rounds.
80Power Word: Pain6Magical/Debuff90% accuracy (hard to resist). Target’s next 2 skills have -30% accuracy.
90Arcane Barrage3Magical/AoEFire 5 bolts at random enemies. 78% accuracy each. Each bolt that crits resets cooldown of one charge-based skill.
100Oblivion Ray9UltimateSingle-target annihilation beam. 92% accuracy. 6x damage. Ignores all evasion and resistances. 5-encounter cooldown.

Shields (Off-Hand)

ProfSkillInitTypeDescription
0Block1DefensiveReduce next incoming hit by 30%.
10Shield Bash4PhysicalSmash with shield. 75% accuracy. Low damage + Stunned (1 round).
20Brace2DefensiveReduce ALL incoming damage by 15% for this round.
30Reflect3DefensiveOn next incoming hit, reflect 50% of damage back to attacker.
40Guardian Stance1Defensive/BuffRedirect attacks from lowest-HP ally to self for 2 rounds. +20% evasion while active.
50Shield Wall5Defensive/AoEGrant all allies +10% evasion for 2 rounds.
60Concussive Slam6Physical/AoEGround slam. 70% accuracy. AoE. Low damage + Slowed.
70Aegis2DefensiveAbsorb the next hit entirely (up to 30% of your max HP). 2/dungeon.
80Rallying Defense3Buff/AoEAll allies: +10% accuracy and Shielded (absorb 10% of your max HP).
90Fortress1DefensiveFor 2 rounds: evasion doubled, immune to conditions. Cannot attack.
100Immortal Bulwark0UltimateFor 1 round: you and all allies cannot be reduced below 1 HP. 5-encounter cooldown.

Party Combat

In multiplayer encounters, all party members’ queues execute simultaneously alongside enemies.

Turn Order (Party)

ROUND 1 — 4-Player Party vs. Orc Warband

All combatants' next queued skills, sorted by initiative:
  [Init 1] Fighter → Block (shield skill)
  [Init 2] Rogue → Backstab
  [Init 2] Orc Grunt A → Slash (tie: resolved by character initiative stat)
  [Init 3] Ranger → Rapid Shot
  [Init 4] Orc Shaman → Hex Bolt
  [Init 5] Wizard → Arcane Bolt
  [Init 5] Orc Grunt B → Slash
  [Init 6] Orc Chief → War Cry (buff)
  [Init 7] Fighter → Crushing Blow
  [Init 8] Rogue → Eviscerate
  [Init 8] Ranger → Aimed Shot
  [Init 9] Wizard → Elemental Burst

Healing and Support Targeting

  • Heal skills target based on the player’s configured target rule (e.g., “lowest HP ally”)
  • Buff skills target based on configured rule (e.g., “self” or “highest threat ally”)
  • Party synergy: A well-coordinated party queues complementary skills:
    • Tank leads with Block/Guardian Stance (fast initiative, protects party)
    • Debuffer applies Weakened/Sunder Armor early
    • DPS follows with Power Strikes against softened targets
    • Healer places heals mid-queue with “if ally HP < 50%” conditionals

Combat Log / Replay

The combat log is how players experience combat after the fact. It must be detailed, readable, and instructional.

Log Format Example

═══ ENCOUNTER 4: Goblin Ambush ═══
Location: Collapsed Mine, Chamber 3
Enemies: Goblin Boss (Lv.5), Goblin Archer ×3 (Lv.3), Goblin Shaman (Lv.4)

⚠ SURPRISE: Perception check: d100 roll 67 vs. 42% detection chance → FAIL
  Enemies get a surprise round!

── Surprise Round ──
  [Init 2] Goblin Archer 1 → Snap Shot at YOU: d100: 31 vs. 68% → HIT → 7 piercing
  [Init 2] Goblin Archer 2 → Snap Shot at YOU: d100: 82 vs. 68% → MISS
  [Init 4] Goblin Shaman → Hex Bolt at YOU: d100: 28 vs. 71% → HIT → 5 necrotic + Weakened (2 rounds)

── Round 1 ──
  [Init 2] Goblin Archer 3 → Snap Shot at YOU: d100: 55 vs. 68% → HIT → 7 piercing
  [Init 3] YOU → Queue Slot 1: Quick Thrust → Goblin Shaman [Target: Highest Threat]
       d100: 22 vs. 81% → HIT → 14 piercing damage (Shaman HP: 18/32)
  [Init 5] YOU → Queue Slot 2: Crushing Blow → Goblin Shaman [Target: Highest Threat]
       d100: 44 vs. 74% → HIT → 23 slashing damage (Shaman HP: 0/32) → DEAD
  [Init 5] Goblin Boss → Power Swing at YOU: d100: 15 vs. 72% → HIT → 12 slashing
  [Init 6] Goblin Archer 1 → Aimed Shot at YOU: d100: 91 vs. 65% → MISS
  [Init 6] Goblin Archer 2 → Snap Shot at YOU: d100: 48 vs. 68% → HIT → 7 piercing

  Your HP: 38/62 (61%) | Stamina: 74/100 | Conditions: Weakened (1 round remaining)

── Round 2 ──
  [Init 3] YOU → Queue Slot 3: Whirlwind Slash → All Adjacent [AoE: max enemies]
       Goblin Boss: d100: 38 vs. 69% → HIT → 11 slashing
       Goblin Archer 1: d100: 71 vs. 69% → MISS
       Goblin Archer 2: d100: 12 vs. 69% → HIT → 11 slashing (HP: 3/14)
  [Init 4] Goblin Boss → Rallying Shout → All goblins gain Inspired (+10% acc, +10% dmg, 2 rounds)
  [Init 5] YOU → Queue Slot 4: Healing Surge [IF HP < 50%]
       Condition MET (HP at 61%... wait, 61% > 50%) → SKIPPED
       ↳ Queue advances to Slot 5: Power Strike → Goblin Boss [Target: Highest HP]
       d100: 03 vs. 78% → ★ CRITICAL HIT ★ → 34 slashing (1.5× damage!) → Boss HP: 21/48
  [Init 5] Goblin Archer 1 → Aimed Shot at YOU: d100: 29 vs. 75% (Inspired) → HIT → 9 piercing
  [Init 5] Goblin Archer 2 → Snap Shot at YOU: d100: 88 vs. 78% (Inspired) → MISS
  ...

── Result ──
  VICTORY — All enemies defeated in 4 rounds
  HP remaining: 26/62 (42%)
  Stamina remaining: 41/100
  Consumables used: 0

  📊 QUEUE PERFORMANCE:
     Quick Thrust: 2 uses, 2 hits (100%)
     Crushing Blow: 2 uses, 1 hit, 1 miss (50%)
     Whirlwind Slash: 1 use, 2/3 targets hit (67%)
     Healing Surge: 1 trigger, 1 skipped (condition not met)
     Power Strike: 1 use, 1 crit! (100%)

  💡 TIP: You entered this fight at 61% HP due to surprise round damage.
     Higher Perception (currently 42%, need ~68%) would avoid ambushes here.
     Consider gear with Perception bonuses or the Observant feat.

  Loot: 15 gold, Goblin Scimitar +1, Minor Healing Potion

Log Features

  • Color-coded outcomes: Hits highlighted, misses dimmed, crits in gold, heals in green
  • Queue transparency: Shows which slot fired, the target rule used, and conditional evaluation
  • Queue performance summary: After each encounter, shows hit rates per skill — helps the player evaluate their queue effectiveness
  • Dice breakdown: Every d100 roll shown with the success threshold
  • Tips: Context-sensitive suggestions after tough encounters
  • Expandable detail: Summary view by default, expand for full roll-by-roll
  • Run timeline: Visual progress bar showing all encounters, colored by outcome

Enemy Design and AI

Overview

Enemies use the same skill queue system as player characters. Every enemy has a stat block, a skill list, and a fixed skill queue that determines their behavior in combat. The key difference: enemy queues are pre-authored by designers, not configured by players. This makes enemy behavior predictable once learned — the first time you fight a Goblin Shaman, you don’t know what it does. The tenth time, you know exactly what’s coming and can build your queue to counter it.

Enemy Stat Blocks

Every enemy has:

GOBLIN SHAMAN (Level 12 Elite)
─────────────────────────────────
HP: 180
Evasion: 14
Attributes: MGT 8 | LOG 16 | SPD 10 | PRS 14 | FRT 10 | LCK 8
Resistances: +20% vs. Charmed, +10% vs. Silenced
Weaknesses: Vulnerable to fire (+25% fire damage taken)
Loot Table: Goblinoid Caster (Uncommon+)

Skill Queue (loops):
  1. Hex Bolt (Init 4, magical, targets highest-threat player) — 78% accuracy, moderate necrotic damage + Weakened (2 rounds)
  2. Healing Chant (Init 7, heal, targets lowest-HP ally) — Heal 15% of target's max HP [IF any ally below 50% HP, else skip]
  3. Venom Cloud (Init 6, AoE magical, targets player cluster) — 70% accuracy, Poisoned condition (4 rounds)
  4. Hex Bolt (Init 4, targets highest-threat player) — repeat damage

Skills per round: 2

Enemy Tiers

TierLabelHP MultiplierSkillsBehaviorExample
MinionTrash mob0.5x2-3 simple skillsTargets nearest, no tacticsGoblin, Rat, Skeleton
StandardRegular enemy1x3-4 skills with conditionsUses debuffs, targets threatsOrc Warrior, Bandit Archer
EliteNamed/buffed enemy2x4-6 skills with conditionalsUses healing, buffs allies, applies conditionsGoblin Shaman, Orc Warchief
BossDungeon boss5-10x6-8 skills, multi-phasePhase transitions, adds, special mechanicsBugbear Chieftain, Wraith Lord
Raid BossRaid encounter20-50x8-12 skills, 3+ phasesEnrage, role-specific mechanics, coordination requiredFlamelord, Lich King

Enemy Queue Behavior

Enemies have the same queue mechanics as players — fixed order, looping, with light conditionals. The difference is that enemy queues are designed to create specific challenges:

Aggressive enemies (orcs, demons, berserkers):

  • Front-load damage skills with low initiative (act fast, hit hard)
  • Few or no defensive skills
  • Designed to pressure the player’s HP and test their healing/defensive planning

Tactical enemies (shamans, commanders, mages):

  • Mix of damage, debuffs, and support skills
  • Conditionals like “heal ally if below 50% HP”
  • Designed to create priority targets — “kill the healer first” moments

Defensive enemies (golems, shield-bearers, turtles):

  • High evasion, Shielded buffs, damage reduction skills
  • Slow but durable — punish players who rely only on burst damage
  • Designed to test sustained DPS and condition application (DoTs bypass shields)

Swarm enemies (goblins, rats, spiders):

  • Low individual HP, appear in groups of 3-6
  • Simple queues but overwhelm through numbers
  • Designed to test AoE skills and queue efficiency

Boss Mechanics

Bosses are the climax of dungeons. They use the same queue system but with phases — when a boss reaches an HP threshold, their queue changes.

Phase Transitions

WRAITH LORD (Level 25 Boss)
─────────────────────────────────
Total HP: 1,200

PHASE 1 (100% - 60% HP):
  Queue: Shadow Bolt → Life Drain → Shadow Bolt → Fear Aura
  Behavior: Standard ranged caster. Drains HP to self-heal.

PHASE 2 (60% - 30% HP): ← Queue changes here
  Queue: Summon Wraiths → Necrotic Burst (AoE) → Shadow Bolt → Life Drain
  Behavior: Summons 2 Wraith adds (minion tier). AoE pressure increases.
  New Mechanic: Cursed Ground environmental condition activates (healing reduced 50%)

PHASE 3 (30% - 0% HP): ← Queue changes again
  Queue: Death Coil (massive single-target) → Necrotic Burst → Death Coil → Soul Harvest (full heal if any adds alive)
  Behavior: Desperate, high damage. Soul Harvest makes killing adds before Phase 3 critical.
  New Mechanic: Boss gains Hasted (3 skills per round instead of 2)

Boss Design Principles

  1. Each phase changes the fight. A boss with one phase is just a big health pool. Phase transitions force the player to adapt mid-encounter (their queue loops, so the same skills hit different contexts).
  2. Bosses telegraph. The combat log should make phase transitions clear: “The Wraith Lord shrieks as spectral energy surrounds it — PHASE 2 BEGINS.” Players can study this from failed runs to prepare.
  3. At least one mechanic per boss must be counterable through preparation. Wraith Lord’s Soul Harvest is devastating if adds are alive — so the counter is AoE skills to kill adds before Phase 3. Flamelord’s fire damage is brutal — so the counter is Fire Resistance potions.
  4. Enrage timer on raid bosses. After X rounds (typically 20-30), raid bosses gain a stacking +10% damage buff per round. This prevents infinite stalling and creates a DPS check.

Enemy Targeting Logic

Enemies use target rules just like players, but their rules are fixed per enemy type:

Enemy TypeDefault Target RuleWhy
Melee minionsNearestSimple, predictable
Ranged minionsLowest EvasionShoot the easy target
Standard meleeHighest ThreatFocus the damage dealer
Standard rangedLowest HPFinish off wounded targets
Healer/supportLowest HP ally (heal) / Highest Threat (debuff)Keep allies alive, shut down threats
Boss (Phase 1)Highest ThreatFocus the top damage dealer
Boss (Phase 2+)Varies by mechanicPhase-specific targeting creates new challenges

Threat is calculated as: total damage dealt this encounter × 1.0 + healing done × 0.5 + debuffs applied × 0.3. Tanks can increase their threat through Taunt skills.

Enemy Condition Usage

Enemies apply conditions just like players. Each enemy type has thematic conditions:

Enemy ThemeConditions AppliedCounter Strategy
UndeadFrightened, Weakened, ExhaustionHigh Presence, anti-undead gear
FireBurning, Corroded (heat melts armor)Fire resistance, cold skills
IceFrozen, SlowedFire skills (break Frozen), Haste potions
Poison/NaturePoisoned, Bleeding, RootedAntidotes, high Fortitude, fire (burns roots)
ArcaneSilenced, Confused, ShockedHigh Logic, anti-magic gear (Inquisitor)
BeastBleeding, Stunned (charge attacks)High Fortitude, Shielded buffs
Humanoid (martial)Weakened, Stunned, BleedingMixed defenses, control conditions back
Humanoid (magic)Charmed, Frightened, BurningHigh Presence, damage to break Charm

Enemy Bestiary

When a player encounters an enemy for the first time, basic info is recorded in the Bestiary:

  • Name, tier, and visual description
  • HP range and general toughness
  • “Known” conditions they apply (after being hit by them)

Subsequent encounters reveal more:

  • Exact skill list (after seeing each skill fire)
  • Resistances and weaknesses (after testing different damage types)
  • Optimal counter-strategy tips (after multiple encounters)

The Verdani species skill Aethersight reveals ALL enemy info immediately for one encounter — a powerful scouting ability.

Enemy Scaling

Enemies don’t scale to the player’s level — they have fixed levels tied to the dungeon. A level 20 dungeon always has level 18-22 enemies. This means:

  • Returning to low-level content makes you feel powerful (enemies are trivial)
  • Attempting content above your level is genuinely dangerous
  • The world has a consistent difficulty geography

Enemy Groups and Composition

Encounters don’t use random enemy packs. Each encounter is designed with a composition that creates a specific challenge:

CompositionExampleDesign Intent
Pure melee4 Orc WarriorsTest sustain and AoE
Ranged + melee2 Archers + 2 WarriorsTest target priority (kill archers first?)
Healer + DPS1 Shaman + 3 GoblinsTest focus fire (must kill healer or fight never ends)
Tank + DPS1 Shield-Bearer + 2 AssassinsTest ability to handle high-evasion target + burst damage
Swarm6 RatsTest AoE efficiency
Solo elite1 TrollTest sustained single-target DPS and condition management
Boss + addsBoss + 2 Minions (respawning)Test AoE + single-target + phase awareness

Gear Durability

Gear degrades gradually through use. Durability is a gold sink, not a combat penalty — your gear always performs at full power regardless of durability. The only consequence of low durability is that you must repair before you can enhance or reforge the item.

  • Max durability: 100 for all gear
  • Loss per dungeon run: -5 durability on all equipped items (regardless of success or failure)
  • At 0 durability: Gear still works at full power in combat. BUT it cannot be enhanced (+1 through +5) or reforged until repaired. A visual indicator marks gear as “worn” in the UI.
  • Repair: Instant at any blacksmith vendor. Costs gold based on item rarity:
RarityRepair Cost (0→100)
Common10 gold
Uncommon50 gold
Rare150 gold
Very Rare400 gold
Legendary1,000 gold
  • Partial repair costs proportionally less (repairing from 50→100 costs half)
  • Repair all button repairs every equipped item in one click
  • Players who run 10+ dungeons before repairing save time but pay the same total gold

This creates a steady, predictable gold drain that scales with how actively a player runs content — exactly the kind of friction-free gold sink the economy needs.


Combat Design Principles

  1. The queue IS the game. Arranging skills, choosing initiative trade-offs, setting conditionals, and managing resources across encounters — this is where all player skill lives.
  2. Speed vs. power is the core trade-off. Fast skills (low init) are weaker. Slow skills (high init) are stronger. Do you want to act first or hit harder?
  3. Combos reward mastery. A debuff that lowers evasion into a power strike into an execute creates a satisfying chain. Players who understand skill synergy outperform those who just queue their highest-damage skills.
  4. Weapon proficiency is the endless treadmill. Even at max character level, there are always more weapon types to master. Switching to a new weapon means starting at proficiency 0 — a new progression journey.
  5. Resources create meaningful scarcity. You can’t spam your best skills forever. Long dungeons demand efficiency. Short dungeons reward aggression. The player must read the situation and build their queue accordingly.
  6. Every run teaches something. The combat log, queue performance stats, and tips ensure the player always knows what to improve.

Equipment and Loot

Overview

Loot is the lifeblood of Delve. It’s the primary tangible reward for dungeon runs, the fuel for crafting, the currency of the marketplace, and the core of character power expression. The loot system is built on three principles:

  1. No loot is ever worthless. Every drop can be equipped, sold, or salvaged into useful crafting materials — regardless of level.
  2. Endgame loot is unique to YOU. Rare+ items roll randomized bonus properties, so no two legendaries are identical. The chase is finding (or reforging) the perfect combination.
  3. Transparency and fairness. All item properties are fully visible. No hidden stats, no loot boxes, no mystery. What you see is what you get — on the marketplace or in a dungeon.

Gear Slots

Each character has the following equipment slots:

SlotWhat Goes ThereCombat Relevance
Main HandOne-handed weapon, two-handed weapon, staffPrimary damage source. Determines weapon proficiency track and available weapon skills.
Off HandShield, second weapon (dual-wield), focus, torchShield grants Evasion + shield skills. Dual-wield enables off-hand weapon skills. Focus boosts magical skill potency.
HeadHelms, circlets, hoodsOften provides condition resistance bonuses or Perception boosts.
ChestArmor (light, medium, heavy)Primary Evasion rating source. Defines armor class and stealth penalty.
HandsGloves, gauntlets, bracersOften accuracy bonuses, melee damage bonuses, or crafting speed boosts.
FeetBoots, greaves, sandalsSpeed-related bonuses: initiative tie-breaking, evasion, trap avoidance.
CloakCloaks, capes, mantlesDefensive or utility effects: condition resistance, stealth bonuses, elemental protection.
Ring 1Magical ringsVaried effects. Rings are the most likely slot to carry gear skills.
Ring 2Magical ringsSame as Ring 1. Two ring slots enable powerful combinations.
AmuletNecklaces, pendants, holy symbolsOften resource pool bonuses (mana, devotion, etc.) or healing effectiveness.
BeltBelts, sashesAttribute bonuses (often Might or Fortitude). Provides quick slots.

Quick Slots (Belt)

The belt provides 3 quick slots for consumable items (potions, scrolls) that the skill queue can access during encounters without consuming a queue action. Items not in quick slots require spending a queue action to use.


Rarity Tiers

TierColorPropertiesWhere FoundTradeable?
CommonWhiteFixed stats only. No magical properties. No random rolls.All content, NPC vendorsYes
UncommonGreenFixed base + 1 fixed magical property. No random rolls.Levels 5+ content, craftingYes
RareBlueFixed base + signature effect + 1 random bonus with random potency.Levels 15+ content, crafting, bossesYes
Very RarePurpleFixed base + signature effect + 2 random bonuses with random potency.Levels 25+ content, raids, craftingYes
LegendaryOrangeFixed base + powerful signature effect + 2 random bonuses with random potency. May include a gear skill.Levels 35+ content, major raids, world bossesYes
ArtifactGoldFixed base + unique signature effect + 3 random bonuses + guaranteed gear skill. Server-unique.Special events, ultimate challengesNo (soulbound)

Key Design: Fixed Base + Random Bonuses

This is the core of the loot system for Rare+ items:

  • Fixed base: The item always has specific stats (Evasion for armor, damage for weapons, etc.) determined by its type and level.
  • Signature effect: A defining property that makes this specific named item what it is. A “Flamebrand Longsword” ALWAYS has fire damage. A “Frostweave Robe” ALWAYS has cold resistance. The signature is part of the item’s identity.
  • Random bonuses: 1-3 additional properties rolled from a pool when the item drops. Both the property type AND the potency are randomized. This is what makes every drop unique.

Example: Two Flamebrand Longswords

FLAMEBRAND LONGSWORD (Legendary)
─────────────────────────────────
Type: Sword | Level 40 | Weapon Damage: 45-62
Signature: Fire Blade — All sword skills deal +15% bonus fire damage.
            Hits have a 20% chance to apply Burning (2 rounds).

Player A's drop:                    Player B's drop:
  Random Bonus 1:                     Random Bonus 1:
    +8% critical hit chance             +12% accuracy
  Random Bonus 2:                     Random Bonus 2:
    +4 Speed                            +6 Might

  Gear Skill: Flame Burst              Gear Skill: Flame Burst
    (Init 5, AoE fire around target)    (Init 5, AoE fire around target)

Both are Flamebrand Longswords with the same signature effect and gear skill. But Player A’s is a crit-focused speed build weapon, while Player B’s is a raw accuracy/power weapon. Both are excellent — just different.

Random Bonus Pools

When a Rare+ item drops, its random bonuses are rolled from this pool:

Offensive Bonuses:

BonusPotency Range
+X% accuracy (all skills)3-12%
+X% damage (all skills)3-10%
+X% critical hit chance2-8%
+X% damage to [condition] targets5-15% (e.g., “+12% damage to Poisoned targets”)
+X% accuracy with [weapon type]5-15%
+X% [element] damage5-15%

Defensive Bonuses:

BonusPotency Range
+X Evasion2-8
+X% condition resistance (all)3-10%
+X% resistance to [specific condition]8-20%
+X% max HP3-10%
+X% healing received5-15%
Reduce critical hit damage taken by X%10-25%

Attribute Bonuses:

BonusPotency Range
+X Might1-6
+X Logic1-6
+X Speed1-6
+X Presence1-6
+X Fortitude1-6
+X Luck1-6

Resource Bonuses:

BonusPotency Range
+X% resource pool (Stamina/Mana/etc.)3-10%
+X% resource recovery between encounters3-8%
X% chance skill doesn’t consume resources2-6%

Utility Bonuses:

BonusPotency Range
+X% gold find5-15%
+X% loot quality2-8%
+X% trap detection5-15%
+X% crafting speed5-12%
+X% weapon proficiency gain5-15%

Potency Tiers

When a bonus rolls, its potency is determined by a quality roll (d100):

RollQualityPotencyRarity
1-50StandardLow end of rangeCommon outcome
51-80SuperiorMid rangeDecent
81-95ExceptionalHigh end of rangeNoteworthy
96-100PerfectMaximum valueVery rare — “god roll” on this bonus

A fully “god-rolled” legendary (all bonuses at perfect potency) is extremely rare — roughly 1 in 8,000 chance for a 2-bonus item. This creates the long-term chase.

Artifact Rarity

Artifacts are server-unique — only one copy of each exists at a time on the server.

  • If the holder goes inactive for 30+ days, the artifact returns to the loot pool
  • Artifacts are soulbound (cannot be traded) — you must earn them
  • Artifacts have 3 random bonuses + a guaranteed powerful gear skill
  • Artifacts are designed to be prestigious but not required — a well-rolled legendary can compete

Weapons

Weapon Types and Base Stats

Weapons are categorized by type, which determines which proficiency track they use (see 04-combat-system.md for the full proficiency system). Base damage scales with item level.

Weapon TypeExamplesDamage StylePrimary Attribute
SwordsShortsword, Longsword, GreatswordBalanced, combo-orientedMight or Speed (Finesse)
AxesHandaxe, Battleaxe, GreataxeHigh burst, cleaveMight
Maces & HammersMace, Warhammer, MaulAnti-armor, stun potentialMight
DaggersDagger, Stiletto, Ritual KnifeFast, DoT-focusedSpeed
PolearmsSpear, Halberd, GlaiveReach, area controlMight
BowsShortbow, Longbow, Composite BowRanged sustained DPSSpeed
CrossbowsHand Crossbow, Light Crossbow, Heavy CrossbowRanged burst, slowSpeed
StavesQuarterstaff, Battle Staff, Arcane StaffHybrid melee/magicMight or Logic
WandsWand, Rod, ScepterPure magic, rangedLogic, Presence
ShieldsBuckler, Kite Shield, Tower ShieldDefensive skills, evasionFortitude

Base Damage Scaling

Weapon base damage scales with item level, not character level. A level 30 longsword does more base damage than a level 10 longsword, period.

Item Level RangeBase Damage Range (example: Longsword)
1-108-15
11-2016-28
21-3029-45
31-4046-65
41-5066-85

Weapon Properties

  • Finesse: Use Might or Speed for accuracy/damage calculation (whichever is higher)
  • Light: Can dual-wield with another light weapon (enables off-hand skill slot)
  • Heavy: Small species (Glimkin) have -15% accuracy. Deals +10% damage as compensation for the restriction.
  • Two-Handed: Occupies both Main Hand and Off Hand. Higher base damage than one-handed equivalents.
  • Ammunition: Requires arrows/bolts (tracked as a supply, not per-arrow)

Weapon Proficiency

Each character has a weapon proficiency score (0-100) per weapon type. Using a weapon in combat increases proficiency, unlocking new weapon skills for the skill queue at milestones (every 10 levels). Full details in 04-combat-system.md.

Gear Skills on Weapons

Legendary and Artifact weapons can grant a gear skill — a bonus skill that can be placed in the skill queue while the weapon is equipped. Gear skills are part of the item’s signature (not randomized — every Flamebrand has Flame Burst).

Examples:

WeaponRarityGear SkillInitEffect
Flamebrand LongswordLegendaryFlame Burst5AoE fire damage around the target. 75% accuracy. Applies Burning.
Frostfang DaggerLegendaryIce Shiv2Fast cold damage strike. 80% accuracy. Applies Frozen on crit.
Thundercaller BowLegendaryLightning Arrow6Ranged lightning attack that chains to 2 adjacent enemies. Applies Shocked.
DoomhammerLegendarySeismic Slam8Massive AoE. 65% accuracy. Applies Stunned to all targets hit.
Lifedrinker RodLegendarySoul Siphon4Necrotic damage. Heals caster for 40% of damage dealt.
Aegis of the DawnLegendary (Shield)Divine Barrier1Grant Shielded (25% of your max HP) to self and lowest-HP ally.

Armor

Armor Types and Evasion

ArmorTypeBase EvasionMGT ReqStealth PenaltyNotes
PaddedLight11 + Speed-10%Cheap, basic
LeatherLight11 + SpeedNo penalty, default light
Studded LeatherLight12 + SpeedBest light for most builds
HideMedium12 + Speed (max +2)Basic medium
Chain ShirtMedium13 + Speed (max +2)Common medium
Scale MailMedium14 + Speed (max +2)-10%Heavier medium
BreastplateMedium14 + Speed (max +2)Best medium, no penalty
Half PlateMedium15 + Speed (max +2)-10%Highest medium evasion
Ring MailHeavy14-15%Entry heavy
Chain MailHeavy16MGT 13-15%Standard heavy
SplintHeavy17MGT 15-15%Strong heavy
PlateHeavy18MGT 15-20%Maximum evasion, maximum penalty
Shield+5Off-hand, enables shield skills

Base Evasion values are for common versions. Higher rarity armors of the same type get +1 (Uncommon), +2 (Rare), +3 (Very Rare), +4 (Legendary) to base Evasion, plus their signature effects and random bonuses.

Armor and Class Synergy

  • Light armor: Full Speed bonus to Evasion. No stealth penalty (usually). Best for Shades, Pathfinders, Hexbinders.
  • Medium armor: Speed bonus capped at +2. Balanced. Best for Songweavers, Wardens, Pathfinders.
  • Heavy armor: No Speed bonus. Highest flat Evasion. Best for Vanguards, Oathblades, Berserkers (though Berserkers can opt for unarmored — Fortitude replaces Evasion from armor).

Item Level and Why Old Loot Still Matters

The Problem with Traditional MMO Loot

In most games, a Rare sword from level 10 is vendored the moment you hit level 15. Hours of dungeon running produce gear that’s worthless within days. This feels bad.

Delve’s Solution: Rarity-Scaled Salvage

Every item, regardless of level, salvages into the same materials based on its rarity. A level 5 Rare longsword and a level 45 Rare longsword both produce the same Rare-tier crafting materials.

This means:

  • A level 5 Rare drop is never worthless — it salvages into materials you need for endgame crafting
  • Revisiting low-level dungeons to farm specific enemies or materials is always viable
  • New players can sell Rare drops on the marketplace to endgame crafters who want the salvage materials
  • The economy stays healthy because supply comes from all level ranges, not just endgame

Salvage Table

Item RaritySalvage Output
Common2-4 Common Fragments + small gold value
Uncommon3-5 Common Fragments + 1-2 Uncommon Shards
Rare2-4 Uncommon Shards + 1-2 Rare Cores
Very Rare2-3 Rare Cores + 1 Prismatic Essence
Legendary2-4 Rare Cores + 1-2 Prismatic Essences + 1 Legendary Spark
ArtifactCannot be salvaged (soulbound)

Material uses:

  • Common Fragments: Basic crafting, leveling crafting professions
  • Uncommon Shards: Mid-tier crafting, gear enhancement (+1)
  • Rare Cores: Advanced crafting, gear enhancement (+2), reforging
  • Prismatic Essence: High-tier crafting, enchanting, gear enhancement (+3)
  • Legendary Spark: Reforging legendary items, crafting legendary recipes

Disenchanting (Magical Items Only)

Uncommon+ items can be disenchanted instead of salvaged. Disenchanting extracts Magical Essence — a separate material used specifically for enchanting and adding magical properties to crafted gear.

Item RarityMagical Essence Yield
Uncommon1-2 Magical Essence
Rare2-4 Magical Essence
Very Rare4-6 Magical Essence
Legendary6-10 Magical Essence

Salvage vs. Disenchant is a meaningful choice — you can do one or the other, not both. Do you need crafting materials or enchanting materials?


The Reforging System

Reforging is the primary endgame resource sink and the answer to “I got a Legendary drop but the random bonuses are bad.”

How Reforging Works

  1. Take a Rare+ item to a Reforger NPC (available in major hub cities)
  2. Select one random bonus to reforge (you choose which bonus slot to re-roll)
  3. Pay the reforging cost (materials + gold)
  4. The selected bonus is replaced with a new random bonus from the full pool, with a new random potency

Reforging Costs

Item RarityMaterials RequiredGold Cost
Rare3 Rare Cores + 2 Uncommon Shards500
Very Rare5 Rare Cores + 2 Prismatic Essences2,000
Legendary3 Prismatic Essences + 1 Legendary Spark5,000

Reforging Rules

  • You choose WHICH bonus to reforge. The other bonuses remain untouched.
  • The signature effect is never reforged — it’s permanent.
  • The new bonus is fully random — it could be the same type you just had, or completely different.
  • There is no guarantee of improvement. You might reforge a +8% accuracy into a +3% gold find. This is the gamble.
  • Cooldown: Each item can only be reforged once per day (prevents mindless spam-reforging in a single session)
  • No destruction risk. The item is never damaged or destroyed by reforging.

Why Reforging Works

  • Resource sink: Rare Cores and Prismatic Essences are consumed in large quantities, keeping salvage materials in demand at all times
  • Gold sink: 500-5,000 gold per attempt adds up fast when chasing perfect rolls
  • Endless endgame: A player with a “good” legendary can always chase a “perfect” one through reforging
  • Marketplace interaction: Players who don’t want to gamble on reforging can buy pre-rolled items on the marketplace instead. Players who enjoy the chase can reforge and sell the results.
  • Salvage demand: Since reforging consumes materials from salvaging, EVERY item in the game has value as salvage fuel — even level 1 drops

Location-Specific and Dungeon-Specific Loot

Philosophy

Regular loot (Common through Rare) drops everywhere and has no location restrictions. But Very Rare and Legendary items are often tied to specific dungeons, raids, or regions. This gives endgame players a reason to target specific content.

How It Works

Generic loot (Common-Rare): Drops from any content of appropriate level. Generic swords, armor, accessories with random names and properties.

Named loot (Very Rare-Legendary): Specific named items that only drop from specific sources. These are the items with signature effects and gear skills.

Source TypeNamed Loot Examples
Regional bosses“Thornvale Bramble Shield” (Thornvale region only)
Dungeon bosses“Undercrypt Wraith Blade” (Undercrypt dungeon final boss)
Raid bosses“Flamelord’s Crown” (Burning Citadel raid)
World bosses“Earthshaker Maul” (world boss event)
Faction vendors“Iron Compact Greatsword” (Exalted reputation purchase)
Crafted“Masterwork Adamantine Plate” (Level 50 Blacksmithing recipe)

Named Item Registry

The game maintains a Named Item Registry — a catalog of all named Very Rare+ items showing:

  • Where they drop
  • Their signature effect
  • Their gear skill (if any)
  • What random bonus slots they have
  • Player-reported “best rolls” for each item

This registry is viewable in-game and helps players plan which dungeons to target.


Consumables

Consumables are single-use items critical to dungeon preparation. They plug directly into the skill queue and condition systems.

Potions

PotionEffectRarityCondition Interaction
Healing SalveRestore 15% max HPCommon
Greater Healing SalveRestore 30% max HPUncommon
Superior Healing SalveRestore 50% max HPRareAlso removes 1 stack of Bleeding
Supreme Healing SalveRestore 75% max HPVery RareRemoves all Bleeding stacks + Poisoned
AntidoteCure Poisoned conditionCommonSpecifically targets Poisoned
Burn SalveCure Burning conditionCommonSpecifically targets Burning
Fire Resistance Draught+30% resistance to Burning for 3 encountersUncommonReduces Burning damage taken by 50%
Cold Resistance Draught+30% resistance to Frozen for 3 encountersUncommonReduces Frozen duration by 1 round
Potion of SpeedGrants Hasted for 2 rounds (one combat)RareHaste: 3 skills/round, cancels Slowed
Potion of InvisibilityGrants Invisible for 1 encounterRareSee Invisible condition in combat doc
Elixir of Titanic Might+8 Might for 1 encounterRareAffects all Might-based calculations
Elixir of Clarity+8 Logic for 1 encounterRareAffects all Logic-based calculations
Cleansing TonicRemove all debuffsVery RareNuclear option — removes everything
Elixir of Fortune+5 Luck for 1 encounterRareBetter crits, fewer crit misses, better loot for that encounter

Scrolls

  • Scrolls grant a one-time skill usable in the skill queue for one encounter
  • Any class can use any scroll, but off-class scrolls have -15% accuracy
  • Scrolls are consumed when the encounter starts (whether the skill fires or not)
  • Can be crafted by Arcanists (see 07-crafting-and-gathering.md)
  • Examples: Scroll of Fireball (AoE fire), Scroll of Healing Wave (party heal), Scroll of Haste (grant Hasted)

Supplies

SupplyWeight (slots)Consumption RateRunning Out
Rations1 slot per 51 per encounterExhaustion accumulates
Torches1 slot per 51 per dark areaDarkness condition applies (see combat doc)
Ammunition1 slot per 20Per ranged skill useMust switch to melee skills
Lockpicks1 slot per 31 per lock attemptCannot pick locks (must force with Might)
Rope1 slotPer climbing encounterHarder Might checks, or blocked paths
Healer’s Kit1 slot per 31 per Medicine checkCannot stabilize unconscious allies without magic
Antidotes1 slot per 3Per Poisoned encounterMust endure full Poisoned duration

Gear Enhancement

Enhancement Levels (+1 to +5)

Any weapon or armor can be enhanced at a blacksmith NPC, increasing its base stats.

EnhancementEffect (Weapons)Effect (Armor)Success RateMaterials
+1+5% base damage+1 Evasion100%3 Uncommon Shards + 200g
+2+10% base damage+2 Evasion85%5 Uncommon Shards + 2 Rare Cores + 500g
+3+15% base damage+3 Evasion70%3 Rare Cores + 1 Prismatic Essence + 1,500g
+4+20% base damage+4 Evasion55%5 Rare Cores + 2 Prismatic Essences + 3,000g
+5+25% base damage+5 Evasion40%3 Prismatic Essences + 1 Legendary Spark + 5,000g

Failure does NOT destroy or downgrade the item. It just consumes the materials and gold. You can try again immediately.

Enhancement level is preserved when reforging — a +3 Flamebrand stays +3 after reforging a random bonus.

Enchanting

Enchanting adds or modifies magical properties on gear. This is a crafting profession (see 07-crafting-and-gathering.md) — player Enchanters perform this service.

  • Common/Uncommon items: Can have 1 enchantment added (effectively giving them a signature-like effect)
  • Rare+ items: Cannot be enchanted (they already have signature effects and random bonuses)
  • Enchanting uses Magical Essence (from disenchanting unwanted magic items)

Loot Tables and Drops

How Loot Works

Each dungeon encounter has a loot table influenced by:

  1. Encounter difficulty — Harder enemies roll on better loot tables
  2. Dungeon tier — Higher-level dungeons have better base pools
  3. Enemy type — Specific enemies drop thematic items (fire enemies → fire gear, undead → necrotic gear)
  4. Luck attribute — Higher LCK improves the quality roll on drops (see Potency Tiers above)
  5. Bad luck protection — Hidden counter that boosts drop rates after dry streaks

Drop Rate Guidelines

Content LevelCommonUncommonRareVery RareLegendary
Levels 1-1090%10%<1%
Levels 11-2070%25%5%<1%
Levels 21-3050%35%12%3%<1%
Levels 31-4030%35%25%8%2%
Levels 41-5020%30%30%15%5%
Raid bosses10%40%35%15%
World bosses30%40%30%

These are per-encounter rates for the “bonus drop” slot (beyond guaranteed gold + common item).

Bad Luck Protection

  • A hidden counter tracks encounters since your last Rare+ drop
  • Every encounter without a Rare+ drop increases the next encounter’s drop rate by +1%
  • Counter resets when a Rare+ item drops
  • This ensures even the unluckiest player will eventually get upgrades
  • LCK attribute makes this counter increase slightly faster

Boss Drops

  • Dungeon bosses always drop at least one item of the dungeon’s highest tier
  • Raid bosses always drop 2-3 items, with at least one Very Rare+
  • World bosses always drop 1-2 items for EACH participant, at least Rare quality

Loot Distribution (Party Play)

After a party run completes, shared loot enters a Need/Greed window:

  1. Need — “I want this for my build.” Only available if the item is usable by your class/weapon proficiency.
  2. Greed — “I want this for selling/salvage.” Always available.
  3. Pass — “I don’t want it.”
  • Need rolls take priority over Greed rolls (d100 roll-off for ties)
  • Personal loot (gold, consumables, materials) is NOT shared — each player gets their own
  • Loot window: 24 hours after run completion. Unclaimed items are distributed randomly among Greed rollers.
  • Transparent: All players can see who rolled Need on what. No hidden rolls.

Trading and the Marketplace

What’s Tradeable

RarityTradeable?Notes
CommonYesLow value, mostly vendor/salvage
UncommonYesModerate marketplace activity
RareYesActive marketplace — random bonuses create varied values
Very RareYesHigh marketplace value — location-specific, good rolls command premium
LegendaryYesPremium marketplace items. “God-rolled” legendaries are the most valuable items in the game.
ArtifactNoSoulbound on pickup

Marketplace Value Factors

A Rare+ item’s marketplace value depends on:

  1. Signature effect — Is it from a desirable dungeon? Is the signature useful?
  2. Random bonus types — Are the bonuses synergistic? (e.g., +accuracy AND +crit on a weapon = high value)
  3. Random bonus potency — How close to “perfect” are the rolls?
  4. Enhancement level — A +3 item is worth significantly more than a +0
  5. Demand — Is this weapon type or armor type popular for current meta builds?

See 08-economy-and-trading.md for full marketplace details.


Inventory Management

Carrying Capacity

  • Base capacity: 20 item slots (not weight-based — simplicity over simulation)
  • Equipped gear does NOT count against inventory
  • Stackable items (potions, rations, materials) stack up to 20 per slot
  • Belt quick slots are separate (3 slots for combat consumables)

Bank Storage

  • Characters have a bank in town with 50 slots (base)
  • Additional bank space available as a permanent purchase ($1 per +25 slots — see 14-monetization.md)
  • Bank is accessible between runs, not during them
  • Material bank is separate — 100 slots for crafting materials only (see 07-crafting-and-gathering.md)

Inventory Overflow

  • If a dungeon run yields more loot than inventory can hold, excess goes to temporary overflow (persists 48 hours)
  • Players must clear overflow before starting a new run
  • After 48 hours, overflow items are auto-sold at vendor price (with notification)
  • Overflow items CAN be salvaged/disenchanted directly from the overflow screen

Item Comparison UI

When viewing any item, the UI shows a side-by-side comparison with currently equipped gear:

┌─ CURRENTLY EQUIPPED ──────────┐  ┌─ NEW DROP ─────────────────────┐
│ Steel Longsword +1 (Uncommon) │  │ Flamebrand Longsword (Legend.) │
│ Damage: 22-35                 │  │ Damage: 48-65                  │
│ +5% accuracy (fixed)          │  │ Signature: Fire Blade          │
│                               │  │   +15% fire damage on skills   │
│                               │  │   20% chance to Burn           │
│                               │  │ Bonus: +8% crit chance  ▲ NEW │
│                               │  │ Bonus: +4 Speed         ▲ NEW │
│                               │  │ Gear Skill: Flame Burst  ▲ NEW│
├───────────────────────────────┤  ├────────────────────────────────┤
│ Overall: ▼ SIGNIFICANT        │  │ Overall: ▲ SIGNIFICANT         │
│          DOWNGRADE            │  │          UPGRADE               │
└───────────────────────────────┘  └────────────────────────────────┘

  Estimated DPS change: +45% ▲
  Evasion change: 0 (same armor)
  New conditions available: Burning (via Fire Blade + Flame Burst)

Key features:

  • Green ▲ for improvements, Red ▼ for downgrades
  • DPS estimate calculated from accuracy × damage × crit chance × skills-per-round
  • Condition availability highlighted when new gear enables applying or resisting conditions
  • Gear skill preview showing what the skill does and its initiative value
  • One-click “Equip” or “Salvage” or “Send to Bank” from the comparison screen

Loot Design Principles

  1. Every drop has value. Equip it, sell it, or salvage it. Nothing goes to waste.
  2. The signature makes the item. Named items have a clear identity. You know what a Flamebrand does before you see its random rolls.
  3. Random bonuses create the chase. Two players with the same named item will have different builds because their bonuses rolled differently.
  4. Reforging is the endgame. Once you find the item you want, the long-term goal is perfecting its random bonuses through reforging.
  5. Transparency builds trust. All stats visible, all rolls visible, no hidden mechanics. The marketplace works because buyers know exactly what they’re getting.
  6. Level doesn’t kill value. A level 10 Rare is worth the same salvage as a level 40 Rare. Low-level content stays relevant.

Quests and Dungeons

Overview

Quests and dungeons are the primary content in Delve — where characters spend their time, earn XP, and find loot. The quest system is built around a quest board where players select from available challenges, prepare their character, and commit to a run that resolves over real-world time.

The key design goal: every run tells a story. Win or lose, the player should be able to read through the run timeline and understand exactly what happened, learn from mistakes, and plan better for next time.

Quest Board

The quest board is the central hub for selecting content. It’s presented as a bulletin board in the character’s current town.

Board Refresh

  • The quest board refreshes every 6 hours with a new selection of quests
  • Some quests persist across refreshes (major questlines, recurring bounties)
  • Players can pin up to 3 quests to save them across refreshes
  • Higher-level characters see more quests and harder options

Quest Information Display

Each quest on the board shows:

  • Name and flavor text — “Clear the Goblin Warren,” “Investigate the Haunted Manor”
  • Type — Bounty, Questline, Dungeon Crawl, Raid (see below)
  • Difficulty rating — Skull icons (1-5) plus a recommended level range
  • Estimated duration — Real-world time to complete (e.g., “~45 minutes”, “~3 hours”)
  • Encounter count — How many encounters to expect
  • Environment type — Cave, forest, undead crypt, etc. (affects Pathfinder favored terrain, elemental resistance needs)
  • Known enemy types — General info (e.g., “Undead heavy”, “Goblinoid raiders”) — not full roster
  • Reward preview — XP range, gold range, potential loot tier (e.g., “Rare+ drops possible”)
  • Supply recommendation — Suggested rations, potions, torches based on dungeon length
  • Party size — Solo, 2-player, 4-player, or raid (8+ player)

Quest Types

Bounties

  • Length: 1-3 encounters
  • Duration: 15-45 minutes real-time
  • Purpose: Quick content for short play sessions or grinding specific resources
  • Structure: Travel to location → fight target → return
  • Examples: “Slay the Dire Wolf terrorizing the eastern road,” “Eliminate the bandit captain at Crow’s Perch”
  • Rewards: Modest XP and gold, targeted loot (bounty targets drop specific item types)

Questlines

  • Length: 5-8 encounters
  • Duration: 1-3 hours real-time
  • Purpose: The bread-and-butter content. Narrative-driven multi-encounter sequences.
  • Structure: A series of encounters connected by a narrative thread. Includes combat, traps, decisions, and sometimes branching paths.
  • Branching decisions: At certain points, the character faces a choice (e.g., “Left passage or right passage?”). Players configure these choices before the run or set decision-making rules (e.g., “always take the safer path,” “always take the path with more treasure potential”).
  • Examples: “Investigate the disappearances in Millhaven,” “Recover the Sunstone from the Forgotten Temple”
  • Rewards: Good XP, solid loot, occasional unique quest rewards (named items)
  • Narrative continuity: Some questlines are multi-part — completing part 1 unlocks part 2 on a future board refresh

Dungeon Crawls

  • Length: 10-20 encounters
  • Duration: 3-8 hours real-time
  • Purpose: Major undertakings. The flagship content for dedicated players.
  • Structure: A full dungeon with multiple rooms, branching paths, rest points, traps, puzzles, minibosses, and a final boss.
  • Rest points: Locations within the dungeon where the character can rest (recover some HP and resource pools). The skill queue can be configured for rest behavior (rest immediately, rest only if below X% HP, skip rest to save time).
  • Supply management: Long dungeons require careful supply planning. Running out of rations means exhaustion. Running out of torches means missed traps.
  • Examples: “The Undercrypt of Ashenmoor (Level 15-20, 15 encounters),” “The Dragon’s Hoard of Frostpeak (Level 35-40, 20 encounters)”
  • Rewards: High XP, best loot, dungeon completion achievements, rare/very rare drops guaranteed from final boss

Raids

  • Length: 15-30 encounters
  • Duration: 4-12 hours real-time
  • Purpose: Multiplayer endgame content. Requires a full party (4-8 players).
  • Structure: Large-scale dungeon with encounters designed for party composition. Some encounters require specific roles (tank to hold aggro, healer to keep party alive, DPS to meet damage thresholds).
  • Timed lobby: Raids start at a scheduled time (see 09-social-and-mmo-systems.md). Players join the raid lobby and configure their character before the start time.
  • Examples: “The Siege of Ironhold (8-player, Level 35+),” “Abyssal Rift (4-player, Level 50)”
  • Rewards: Best loot in the game, raid-exclusive legendary items, guild reputation, seasonal leaderboard ranking

Encounter Types

Dungeons are composed of a sequence of encounters. Each encounter type tests different aspects of the character’s build.

Combat Encounters

  • Standard fight against one or more enemies
  • Enemies have stat blocks (HP, Evasion rating, attacks, abilities, resistances)
  • Resolved using the combat system (see 04-combat-system.md)
  • Variants:
    • Standard: Fight a group of enemies
    • Ambush: Enemies get a surprise round (failed Perception check — Logic-based)
    • Boss: Powerful single enemy or enemy with minions. Higher HP, special abilities, multiple phases.
    • Waves: Multiple rounds of enemies with short breaks between
    • Timed: Must defeat enemies within X rounds or face consequences (reinforcements, collapsing room)

Trap Encounters

  • The character encounters a trap (pit, poison darts, falling rocks, magical ward)
  • Resolution:
    1. Detection: Perception (Logic) or Investigation (Logic) check to notice the trap
    2. Disarming: Sleight of Hand, Arcana, or Thieves’ Tools check to disarm (if detected)
    3. Avoidance: Speed resistance check to dodge (if triggered)
    4. Endurance: Take the damage and move on
  • Shades excel here — higher detection rates, better disarm chances
  • Configurable behavior: “attempt to disarm” vs. “just dodge it” vs. “trigger and tank it” (useful for high-HP characters in low-danger traps)
  • Traps may inflict conditions: Poisoned, Burning, Bleeding, etc.

Decision Points

  • A narrative fork where the character must choose between options
  • Examples:
    • “Two passages: one smells of sulfur, the other echoes with dripping water”
    • “A wounded NPC asks for help. Stop to aid them, or press forward?”
    • “The treasure chest has a strange aura. Open it, or leave it?”
  • Pre-configured decisions: Players set decision-making heuristics:
    • “Prioritize: Safety / Treasure / Speed / Exploration”
    • Specific overrides: “Always help NPCs,” “Never open suspicious chests,” “Always take the path with potential treasure”
  • Decision outcomes affect:
    • Which encounters come next (branching paths)
    • Bonus loot or bonus encounters
    • NPC relationships (faction reputation)
    • Sometimes avoiding a harder fight entirely

Environmental Hazards

  • Non-trap obstacles that test specific abilities
  • Examples:
    • Flooded room (Athletics/Might to swim, or lose rations)
    • Collapsed passage (Might check to clear, or find alternate route)
    • Magical darkness (torches useless — need Darkvision or Light spell)
    • Extreme cold (Fortitude resistance check or take damage each round, fire resistance helps)
    • Rickety bridge (Speed check or fall, taking damage)
  • Skills and supplies matter: rope for climbing, torches for dark areas, rations for long detours

Rest Points

  • Safe areas within longer dungeons where the character can recover
  • Rest provides:
    • HP recovery (50% of max HP, or 100% with Soldier background bonus)
    • Resource pool recovery (half of expended Mana/Stamina/Devotion/etc., rounded down)
    • Rations consumed (1 ration)
    • Condition removal (Poisoned, exhaustion level 1)
  • Players configure rest behavior in the skill queue:
    • “Rest whenever available”
    • “Rest only if below X% HP”
    • “Rest only if resource pool below X”
    • “Skip rest” (for speed-running)

Puzzle Encounters

  • Logic or Presence-based challenges
  • Resolution is a skill check (d100 percentile roll) with bonuses from relevant proficiencies
  • Examples:
    • Magical lock requiring Arcana check
    • Ancient riddle requiring History check
    • Pattern recognition requiring Investigation check
  • Failure consequence: miss bonus loot, trigger a trap, or face an extra combat encounter
  • Not all characters need to solve puzzles — failure is an alternate path, not a dead end

Run Timeline

The run timeline is the complete record of a dungeon run. It’s the primary thing the player reviews after a run.

Timeline View

A visual representation of the dungeon run showing:

DUNGEON: The Goblin Warren (Level 10, Questline)
Duration: 1 hour 23 minutes | Encounters: 7 | Result: SUCCESS

[1]──[2]──[3]──[4]──[5]──[6]──[7]
 ⚔    ⚠   🔀    ⚔    🏕    ⚔    ⚔★

1. ⚔ Combat: Goblin Patrol (3 goblins) ─── VICTORY, clean [HP: 95%]
2. ⚠ Trap: Pit Trap ─── DETECTED & DISARMED [Perception: 72 vs DC 45]
3. 🔀 Decision: Left (sulfur) or Right (water) ─── Chose LEFT [Treasure priority]
4. ⚔ Combat: Fire Beetles (5) ─── VICTORY, took damage [HP: 62%]
5. 🏕 Rest Point ─── Rested, consumed 1 ration [HP: 62% → 85%]
6. ⚔ Combat: Goblin Boss + Shaman ─── VICTORY, hard fight [HP: 34%]
7. ⚔★ Boss: Bugbear Chieftain ─── VICTORY [HP: 12%]

LOOT SUMMARY:
  Gold: 127
  Items: Bugbear's Morningstar +1 (Uncommon), Shaman's Robe (Common), 3x Minor Healing Potion
  Materials: 4x Leather Scraps, 2x Goblin Teeth (alchemy reagent)

SUPPLIES CONSUMED:
  Rations: 4 of 6 brought (2 remaining)
  Torches: 2 of 4 brought (2 remaining)
  Healing Potions: 2 used during combat

XP EARNED: 450 (Level 8 → 72% to Level 9)

Expanding Encounters

Each encounter in the timeline can be expanded to show the full combat log (see 04-combat-system.md) or the full skill check breakdown for traps and hazards.

Failure Analysis

When a run fails, the timeline includes a failure summary that highlights exactly what went wrong:

DUNGEON: The Undercrypt (Level 20, Dungeon Crawl)
Duration: 2 hours 47 minutes | Encounters: 12 of 15 | Result: FAILED at Encounter 12

FAILURE SUMMARY:
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
  Cause of Death: Reduced to 0 HP by Wraith Lord's Necrotic Burst

  Contributing Factors:
  ⚠ Entered encounter 12 with only 28% HP (entered rest point at encounter 9
    with 71% HP but skill queue was set to "rest only below 30%")
  ⚠ No healing potions remaining (last used at encounter 8)
  ⚠ Wraith Lord has necrotic resistance — your primary damage type is necrotic
    (consider radiant damage weapon or spell)
  ⚠ Failed Presence resistance check against Wraith's fear aura (PRS check: 23
    vs DC 55) — spent 2 rounds frightened, unable to close distance

  Recommendations:
  → Bring more healing potions (you brought 3, recommend 5+ for this dungeon length)
  → Lower rest threshold to 50% HP for dungeons with 15+ encounters
  → Consider equipping a radiant damage option for undead-heavy dungeons
  → Increasing Presence (currently 10) or taking Resilient (PRS) would help against
    fear effects common in undead encounters
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

Difficulty Tiers

Each quest has a difficulty rating relative to the player’s level:

DifficultySkull RatingRelative LevelCompletion RateXP/Loot Bonus
Trivial10+ below~99%50% penalty
Easy☠☠5-9 below~90%None
Normal☠☠☠At level~70%None
Hard☠☠☠☠1-5 above~50%+25% XP and gold
Deadly☠☠☠☠☠6+ above~25%+50% XP and gold, better loot table

The completion rates are rough targets assuming appropriate gear and average skill queue configuration. Well-prepared characters with good builds and smart skill queue configuration can push above these rates. Poorly prepared characters will fall below them.

Level Scaling

  • Quests have fixed levels — they don’t scale to the character
  • A level 25 character returning to a level 10 dungeon will find it trivial
  • This is intentional — it provides a sense of power progression and allows farming lower content for specific drops or materials

Time Durations

Real-world time for dungeon runs is a core idle mechanic. Durations are based on quest type and difficulty:

Quest TypeEncounter CountDuration
Bounty (easy)1-215-30 minutes
Bounty (hard)2-330-60 minutes
Questline (easy)4-61-2 hours
Questline (hard)6-82-4 hours
Dungeon Crawl (short)8-123-5 hours
Dungeon Crawl (long)12-205-8 hours
Raid (small)10-154-6 hours
Raid (large)15-306-12 hours

Duration Philosophy

  • Short sessions (bounties) should be completable during a lunch break
  • Medium sessions (questlines) should complete while at work or overnight
  • Long sessions (dungeon crawls) should be overnight or full-day affairs
  • Raids are events — they happen at scheduled times and run for a significant period
  • Dungeon run durations cannot be sped up with real money. This is a core design principle. Everyone waits the same amount.

Supplies System

Preparation is a key part of the gameplay loop. Players must stock their character with supplies before committing to a run.

Supply Planning

The quest board shows recommended supplies. Players choose what to bring, trading off between safety and inventory space.

SupplyWeight (slots)Consumption RateRunning Out
Rations1 slot per 51 per encounterExhaustion accumulates
Torches1 slot per 51 per dark area (varies by dungeon)Can’t see traps, -20% to Perception checks
Healing Potions1 slot eachAs needed in combatNo emergency healing
Ammunition1 slot per 20Per ranged attackMust switch to melee/cantrips
Lockpicks1 slot per 31 per lock attemptCan’t pick locks
Rope1 slotPer climbing/traversal encounterHarder Athletics (Might) checks, or blocked paths
Antidotes1 slot per 3Per poison encounterMust endure Poisoned condition

Supply Strategy

  • A 10-encounter dungeon needs at least 10 rations (2 slots)
  • Cave dungeons need more torches; outdoor quests need few or none
  • Undead dungeons benefit from extra healing potions (no short rests in crypts?)
  • Over-packing supplies means less room for loot on the way out
  • Under-packing means risking failure

This tension — preparation vs. capacity — is the core strategic decision before every run.

Recurring and Seasonal Content

Daily Bounties

  • 3 bounties refresh daily with bonus XP and gold
  • Completing all 3 grants a daily completion bonus (bonus loot chest)

Weekly Challenges

  • Special modifier dungeons that rotate weekly
  • Examples: “All enemies have double HP,” “No healing potions allowed,” “Timed run: complete in fewer encounters for bonus rewards”
  • Higher risk, higher reward

Seasonal Dungeons

  • Time-limited dungeons available during seasonal events (see 15-progression-hooks-and-retention.md)
  • Unique enemies, unique loot, unique environmental themes
  • Available for the duration of the season (typically 2-3 months)

Economy and Trading

Overview

The economy is the connective tissue of Delve. Gold and materials flow between dungeon runs, crafting, the marketplace, and NPC vendors. A healthy economy requires careful balance: enough currency entering the system to feel rewarding, enough leaving (gold sinks) to prevent inflation, and enough player-to-player trading to create a real marketplace.

Currencies

Gold (Primary Currency)

  • Earned from: dungeon runs, quest rewards, NPC vendor sales, daily bonuses
  • Spent on: NPC vendor purchases, crafting station fees, respec costs, auction house fees, guild creation
  • Gold is tradeable between players via the marketplace and mail

Faction Tokens (Reputation Currency)

  • Earned by completing faction-specific quests and dailies
  • Spent at faction vendors for exclusive recipes, gear, and cosmetics
  • Each faction has its own token type
  • NOT tradeable — must be earned personally
  • See 11-factions-and-reputation.md

Raid Tokens

  • Earned from completing raid content
  • Spent on raid-exclusive gear at raid vendors
  • Weekly cap on how many can be earned (prevents no-lifing the system)
  • NOT tradeable

Gold Economy

Gold Sources (Faucets)

SourceGold/InstanceFrequency
Dungeon run (bounty)50-200Multiple per day
Dungeon run (questline)200-8001-3 per day
Dungeon run (crawl)500-20001 per day
Raid completion1000-50001-2 per week
NPC vendor salesVariesConstant
Daily first-run bonus100 flat1 per day
Quest completion bonus50-500Per quest

Gold Sinks (Drains)

SinkCostPurpose
Respec (attributes)500-5000 (scales with level)Discourages constant respec, provides meaningful choice
Respec (feats)1000-10000Same as above
Crafting station fees10-500 per craftSmall per-transaction drain
Auction house listing fee5% of listing priceDiscourages low-value listings
Auction house sale tax10% of sale pricePrimary marketplace gold sink
Gear upgrade attempts100-5000 per attemptEscalating with enhancement level
Gear repair10-1000Per item, scales with rarity. Steady drain from active play.
Reforging fees500-5000Per reforge attempt (scales with rarity)
Guild creation10,000One-time cost
Guild bank expansion5,000 per slotOngoing guild gold sink
Cross-character mail transfer fee5% of gold sentPrevents zero-cost gold shuffling
NPC vendor purchases (consumables)VariesRations, basic potions, etc.

Inflation Control Philosophy

  • Gold sinks should feel like natural costs of doing business, not arbitrary taxes
  • The auction house tax is the primary inflation control — it removes gold proportional to economic activity
  • If inflation becomes an issue, seasonal events can introduce additional gold sinks (cosmetic vendors, limited-time items for gold)
  • Monitoring: track median gold holdings by level bracket and adjust faucets/sinks accordingly

Player Marketplace (Auction House)

The marketplace is where players trade items for gold. It’s the central economic hub.

Listing Items

  • Any non-bound item can be listed (most loot is tradeable)
  • Set a buyout price (instant purchase)
  • Set an optional auction starting price (bidding over 24/48 hours)
  • Listing fee: 5% of buyout price (non-refundable, acts as gold sink)
  • Listings last 48 hours by default
  • Max active listings: 20 (base), expandable via permanent purchase ($1 per +5 slots)

Buying Items

  • Browse by category, rarity, level range, stats, or keyword search
  • Sort by price, time remaining, or relevance
  • “Buy Now” at the buyout price
  • Bid on auction listings (outbid notification)
  • Purchase history for reference

Sale Tax

  • When an item sells, 10% of the sale price is taken as tax (gold sink)
  • Seller receives 90% of the sale price
  • Merchant background reduces tax to 8% (Merchant background grants +1 Luck)

Item Binding

Most items are freely tradeable, but some are bind-on-pickup (BoP):

  • Raid-exclusive legendary gear
  • Quest reward items with unique effects
  • Artifact-rarity items
  • Achievement rewards

Some items are bind-on-equip (BoE):

  • Can be traded until first equipped
  • Encourages marketplace activity for high-end gear
  • Creates the “equip or sell?” dilemma — a valuable gear piece might be worth more on the market than on your character

Market Manipulation Prevention

  • Price floor: Items cannot be listed below NPC vendor price
  • No buyout sniping bots: Rate limiting on purchases, CAPTCHA-like verification for rapid purchases
  • Price history: Visible graph of average sale prices over the last 30 days for any item type
  • Report system: Players can flag suspicious trading patterns for review

NPC Vendors

General Goods Vendor

  • Sells: Rations, torches, basic potions, rope, lockpicks, ammunition, healer’s kits
  • Prices are fixed and do not fluctuate
  • Always available

Equipment Vendor

  • Sells: Common-quality weapons and armor
  • Rotating stock of uncommon items (refreshes daily)
  • Prices are fixed

Specialty Vendors (Unlocked by Progression)

  • Alchemist: Sells potion recipes and rare reagents (limited stock, refreshes weekly)
  • Blacksmith: Sells gear upgrade and enhancement services
  • Enchanter: Sells enchanting materials and basic enchantments
  • Exotic Trader: Appears randomly with unusual items (rare recipes, unique consumables, cosmetics for gold)

Vendor Buy Prices

  • Vendors buy items at 50% of their sell price (base)
  • Merchant background: 60%
  • High faction reputation with Merchant Consortium: up to 70%
  • This makes the marketplace almost always a better option for valuable items, driving player-to-player trade

Trading Between Players

Marketplace (Primary)

  • The auction house is the primary trading mechanism
  • Anonymous — buyers and sellers don’t know each other
  • Safe — no scam risk

Mail System

  • Players can mail items and gold to specific players
  • Gold transfer fee: 5% (gold sink)
  • Item mail: Free, but items are held for 1 hour before delivery (prevents impulse scam trades)
  • Mail between characters on the same account uses the same system

No Direct Trade

  • There is no direct trade window between players
  • All trades go through the marketplace or mail
  • This prevents social engineering scams (“put your item up first, I promise I’ll pay”)
  • It also ensures all trades are taxed appropriately

Real-Money Purchases and the Economy

See 14-monetization.md for the full monetization model. Key points relevant to the economy:

  • There is no premium currency. No gems, no crystals, no tokens. All purchases are in real dollars at transparent prices.
  • Nothing that affects combat stats is sold for real money. No gear, no XP, no gold, no loot boosts.
  • Patron subscribers get 50% faster crafting and dungeon runs — this means subscribers generate materials and loot at a faster rate, which increases marketplace supply. This is healthy for the economy (more supply = lower prices = better for free players).
  • Permanent purchases (character slots, storage, marketplace listing slots) are small one-time buys that don’t distort the economy.

Economic Health Indicators

The game should track and monitor:

  • Median gold by level bracket — Are new players too poor? Are endgame players hoarding?
  • Marketplace transaction volume — Is the market healthy and active?
  • Average item prices over time — Is inflation occurring?
  • Gold faucet/sink ratio — Is more gold entering or leaving the system?
  • Subscriber vs. free player economic participation — Are subscribers dominating the marketplace unfairly?

These metrics inform tuning decisions — adjusting drop rates, vendor prices, tax rates, and gold rewards to keep the economy balanced.

Social and MMO Systems

Overview

Delve is an MMO, not a single-player idle game. Social systems are what transform individual dungeon runs into a shared world. The core challenge: making multiplayer meaningful and engaging in an asynchronous game where players are rarely online at the same time.

The solution is the timed lobby system — group content starts at scheduled times, and players prepare their characters before the deadline. You don’t need to be online at the same time as your party; you just need to be ready before kickoff.

Guilds

What Is a Guild?

A guild is a persistent group of players who share resources, coordinate on raids, and compete together. Guilds are the primary social structure in Delve.

Guild Creation

  • Cost: 10,000 gold
  • Requirements: Level 10+ character
  • Guild name: Unique server-wide, 3-24 characters
  • Guild tag: 2-4 character abbreviation displayed next to member names

Guild Size

  • Base capacity: 50 members
  • Expandable via guild upgrades (gold cost): up to 200 members
  • No hard cap on inactive members, but guilds can set auto-kick thresholds

Guild Ranks and Permissions

RankPermissions
Guild MasterAll permissions, transfer ownership, disband guild
OfficerInvite/kick members, schedule raids, manage guild bank, edit MOTD
VeteranAccess guild bank (deposit + limited withdrawal), join raid lobbies
MemberAccess guild bank (deposit only), join raid lobbies, guild chat
RecruitGuild chat only, 7-day probation period

Guild masters can create custom ranks with granular permissions.

Guild Bank

  • Shared storage for items and gold
  • Members deposit items/gold; withdrawal permissions are rank-based
  • Withdrawal logs visible to officers (prevents theft without accountability)
  • Bank size: 50 slots base, expandable with guild gold
  • Acts as a gold sink (expansion costs) and a social coordination tool

Guild Buffs

Guilds can invest gold into temporary server-wide buffs for all members:

BuffCostDurationEffect
Fortune’s Favor5,000 gold24 hours+10% gold from dungeon runs
Scholar’s Blessing5,000 gold24 hours+10% XP from dungeon runs
Artisan’s Focus3,000 gold24 hours15% faster crafting
Gatherer’s Bounty3,000 gold24 hours15% more gathering yield
Endurance4,000 gold24 hours+5% max HP during runs
  • Only one buff active at a time per guild
  • Acts as a meaningful gold sink
  • Encourages active guild management

Guild Leveling

  • Guilds earn XP from member activities (dungeon completions, raid completions, PVP wins)
  • Guild levels unlock:
    • Higher member cap
    • More guild bank slots
    • Access to guild-exclusive crafting stations (10% crafting time reduction)
    • Guild hall cosmetic upgrades
    • Guild achievements and titles

Guild Hall

  • A visual representation of the guild’s home base
  • Upgradeable with gold and materials
  • Contains: guild bank, crafting stations, quest board (guild-specific bounties), trophy room (displays raid achievements)
  • Primarily a social and cosmetic space — a “home” for the guild

Party System

Timed Lobby System

This is the core multiplayer mechanic. Here’s how it works:

  1. A player (or guild officer) creates a party lobby for a specific quest/dungeon/raid
  2. A start time is set — e.g., “This raid starts at 8:00 PM server time on Saturday”
  3. Players join the lobby before the start time, slotting their configured character into a party role
  4. At the start time, the run begins automatically — regardless of whether players are online at that moment
  5. The run resolves over real-world time as usual
  6. All party members can review results when the run completes

Lobby Details

  • Party size: 2-player (duo), 4-player (standard), 8-player (raid)
  • Role slots: Lobbies can specify role requirements:
    • Tank (1-2): Vanguard, Berserker, Oathblade
    • Healer (1-2): Warden, Songweaver, Oathblade
    • DPS (2-4): Any damage-focused build
    • Support (0-2): Songweaver, Arcanist (utility), Pathfinder (scout)
  • Minimum level: Set by the quest requirements
  • Ready check: Players must mark “Ready” after configuring their character
  • Auto-fill option: If the lobby isn’t full by start time, the system can optionally auto-fill from a public queue (configurable by lobby creator)
  • Late join window: Players can join up to 30 minutes before start time

Lobby Scheduling

  • Lobbies can be created up to 7 days in advance
  • Guild officers can create recurring lobbies (e.g., “Every Saturday at 8 PM: Weekly Raid”)
  • Notification system: Players receive notifications:
    • When a lobby they might be interested in is created (guild lobbies, friend lobbies)
    • 1 hour before a lobby starts
    • 15 minutes before a lobby starts (final reminder)
    • When the run is complete

Public Queue

For players without a guild or for casual grouping:

  • Queue for a quest — the system matches you with other queued players when enough are available
  • Matching prioritizes: level range, role balance, queue time
  • Once matched, a lobby is created with a 1-hour countdown — giving all matched players time to configure
  • Less control than a private lobby, but zero coordination required

Party Combat

  • Party members act in initiative order alongside enemies
  • Each player’s skill queue operates independently based on their configuration
  • Allied skill queue awareness: Skill queues can reference ally conditions:
    • “Heal the ally with the lowest HP”
    • “Use Inspiring Melody on the Shade when they attack the boss”
    • “Taunt enemies attacking the Arcanist”
  • Party composition matters — a party of 4 DPS will struggle without a healer

Raids

Raids are the pinnacle multiplayer content. See 06-quests-and-dungeons.md for encounter structure.

Raid-Specific Features

  • 8-player parties with strict role requirements
  • Multi-phase boss fights with unique mechanics:
    • Phase transitions at HP thresholds
    • Environmental hazards (stand in fire = take damage)
    • Add spawns (boss summons minions periodically)
    • Enrage timers (boss gets stronger if fight goes too long — DPS check)
    • Role-specific mechanics (tank must hold aggro, healer must dispel debuff, DPS must focus specific target)
  • Raid lockouts: Characters can only complete a specific raid once per week for full rewards
    • Additional completions in the same week give reduced rewards (partial XP, no bonus loot)
    • Lockout resets every Monday at server reset time
  • Raid difficulty tiers: Normal / Heroic / Mythic
    • Each tier increases enemy stats, adds mechanics, and improves loot quality
    • Mythic raids drop the best gear in the game

Raid Scheduling

  • Guilds schedule raids via the lobby system
  • Raid lobbies appear on a server-wide raid calendar (for public raids)
  • Raid start times are prominently displayed with countdown timers

Friends List

  • Add players by character name
  • See friends’ online status, current activity, and level
  • Quick-invite to party lobbies
  • Friend activity feed: See when friends complete notable dungeons, earn achievements, or find legendary loot
  • Max friends: 100

Messaging and Mail

In-Game Mail

  • Send items, gold, and text messages to any player
  • Item mail: 1-hour delivery delay (anti-scam)
  • Gold mail: 5% transfer fee (gold sink)
  • Text mail: Instant delivery
  • Mail expires after 30 days if unclaimed
  • Used for: auction house payments, guild communications, friend-to-friend trading

Chat System

Channels:

  • Global: Server-wide chat (rate-limited to prevent spam)
  • Guild: Guild members only
  • Party: Current party/lobby members
  • Whisper: Private 1-on-1 messages
  • Trade: Dedicated channel for trade offers and requests
  • LFG (Looking for Group): Dedicated channel for finding parties

Chat is persistent — messages are stored and visible when you log in (last 100 messages per channel). This is crucial for async play — guild coordination happens over hours, not minutes.

Chat Moderation

  • Profanity filter (configurable: on/off/custom)
  • Report system for harassment
  • Mute/block individual players
  • Rate limiting on global/trade channels
  • Automated spam detection

Player Inspection

  • Click on any player’s name to view their public profile:
    • Character name, title, guild
    • Level and class
    • Equipped gear (visible to all)
    • Achievement showcase (player-selected highlights)
    • PVP rank
    • Dungeon completion statistics
  • Players can set their profile to private (hides gear and stats, shows only name/level/guild)

Social Features Summary

FeatureSolo BenefitMultiplayer Benefit
GuildsGuild buffs, bank storageRaid access, coordination, community
Party LobbyN/AGroup content, harder dungeons, better loot
FriendsActivity feedQuick party invites, social connection
MailCross-character transfersTrading, communication
ChatTrade channel, LFGGuild coordination, socializing
MarketplaceBuy/sellPlayer-driven economy

PVP System

Overview

PVP in Delve is fully asynchronous. You configure your character’s skill queue, queue for a match, and the system resolves the fight. You can review the combat log afterward, just like a dungeon run. This makes PVP accessible to all time zones and schedules while preserving the strategic depth of build optimization and skill queue configuration.

Arena PVP

1v1 Arena

The core PVP mode. Your character fights another player’s character in a controlled environment.

How It Works

  1. Queue for 1v1 — Your character enters the matchmaking queue
  2. Matchmaking — System finds an opponent near your rating
  3. Fight resolves immediately — No waiting period (unlike dungeon runs)
  4. Review the log — Full combat log shows every roll, decision, and outcome

The fight resolves instantly because there’s no dungeon exploration — just two configured characters fighting. This makes PVP feel snappy and repeatable.

Matchmaking

  • ELO-based rating system — Win against higher-rated opponents = more rating gain
  • New characters start at 1000 ELO
  • Rating range for matchmaking: +/- 150 ELO (widens over time if no match found)
  • Level-based brackets to prevent level 50s from fighting level 5s:
    • Bracket 1: Levels 1-12
    • Bracket 2: Levels 13-25
    • Bracket 3: Levels 26-37
    • Bracket 4: Levels 38-50
  • Within a bracket, gear and build differences create the competitive space

Arena Rules

  • Standardized arena — Flat terrain, no environmental factors. Pure build vs. build.
  • No consumables — Potions, scrolls, and supplies are not used in arena PVP. Prevents pay-to-consume advantages.
  • Full HP/resources — Both fighters start at full HP, full ability charges, all abilities available
  • 10-round time limit — If neither fighter is dead after 10 rounds, the one with higher HP percentage wins
  • Death is not permanent — Losing an arena match has zero character consequences (no gear loss, no recovery timer)

Team Arena (3v3)

  • Same matchmaking system but team-based
  • Premade teams (guild members, friends) or solo queue (auto-matched)
  • Team rating is separate from 1v1 rating
  • Party composition matters heavily — tank/healer/DPS vs. triple DPS is a real strategic choice
  • Skill queues can reference teammate conditions (same as party dungeon runs)

Arena Rewards

RewardSource
PVP RatingWin/loss affects ELO
Honor PointsEarned per match (more for wins), spent at PVP vendor
Season RatingBest rating achieved during the current season
TitlesEarned at rating thresholds

PVP Vendor

Spends Honor Points on:

  • Cosmetic gear skins unique to PVP
  • Titles at various honor point thresholds
  • PVP-specific consumables (usable only in guild war content, not arena)
  • Portraits and profile frames showing PVP rank

No stat gear from PVP vendor. PVP rewards are cosmetic and prestige-based. Gear comes from PVE (dungeons, crafting, raids). This prevents a mandatory PVP grind for PVE players and vice versa.

PVP Seasons

Season Structure

  • Seasons last 3 months (aligned with real-world quarters)
  • At the start of each season, arena ratings soft reset (compressed toward 1000, not fully wiped)
  • Season rewards are distributed at the end based on peak rating achieved during the season

Season Rewards

Rating TierTitleReward
Bronze (1000-1199)CombatantBronze portrait frame
Silver (1200-1399)DuelistSilver portrait frame, exclusive silver armor skin
Gold (1400-1599)GladiatorGold portrait frame, exclusive gold armor skin, cosmetic pet
Platinum (1600-1799)ChampionPlatinum portrait frame, exclusive platinum armor skin, unique title
Diamond (1800+)LegendDiamond portrait frame, legendary armor skin, unique animated title, statue in PVP hall
  • All season rewards are permanent — earned once, kept forever
  • Previous season rewards are no longer earnable (creates exclusivity and bragging rights)

Leaderboard

  • Top 100 players per bracket displayed on a public leaderboard
  • Shows: rank, character name, guild, class, win/loss record, peak rating
  • Updated in real-time as matches resolve

PVP Balance

The Balance Challenge

PVE gear in PVP creates inherent imbalance — a player with legendary raid gear will outperform someone in quest greens at the same skill level. Delve addresses this with stat normalization:

Stat Normalization in Arena

  • All gear in arena PVP is scaled to a baseline item level
  • A player in common gear fights at the same effective stat level as a player in legendary gear
  • Gear properties still matter — enchantments, set bonuses, and special effects function normally, but raw stats (Evasion rating, damage dice, attribute bonuses from MGT/LOG/SPD/PRS/FRT/LCK) are equalized
  • This means: your choice of enchantments, class build, feat selection, and skill queue configuration determine PVP outcomes — not how many raid clears you have

Why Normalization?

  • Makes PVP accessible to all players regardless of PVE progression
  • Prevents “you need raid gear to compete” gatekeeping
  • Keeps the competitive focus on strategy and build decisions
  • Players who don’t enjoy PVE can still compete in PVP

What’s NOT Normalized

  • Level — Higher level characters have more abilities, feats, and base stats. This is why PVP has level brackets.
  • Class and subclass — Some matchups are inherently favored (rock-paper-scissors element). Over many games, this evens out.
  • Skill queue configuration — The primary competitive differentiator. A well-configured skill queue beats a poorly configured one.

Guild Wars

Guild wars are opt-in, ongoing conflicts between two guilds that add PVP stakes to normal play.

Declaring War

  • A guild officer challenges another guild to war
  • The challenged guild has 48 hours to accept or decline
  • Both guilds set a war wager (gold from the guild bank)
  • War lasts 1 week from acceptance

War Mechanics

  • During the war period, members of opposing guilds are automatically matched for war arena matches when both queue for PVP
  • War matches award war points to the winning guild
  • At the end of the week, the guild with more war points wins the wager
  • War matches use the same normalized arena rules

War Standings

  • Tracked on a war scoreboard visible to both guilds
  • Individual performance tracked (top contributors earn bonus honor points)
  • Guild chat gets automated updates (“Your guild is winning the war 45-38!”)

War Rewards

  • Winning guild receives the loser’s wager
  • Winning guild members receive bonus honor points
  • “War Victor” title available for the winning guild during the following week

Faction Warfare

Faction warfare is a server-wide, persistent PVP system tied to the faction system (see 11-factions-and-reputation.md).

How It Works

  • Certain world zones are contested territory controlled by factions
  • Players aligned with a faction can queue for faction battles to capture or defend territory
  • Faction battles are larger-scale (8v8 or 16v16), using the timed lobby system
  • Territory control grants server-wide buffs to all members of the controlling faction

Territory Control Benefits

TerritoryControlling Faction Bonus
Silver Mines+5% gold from all sources
Ancient Library+5% XP from all sources
Sacred Grove+5% gathering yield
Forge of Ages+5% crafting speed
  • Territories can be challenged once per day by an opposing faction
  • The defending faction’s battle happens at a set time (timed lobby — same async-friendly system)
  • Control changes are announced server-wide

Faction PVP Rating

  • Separate from arena rating
  • Affects faction reputation gain rate
  • Top faction PVP contributors earn exclusive faction titles and cosmetics

PVP Design Principles

  1. PVP is always optional. No PVE content requires PVP participation. No PVP rewards give PVE advantages (beyond cosmetics).
  2. Skill > gear. Stat normalization ensures PVP outcomes depend on build choices and skill queue configuration, not gear farming.
  3. Async-friendly. All PVP resolves without requiring both players online simultaneously.
  4. Meaningful rewards without mandatory participation. PVP rewards are cosmetic prestige items. FOMO is limited to seasonal titles (which are purely visual).
  5. Anti-griefing. No open-world PVP, no ganking, no corpse camping. All PVP is consensual and structured.

Factions and Reputation

Overview

Factions are persistent organizations in the game world that players align with to unlock exclusive rewards, recipes, enchantments, and consumables. Reputation is earned over time through quests and activities — it’s a long-term progression system that complements the level and gear treadmills.

Factions create meaningful choices. Some factions are in conflict, so raising reputation with one may lower it with another. This encourages players to specialize or plan carefully.

Design Principle: No Class Funneling

Every faction’s rewards are usable by all 9 classes. Factions do not map to class archetypes. There is no “correct” faction for a Shade, Arcanist, or Vanguard. Instead, each faction optimizes a different gameplay strategy dimension — durability, burst damage, loot discovery, gear enhancement, consumable power, risk/reward, or economic advantage. Any class benefits from any faction.

A Shade might choose Iron Compact (shore up squishiness with durability), Covenant of Dusk (maximize burst damage at the cost of fragility), or Shadow Court (optimize loot per run). All three are valid builds that produce meaningfully different characters.


Faction List

The Iron Compact

  • Theme: Military order, discipline, endurance
  • Headquarters: Ironhold Citadel (The Ironmarch)
  • Conflict with: The Covenant of Dusk
  • Gameplay Dimension: Durability & Endurance
    • Rewards focus on surviving longer, recovering more between encounters, and shrugging off conditions. For players who want to go deeper into dungeons and never die.
  • Rewards:
    • Enchantments (all gear types): +max HP, +condition resistance, +HP recovery between encounters, +rest point effectiveness
    • Consumables: Extended-duration rations (last 2 encounters instead of 1), fortification elixirs (+Fortitude for full dungeon run), condition immunity tonics
    • Recipes: Reinforced armor upgrades (any weight class), durable weapon coatings (reduce gear degradation), bulk supply crafting (craft supplies in larger batches)
    • Passive (Exalted): +10% HP recovery at rest points, +10% condition resistance in all content
    • Cosmetics: Heavy-plated armor skins, “Iron Warden” title, fortress-themed portrait frames

The Shadow Court

  • Theme: Intelligence network, information brokers, treasure hunters
  • Headquarters: The Undercity (The Shallows)
  • Conflict with: The Order of the Dawn
  • Gameplay Dimension: Loot & Discovery
    • Rewards focus on finding more treasure, detecting traps and hidden rooms, and increasing loot quality. For players who want to maximize the value of every dungeon run.
  • Rewards:
    • Enchantments (all gear types): +loot quality, +trap detection, +hidden room discovery chance, +gold find
    • Consumables: Treasure-finding scrolls (reveal all hidden caches in current dungeon), trap-sight potions (+50% trap detection for a full run), appraisal dust (identify items on pickup)
    • Recipes: Lockpick crafting (all tiers), loot-enhancing weapon oils (bonus drop chance from kills), salvage kits (bonus materials from salvaging)
    • Passive (Exalted): +5% loot quality on all dungeon runs, +15% trap detection in all content
    • Cosmetics: Dark leather armor skins, “Shadow Blade” title, mysterious portrait frames

The Arcane Conclave

  • Theme: Academy of magic, research, craftsmanship
  • Headquarters: The Spire Atrium (The Spire)
  • Conflict with: The Primal Circle
  • Gameplay Dimension: Gear Enhancement & Reforging
    • Rewards focus on making gear better — reforging, enchanting, and enhancement. For players who want to min-max their equipment and chase perfect rolls.
  • Rewards:
    • Enchantments (all gear types): +enchantment potency (existing enchantments are stronger), +reforge quality floor (minimum potency on reforge rolls), weapon/armor enhancement success rate bonus
    • Consumables: Reforging catalysts (guarantee the new bonus is different from the old one), enhancement boosters (+15% success rate on next enhancement attempt), essence amplifiers (double magical essence from next disenchant)
    • Recipes: Advanced enchanting formulas (unique enchantments not available elsewhere), gem cutting techniques (higher quality cuts), enhancement protection charms (prevent material loss on failed enhancement)
    • Passive (Exalted): Reforging costs reduced by 15%, +5% gear enhancement success rate
    • Cosmetics: Arcane-effect armor skins, “Archmage” title, glowing rune portrait frames

The Primal Circle

  • Theme: Harmony with nature, self-sufficiency, the land provides
  • Headquarters: The Eldergrove (The Verdant Deep)
  • Conflict with: The Arcane Conclave
  • Gameplay Dimension: Gathering & Consumable Power
    • Rewards focus on gathering more materials, crafting better consumables, and getting more out of alchemy and cooking. For players who want the best supply chain and the strongest potions/food.
  • Rewards:
    • Enchantments (all gear types): +gathering yield, +consumable effectiveness (potions heal more, elixirs last longer), +crafting speed, +critical craft chance
    • Consumables: Gathering boosters (double yield on next gathering expedition), potency enhancers (next consumable used has +50% effect), nature’s bounty scrolls (bonus materials from dungeon node encounters)
    • Recipes: Upgraded versions of all alchemy recipes (greater potency), exclusive cooking recipes (strongest food buffs), bulk crafting formulas (craft in larger batches), rare herb cultivation (grow rare herbs with a personal garden system)
    • Passive (Exalted): +10% gathering yield from all sources, +10% consumable effectiveness
    • Cosmetics: Nature-themed armor skins, “Warden of the Wild” title, living-vine portrait frames

The Order of the Dawn

  • Theme: Zealous order, strength through conviction, overwhelming force
  • Headquarters: The Sunspire Cathedral (The Pale Reaches)
  • Conflict with: The Shadow Court
  • Gameplay Dimension: Burst Power & Boss Killing
    • Rewards focus on dealing more damage, especially to bosses and elites. For players who want to optimize kill speed and tackle the hardest combat content.
  • Rewards:
    • Enchantments (all gear types): +damage vs. bosses, +damage vs. elites, +critical hit damage, +skill damage (flat bonus to all damage skills)
    • Consumables: Wrath elixirs (+20% damage for 3 encounters, -10% max HP for duration), boss-slayer oils (weapon coating: +25% damage to boss-type enemies for one fight), fury tonics (+15% critical hit chance for one encounter)
    • Recipes: High-damage weapon coatings for all weapon types, boss-tuned ammunition (bonus damage to large enemies), sharpening kits (temporary flat damage boost to any weapon)
    • Passive (Exalted): +8% damage to boss and elite enemies, +5% critical hit damage
    • Cosmetics: Radiant-themed armor skins, “Dawnbringer” title, sunrise portrait frames

The Covenant of Dusk

  • Theme: Forbidden knowledge, power at a price, risk and reward
  • Headquarters: The Duskhollow (The Ashlands)
  • Conflict with: The Iron Compact
  • Gameplay Dimension: Risk/Reward & Condition Exploitation
    • Rewards focus on powerful effects with trade-offs, condition manipulation, and getting stronger as things get more dangerous. For players who like glass cannon builds and gambling on big payoffs.
  • Rewards:
    • Enchantments (all gear types): +damage when below 50% HP, +damage per debuff on target, chance to apply random condition on hit, +damage but -max HP (tunable trade-off enchantments)
    • Consumables: Blood elixirs (spend 20% HP to gain +30% damage for 3 rounds), dusk vials (apply a random debuff to all enemies at encounter start, but also apply one to yourself), desperation draughts (all stats +15% when below 25% HP)
    • Recipes: Condition-enhancing weapon coatings (conditions you apply last 1 extra round), volatile potions (random potency — could be weak or incredibly strong), cursed gear upgrades (powerful enhancement with a drawback)
    • Passive (Exalted): +10% damage when below 50% HP, conditions you apply last 1 additional round
    • Cosmetics: Shadow-effect armor skins, “Duskwalker” title, dark-flame portrait frames

The Merchant Consortium

  • Theme: Trade guild, commerce, mutual profit
  • Headquarters: The Grand Exchange (The Shattered Coast)
  • Conflict with: None (neutral faction)
  • Gameplay Dimension: Economy & Trade
    • Rewards focus on making more gold, spending less gold, and having better marketplace access. For players who want to build wealth and dominate the economy.
  • Rewards:
    • Enchantments (all gear types): +gold find, +vendor sell prices, +material yield from salvage, reduced enhancement costs
    • Consumables: Merchant’s eye (identify full value of all loot for one dungeon — helps decide equip vs. sell vs. salvage), golden touch scrolls (+50% gold from next dungeon run), trade route maps (bonus gathering yield from one zone for 24 hours)
    • Recipes: Efficient salvage techniques (bonus materials from salvaging), market-ready crafting (crafted items sell for 20% more to vendors), luxury goods crafting (high gold value items crafted from common materials)
    • Passive (Exalted): Auction house sale tax reduced from 10% to 7%, NPC vendor buy prices increased by 15%
    • Cosmetics: Wealthy-themed armor skins, “Grand Merchant” title, gold-coin portrait frames

Conflict Pairs

Factions exist in three conflict pairs, each representing a genuine gameplay trade-off that every class must consider.

Iron Compact vs. Covenant of Dusk — Safety vs. Power

  • The trade-off: Do you want to survive longer and go deeper into dungeons, or hit harder at the cost of fragility?
  • Why it matters for everyone:
    • A Vanguard might go Iron Compact (unkillable tank) or Covenant of Dusk (offensive Vanguard that hits like a truck when hurt)
    • A Shade might go Iron Compact (shore up low HP to survive longer) or Covenant of Dusk (maximize burst damage with risk/reward synergy)
    • An Arcanist might go Iron Compact (survive long enough to cast) or Covenant of Dusk (glass cannon blaster)
  • Gaining reputation with one causes 50% of that gain as a loss to the other

Order of the Dawn vs. Shadow Court — Kill Speed vs. Loot Efficiency

  • The trade-off: Do you want to kill bosses faster and deal more damage, or find more loot and hidden treasure per run?
  • Why it matters for everyone:
    • A Berserker might go Order of the Dawn (maximize already-high damage against bosses) or Shadow Court (offset Berserker’s poor trap detection and find more loot)
    • A Warden might go Order of the Dawn (add damage to a support class) or Shadow Court (lean into utility and treasure finding)
    • A Pathfinder might go Order of the Dawn (add boss-killing power to ranged DPS) or Shadow Court (double down on scouting and exploration strengths)
  • Gaining reputation with one causes 50% of that gain as a loss to the other

Arcane Conclave vs. Primal Circle — Gear Investment vs. Consumable Economy

  • The trade-off: Do you want to make your permanent gear as powerful as possible, or have the best consumables and gathering yields?
  • Why it matters for everyone:
    • A min-maxer who reforges obsessively wants Arcane Conclave
    • A player who runs long dungeons and burns through supplies wants Primal Circle
    • A crafter-focused player might want Primal Circle for gathering, or Arcane Conclave for enhancement recipes — depends on what they craft
    • A casual player who doesn’t reforge much gets more from Primal Circle’s consumable bonuses
  • Gaining reputation with one causes 50% of that gain as a loss to the other

Merchant Consortium — Neutral

  • Gaining reputation with the Merchant Consortium does not affect any other faction
  • Every player benefits from economic advantages, but the Consortium competes with other factions for the player’s limited daily quest time

Why This Works for Build Diversity

The faction system creates 9 classes x 3 subclasses x 7 faction choices = hundreds of distinct character identities. Two Shade Assassins with different faction alignments play very differently:

  • Shade Assassin + Iron Compact: Tanky assassin who survives long dungeons. Uses durability enchantments to offset low HP. Takes on attrition content that normally kills Shades.
  • Shade Assassin + Covenant of Dusk: Glass cannon who gets stronger as HP drops. Uses risk/reward consumables to spike damage. Dominant in short dungeons and boss fights but fragile.
  • Shade Assassin + Shadow Court: Loot-focused treasure hunter. Uses discovery enchantments to find hidden caches. Runs exploration dungeons in The Shattered Coast and The Sunken Kingdoms for maximum haul.
  • Shade Assassin + Order of the Dawn: Boss killer. Stacks damage bonuses to delete bosses in The Pale Reaches. Less versatile but devastating in boss-focused content.
  • Shade Assassin + Arcane Conclave: Min-maxer who reforges obsessively. Gear is immaculate. Less situational power but the best possible base stats.
  • Shade Assassin + Primal Circle: Consumable-focused. Burns through high-potency potions every run. Great at sustained play and always has the best supplies.
  • Shade Assassin + Merchant Consortium: Economy player. Makes gold efficiently, plays the marketplace, funds alts. Less combat power but wealthiest on the server.

Reputation System

Reputation Tiers

TierRep RequiredBenefits
Hostile-3000 to -1001Faction NPCs refuse service, faction quests unavailable
Unfriendly-1000 to -1No access to faction vendors or quests
Neutral0Starting state for all factions. Basic faction quests available
Friendly1 to 2999Access to Tier 1 faction vendor items and more quests
Honored3000 to 8999Access to Tier 2 vendor items, faction daily quests
Revered9000 to 20999Access to Tier 3 vendor items, faction-exclusive recipes
Exalted21000+Access to all faction rewards, faction passive bonus, unique title, cosmetic rewards

Reputation Gains

ActivityRep GainedFrequency
Faction daily quest100-2503 per day per faction
Dungeon run in faction-presence zone50-100Per completion
Faction bounty (repeatable task)25-75No daily limit
Faction-aligned crafting25-50Per craft using faction recipes
Faction warfare victory200-500Per battle
Turning in faction-requested materials10-50Repeatable

Faction Conflicts and Rep Loss

  • Factions exist in pairs of conflict: Iron Compact vs. Covenant of Dusk, Order of the Dawn vs. Shadow Court, Arcane Conclave vs. Primal Circle
  • Gaining reputation with one faction in a pair causes 50% of that gain as a loss to the opposing faction
  • Example: Earning 200 rep with Iron Compact loses 100 rep with Covenant of Dusk
  • The Merchant Consortium is neutral — gaining rep with them doesn’t affect other factions
  • This means a character can realistically be Exalted with 2-3 factions but must choose which rival factions to support

Recovering Lost Reputation

  • A character can never fall below Hostile (-3000) with any faction
  • Lost reputation can be recovered by doing quests and activities for the faction
  • There are rare “diplomacy” bounties that grant rep with BOTH factions in a conflicting pair (limited, don’t fully resolve the tension)

Faction Quests

Daily Quests

  • 3 daily quests per faction (available at Friendly+)
  • Quick procedurally generated bounty-style tasks taking 15-30 minutes
  • Grant faction reputation, gold, and faction tokens

Faction Bounties

  • Repeatable procedural tasks: gather specific materials, defeat specific enemy types, craft specific items
  • Lower rep reward than daily quests but no daily limit
  • Good for players who want to grind reputation

Faction Tokens

  • Earned alongside reputation from faction activities
  • Spent at faction vendors for exclusive rewards
  • Cannot be traded
  • Different from reputation — you might be Exalted but still saving up tokens for that legendary recipe

Faction Vendor Tiers

TierRep RequiredToken Cost RangeItems Available
Tier 1Friendly50-200 tokensBasic consumables, common recipes, faction tabard cosmetic
Tier 2Honored200-500 tokensUncommon enchantment formulas, rare consumable recipes, faction cosmetic
Tier 3Revered500-1500 tokensRare enchantment formulas, exclusive recipes, faction cosmetic set piece
Tier 4Exalted1500-5000 tokensLegendary recipes, unique enchantment formulas, faction passive unlocked, faction title, full cosmetic set

Strategic Considerations

For Build Optimization

  • Players should evaluate which faction dimension matters most for their content focus and playstyle, not their class
  • A player who runs boss-focused content in The Pale Reaches benefits from Order of the Dawn regardless of class
  • A player who runs long attrition dungeons in The Bonewood benefits from Iron Compact regardless of class
  • A player who focuses on crafting and marketplace play benefits from Primal Circle or Arcane Conclave

For Guild Strategy

  • Guilds benefit from having members across different factions — covering all vendor inventories
  • A guild with members Exalted across all factions has access to every recipe and enchantment between them
  • Guild coordination on faction warfare can control territory bonuses for all members

For Alts

  • Since faction choice is per-character (not account-wide), players can align different characters with different factions
  • A player’s main might be Iron Compact for durability, while their alt is Covenant of Dusk for a different playstyle
  • Faction tokens are per-character, encouraging long-term play across multiple characters

For Faction Warfare

  • Faction warfare provides team-based PVP content with real stakes (territory control — see 10-pvp-system.md)
  • Territory bonuses affect all members of the controlling faction server-wide
  • Top faction PVP contributors earn exclusive faction titles and cosmetics

World and Setting

Overview

Delve takes place in Aethermere, a classic high-fantasy world fragmented by a magical catastrophe. The world exists to serve gameplay — every zone is designed around the game’s systems (procedural quests, factions, gathering, crafting, progression). There is no central storyline. Quests are procedurally generated tasks that players repeat to gain experience, loot, and materials. Lore exists as flavor text and environmental context, never as required reading.

The World of Aethermere

The Premise

Aethermere was once a unified empire, but a catastrophic magical event — The Sundering — shattered the world into fragmented regions connected by dangerous wilderness. Civilization survives in pockets: walled cities, fortified towns, and scattered settlements. Between them lie dungeons, ruins, monster-infested wilds, and forgotten places filled with treasure.

Adventurers exist because someone has to explore the dangerous places, clear the monsters, recover the artifacts, and keep the roads open. That someone is the player’s character.

Tone

  • Hopeful but dangerous. The world is recovering, not dying. There are safe havens, friendly NPCs, and reasons to fight. But the wilds are genuinely lethal.
  • Classic fantasy with texture. Dungeons, dragons, ancient ruins — but the world has depth. Factions have real conflicts. Player choices have consequences.
  • Discovery over exposition. The Sundering left gaps in history. Ancient ruins hold secrets. Players discover lore fragments through play.

Zone Design Philosophy

Level-Scaling Content

Every zone has content for every level. Zones are not level-locked. A level 1 character and a level 50 character can both adventure in the same zone — the quest board generates level-appropriate dungeons, the gathering nodes yield tier-appropriate materials based on gathering skill, and enemies scale to the content selected, not the zone.

This means players never have to leave a zone they enjoy. A player who loves the dungeon style of the Verdant Deep can quest there from level 1 to 50 and into Paragon. They’ll just be running harder dungeons with tougher enemies and better loot as they progress.

Why Players Spread Out

Every zone offers content for all character types and all levels, but zones differ in what resources, enemy types, dungeon styles, and faction reputation they emphasize. Two players of the same class and level may choose completely different zones based on:

  • What gathering materials they need — ores in the mountains, herbs in the forests, hides in the wilds
  • What enemy types they want to farm — undead drop different salvage than elementals or beasts
  • What dungeon styles they prefer — trap-heavy vs. combat-heavy vs. environmental hazard focus
  • Which factions they’re building reputation with — each zone has different faction presence
  • What crafting recipes require — zone-specific rare materials drive players to specific regions

How Level-Scaling Works

  • Quest boards in every zone generate bounties, dungeon crawls, and raids appropriate to the character’s level. A level 5 in the Ashlands gets level 5 volcanic dungeon runs. A level 40 in Thornvale gets level 40 farmland dungeon runs.
  • Gathering nodes yield materials based on the character’s gathering skill level, not the zone. A skilled miner in any zone with mining nodes extracts tier-appropriate ore.
  • Enemy families are zone-specific (goblins in Thornvale, demons in the Ashlands), but their stat blocks scale to the dungeon’s difficulty tier. A level 5 goblin warband and a level 45 goblin warband are different fights.
  • Zone-specific rare materials drop at all levels but in quantities and qualities that scale with character level and gathering skill.
  • Faction dailies are available at all levels in every zone where the faction has presence.

Zone Structure

Each zone provides:

  • Hub town with quest board, vendors, crafting stations, and gathering dispatch
  • Multiple dungeon entrances generating content at the character’s level
  • Gathering nodes for 2-3 gathering professions (no zone has all four at high yield)
  • Faction presence from 2-3 factions (with at least one faction vendor)
  • Environmental type (relevant to Pathfinder’s Terrain Mastery and elemental resistances)
  • Dominant enemy families (determines loot tables, salvage types, and which damage types/resistances matter)
  • Zone-specific rare materials (unique to this zone, used in specific crafting recipes)

Zone Unlocking

Zones unlock as the player explores the world. New characters start with access to 3 zones and unlock additional zones by completing a threshold number of dungeon runs (in any zone). This is purely an exploration gate, not a level gate — a level 1 character who runs enough dungeons unlocks zones just as fast as a level 30.

Unlock StageZones AvailableRequirement
StartingThornvale, The Shallows, DusthollowCharacter creation
First ExpansionThe Ironmarch, The Verdant Deep, The Drowned TunnelsComplete 10 dungeon runs (any zone)
Second ExpansionThe Ashlands, The Shattered Coast, The BonewoodComplete 30 dungeon runs (any zone)
Third ExpansionStormhaven Plateau, The Tangled Warren, The Pale ReachesComplete 60 dungeon runs (any zone)
Fourth ExpansionThe Spire, The Sunken Kingdoms, The BlightmoorComplete 100 dungeon runs (any zone)
EndgameThe Rift, The CrucibleComplete 150 dungeon runs (any zone)

Players unlock zones in batches. The unlocking is account-wide — once unlocked, all characters on the account can access the zone. The threshold counts are cumulative across all characters.


Zones

Thornvale

  • Environment: Pastoral farmlands, light forests, rolling hills
  • Hub Town: Millhaven — a market town with all basic services
  • Gathering Emphasis: Herbalism (herbs, roots, wildflowers), Logging (softwood, hardwood, heartwood)
  • Secondary Gathering: Mining (low yield — scattered surface deposits)
  • Dungeon Style: Balanced — even mix of combat, traps, environmental encounters, and decision points. No single mechanic dominates. Good for generalist builds and new players learning the systems.
  • Enemy Families: Goblins, wolves, bandits, giant spiders, boars, treants
  • Salvage Focus: Leather scraps, crude weapons (Blacksmithing materials), beast parts (Alchemy reagents)
  • Faction Presence: Iron Compact (full hub), Merchant Consortium (trade post)
  • Zone-Specific Rare: Thornvale Sap — used in Alchemy and Cooking recipes (healing and buff consumables)
  • Why Go Here: Best Herbalism and Logging yields in the game. Balanced dungeons suit any build. Good starting zone but remains efficient at all levels for gathering-focused play.

The Shallows

  • Environment: Coastal wetlands, tidal caves, river deltas, mangrove mazes
  • Hub Town: Reedhaven — a stilted fishing village turned adventurer outpost
  • Gathering Emphasis: Skinning (fish leather, scale scraps, chitin, crustacean shell), Mining (river gems, bog iron, clay deposits)
  • Secondary Gathering: Herbalism (swamp herbs, mushrooms, waterlogged roots)
  • Dungeon Style: Hazard-heavy — flooded passages, visibility issues, poisonous gas pockets, quicksand, tidal surges. Rewards Fortitude, good supply management, and preparation over raw combat power.
  • Enemy Families: Crabs, bog trolls, swamp serpents, mud elementals, pirates, leeches
  • Salvage Focus: Chitin, scales, monster parts (Alchemy materials), rough gems (Jewelcrafting)
  • Faction Presence: Shadow Court (full hub), Merchant Consortium (trade post)
  • Zone-Specific Rare: Tidestone — used in Jewelcrafting and water-resistance Enchanting recipes
  • Why Go Here: Best Skinning yields plus early gem access for Jewelcrafting. Hazard-heavy dungeons reward tanky builds and players who invest in supply planning. Shadow Court reputation.

Dusthollow

  • Environment: Arid badlands, mesas, sandstone ruins, desert canyons, oasis camps
  • Hub Town: Sandspire — a cliffside settlement built into canyon walls
  • Gathering Emphasis: Mining (sandstone, ore veins, rough gems, crystal formations), Skinning (lizard hides, scorpion chitin, vulture feathers)
  • Secondary Gathering: Herbalism (desert succulents, cactus extract, dry sage)
  • Dungeon Style: Combat-dense — wave-style encounters and timed challenges. Enemies come in numbers. AoE damage, sustained resource management, and offensive builds are rewarded. Fastest XP per hour for players who can handle the pace.
  • Enemy Families: Scorpions, sand elementals, desert bandits, hyenas, dust wraiths, sand wurms
  • Salvage Focus: Chitin, venom sacs (Alchemy poisons), raw gems, sand-scoured metal (Blacksmithing)
  • Faction Presence: Merchant Consortium (trade outpost), Covenant of Dusk (hidden shrine)
  • Zone-Specific Rare: Sunite Glass — used in Jewelcrafting and Enchanting recipes (light/fire themed)
  • Why Go Here: Combat-dense dungeons are the fastest XP grind for well-geared offensive characters. Good Mining and Skinning. Merchant Consortium and Covenant of Dusk reputation.

The Ironmarch

  • Environment: Mountain passes, ancient ruins, underground caverns, crumbling fortresses
  • Hub Town: Hammerfall — a fortified trading post at the mountain’s base
  • Gathering Emphasis: Mining (all ore types, gems, stone), Logging (hardwood, petrified wood, mountain oak)
  • Secondary Gathering: Skinning (cave beast hides, mountain goat pelts)
  • Dungeon Style: Trap-heavy — mechanical traps, collapsing passages, locked doors, pressure plates, poison dart walls, pit traps. Logic and Speed checks are frequent. Every class can succeed with the right supplies (lockpicks, trap detection potions), but Shades and high-Logic characters have a natural edge.
  • Enemy Families: Orcs, trolls, cave beasts, undead miners, stone golems, mountain drakes
  • Salvage Focus: Metal scraps, stone components (Blacksmithing, Jewelcrafting), enchanting dust from golems
  • Faction Presence: Iron Compact (full hub), Shadow Court (hidden outpost)
  • Zone-Specific Rare: Deepvein Crystal — used in Jewelcrafting and Enchanting recipes
  • Why Go Here: Best Mining yields in the game. Trap-heavy dungeons drop lockpick recipes and trap-disarm tools useful everywhere. Iron Compact daily quests. Strong Logging secondary.

The Verdant Deep

  • Environment: Dense ancient forest, druidic circles, fey-touched groves, overgrown ruins
  • Hub Town: Sylvanus — a treetop settlement
  • Gathering Emphasis: Herbalism (rare herbs, fungi, ironwood bark, mosses), Logging (ironwood, living wood, ancient timber)
  • Secondary Gathering: Skinning (beast hides, insect chitin, feathers)
  • Dungeon Style: Decision-heavy — branching paths with many encounters offering alternative resolutions. Diplomacy, stealth, and brute force are all viable paths through the same dungeon. Presence and Speed checks appear alongside standard combat. Rewards diverse attribute spreads and adaptable builds.
  • Enemy Families: Corrupted beasts, fey creatures, plant monsters, giant insects, dryads, forest spirits
  • Salvage Focus: Organic components (Alchemy, Cooking), rare wood (Blacksmithing weapon hafts), magical essence from fey
  • Faction Presence: Primal Circle (full hub), Arcane Conclave (research outpost)
  • Zone-Specific Rare: Feybloom Pollen — used in Alchemy and Cooking recipes (powerful buff consumables)
  • Why Go Here: Best Herbalism yields alongside strong Logging. Decision-heavy dungeons mean multiple valid approaches per run — high replay value. Primal Circle reputation.

The Drowned Tunnels

  • Environment: Flooded underground river systems, bioluminescent caverns, subterranean lakes, crystal grottoes
  • Hub Town: Glowport — a cavern settlement lit by fungal growths
  • Gathering Emphasis: Mining (phosphite crystals, cave gems, deep iron), Herbalism (glowing fungi, cave moss, mineral-fed roots)
  • Secondary Gathering: Skinning (cave fish, amphibious beasts, blind crawlers)
  • Dungeon Style: Endurance/Hazard — environmental hazards (flooding, underwater passages, toxic gas, darkness) combined with long dungeon crawls and infrequent rest points. Supply management is critical. Characters with high Fortitude and good preparation thrive. Running out of torches or rations here is punishing.
  • Enemy Families: Cave fish, amphibians, myconids, oozes, blind cave trolls, crystal elementals
  • Salvage Focus: Ooze residue (Alchemy), crystal shards (Enchanting), bioluminescent material (Jewelcrafting)
  • Faction Presence: Arcane Conclave (research team), Shadow Court (smuggler route)
  • Zone-Specific Rare: Luminous Spore — used in Alchemy and Enchanting recipes (light and detection themed)
  • Why Go Here: Unique gathering materials found nowhere else. Long dungeon crawls reward endurance builds and heavy supply preparation. Two strong gathering professions. Arcane Conclave reputation.

The Ashlands

  • Environment: Volcanic wasteland, lava fields, obsidian formations, ash-choked ruins, magma vents
  • Hub Town: Cinderport — a heat-resistant fortress city
  • Gathering Emphasis: Mining (obsidian, fire gems, volcanic ore, sulphur), Skinning (salamander hides, demon chitin, drake scales)
  • Secondary Gathering: Herbalism (ash bloom, fire lichen, magma root)
  • Dungeon Style: High-damage — fire hazards, lava flows, heat exhaustion, and enemies that hit exceptionally hard. Encounters test raw durability and burst damage output. Fire resistance gear and healing consumables are near-mandatory. Short, intense dungeons.
  • Enemy Families: Fire elementals, demons, salamanders, ash golems, flame drakes, magma crawlers
  • Salvage Focus: Fire essence (Enchanting), demon parts (Alchemy), obsidian shards (Blacksmithing, Jewelcrafting)
  • Faction Presence: Covenant of Dusk (full hub), Order of the Dawn (crusader outpost)
  • Zone-Specific Rare: Molten Core Fragment — used in fire-themed Blacksmithing and Enchanting recipes
  • Why Go Here: Best source of fire gems and volcanic crafting materials. High-damage dungeons reward burst-oriented builds. Covenant of Dusk reputation. Short dungeon durations make it efficient for quick sessions.

The Shattered Coast

  • Environment: Coastal ruins, underwater caves, shipwreck reefs, pirate coves, cliff fortresses
  • Hub Town: Tidegate — a port city and major trading hub
  • Gathering Emphasis: Skinning (sea creature hides, coral, pearl oysters, shark teeth), Herbalism (sea kelp, tide bloom, salt crystals, coastal herbs)
  • Secondary Gathering: Mining (sea-floor deposits, coral gems)
  • Dungeon Style: Exploration — branching paths, hidden rooms, secret caches, optional boss encounters. Dungeons are large with many off-the-beaten-path discoveries. Perception, Investigation, and Luck characters find significantly more loot per run. Any build can complete the main path, but thorough explorers are heavily rewarded.
  • Enemy Families: Pirates, sea serpents, merfolk raiders, water elementals, drowned undead, kraklings
  • Salvage Focus: Nautical components, pearl dust (Jewelcrafting), sea salt (Cooking, Alchemy), waterlogged enchanting materials
  • Faction Presence: Merchant Consortium (full hub — Grand Exchange), Shadow Court (smuggler network)
  • Zone-Specific Rare: Abyssal Pearl — used in Jewelcrafting and Enchanting recipes (water and luck themed)
  • Why Go Here: Merchant Consortium headquarters means best trade access and lowest auction fees while here. Exploration-heavy dungeons yield the most total loot per run. Strong Skinning and Herbalism.

The Bonewood

  • Environment: Dead forest, necromantic corruption, bone-white trees, haunted ruins, crypts
  • Hub Town: Ashwick — a walled town at the forest’s edge
  • Gathering Emphasis: Logging (bonewood, petrified timber, ghost oak), Herbalism (grave bloom, spirit moss, decay fungi)
  • Secondary Gathering: Skinning (undead beast remains, spectral residue)
  • Dungeon Style: Attrition — long dungeons with many encounters and scarce rest points. Enemies apply debuffs and conditions (poison, fear, life drain, curse). Sustained healing, condition removal, and careful resource rationing are critical. Punishes front-loaded builds that burn resources early.
  • Enemy Families: Undead (skeletons, zombies, wraiths, ghouls), necromancers, death knights, bone constructs, spectral beasts
  • Salvage Focus: Necrotic essence (Enchanting), bone dust (Alchemy), ectoplasm (Alchemy, Enchanting), grave iron (Blacksmithing)
  • Faction Presence: Order of the Dawn (full hub), Primal Circle (restoration outpost)
  • Zone-Specific Rare: Soulstone Shard — used in necrotic and radiant Enchanting recipes
  • Why Go Here: Best source of necrotic crafting materials. Attrition dungeons reward sustain-focused builds. All classes can bring radiant consumables for the undead-heavy enemies. Order of the Dawn reputation. Strong Logging and Herbalism.

Stormhaven Plateau

  • Environment: Windswept highlands, perpetual thunderstorms, lightning-struck ruins, sky temples, floating rock formations
  • Hub Town: Tempest Hold — a fortress built to withstand constant storms
  • Gathering Emphasis: Mining (storm iron, charged crystals, sky gems), Logging (stormwood, lightning-split timber)
  • Secondary Gathering: Herbalism (storm thistle, wind sage, charged petals)
  • Dungeon Style: Speed/Initiative — timed encounters, fast enemies, ambush-heavy. Initiative order matters more here than anywhere else. Enemies strike first if you’re slow. Quick skill queues and Speed-focused builds dominate, but any class can invest in initiative gear and consumables.
  • Enemy Families: Air elementals, storm harpies, lightning drakes, thunder bears, sky raiders, wind wraiths
  • Salvage Focus: Charged crystals (Enchanting), storm iron (Blacksmithing), wind essence (Alchemy), lightning shards (Jewelcrafting)
  • Faction Presence: Arcane Conclave (observatory), Iron Compact (garrison)
  • Zone-Specific Rare: Stormheart Crystal — used in lightning-themed Enchanting and Blacksmithing recipes
  • Why Go Here: Speed-focused dungeons are ideal for initiative-optimized builds. Unique storm-themed crafting materials found nowhere else. Best source of charged crystals. Arcane Conclave and Iron Compact reputation.

The Tangled Warren

  • Environment: Massive underground insect hive, tunnels of chitin and webbing, fungal gardens, brood chambers
  • Hub Town: Burrower’s Rest — a settlement carved from abandoned hive chambers
  • Gathering Emphasis: Skinning (chitin plates, spider silk, hive wax, insect wings), Herbalism (hive fungi, royal jelly, spore pods)
  • Secondary Gathering: Mining (hive-encrusted ores, amber deposits)
  • Dungeon Style: Wave/AoE — swarms of smaller enemies with occasional massive boss creatures. Encounters regularly feature 8-15+ enemies at once. AoE damage and crowd control are heavily rewarded. Single-target specialists can still succeed but runs take longer.
  • Enemy Families: Giant spiders, hive beetles, wasp swarms, centipedes, brood mothers, myconids, hive queens
  • Salvage Focus: Chitin (Blacksmithing armor), silk thread (light armor crafting), venom (Alchemy poisons), amber (Jewelcrafting)
  • Faction Presence: Primal Circle (research team), Covenant of Dusk (harvesters)
  • Zone-Specific Rare: Royal Chitin — used in unique light and medium armor Blacksmithing recipes
  • Why Go Here: Swarm encounters make this the best zone for AoE-focused builds. Best chitin and silk source for armor crafting. Royal Chitin armor recipes are highly sought-after. Primal Circle and Covenant of Dusk reputation.

The Pale Reaches

  • Environment: Frozen tundra, glacial caverns, ancient ice fortresses, aurora-lit wastelands, permafrost ruins
  • Hub Town: Last Light — humanity’s northernmost settlement
  • Gathering Emphasis: Mining (adamantine, frost gems, glacial iron), Logging (frostwood, petrified ancient wood)
  • Secondary Gathering: Skinning (frost beast pelts, ice drake scales, mammoth hide)
  • Dungeon Style: Boss-focused — fewer encounters per dungeon but each is a significant challenge. Multi-phase boss fights, powerful elites, and raid-caliber encounters even in solo/party content. Rewards single-target damage optimization, tank/healer coordination, and learning boss patterns over multiple runs.
  • Enemy Families: Frost giants, white dragons, ice elementals, revenants, undead armies, liches, frost wolves
  • Salvage Focus: Adamantine scraps (Blacksmithing), frost essence (Enchanting), dragon parts (all professions), lich dust (Alchemy)
  • Faction Presence: Order of the Dawn (full hub — Sunspire Cathedral), Covenant of Dusk (hidden presence)
  • Zone-Specific Rare: Frozen Aether — used in legendary Enchanting and Alchemy recipes
  • Why Go Here: Adamantine mining — the premier Blacksmithing material. Boss-heavy dungeons drop the best individual item rewards. Cold resistance gear and consumables are useful here. Order of the Dawn reputation.

The Spire

  • Environment: Massive magical tower, reality-warping floors, planar rifts, arcane laboratories, impossible geometry
  • Hub Town: The Spire Atrium (Arcane Conclave headquarters)
  • Gathering Emphasis: Herbalism (planar herbs, aether bloom, void spores), Mining (arcane crystals, planar ore)
  • Secondary Gathering: Skinning (construct components, extraplanar hide)
  • Dungeon Style: Puzzle/Mechanic — each floor has unique rules (reversed gravity, phase-shifting walls, mana-draining fields, temporal loops). Adaptability and diverse skill queues are rewarded. Procedurally varied floors mean no two runs are identical. Logic checks are common but not mandatory — brute force is always an option, just less efficient.
  • Enemy Families: Arcane constructs, displaced elementals, rogue mages, reality aberrations, planar beings, clockwork guardians
  • Salvage Focus: Magical essence (premium grade — Enchanting), arcane components (all magical crafting), construct parts (Blacksmithing, Jewelcrafting)
  • Faction Presence: Arcane Conclave (full hub), Primal Circle (opposition research team)
  • Zone-Specific Rare: Aether Core — used in legendary Enchanting and Jewelcrafting recipes
  • Why Go Here: Best source of magical essence and arcane crafting materials. Puzzle-heavy dungeons reward adaptable builds. Procedural floor variation keeps runs fresh forever. Arcane Conclave reputation.

The Sunken Kingdoms

  • Environment: Submerged ruins of a pre-Sundering civilization, air-pocket cities, deep-sea trenches, coral palaces, abyssal vents
  • Hub Town: Depthgate — an air-domed settlement at the ocean floor
  • Gathering Emphasis: Skinning (deep-sea leviathan hide, abyssal chitin, kraken ink), Mining (deep-sea gems, pressure-forged ore, abyssal metal)
  • Secondary Gathering: Herbalism (abyssal kelp, deep coral, pressure bloom)
  • Dungeon Style: Exploration (deep) — massive non-linear dungeon maps with multiple paths, hidden areas, secret boss encounters, and environmental storytelling. Similar to The Shattered Coast’s exploration style but larger-scale and more dangerous. High Perception, Investigation, and Luck characters find significantly more content per run.
  • Enemy Families: Deep-sea leviathans, abyssal horrors, merfolk warlords, pressure elementals, ancient guardians, coral golems
  • Salvage Focus: Abyssal materials (all professions — unique tier), leviathan parts (Alchemy, Cooking), deep gems (Jewelcrafting premium)
  • Faction Presence: Merchant Consortium (deep trade route), Shadow Court (treasure hunters)
  • Zone-Specific Rare: Depthstone — used in legendary Blacksmithing and Jewelcrafting recipes
  • Why Go Here: Unique deep-sea materials used in crafting recipes found nowhere else. Exploration dungeons yield the most total loot per run for thorough players. Merchant Consortium and Shadow Court reputation.

The Blightmoor

  • Environment: Corrupted swampland, toxic fog, mutated landscapes, ruined laboratories, quarantine walls
  • Hub Town: Holdfast — a quarantined fortress on the moor’s edge
  • Gathering Emphasis: Herbalism (blight herbs, toxic bloom, mutation spores, purified extracts), Skinning (mutant hides, toxic chitin, aberrant tissue)
  • Secondary Gathering: Mining (corrupted ore, blight crystals)
  • Dungeon Style: Attrition/Condition — enemies apply stacking debuffs, environmental conditions are constant (poison, disease, exhaustion, mutation). Resource management and condition resistance define success. The longest average dungeon runs in the game. Similar to The Bonewood’s attrition style but with environmental hazards layered on top.
  • Enemy Families: Mutant beasts, plague spreaders, aberrations, toxic elementals, hive minds, blight cultists
  • Salvage Focus: Toxic components (Alchemy — powerful poisons and antidotes), mutation catalysts (Enchanting), blight-resistant materials (Blacksmithing specialty armor)
  • Faction Presence: Primal Circle (restoration effort), Iron Compact (containment force)
  • Zone-Specific Rare: Purified Blight Essence — used in the most powerful Alchemy recipes and condition-resistance Enchanting
  • Why Go Here: Best source of Alchemy materials for poisons and antidotes. Condition-heavy dungeons reward Fortitude-stacked builds and condition-resistance gear. Longest dungeons mean highest total XP per run for characters who can survive. Primal Circle and Iron Compact reputation.

The Rift

  • Environment: Fractured reality, shifting planar landscapes, fragments of the Sundering’s epicenter
  • Hub Town: Riftwatch — a stabilized platform at the Rift’s edge, maintained by all factions
  • Gathering Emphasis: All four gathering professions available at all tiers. Nodes are randomized per visit.
  • Dungeon Style: Fully procedural — every run generates a unique dungeon with randomized environments, enemy combinations, trap types, and boss mechanics. Players can add optional difficulty modifiers for better rewards. No two runs are ever the same.
  • Enemy Families: Everything — the Rift pulls enemies from all zones. Any enemy family, any damage type, any mechanic.
  • Salvage Focus: All material types, plus Rift-exclusive components used in legendary crafting
  • Faction Presence: All factions maintain a presence. Rift runs grant reputation with a faction of the player’s choice.
  • Zone-Specific Rare: Aethershard — the universal legendary crafting material, used in every top-tier recipe
  • Why Go Here: The ultimate variety zone. Procedural generation means infinite replayability. All gathering and all faction reputation available. Optional difficulty modifiers for competitive play. Leaderboards track deepest Rift clears.

The Crucible

  • Environment: An ancient arena complex, built before the Sundering, reactivated by unknown forces
  • Hub Town: Uses Riftwatch as hub (shared with The Rift)
  • Gathering Emphasis: None — combat trophies only
  • Dungeon Style: Pure combat gauntlet — no traps, no puzzles, no environmental hazards. Just increasingly difficult fights. Wave-based with leaderboard rankings. Curated encounters designed to test specific combat scenarios — single boss, swarm, mixed, anti-magic, anti-melee, etc.
  • Enemy Families: Curated from all zones, arranged in escalating difficulty tiers
  • Salvage Focus: High-value combat trophies tradeable for faction tokens or rare crafting materials
  • Faction Presence: All factions. Crucible rankings affect faction warfare standings.
  • Why Go Here: Pure combat optimization testing. Best way to benchmark builds against other players. Leaderboard competition. Efficient faction token farming through combat trophies.

Zone Summary Table

ZoneEnvironmentPrimary GatheringDungeon StyleFactions
ThornvaleFarmland/ForestHerbalism, LoggingBalancedIron Compact, Merchant Consortium
The ShallowsCoastal WetlandsSkinning, MiningHazard-heavyShadow Court, Merchant Consortium
DusthollowDesert BadlandsMining, SkinningCombat-denseMerchant Consortium, Covenant of Dusk
The IronmarchMountains/CavernsMining, LoggingTrap-heavyIron Compact, Shadow Court
The Verdant DeepAncient ForestHerbalism, LoggingDecision-heavyPrimal Circle, Arcane Conclave
The Drowned TunnelsUnderground RiversMining, HerbalismEndurance/HazardArcane Conclave, Shadow Court
The AshlandsVolcanic WastelandMining, SkinningHigh-damageCovenant of Dusk, Order of the Dawn
The Shattered CoastCoastal RuinsSkinning, HerbalismExplorationMerchant Consortium, Shadow Court
The BonewoodDead ForestLogging, HerbalismAttritionOrder of the Dawn, Primal Circle
Stormhaven PlateauThunderstorm HighlandsMining, LoggingSpeed/InitiativeArcane Conclave, Iron Compact
The Tangled WarrenUnderground HiveSkinning, HerbalismWave/AoEPrimal Circle, Covenant of Dusk
The Pale ReachesFrozen TundraMining, LoggingBoss-focusedOrder of the Dawn, Covenant of Dusk
The SpireMagical TowerHerbalism, MiningPuzzle/MechanicArcane Conclave, Primal Circle
The Sunken KingdomsSubmerged RuinsSkinning, MiningExploration (deep)Merchant Consortium, Shadow Court
The BlightmoorToxic SwamplandHerbalism, SkinningAttrition/ConditionPrimal Circle, Iron Compact
The RiftFractured RealityAllProceduralAll (player choice)
The CrucibleAncient ArenaNone (trophies)Pure CombatAll (rankings)

Gathering Distribution

Each gathering profession has high-yield nodes in specific zones. Since all zones scale to all levels, this drives player movement based on what materials they need, not what level they are.

ProfessionBest Zones
MiningThe Ironmarch (best overall), Dusthollow, The Ashlands, Stormhaven Plateau, The Pale Reaches, The Sunken Kingdoms
HerbalismThe Verdant Deep (best overall), Thornvale, The Drowned Tunnels, The Bonewood, The Spire, The Blightmoor
LoggingThornvale (best overall), The Ironmarch, The Verdant Deep, The Bonewood, Stormhaven Plateau, The Pale Reaches
SkinningThe Shallows (best overall), Dusthollow, The Shattered Coast, The Tangled Warren, The Sunken Kingdoms, The Blightmoor

Zone-Specific Materials

Every zone produces a unique rare material that cannot be found elsewhere. These materials are used in specific crafting recipes, guaranteeing that every zone stays relevant and populated regardless of player level.

ZoneRare MaterialPrimary Crafting Use
ThornvaleThornvale SapAlchemy, Cooking (healing/buff consumables)
The ShallowsTidestoneJewelcrafting, Enchanting (water resistance)
DusthollowSunite GlassJewelcrafting, Enchanting (light/fire)
The IronmarchDeepvein CrystalJewelcrafting, Enchanting
The Verdant DeepFeybloom PollenAlchemy, Cooking (powerful buffs)
The Drowned TunnelsLuminous SporeAlchemy, Enchanting (light/detection)
The AshlandsMolten Core FragmentBlacksmithing, Enchanting (fire)
The Shattered CoastAbyssal PearlJewelcrafting, Enchanting (water/luck)
The BonewoodSoulstone ShardEnchanting (necrotic/radiant)
Stormhaven PlateauStormheart CrystalEnchanting, Blacksmithing (lightning)
The Tangled WarrenRoyal ChitinBlacksmithing (light/medium armor)
The Pale ReachesFrozen AetherEnchanting, Alchemy (legendary)
The SpireAether CoreEnchanting, Jewelcrafting (legendary)
The Sunken KingdomsDepthstoneBlacksmithing, Jewelcrafting (legendary)
The BlightmoorPurified Blight EssenceAlchemy, Enchanting (condition resistance)
The RiftAethershardUniversal legendary crafting material

Faction Distribution

Each faction has presence across multiple zones, ensuring players can build reputation with their chosen faction regardless of where they prefer to play.

FactionZone Presence
Iron CompactThornvale, The Ironmarch, Stormhaven Plateau, The Blightmoor, The Rift
Shadow CourtThe Shallows, The Ironmarch, The Drowned Tunnels, The Shattered Coast, The Sunken Kingdoms, The Rift
Arcane ConclaveThe Verdant Deep, The Drowned Tunnels, Stormhaven Plateau, The Spire, The Rift
Primal CircleThe Verdant Deep, The Bonewood, The Tangled Warren, The Spire, The Blightmoor, The Rift
Order of the DawnThe Ashlands, The Bonewood, The Pale Reaches, The Rift
Covenant of DuskDusthollow, The Ashlands, The Tangled Warren, The Pale Reaches, The Rift
Merchant ConsortiumThornvale, The Shallows, Dusthollow, The Shattered Coast, The Sunken Kingdoms, The Rift

Dungeon Style Distribution

Different dungeon styles reward different playstyles, ensuring no single build dominates all content. Players are incentivized to either specialize in zones that match their build or diversify their character to handle multiple styles.

Dungeon StyleZonesWhat It Rewards
BalancedThornvaleAll builds equally — good for generalists
Hazard-heavyThe Shallows, The Drowned TunnelsHigh Fortitude, supply management, preparation
Combat-denseDusthollow, The Tangled WarrenAoE damage, sustained resources, offensive builds
Trap-heavyThe IronmarchLogic/Speed, Shade class bonus, trap gear
Decision-heavyThe Verdant DeepDiverse attributes, Presence, Speed, adaptability
Endurance/HazardThe Drowned TunnelsFortitude, supplies, endurance builds
High-damageThe AshlandsDurability, fire resistance, burst healing
ExplorationThe Shattered Coast, The Sunken KingdomsPerception, Investigation, Luck — bonus loot
AttritionThe Bonewood, The BlightmoorSustain, condition resistance, healing, rationing
Speed/InitiativeStormhaven PlateauSpeed, initiative optimization, fast queues
Wave/AoEThe Tangled WarrenAoE damage, crowd control
Boss-focusedThe Pale ReachesSingle-target DPS, tank/healer coordination
Puzzle/MechanicThe SpireLogic, adaptability, diverse skill queues
ProceduralThe RiftBroad preparation, adaptability
Pure CombatThe CrucibleOptimized combat builds, raw DPS/survivability

The Sundering (Core Lore)

The Sundering happened approximately 200 years before the game’s present day. Key facts:

  • The old empire attempted a massive magical working — a spell to grant the emperor godhood
  • The spell failed catastrophically, tearing reality apart
  • The physical world was fractured — mountains rose, coastlines shifted, underground caverns opened
  • The magical fallout created dungeons: places where reality is thin, monsters spawn, and treasures accumulate
  • The factions emerged in the aftermath, each with a different philosophy about how to rebuild
  • No one fully understands what happened — fragments of truth are scattered across the world’s dungeons

Why Dungeons Exist

Dungeons in Aethermere aren’t just underground caves. They’re Sundering scars — places where the magical catastrophe left permanent damage to reality. This is why they:

  • Generate monsters (reality is thin, things slip through)
  • Contain treasure (the Sundering displaced objects across time and space)
  • Reset and repopulate (they’re self-healing wounds in reality)
  • Scale in danger (the deeper the scar, the worse the damage to reality)

This provides a lore justification for the game’s repeatable, procedurally generated, level-scaling dungeon content. A level 5 dungeon and a level 50 dungeon in the same zone are simply different depths of the same Sundering scar.


Key NPCs

NPCs serve as quest board operators, vendors, faction representatives, and crafting trainers. They are functional game interfaces with personality flavor. They don’t have personal storylines — they exist to make each hub town feel distinct.

Recurring NPC Roles (Per Hub Town)

  • Quest Board Operator — manages the local quest board, provides context on available runs
  • General Vendor — buys/sells common supplies (rations, torches, potions)
  • Faction Representative(s) — one per faction present in the zone; offers faction dailies and sells faction vendor items
  • Crafting Trainer — teaches recipes appropriate to the zone’s gathering focus
  • Gathering Dispatcher — manages gathering expeditions to the zone’s nodes
  • Gear Vendor — sells level-appropriate equipment

World Design Principles

  1. Gameplay first. Every zone exists to serve a game system. No scenery-only areas.
  2. All zones, all levels. Every zone has content for every character level. Quest boards generate level-appropriate content. Gathering scales with skill. No zone is ever “too low” or “too high.”
  3. Player choice, not class funneling. All zones are useful for all classes. Players choose zones based on what resources and activities they want, not what class they play.
  4. Spread the population. Gathering emphasis, faction presence, dungeon style, and zone-specific rare materials ensure no single zone is universally “best.” Different goals send players to different places.
  5. Unlock through play, not level. Zone unlocking is based on total dungeon runs completed, not character level. Active players unlock zones faster regardless of their character’s level.
  6. No dead zones. Zone-specific rare materials, scaling content, and faction dailies keep every zone populated and relevant at all stages of the game.
  7. Procedural content. Quests are generated tasks — kill targets, gather items, clear dungeons, complete bounties. Names and flavor text are procedural. Players engage with the systems, not a plot.
  8. Room to expand. The Sundering fractured the world into many pieces — new zones can always be added without disrupting existing progression.

Idle and Time Mechanics

Overview

Delve is fundamentally an idle game — the core activities (dungeon runs, crafting, gathering) happen on real-world timers. The design challenge is making the passage of time feel rewarding, not punishing. Players should look forward to checking their results, not feel stressed about falling behind.

Core Idle Philosophy

Time is the universal currency. Everyone — free players and paying players alike — waits for dungeon runs to resolve. This creates a level playing field where the differentiator is how well you prepare, not how much you play.

Key Principles

  1. Offline progress is real progress. Your character advances whether you’re watching or not.
  2. No penalty for absence. Missing a day (or a week) should never feel punishing. Daily bonuses are additive, not restorative.
  3. Active play is a bonus, not a requirement. Players who log in frequently can optimize more, but the game doesn’t punish those who check in once a day.
  4. Notifications inform, not nag. Alerts are helpful (“Your run is done!”), not guilt-inducing (“You haven’t logged in today!”).

Time-Gated Activities

Dungeon Runs

  • Duration: 15 minutes to 12 hours depending on quest type
  • Cannot be sped up with real money (core design principle)
  • One active run per character at a time
  • Character is unavailable for other activities while on a run
  • Run completes regardless of whether the player is online

Crafting

  • Duration: 15 minutes to 12 hours depending on recipe tier
  • 50% faster for Patron subscribers (see 14-monetization.md)
  • One active craft per profession at a time
  • Runs in parallel with dungeon runs — character can craft while dungeon running
  • Completes offline

Gathering

  • Duration: 1 to 12 hours
  • 50% faster for Patron subscribers
  • One active task per gathering profession at a time
  • Runs in parallel with everything else
  • Completes offline

Marketplace Listings

  • Duration: 48 hours per listing
  • Auto-expires if not sold
  • Revenue collected via mail upon sale (happens offline)

Raid Lobbies

  • Countdown timer to scheduled start (set by lobby creator)
  • Players must configure and “Ready” before the start time
  • Raid starts at the scheduled time whether all slots are filled or not (unfilled slots can optionally be auto-filled from public queue)

Activity Parallelism

At any given time, a character can have ALL of the following running simultaneously:

ActivitySlotsRuns in Parallel?
Dungeon run1Yes (but character is “away”)
Crafting (per profession)1 eachYes
Gathering (per profession)1 eachYes
Marketplace listings20Yes
Raid lobby (waiting)1Yes

This means even during a long dungeon run, players can:

  • Queue crafting recipes
  • Start gathering expeditions
  • Manage marketplace listings
  • Join a raid lobby for a future run
  • Chat with guild members
  • Manage a second character (if unlocked)

Offline Progress

What Happens When You Log Off

Everything continues. Specifically:

  • Active dungeon run resolves on schedule
  • Active crafting completes on schedule
  • Active gathering completes on schedule
  • Marketplace items can sell (revenue held in mail)
  • Raid lobbies count down (notifications sent if applicable)

What Doesn’t Happen Offline

  • No automatic re-queuing (the player must choose the next activity)
  • No automatic selling or salvaging
  • No automatic quest selection
  • No passive XP or gold generation (you must be doing something)

This means the game requires brief check-ins to remain active — but those check-ins can be as short as 2 minutes.

Idle Efficiency

The game tracks how efficiently you use your character’s time:

  • Time spent “idle” (no active task) is wasted potential
  • The UI shows a gentle indicator: “Your character has been idle for 3 hours. Ready for a new adventure?”
  • This is informational, not punitive — no XP decay, no penalty

Active Play Bonuses

Players who are online and actively playing get minor bonuses that reward engagement without punishing absence:

Active Player Benefits

  • Real-time quest board browsing — Spot high-value quests as they appear on refresh
  • Marketplace sniping — Buy underpriced items before others notice
  • Immediate re-queuing — Start a new run the moment the previous one finishes (no idle time)
  • Social interaction — Chat, guild coordination, party formation
  • Manual optimization — Review combat logs between runs and fine-tune skill queue configuration
  • Daily bonus collection — First-run bonus, daily bounties (available for 24 hours, so very flexible)

What Active Play Does NOT Provide

  • No bonus XP for being online
  • No bonus loot for being online
  • No faster dungeon completion for being online
  • No advantages in combat for being online
  • No “energy” system that requires regular play to maintain

Notification System

Notifications are how the game communicates with idle players. They should be helpful and respectful.

Notification Types

NotificationTriggerPriority
“Dungeon run complete!”Run finishesHigh
“Crafting complete!”Craft finishesMedium
“Gathering complete!”Gathering finishesMedium
“Item sold on marketplace!”Auction sellsMedium
“Raid starting in 1 hour”Lobby countdownHigh
“Raid starting in 15 minutes”Lobby countdownHigh
“Your raid is complete!”Raid finishesHigh
“Quest board has refreshed”6-hour refreshLow
“New mail received”Mail arrivalLow
“Guild war declared!”Guild eventMedium

Notification Settings

Players can customize:

  • Which notifications to receive
  • Push notifications (mobile/browser) vs. in-game only
  • “Do not disturb” hours
  • Batched notifications (send a summary instead of individual alerts)

What We Never Notify

  • “You haven’t logged in today!” — No guilt notifications
  • “Your energy is full!” — No energy system
  • “Limited time offer!” — No predatory urgency
  • “Your character is idle!” — Informational in-game only, never a push notification

Anti-Burnout Design

The Problem with Idle Games

Many idle games create a treadmill where players feel compelled to check in constantly or fall behind. Delve explicitly designs against this.

Anti-Burnout Mechanisms

No Stamina/Energy System

  • There is no “energy” that regenerates over time and caps out
  • There is no “daily limit” on dungeon runs (limited by real-time duration, not artificial caps)
  • A player who checks in once per day and a player who checks in ten times get the same dungeon run quality

No Streak Bonuses

  • Daily first-run bonus is available every day but there is no “consecutive day” multiplier
  • Missing a day doesn’t break a streak or lose accumulated bonus
  • This prevents the psychology of “I have to log in or lose my 30-day streak”

Catch-Up Friendly

  • A player who takes a week off can jump right back in
  • No accumulated disadvantage beyond time not spent progressing
  • Rested bonus: After 24+ hours offline, the first dungeon run gives +25% XP (caps at 3 days of rest for +50%). Rewards returning, not punishes leaving.

Reasonable Time Gates

  • The longest activity in the game is a 12-hour raid
  • Most content is 1-4 hours
  • Players are never asked to wait more than half a day for a single result

Multiple Progression Paths

  • If a player is tired of dungeon runs, they can focus on crafting, gathering, PVP, faction reputation, or social activities
  • Burnout on one system doesn’t mean burnout on the whole game

Time Zone Considerations

Server Time

  • All timed events (raid schedules, quest board refreshes, daily resets) use server time
  • Server time is prominently displayed in the UI
  • Daily reset: midnight server time

Raid Scheduling

  • Raid lobbies show start times in both server time AND the player’s local time
  • Guilds with members across time zones can schedule multiple raid windows
  • The timed lobby system inherently accommodates time zones — you prepare whenever you’re online, the raid starts at the set time

Monetization

Overview

Delve uses a Free-to-Play with Optional Subscription model. There is no premium currency. There are no loot boxes. There are no cosmetic microtransactions. The game makes money two ways:

  1. A cheap monthly subscription that makes time-based activities 50% faster
  2. Small permanent purchases for account upgrades (character slots, bank space)

That’s it. The game is designed to be fully playable — and fully competitive — without spending a cent. Subscribers don’t hit harder, find better loot, or gain more XP. They wait less.

Design Philosophy

Why No Premium Currency

Premium currencies (gems, crystals, coins) exist to obscure the real cost of purchases. When you buy 1,100 gems for $9.99 and a skin costs 950 gems, it’s deliberately hard to calculate the real price — and you’re left with 150 gems that are useless without buying more. This is manipulative by design.

Delve charges real money for real things at real prices. $5/month for a subscription. $2 for a character slot. No conversion rates, no leftover currency, no “just 50 more gems” psychology.

Why No Cosmetics

Delve is an async idle game. You experience combat through text logs, not 3D animations. Your character is a portrait and a stat sheet, not a rendered model walking through a dungeon. Selling armor skins or weapon effects for a character you never watch fight would be dishonest — we’d be charging for something that has almost no visible impact on the player experience.

Cosmetics in Delve (titles, portrait frames, profile badges) are earned through gameplay — achievements, faction reputation, PVP seasons, and seasonal events. They represent accomplishment, not spending.

The Core Principle

A subscriber and a free player in the same dungeon run have the same chance of success, the same loot tables, and the same XP. The subscriber just got there faster.


Delve Patron Subscription

Price: $5.00 / month

(or $48/year — 2 months free with annual plan)

What Subscribers Get

50% faster time-based activities:

ActivityFree PlayerSubscriber
Bounty (15-45 min)15-45 min10-30 min
Questline (1-3 hours)1-3 hours40 min - 2 hours
Dungeon Crawl (3-8 hours)3-8 hours2-5.5 hours
Raid (4-12 hours)4-12 hours2.5-8 hours
Crafting (15 min - 12 hours)15 min - 12 hours10 min - 8 hours
Gathering (1-12 hours)1-12 hours40 min - 8 hours
Post-death recovery timer15 min - 2 hours10 min - 1.5 hours

Seasonal Pass (Premium Track):

During active seasons (~3 months each, 4 per year), Patron subscribers automatically unlock the Premium Season Track — bonus seasonal content and a reward progression track. See the Seasonal Pass section below for full details.

That’s it. No bonus XP, no bonus gold, no bonus loot, no better drop rates, no combat advantages, no extra skill queue slots, no bonus stats.

What 50% Faster Means in Practice

  • A free player who checks in twice a day (morning and evening) can complete roughly 2 questlines or 1 dungeon crawl per day
  • A subscriber on the same schedule can complete 3 questlines or 1.5 dungeon crawls per day
  • Over a week, the subscriber has done roughly 50% more content — not because they’re stronger, but because each run finishes sooner
  • Over months, subscribers reach endgame faster. But a free player who reaches endgame is exactly as powerful as a subscriber who reached it faster.

Subscription is NOT Required For:

  • Any gameplay content (all dungeons, raids, quests, PVP — free)
  • Competitive PVP (arena, guild wars, faction warfare — all free, no time advantage in PVP)
  • Trading on the marketplace
  • Joining guilds, parties, raids
  • Crafting any recipe or gathering any material
  • Any feature in the game

PVP and Subscription Fairness

Arena PVP matches resolve instantly (no time duration — see 10-pvp-system.md), so the subscription speed bonus has zero impact on PVP. A subscriber and a free player in the arena are on perfectly equal footing.

Subscriber Status Display

  • A small, subtle Patron badge next to the subscriber’s name in chat and profile
  • This is the ONLY visual indicator. No glowing effects, no special colors, no “premium” aesthetic
  • The badge is informational, not aspirational — it doesn’t say “I’m better,” it says “I support the game”

Seasonal Pass

How Seasons Work

Delve runs 4 seasons per year (~3 months each), each with a theme, unique seasonal dungeons, new enemies, and seasonal mechanics. See 15-progression-hooks-and-retention.md for full seasonal content details.

Two Tracks: Free and Premium

Every season has two parallel reward tracks:

Free Track (all players):

  • Access to all seasonal dungeons and content (gameplay is never gated)
  • Basic seasonal reward track with milestones: gold, common/uncommon crafting materials, 1-2 seasonal titles
  • Seasonal leaderboard participation
  • 15 tiers of rewards earned through seasonal play

Premium Track (Patron subscribers only):

  • Everything in the Free Track, PLUS:
  • Bonus seasonal challenge dungeons — harder encounters with unique modifiers that only appear during the season
  • Extended reward track — 30 additional tiers beyond the free track’s 15
  • Premium track rewards include:
    • Rare and Very Rare crafting materials
    • Exclusive seasonal portrait and profile frame (earned, not bought — you must play through the track)
    • Exclusive seasonal title
    • Bonus gold at milestones
    • Rare salvage materials (Rare Cores, Prismatic Essences)
    • A guaranteed Named Item at the final tier (seasonal-exclusive, with the usual random bonus rolls)

Seasonal Challenge Dungeons (Premium Track)

These are the premium track’s main content offering — unique dungeons that test different builds and strategies:

SeasonChallenge DungeonUnique Mechanic
Season of FlameThe Erupting CalderaHeat meter — the longer you’re in, the more fire damage you take. Speed is survival.
Season of FrostThe Frozen AbyssFrost accumulation — characters gradually slow (initiative penalties) unless they find warmth sources.
Season of ShadowThe Harvest of SoulsSoul economy — defeated enemies drop souls spent on temporary buffs OR saved for tier rewards.
Season of GrowthThe Awakening GroveGrowth — plant seeds at rest points that bloom into useful effects in later encounters.

Challenge dungeons award Seasonal Tokens — a currency spent to progress through the premium reward track. Regular seasonal dungeons (free track) also award Seasonal Tokens, but challenge dungeons award more.

Track Progression

TierFree Track RewardPremium Track Reward
1-5Gold, Common FragmentsGold, Uncommon Shards
6-10Uncommon Shards, seasonal titleRare Cores, seasonal portrait
11-15Rare Core, seasonal profile framePrismatic Essence, seasonal profile frame (animated)
16-20— (Free track ends at 15)Rare Cores, bonus gold, seasonal title (exclusive)
21-25Prismatic Essences, Legendary Spark
26-30Named Seasonal Weapon or Armor (Legendary, random rolls)

Seasonal Pass Principles

  • No separate purchase. The premium track is included in the Patron subscription. If you’re a subscriber, you have it.
  • All gameplay content is still free. Non-subscribers can play the seasonal dungeons and earn free track rewards. The premium track adds BONUS challenges and better rewards, not access gates.
  • Rewards are earned, not given. Having the premium track doesn’t hand you anything — you must play through the tiers. A subscriber who doesn’t play the season gets nothing.
  • Seasonal exclusivity. Premium track rewards (the exclusive portrait, title, and named item) are only available during that season. This creates healthy FOMO tied to gameplay effort, not spending.
  • No catch-up purchases. You can’t buy tiers. If you didn’t finish the track, you didn’t finish it. This prevents the “I can just buy my way to tier 30” problem.

Why This Works

  • Subscribers get quarterly fresh content that justifies ongoing subscription — not just speed, but actual new challenges and rewards
  • Free players get the seasonal dungeons and basic rewards — they’re not excluded from the fun
  • The premium track gives subscribers something to work TOWARD, increasing engagement and retention during seasons
  • No additional purchase required — the subscription covers everything

Permanent Purchases

Small, one-time purchases for account-level upgrades. Priced in real currency. No bundles, no “deals,” no urgency tactics.

Character Slots

PurchasePriceNotes
2nd character slot$2.00First slot is free
3rd character slot$2.00
4th character slot$2.00
5th character slot$2.00
6th character slot (max)$2.00Hard cap — no one needs more than 6

Total for all slots: $10.00. One-time cost, permanent, account-wide.

Each character is fully independent (own inventory, quests, progression). Characters on the same account can mail items/gold to each other (with the standard transfer fee as a gold sink).

Storage Upgrades

PurchasePriceNotes
+25 bank slots$1.00Per character, stackable up to +100 (4 purchases max)
+50 material bank slots$1.00Per character, stackable up to +200 (4 purchases max)
+5 marketplace listing slots$1.00Per account, stackable up to +20 (4 purchases max)

Maximum storage spend per character: $8.00 (4 bank + 4 material bank). This is a convenience upgrade — the base storage is sufficient for normal play but tight for serious crafters and traders.

Quality of Life

PurchasePriceNotes
Name change$1.00Change character name
Appearance reset$1.00Change character portrait

What is NEVER Sold

This list defines the boundary between “acceptable monetization” and “pay-to-win.” These items will never be available for real money under any circumstances:

  • Gear, weapons, or items with combat stats
  • XP boosts or level skips
  • Gold or gold boosts
  • Loot or loot quality boosts
  • Drop rate boosts
  • Combat advantages of any kind (bonus stats, bonus skills, bonus queue slots)
  • Dungeon or quest unlocks (all content is free)
  • Reforging materials or shortcuts
  • Crafting materials
  • Premium currency (doesn’t exist)
  • Loot boxes or randomized purchases (don’t exist)
  • Cosmetic items (earned through gameplay only)
  • Season pass as a separate purchase (premium track is included in Patron subscription)
  • “Convenience” items that are actually power (no stat potions, no temporary buffs)

Revenue Model Analysis

Revenue Sources

SourceTypeEst. Revenue Per User
Patron SubscriptionRecurring ($5/mo or $48/yr)Primary revenue. Includes seasonal premium track. Target: 15-25% of active players subscribe.
Character SlotsOne-time ($2 each)Secondary. Most players buy 1-2 extra slots over their lifetime ($2-4).
Storage UpgradesOne-time ($1 each)Tertiary. Serious players buy most; casual players buy few.
Name/AppearanceOne-time ($1 each)Minimal. Rare purchases.

Target ARPU (Average Revenue Per User)

  • Free players (75-85% of users): $0/month — perfectly fine, they populate the world and marketplace
  • Occasional spenders (10-15%): $2-10 one-time for slots/storage, no recurring
  • Subscribers (10-20%): $5/month ongoing

Why This Works Financially

  • Low barrier to subscription: $5/month is impulse-purchase territory. A cup of coffee. Low enough that players don’t agonize over it.
  • Clear value proposition: “Your stuff finishes 50% faster” is easy to understand and easy to justify.
  • No whale dependency: The maximum a player can spend is ~$5/month + ~$20 lifetime for all upgrades. There are no whales. Revenue comes from a broad base of modest subscribers, not a tiny number of big spenders. This is healthier and more sustainable.
  • Retention-driven: Since revenue comes from subscriptions, the game is incentivized to keep players engaged and happy long-term — not to create friction that drives impulse purchases.
  • Word of mouth: Fair monetization generates positive word of mouth. “This game doesn’t try to screw you” is a marketing advantage.

Break-Even Considerations

  • Server costs, development, and maintenance must be covered by subscription + purchase revenue
  • The game needs a critical mass of subscribers (exact number depends on infrastructure costs)
  • If the game is good and retention is high, the subscription model is more sustainable than a whale-dependent model
  • If the game needs more revenue, the answer is more content that drives retention, not more things to sell

Anti-Predatory Design

No Dark Patterns

  • No “limited time offers” that create urgency
  • No “first purchase discount” that normalizes spending
  • No “are you sure?” popups that guilt-trip players who try to unsubscribe
  • No “daily login streak” that punishes absence (see 13-idle-and-time-mechanics.md)
  • No notifications about what subscribers are getting that you’re not (“FOMO notifications”)

No Hidden Costs

  • The subscription page shows exactly what you get and what you don’t get
  • One-time purchases show the exact price in real currency
  • No auto-renewal without clear consent and easy cancellation
  • Subscription can be cancelled instantly from the account page — no “talk to support” hoops

Spending Transparency

  • Account settings show total lifetime spend
  • Optional monthly spending cap (self-imposed, can be changed)
  • Parental controls: require password for any purchase, set spending limits
  • No purchases in the middle of gameplay flow (no “buy now to finish faster” popups during a dungeon run)

Player Trust Commitment

  • If we ever break these principles — if we ever add power for sale, premium currency, or predatory mechanics — we will have failed. The monetization model is a promise to players, not a suggestion. It is as much a part of the game design as the combat system.

Frequently Anticipated Objections

“$5/month isn’t enough revenue.” It is if the game retains players. A game with 100,000 active players at 15% subscription rate generates $75,000/month from subscriptions alone, plus one-time purchases. The key is retention, not extraction.

“50% faster is too strong. It’s pay-to-win.” It’s pay-to-wait-less. In an idle game, time IS the mechanic — so this is the only lever that makes sense. But the subscriber doesn’t get better loot, more XP, or stronger stats. They just get their results sooner. In PVP (which resolves instantly), there is zero subscriber advantage.

“Without cosmetics, where’s the long-term revenue?” Subscriptions ARE long-term revenue. A subscriber paying $5/month for 2 years generates $120 — more than most players spend on cosmetics in other games. And the subscription model incentivizes the developer to keep the game good, not to keep adding cosmetic churn.

“What if you need more money later?” More content. New regions, new dungeons, new raids, new classes, new species — content that retains players and drives subscriptions. The answer to “we need more revenue” is always “make the game better,” never “sell more stuff.”

Progression Hooks and Retention

Overview

Retention in an idle game means giving players a reason to come back — not through guilt or punishment, but through anticipation and reward. Every time a player logs in, something good should be waiting for them, and something exciting should be ahead.

This document covers the systems that keep players engaged beyond the core dungeon loop.

Daily Engagement

Daily First-Run Bonus

  • First dungeon run completed each day grants +50% XP and +50% gold for that run
  • No streak requirement — available fresh every day regardless of when you last played
  • Visible on the quest board: “First Run Bonus Available!”

Daily Bounties

  • 3 short bounties refresh every day (separate from the main quest board)
  • Completing all 3 grants a Daily Bounty Chest containing:
    • Bonus gold (scaling with level)
    • Random crafting materials
    • Small chance of uncommon+ gear
  • Bounties are designed to be completable in 30-60 minutes total
  • If not completed, they simply refresh the next day (no loss, no guilt)

Daily Faction Quests

  • Each faction offers 3 daily quests (see 11-factions-and-reputation.md)
  • Available at Friendly reputation or higher
  • Provides faction tokens and reputation

Weekly Engagement

Weekly Challenge Dungeon

  • A special dungeon with a modifier that changes each week
  • Modifiers create unique gameplay situations:
WeekModifierEffect
1FortifiedAll enemies have +25% HP
2VolatileAll enemies explode on death (fire damage in AOE)
3AsceticNo potion use allowed
4SpeedrunBonus rewards for completing under a time threshold
5TyrannicalBoss encounters are significantly harder
6Fog of WarPerception checks are harder
7BountifulAll loot drops are +1 rarity tier
8NemesisA powerful stalker enemy appears at random encounters
  • Completing the weekly challenge grants a Weekly Chest with guaranteed rare+ loot
  • Leaderboard for fastest completion times (bragging rights)

Weekly Raid Reset

  • Raid lockouts reset every Monday
  • Creates a natural weekly rhythm: plan the raid, execute the raid, gear up, repeat

Weekly PVP Cap

  • Raid tokens and honor points have a weekly earning cap
  • Prevents no-lifing while ensuring consistent rewards for regular play

Achievement System

Achievements are permanent milestones that recognize player accomplishments. They provide long-term goals and showcase dedication.

Achievement Categories

Combat Achievements

  • “First Blood” — Complete your first dungeon run
  • “Flawless Victory” — Complete a dungeon without taking damage
  • “Giant Slayer” — Defeat a boss 5 levels above you
  • “Unstoppable” — Complete 100 dungeon runs
  • “Living Legend” — Complete 1,000 dungeon runs
  • “Death’s Door” — Survive a dungeon with less than 5% HP remaining
  • “One Shot” — Kill a boss in a single round

Progression Achievements

  • “Level 25 / 50” — Reach level milestones
  • “Master of Arms” — Equip a full set of rare or better gear
  • “Walking Arsenal” — Own 50 unique weapons
  • “Paragon 10 / 25 / 50 / 100” — Reach Paragon milestones

Crafting Achievements

  • “First Craft” — Craft your first item
  • “Master [Profession]” — Reach skill 100 in a crafting profession
  • “Grand Master” — Reach skill 100 in all crafting professions
  • “Critical Crafter” — Get 10 critical crafts

Social Achievements

  • “Guilded” — Join a guild
  • “Guild Leader” — Create a guild
  • “Raid Ready” — Complete your first raid
  • “Social Butterfly” — Add 10 friends

Exploration Achievements

  • “Explorer” — Visit all regions
  • “Dungeon Crawler” — Complete every dungeon at least once
  • “Lore Hunter” — Find all lore fragments in a region
  • “Cartographer” — Unlock all hidden rooms in a dungeon

PVP Achievements

  • “First Duel” — Complete your first PVP match
  • “Gladiator” — Reach Gold rating in arena
  • “Legend” — Reach Diamond rating in arena
  • “War Hero” — Win a guild war

Collection Achievements

  • “Bestiary Complete” — Encounter every enemy type
  • “Fashionista” — Own 25 cosmetic items
  • “Title Collector” — Earn 10 titles

Achievement Rewards

Each achievement grants one or more of:

  • Achievement points (displayed on profile, total is a prestige indicator)
  • Title (selected achievements grant unique titles)
  • Portrait or profile frame (for exceptional achievements)
  • Gold (modest amounts)
  • Crafting materials (for high-difficulty achievements)

Achievement Showcase

  • Players select up to 5 achievements to display on their public profile
  • Creates a “badge” system that communicates playstyle and dedication at a glance

Seasonal Events

Seasonal events are time-limited content that creates excitement and community engagement. Each season has a Free Track (all players) and a Premium Track (Patron subscribers). See 14-monetization.md for full monetization details.

Season Structure

  • 4 seasons per year aligned with real-world seasons (~3 months each)
  • Each season introduces:
    • New seasonal dungeon(s) with unique enemies and mechanics (free for all players)
    • Free reward track (15 tiers) — gold, materials, 1-2 seasonal titles
    • Premium reward track (30 tiers, Patron subscribers) — rare materials, exclusive portraits, exclusive titles, Named seasonal item at tier 30
    • Bonus challenge dungeons (Patron subscribers) — harder seasonal content with unique modifiers
    • Seasonal leaderboard

Example Seasons

Season of Flame (Summer)

  • Theme: Fire and volcanic activity
  • Seasonal dungeon: The Erupting Caldera — fire-themed enemies, lava hazards
  • Challenge dungeon (Premium): Inferno Core — heat meter increases fire damage the longer you stay. Speed is survival.
  • Unique mechanic: Heat meter
  • Free rewards: “Firewalker” title, gold, crafting materials
  • Premium rewards: “Flamewarden” exclusive title, ember portrait frame, Named seasonal weapon (fire-themed Legendary)

Season of Frost (Winter)

  • Theme: Ice and cold
  • Seasonal dungeon: The Frozen Abyss — ice enemies, slippery terrain, visibility hazards
  • Challenge dungeon (Premium): The Deep Freeze — frost accumulation gradually slows all skills. Warmth sources are scarce.
  • Unique mechanic: Frost accumulation
  • Free rewards: “Frostborn” title, gold, crafting materials
  • Premium rewards: “Frostkeeper” exclusive title, ice crystal portrait frame, Named seasonal armor (cold resistance Legendary)

Season of Shadow (Autumn)

  • Theme: Undead and darkness
  • Seasonal dungeon: The Harvest of Souls — undead hordes, necromantic puzzles
  • Challenge dungeon (Premium): The Soul Gauntlet — defeated enemies drop souls spent on temporary buffs OR saved for bonus track progress
  • Unique mechanic: Soul economy
  • Free rewards: “Soulreaper” title, gold, crafting materials
  • Premium rewards: “Deathless” exclusive title, spectral portrait frame, Named seasonal weapon (necrotic Legendary)

Season of Growth (Spring)

  • Theme: Nature and renewal
  • Seasonal dungeon: The Awakening Grove — fey creatures, plant-based hazards, transformation encounters
  • Challenge dungeon (Premium): The Verdant Trial — plant seeds at rest points that bloom into effects in later encounters. Strategic planting is key.
  • Unique mechanic: Growth and planting
  • Free rewards: “Bloomkeeper” title, gold, crafting materials
  • Premium rewards: “Lifebringer” exclusive title, verdant portrait frame, Named seasonal armor (regeneration Legendary)

Seasonal Content Vault

  • After a season ends, its dungeons and content are removed
  • Seasonal rewards (titles, portraits, named items) are exclusive — they cannot be earned after the season
  • This creates anticipation for each new season and gives seasonal rewards lasting value
  • If a season is extremely popular, it may return in a modified form in a future year (with new rewards)

Leaderboards

Leaderboard Categories

LeaderboardMetricReset
PVP ArenaELO ratingPer season
Dungeon SpeedFastest completion time per dungeonPermanent (seasonal records too)
Weekly ChallengeFastest/best completion of weekly dungeonWeekly
Achievement PointsTotal achievement scorePermanent
CraftingTotal items crafted / highest skillPermanent
WealthTotal gold (liquid + estimated assets)Permanent
RaidFastest raid completion by guildPer season

Leaderboard Display

  • Top 100 per category
  • Player can see their own rank even if outside top 100
  • Guild leaderboards (aggregate of member rankings)
  • Server-wide and (eventually) cross-server

Collection Systems

Collections provide long-term completionist goals.

Bestiary

  • Every enemy encountered is logged in the bestiary
  • Entry includes: enemy name, stat overview, weaknesses, lore snippet
  • Completing regional bestiaries grants exploration achievements
  • Bestiary percentage visible on profile

Item Catalog

  • Every unique item discovered is logged
  • Includes items seen on the marketplace (not just personally owned)
  • “Collect all items of X type” achievements
  • Useful reference for build planning

Title Collection

  • All earned titles visible in a collection
  • Sources shown (achievement, PVP, faction, seasonal)
  • Titles are purely cosmetic but socially valuable

Recipe Collection

  • All learned recipes across all crafting professions
  • Shows undiscovered recipes as “???” to create discovery goals
  • Completion percentage per profession

Prestige and Long-Term Goals

For Level-Capped Characters

See 03-character-progression.md for the Paragon system.

For Completionists

  • Region completion (all quests, all dungeons, all gathering nodes, all lore)
  • Faction Exalted status (time-gated but achievable)
  • Full crafting mastery (skill 100 in all professions)
  • Bestiary completion
  • Achievement hunting (many achievements are designed to take months)

For Competitive Players

  • PVP rating climbing
  • Speed run records
  • Guild raid progression (first guild to clear new content)
  • Seasonal leaderboard competition

For Social Players

  • Guild leveling and hall upgrades
  • Helping newer players (mentoring achievements)
  • Organizing raids and events
  • Marketplace mastery (economic gameplay)

Retention Philosophy

  1. Respect the player’s time. Every login should feel valuable, not obligatory.
  2. Layer short and long-term goals. Daily bounties for today, achievements for this month, collections for this year.
  3. Variety prevents burnout. Multiple systems (combat, crafting, PVP, social, collecting) mean there’s always something fresh to do.
  4. Celebrate accomplishment. Achievements, titles, leaderboards, and cosmetics make progress visible and socially rewarding.
  5. No dead ends. Even max-level characters have Paragon levels, seasonal content, PVP seasons, and collections to pursue.

Delve — Technical Architecture

Table of Contents

  1. Architecture Overview
  2. Technology Stack
  3. Client Architecture
  4. Server Architecture
  5. Database Design
  6. Game Systems — Server
  7. Game Systems — Client
  8. Polling & Notifications
  9. Chat — Discord Integration
  10. Mobile Wrapping
  11. Infrastructure & DevOps
  12. Security
  13. Performance Targets

1. Architecture Overview

Delve is a server-authoritative async idle MMO rendered as a web application and wrapped for mobile distribution. Because combat is never real-time (players configure a skill queue, the server resolves it), the architecture optimizes for throughput of simulation ticks and low-frequency but reliable client updates rather than sub-100ms latency.

┌─────────────────────────────────────────────────────┐
│                     CLIENTS                         │
│  Browser (SPA)  ·  iOS (Capacitor)  ·  Android      │
└──────────┬──────────────────────────────┬───────────┘
           │ HTTPS (REST + polling)       │ Push
           ▼                              ▼
┌─────────────────────┐      ┌────────────────────────┐
│   API Gateway /     │      │  Push Notification     │
│   Load Balancer     │      │  Service (FCM / APNs)  │
│   (Caddy)           │      └────────────────────────┘
└──────────┬──────────┘
           │                  ┌────────────────────────┐
           ▼                  │  Discord               │
┌─────────────────────┐      │  (Chat, community,     │
│   REST API Servers  │      │   LFG, guild comms)    │
└──────────┬──────────┘      └────────────────────────┘
           │
┌──────────┴──────────────────────────────────────────┐
│              BullMQ Job Queue (Redis-backed)         │
└──────┬────────────┬────────────┬────────────────────┘
       ▼            ▼            ▼
┌────────────┐ ┌──────────┐ ┌──────────────┐
│  Simulation│ │ Economy  │ │  PVP Match   │
│  Workers   │ │ Workers  │ │  Workers     │
└────────────┘ └──────────┘ └──────────────┘
       │            │            │
       ▼            ▼            ▼
┌─────────────────────────────────────────────────────┐
│                   Data Layer                        │
│         PostgreSQL  ·  Redis  ·  Backblaze B2       │
└─────────────────────────────────────────────────────┘

Design Principles

  • Server-authoritative: All game state mutations happen server-side. The client is a view layer.
  • Async-first: Most gameplay resolves on the server without a connected client.
  • REST + polling, no WebSockets: The game is inherently async — players wait minutes to hours for results. Polling every 30–60s is perfectly adequate and dramatically simplifies the server (no persistent connections, no connection state, no reconnect logic).
  • Discord for chat: Community, guild coordination, LFG, and trade chat all happen on Discord. This is where the community already lives, and it eliminates an entire real-time system from the codebase.
  • Horizontally scalable: Stateless API servers; sharded workers keyed by character/guild ID.
  • Offline-tolerant: Runs, crafting, and gathering proceed whether the player is online or not.

2. Technology Stack

Client

LayerTechnologyRationale
UI FrameworkSvelteKit (SPA mode)Small bundle size (~30KB framework), fast reactivity, excellent mobile perf. SPA mode since all logic is server-side.
RenderingHTML/CSS + PixiJS (optional)Most of Delve is UI-driven (queues, inventories, logs). PixiJS available for animated run replays and map rendering.
State ManagementSvelte stores + TanStack QueryStores for local UI state; TanStack Query for server state caching, deduplication, and background refetching.
StylingTailwind CSSUtility-first, tree-shakes to small bundle. Fantasy theme via design tokens.
Mobile WrapperCapacitorWeb-to-native bridge for iOS/Android. Access to push notifications, haptics, secure storage.
BuildViteFast HMR in dev, optimized production builds with code splitting.

Server

LayerTechnologyRationale
LanguageRustHigh performance for the simulation engine. Strong type system catches bugs at compile time. Single binary deploys. Memory safety without GC pauses.
API FrameworkAxumTokio-based, ergonomic extractors, tower middleware ecosystem. The standard choice for Rust web services.
Task SchedulingCustom Redis-backed job queue (via redis crate)Delayed jobs for run completion, crafting timers, gathering expeditions, raid scheduling, auction expiry. Rust doesn’t have a BullMQ equivalent — a simple custom queue on Redis ZADD/ZPOPMIN with timestamps is sufficient and avoids a heavy dependency.
ORM / QuerySQLxCompile-time checked SQL queries against the real database. No ORM overhead — write SQL directly with type-safe results. Async Postgres driver built-in.
Serializationserde + serde_jsonIndustry-standard Rust serialization. Used for API request/response bodies, JSONB fields, and game data definitions.
Validationvalidator crate + custom typesDerive-based validation on request structs. Newtype pattern for domain-specific constraints (e.g., AttributeValue(u8) that enforces 1–99 range).
Authargon2 crate + custom session middlewareSession-based auth with Argon2id password hashing. Sessions stored in Redis. OAuth2 via oauth2 crate for social logins.

Data

LayerTechnologyRationale
Primary DBPostgreSQL 16JSONB for flexible item properties, strong indexing, reliable ACID transactions for economy.
Cache / JobsRedis 7 (Valkey)Session store, leaderboard sorted sets, rate limiting, job queue backing store.
Object StorageS3-compatible (Backblaze B2)Run replay logs, seasonal assets, user avatars. Accessed via aws-sdk-s3 crate.
Search (future)MeilisearchMarketplace full-text search, bestiary/recipe lookup.

Infrastructure

LayerTechnologyRationale
ContainersDocker + Docker Compose (dev), Kubernetes (prod)Single binary per service → tiny Docker images (~10–20MB with FROM scratch or Alpine).
Reverse ProxyCaddyAutomatic HTTPS, HTTP/2, simple config.
CI/CDGitHub ActionsBuild, test, deploy pipeline. Rust builds cached via sccache or cargo-chef Docker layer.
MonitoringPrometheus + GrafanaMetrics exported via metrics + metrics-exporter-prometheus crates.
Loggingtracing + tracing-subscriber → JSON → LokiStructured logging with spans. The tracing ecosystem is Rust’s standard for observability.
Error TrackingSentry (sentry-rust crate)Server-side panic/error capture. Client errors via Sentry JS SDK.

3. Client Architecture

3.1 Application Structure

src/
├── lib/
│   ├── api/              # API client, polling, query hooks
│   │   ├── client.ts     # Hono RPC typed client (end-to-end type safety)
│   │   └── queries/      # TanStack Query definitions per domain (with polling intervals)
│   ├── stores/           # Svelte stores for client-side state
│   │   ├── auth.ts       # Current user session
│   │   ├── notifications.ts
│   │   └── ui.ts         # Theme, sidebar state, modals
│   ├── components/       # Reusable UI components
│   │   ├── character/    # Character sheet, skill queue builder
│   │   ├── combat/       # Run replay viewer, encounter log
│   │   ├── inventory/    # Gear grid, item tooltips, drag-and-drop
│   │   ├── marketplace/  # Listings, search, buy/sell flows
│   │   ├── social/       # Guild panel, friends list, Discord links
│   │   └── ui/           # Buttons, modals, toasts, progress bars
│   ├── game/             # Client-side game logic
│   │   ├── tooltips.ts   # Stat calculation for item/skill tooltips
│   │   ├── timers.ts     # Countdown display for active runs/crafts
│   │   └── constants.ts  # Shared enums, rarity colors, etc.
│   └── types/            # TypeScript types matching the Rust API contract
│       ├── character.ts  # Character, Attributes, Species, Class
│       ├── item.ts       # Item, Rarity, ItemLocation, BonusProperty
│       ├── skill.ts      # SkillQueueSlot, QueueCondition
│       ├── combat.ts     # RunLog, EncounterLog, ActionLog
│       └── api.ts        # Request/response types per endpoint
├── routes/
│   ├── (auth)/           # Login, register, password reset
│   ├── (game)/           # Main game layout wrapper
│   │   ├── character/    # Character sheet, progression, skill queue
│   │   ├── quest-board/  # Available quests, active runs
│   │   ├── inventory/    # Gear, backpack, bank
│   │   ├── crafting/     # Profession UIs, recipe browser
│   │   ├── marketplace/  # Auction house
│   │   ├── guild/        # Guild management, lobby scheduling
│   │   ├── pvp/          # Arena queue, leaderboards
│   │   ├── world/        # Map, factions, bestiary
│   │   └── settings/     # Account, notifications, appearance
│   └── +layout.svelte    # Root layout with nav, polling init
└── app.html

3.2 Key Client Patterns

Server State vs. Client State: All game data (character stats, inventory, active runs) is server state managed via TanStack Query. The client never computes authoritative game values — it only displays them. Client state is limited to UI concerns (which tab is open, tooltip position, theme preference).

Optimistic Updates: For low-risk actions (equipping gear, reordering skill queue), the client optimistically updates the UI and rolls back on server rejection. For economy actions (marketplace buy, gold transfer), the client waits for server confirmation.

Polling Strategy: TanStack Query handles all server state polling. Different data types poll at different intervals based on how time-sensitive they are:

DataPoll IntervalRationale
Active runs/crafts/gathering60sClient shows countdown from completesAt — only needs to poll to detect completion
Notifications (in-app)30sGET /api/characters/:id/notifications — new completions, mail, PVP results
Marketplace listings60sNot urgent — player checks when ready
Party/raid lobby status15sMore time-sensitive when coordinating group content
PVP queue status10sNeeds faster feedback when waiting for a match
Everything elseOn demandFetched when the player navigates to that screen

When a countdown timer reaches zero, the client immediately refetches that resource (rather than waiting for the next poll interval) to show the result as soon as it’s available.

Timer Display: Active runs, crafts, and gathering expeditions show countdown timers. The client calculates display time from startedAt + duration timestamps provided by the server. No client-side simulation of progress — just a countdown to the known completion time. On timer expiry, TanStack Query refetches the resource immediately.

Run Replay Viewer: When a dungeon run completes, the server stores a structured log of every encounter, roll, and outcome. The client renders this as a scrollable timeline with expandable encounter cards. Optional PixiJS layer for animated combat playback.

3.3 Responsive Design

The game targets three breakpoints:

BreakpointWidthLayout
Mobile< 640pxSingle column, bottom tab navigation, stacked panels
Tablet640–1024pxTwo-column with collapsible sidebar
Desktop> 1024pxThree-column with persistent sidebar and detail panel

Touch-first interaction design: all drag-and-drop (inventory, skill queue) uses pointer events with touch support. No hover-dependent interactions — tooltips trigger on tap-and-hold on mobile.


4. Server Architecture

4.1 Service Topology

The server is a Rust workspace (Cargo monorepo) deployed as multiple binary targets from a single codebase. This avoids microservice complexity while allowing independent scaling of compute-heavy workers. All binaries share common crates for game logic, database access, and types.

delve-server/
├── Cargo.toml                  # Workspace root
├── crates/
│   ├── api/                    # REST API server binary
│   │   ├── src/
│   │   │   ├── main.rs         # Axum server entry point
│   │   │   ├── routes/         # Route handlers organized by domain
│   │   │   │   ├── auth.rs
│   │   │   │   ├── characters.rs
│   │   │   │   ├── quests.rs
│   │   │   │   ├── inventory.rs
│   │   │   │   ├── crafting.rs
│   │   │   │   ├── marketplace.rs
│   │   │   │   ├── guilds.rs
│   │   │   │   ├── pvp.rs
│   │   │   │   ├── factions.rs
│   │   │   │   ├── social.rs
│   │   │   │   ├── notifications.rs
│   │   │   │   └── admin.rs
│   │   │   ├── middleware/     # Auth, rate limiting, validation, tracing
│   │   │   └── extractors.rs  # Custom Axum extractors (AuthUser, ValidatedJson, etc.)
│   │   └── Cargo.toml
│   ├── workers/                # Background job processor binary
│   │   ├── src/
│   │   │   ├── main.rs         # Worker entry point — registers job handlers, polls Redis queue
│   │   │   ├── simulation/     # Dungeon run resolver
│   │   │   │   ├── engine.rs   # Core d100 combat engine
│   │   │   │   ├── encounters.rs
│   │   │   │   ├── skill_queue.rs
│   │   │   │   ├── conditions.rs
│   │   │   │   └── loot.rs
│   │   │   ├── economy.rs      # Marketplace matching, auction expiry
│   │   │   ├── crafting.rs     # Craft completion, critical craft rolls
│   │   │   ├── gathering.rs    # Expedition completion, yield calculation
│   │   │   ├── pvp.rs          # Arena match resolution, ELO updates
│   │   │   ├── guild.rs        # Guild XP tallying, buff expiry
│   │   │   └── scheduled.rs    # Daily reset, weekly rotation, season transitions
│   │   └── Cargo.toml
│   ├── game/                   # Core game logic library (shared by api + workers)
│   │   ├── src/
│   │   │   ├── combat.rs       # Damage formulas, hit chance, crit calculation
│   │   │   ├── progression.rs  # XP curves, level thresholds, feat unlocks
│   │   │   ├── economy.rs      # Tax rates, vendor prices, inflation formulas
│   │   │   ├── loot_tables.rs  # Drop rates, rarity weights per content tier
│   │   │   ├── time.rs         # Duration calculations for runs, crafts, gathering
│   │   │   └── rng.rs          # Seeded deterministic RNG (ChaCha8Rng)
│   │   └── Cargo.toml
│   ├── db/                     # Database layer (shared)
│   │   ├── src/
│   │   │   ├── lib.rs          # Connection pool (sqlx::PgPool), migrations
│   │   │   ├── models/         # Row types (FromRow derives)
│   │   │   ├── queries/        # SQLx query functions per domain
│   │   │   └── migrations/     # SQL migration files (sqlx migrate)
│   │   └── Cargo.toml
│   ├── types/                  # Shared types, enums, constants
│   │   ├── src/
│   │   │   ├── character.rs
│   │   │   ├── item.rs
│   │   │   ├── skill.rs
│   │   │   ├── quest.rs
│   │   │   ├── combat.rs
│   │   │   └── ids.rs          # Typed ID wrappers (CharacterId, ItemId, etc.)
│   │   └── Cargo.toml
│   └── jobs/                   # Job queue abstraction (shared)
│       ├── src/
│       │   ├── lib.rs          # Redis-backed delayed job queue
│       │   ├── enqueue.rs      # Enqueue jobs with optional delay
│       │   └── process.rs      # Poll and process jobs
│       └── Cargo.toml
├── data/                       # Static game data (TOML/RON files, compiled into binary)
│   ├── items/                  # Item template definitions
│   ├── quests/                 # Quest and dungeon definitions
│   ├── creatures/              # Enemy stat blocks
│   ├── skills/                 # Skill definitions
│   ├── recipes/                # Crafting recipes
│   └── loot_tables/            # Loot table definitions
└── Dockerfile                  # Multi-stage: build with rust image, run with scratch/alpine

Why a Cargo Workspace

  • Single compilation unit for shared code: The game, db, types, and jobs crates are compiled once and shared by both the api and workers binaries.
  • Compile-time guarantees: SQLx checks queries against the real database schema at compile time. Type mismatches between API routes and database models are caught before deployment.
  • Two binaries, one repo: cargo build --bin api and cargo build --bin workers produce independent binaries that can be deployed and scaled separately.
  • Static game data: Item templates, quests, creatures, and loot tables are defined as TOML or RON files in the data/ directory and loaded at startup (or compiled in via include_str!). Balance changes are code changes — reviewed in PRs, versioned in git.

4.2 Process Types

ProcessScalingRole
delve-apiHorizontal (2+ instances behind load balancer)REST endpoints, request validation, auth, notification polling. Axum binary.
delve-workersHorizontal (scale by queue depth)Polls Redis job queue, dispatches to simulation/economy/pvp/crafting handlers. Single binary handles all job types — scaling is just running more instances.
delve-workers --schedulerSingle instanceSame binary with a flag to also run cron-like triggers: daily resets, weekly rotations, season transitions. Only one instance runs scheduled jobs (Redis-based leader election).

Workers handle all background job types in a single binary. The economy queue is processed serially (single consumer) to prevent race conditions, while simulation/pvp/crafting jobs are processed concurrently across all worker instances.

4.3 Request Flow Example — Start a Dungeon Run

1. Client POST /api/quests/start
   Body: { characterId, questId, skillQueue, loadout, supplies }

2. API Server:
   a. Validate session → get userId
   b. Validate character belongs to user, is not already in a run
   c. Validate skill queue (skills owned, correct order, conditionals valid)
   d. Validate loadout (gear owned, correct slots)
   e. Validate supplies (owned, within slot limits)
   f. Calculate run duration based on quest + Patron status
   g. Deduct supplies from inventory
   h. Create run record in DB (status: "in_progress", completesAt: now + duration)
   i. Enqueue BullMQ delayed job: "resolve-run" with delay = duration
   j. Return { runId, completesAt } to client

3. [Time passes — player may be offline]

4. BullMQ triggers "resolve-run" job at completesAt:
   a. Simulation Worker picks up job
   b. Load run record, character snapshot, quest definition
   c. For each encounter in quest:
      - Roll initiative for all participants
      - Execute skill queues round-by-round (d100 rolls, conditional checks)
      - Apply damage, healing, conditions
      - Check for death/completion
      - If rest point: restore resources per rules
      - Log every action and roll to run_log JSONB
   d. Calculate loot drops from completed encounters
   e. Calculate XP and gold earned
   f. Write results: run status, loot, XP, gold, run_log
   g. Insert notification record: { characterId, type: "run_complete", runId }
   h. If character has push notifications enabled and is offline:
      - Send push notification via FCM/APNs: "Your dungeon run is complete!"

5. Client discovers result via one of:
   - Poll: GET /api/characters/:id/notifications returns the "run_complete" event
   - Timer: client countdown hits zero → immediate refetch of run status
   - Push: mobile notification tapped → app opens to run result screen

5. Database Design

5.1 PostgreSQL Schema (Key Tables)

Data-driven convention: All game content references (species, class, weapon type, rarity, faction, etc.) are stored as TEXT columns containing data IDs validated by the application against the GameData registry. No Postgres ENUM types are used for game content — this means adding new content never requires a database migration.

-- ==================== ACCOUNTS ====================

CREATE TABLE users (
    id              UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    email           TEXT UNIQUE NOT NULL,
    password_hash   TEXT NOT NULL,
    patron_tier     SMALLINT DEFAULT 0, -- 0=free, 1=patron
    patron_expires  TIMESTAMPTZ,
    character_slots SMALLINT DEFAULT 2,
    bank_slots      SMALLINT DEFAULT 50,
    marketplace_slots SMALLINT DEFAULT 10,
    created_at      TIMESTAMPTZ DEFAULT now(),
    last_login      TIMESTAMPTZ
);

CREATE TABLE sessions (
    id         TEXT PRIMARY KEY,
    user_id    UUID REFERENCES users(id) ON DELETE CASCADE,
    expires_at TIMESTAMPTZ NOT NULL
);

-- ==================== CHARACTERS ====================

CREATE TABLE characters (
    id              UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    user_id         UUID REFERENCES users(id) ON DELETE CASCADE,
    name            TEXT UNIQUE NOT NULL,
    species         TEXT NOT NULL,       -- data ID, validated by app against GameData registry
    class           TEXT NOT NULL,       -- data ID, validated by app against GameData registry
    subclass        TEXT,                -- data ID, NULL until level 10
    background      TEXT NOT NULL,
    level           SMALLINT DEFAULT 1,
    xp              INTEGER DEFAULT 0,
    paragon_level   INTEGER DEFAULT 0,  -- post-50 progression
    paragon_xp      BIGINT DEFAULT 0,

    -- Core attributes (base values before gear/buffs)
    might           SMALLINT NOT NULL,
    logic           SMALLINT NOT NULL,
    speed           SMALLINT NOT NULL,
    presence        SMALLINT NOT NULL,
    fortitude       SMALLINT NOT NULL,
    luck            SMALLINT NOT NULL,

    -- Non-combat skills (0-100)
    skill_athletics   SMALLINT DEFAULT 0,
    skill_acrobatics  SMALLINT DEFAULT 0,
    skill_stealth     SMALLINT DEFAULT 0,
    skill_perception  SMALLINT DEFAULT 0,
    skill_arcana      SMALLINT DEFAULT 0,
    skill_nature      SMALLINT DEFAULT 0,
    skill_religion    SMALLINT DEFAULT 0,
    skill_persuasion  SMALLINT DEFAULT 0,
    skill_deception   SMALLINT DEFAULT 0,
    skill_intimidation SMALLINT DEFAULT 0,
    skill_medicine    SMALLINT DEFAULT 0,
    skill_survival    SMALLINT DEFAULT 0,

    -- Currency
    gold            BIGINT DEFAULT 0,

    -- Rested bonus (accumulated offline XP multiplier)
    rested_bonus    REAL DEFAULT 0.0,   -- 0.0 to 0.5
    last_active     TIMESTAMPTZ DEFAULT now(),

    -- Chosen feats (JSONB array of feat IDs)
    feats           JSONB DEFAULT '[]',

    created_at      TIMESTAMPTZ DEFAULT now(),

    CONSTRAINT valid_attributes CHECK (
        might BETWEEN 1 AND 99 AND logic BETWEEN 1 AND 99 AND
        speed BETWEEN 1 AND 99 AND presence BETWEEN 1 AND 99 AND
        fortitude BETWEEN 1 AND 99 AND luck BETWEEN 1 AND 99
    )
);

CREATE INDEX idx_characters_user ON characters(user_id);
CREATE INDEX idx_characters_name ON characters(name);

-- ==================== EQUIPMENT & INVENTORY ====================

CREATE TABLE items (
    id              UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    owner_id        UUID REFERENCES characters(id) ON DELETE CASCADE,
    template_id     TEXT NOT NULL,       -- data ID, references item template in GameData
    rarity          TEXT NOT NULL,       -- data ID, references rarity tier in GameData
    enhancement     SMALLINT DEFAULT 0,  -- +0 to +5
    bonus_properties JSONB DEFAULT '[]', -- random rolled properties for rare+
    location        TEXT NOT NULL,       -- 'equipped:main_hand', 'backpack', 'bank', 'mail'
    slot_index      SMALLINT,            -- position within location
    created_at      TIMESTAMPTZ DEFAULT now()
);

CREATE INDEX idx_items_owner ON items(owner_id);
CREATE INDEX idx_items_owner_location ON items(owner_id, location);

-- Artifact tracking (server-unique items)
CREATE TABLE artifacts (
    template_id     TEXT PRIMARY KEY,
    held_by         UUID REFERENCES characters(id),
    acquired_at     TIMESTAMPTZ
);

-- ==================== SKILL QUEUE ====================

CREATE TABLE skill_queues (
    id              UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    character_id    UUID REFERENCES characters(id) ON DELETE CASCADE,
    name            TEXT DEFAULT 'Default',
    is_active       BOOLEAN DEFAULT false,
    slots           JSONB NOT NULL,      -- ordered array of { skillId, condition? }
    created_at      TIMESTAMPTZ DEFAULT now()
);

CREATE INDEX idx_skill_queues_char ON skill_queues(character_id);

-- ==================== WEAPON PROFICIENCY ====================

CREATE TABLE weapon_proficiencies (
    character_id    UUID REFERENCES characters(id) ON DELETE CASCADE,
    weapon_type     TEXT NOT NULL,       -- sword, axe, bow, staff, etc.
    proficiency     SMALLINT DEFAULT 0,  -- 0-100
    PRIMARY KEY (character_id, weapon_type)
);

-- ==================== RUNS & QUESTS ====================

CREATE TABLE runs (
    id              UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    character_id    UUID REFERENCES characters(id) ON DELETE CASCADE,
    quest_id        TEXT NOT NULL,        -- references static quest/dungeon definition
    difficulty      TEXT NOT NULL,
    status          TEXT DEFAULT 'in_progress', -- in_progress, completed, failed, abandoned
    skill_queue     JSONB NOT NULL,       -- snapshot of queue at run start
    loadout         JSONB NOT NULL,       -- snapshot of equipped gear at run start
    supplies        JSONB NOT NULL,       -- snapshot of supplies consumed
    party_id        UUID,                 -- NULL for solo, references party for group content
    started_at      TIMESTAMPTZ DEFAULT now(),
    completes_at    TIMESTAMPTZ NOT NULL,
    completed_at    TIMESTAMPTZ,
    run_log         JSONB,               -- full encounter-by-encounter replay log
    rewards         JSONB,               -- { xp, gold, items[], proficiencyGains }
    created_at      TIMESTAMPTZ DEFAULT now()
);

CREATE INDEX idx_runs_character ON runs(character_id);
CREATE INDEX idx_runs_status ON runs(status) WHERE status = 'in_progress';
CREATE INDEX idx_runs_completes ON runs(completes_at) WHERE status = 'in_progress';

-- ==================== CRAFTING & GATHERING ====================

CREATE TABLE crafting_proficiencies (
    character_id    UUID REFERENCES characters(id) ON DELETE CASCADE,
    profession      TEXT NOT NULL,        -- blacksmithing, alchemy, etc.
    skill_level     SMALLINT DEFAULT 1,   -- 1-100
    PRIMARY KEY (character_id, profession)
);

CREATE TABLE crafting_jobs (
    id              UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    character_id    UUID REFERENCES characters(id) ON DELETE CASCADE,
    recipe_id       TEXT NOT NULL,
    status          TEXT DEFAULT 'in_progress',
    started_at      TIMESTAMPTZ DEFAULT now(),
    completes_at    TIMESTAMPTZ NOT NULL,
    result_item_id  UUID,                 -- set on completion
    is_critical     BOOLEAN
);

CREATE INDEX idx_crafting_jobs_char ON crafting_jobs(character_id);

CREATE TABLE gathering_expeditions (
    id              UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    character_id    UUID REFERENCES characters(id) ON DELETE CASCADE,
    profession      TEXT NOT NULL,         -- mining, herbalism, logging, skinning
    zone            TEXT NOT NULL,
    tier            SMALLINT NOT NULL,     -- 1-5
    status          TEXT DEFAULT 'in_progress',
    started_at      TIMESTAMPTZ DEFAULT now(),
    completes_at    TIMESTAMPTZ NOT NULL,
    yields          JSONB                  -- set on completion: [{ materialId, quantity }]
);

CREATE TABLE known_recipes (
    character_id    UUID REFERENCES characters(id) ON DELETE CASCADE,
    recipe_id       TEXT NOT NULL,
    learned_at      TIMESTAMPTZ DEFAULT now(),
    PRIMARY KEY (character_id, recipe_id)
);

-- ==================== MARKETPLACE ====================

CREATE TABLE marketplace_listings (
    id              UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    seller_id       UUID REFERENCES characters(id) ON DELETE CASCADE,
    item_id         UUID REFERENCES items(id),
    price           BIGINT NOT NULL,
    listing_fee     BIGINT NOT NULL,      -- 5% deducted at listing time
    status          TEXT DEFAULT 'active', -- active, sold, expired, cancelled
    listed_at       TIMESTAMPTZ DEFAULT now(),
    expires_at      TIMESTAMPTZ NOT NULL,  -- listed_at + 48 hours
    sold_to         UUID REFERENCES characters(id),
    sold_at         TIMESTAMPTZ
);

CREATE INDEX idx_marketplace_status ON marketplace_listings(status) WHERE status = 'active';
CREATE INDEX idx_marketplace_expires ON marketplace_listings(expires_at) WHERE status = 'active';
CREATE INDEX idx_marketplace_seller ON marketplace_listings(seller_id);

-- ==================== MAIL ====================

CREATE TABLE mail (
    id              UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    sender_id       UUID REFERENCES characters(id),
    recipient_id    UUID REFERENCES characters(id) ON DELETE CASCADE,
    subject         TEXT,
    body            TEXT,
    gold_amount     BIGINT DEFAULT 0,
    item_ids        UUID[],               -- items attached
    is_read         BOOLEAN DEFAULT false,
    deliverable_at  TIMESTAMPTZ NOT NULL,  -- sent_at + 1 hour
    sent_at         TIMESTAMPTZ DEFAULT now(),
    expires_at      TIMESTAMPTZ            -- auto-delete after 30 days
);

CREATE INDEX idx_mail_recipient ON mail(recipient_id);

-- ==================== GUILDS ====================

CREATE TABLE guilds (
    id              UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    name            TEXT UNIQUE NOT NULL,
    tag             TEXT UNIQUE NOT NULL,  -- 2-4 char tag
    leader_id       UUID REFERENCES characters(id),
    level           SMALLINT DEFAULT 1,
    xp              BIGINT DEFAULT 0,
    bank_gold       BIGINT DEFAULT 0,
    active_buff     TEXT,                  -- current guild buff ID
    buff_expires    TIMESTAMPTZ,
    max_members     SMALLINT DEFAULT 50,   -- scales with guild level, max 200
    created_at      TIMESTAMPTZ DEFAULT now()
);

CREATE TABLE guild_members (
    guild_id        UUID REFERENCES guilds(id) ON DELETE CASCADE,
    character_id    UUID REFERENCES characters(id) ON DELETE CASCADE,
    rank            TEXT DEFAULT 'member', -- leader, officer, member, recruit
    joined_at       TIMESTAMPTZ DEFAULT now(),
    PRIMARY KEY (guild_id, character_id)
);

CREATE INDEX idx_guild_members_char ON guild_members(character_id);

-- ==================== FACTIONS & REPUTATION ====================

CREATE TABLE character_reputation (
    character_id    UUID REFERENCES characters(id) ON DELETE CASCADE,
    faction_id      TEXT NOT NULL,         -- iron_compact, shadow_court, etc.
    reputation      INTEGER DEFAULT 0,    -- -3000 to 21000+
    PRIMARY KEY (character_id, faction_id)
);

-- ==================== PVP ====================

CREATE TABLE pvp_ratings (
    character_id    UUID REFERENCES characters(id) ON DELETE CASCADE,
    bracket         TEXT NOT NULL,         -- '1v1', '3v3'
    rating          INTEGER DEFAULT 1000,  -- ELO
    season          SMALLINT NOT NULL,
    wins            INTEGER DEFAULT 0,
    losses          INTEGER DEFAULT 0,
    PRIMARY KEY (character_id, bracket, season)
);

CREATE TABLE pvp_matches (
    id              UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    bracket         TEXT NOT NULL,
    season          SMALLINT NOT NULL,
    team_a          UUID[] NOT NULL,       -- character IDs
    team_b          UUID[] NOT NULL,
    winner          TEXT,                  -- 'a', 'b', 'draw'
    match_log       JSONB,
    rating_changes  JSONB,                 -- { charId: delta }
    resolved_at     TIMESTAMPTZ DEFAULT now()
);

-- ==================== SOCIAL ====================

CREATE TABLE friends (
    character_id    UUID REFERENCES characters(id) ON DELETE CASCADE,
    friend_id       UUID REFERENCES characters(id) ON DELETE CASCADE,
    status          TEXT DEFAULT 'pending', -- pending, accepted
    created_at      TIMESTAMPTZ DEFAULT now(),
    PRIMARY KEY (character_id, friend_id)
);

-- ==================== PARTIES & RAIDS ====================

CREATE TABLE parties (
    id              UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    leader_id       UUID REFERENCES characters(id),
    type            TEXT NOT NULL,         -- duo, standard, raid
    max_size        SMALLINT NOT NULL,     -- 2, 4, 8
    status          TEXT DEFAULT 'forming', -- forming, ready, in_run, completed
    quest_id        TEXT,
    scheduled_at    TIMESTAMPTZ,           -- for timed lobbies
    created_at      TIMESTAMPTZ DEFAULT now()
);

CREATE TABLE party_members (
    party_id        UUID REFERENCES parties(id) ON DELETE CASCADE,
    character_id    UUID REFERENCES characters(id) ON DELETE CASCADE,
    role            TEXT,                  -- tank, healer, dps, support
    ready           BOOLEAN DEFAULT false,
    PRIMARY KEY (party_id, character_id)
);

-- ==================== ACHIEVEMENTS & COLLECTIONS ====================

CREATE TABLE character_achievements (
    character_id    UUID REFERENCES characters(id) ON DELETE CASCADE,
    achievement_id  TEXT NOT NULL,
    earned_at       TIMESTAMPTZ DEFAULT now(),
    PRIMARY KEY (character_id, achievement_id)
);

CREATE TABLE character_bestiary (
    character_id    UUID REFERENCES characters(id) ON DELETE CASCADE,
    creature_id     TEXT NOT NULL,
    kills           INTEGER DEFAULT 0,
    first_killed    TIMESTAMPTZ DEFAULT now(),
    PRIMARY KEY (character_id, creature_id)
);

-- ==================== DAILY/WEEKLY TRACKING ====================

CREATE TABLE daily_tracking (
    character_id    UUID REFERENCES characters(id) ON DELETE CASCADE,
    date            DATE NOT NULL DEFAULT CURRENT_DATE,
    first_run_bonus BOOLEAN DEFAULT false,
    bounties_completed SMALLINT DEFAULT 0,
    bounty_chest_claimed BOOLEAN DEFAULT false,
    faction_quests  JSONB DEFAULT '{}',   -- { factionId: count }
    PRIMARY KEY (character_id, date)
);

CREATE TABLE weekly_tracking (
    character_id    UUID REFERENCES characters(id) ON DELETE CASCADE,
    week_start      DATE NOT NULL,         -- Monday of the week
    challenge_completed BOOLEAN DEFAULT false,
    raid_tokens_earned INTEGER DEFAULT 0,
    PRIMARY KEY (character_id, week_start)
);

-- ==================== SEASONAL ====================

CREATE TABLE season_progress (
    character_id    UUID REFERENCES characters(id) ON DELETE CASCADE,
    season_id       TEXT NOT NULL,
    track           TEXT NOT NULL,         -- 'free' or 'premium'
    tier_reached    SMALLINT DEFAULT 0,
    xp              INTEGER DEFAULT 0,
    PRIMARY KEY (character_id, season_id)
);

5.2 Static Game Data

Item templates, quest definitions, skill data, creature stats, recipes, and loot tables are not stored in PostgreSQL. They are defined as TOML files in the data/ directory, deserialized into Rust structs at startup via serde, and versioned with the codebase. This keeps game balance changes in source control and avoids DB migrations for tuning.

# data/items/iron_longsword.toml
[iron_longsword]
name = "Iron Longsword"
type = "weapon"
subtype = "sword"
slot = "main_hand"
damage = [8, 14]
speed = 1.0
level_req = 1
rarity = "common"
# data/quests/goblin_warren.toml
[goblin_warren]
name = "Goblin Warren"
type = "bounty"
level_range = [1, 5]
base_duration_secs = 1800  # 30 minutes
loot_table = "goblin_bounty_t1"

[[goblin_warren.encounters]]
type = "combat"
enemies = ["goblin_scout", "goblin_scout"]
# ...
#![allow(unused)]
fn main() {
// crates/game/src/data.rs
use once_cell::sync::Lazy;
use std::collections::HashMap;

pub static ITEMS: Lazy<HashMap<String, ItemTemplate>> = Lazy::new(|| {
    load_toml_dir("data/items")
});

pub static QUESTS: Lazy<HashMap<String, QuestDefinition>> = Lazy::new(|| {
    load_toml_dir("data/quests")
});
}

5.3 Redis Data Structures

# Session store
session:{sessionId} → JSON { userId, expiresAt }     TTL: 30 days

# Leaderboards (sorted sets)
leaderboard:pvp:1v1:season:{n} → ZADD score=rating member=charId
leaderboard:pvp:3v3:season:{n} → ZADD score=rating member=charId
leaderboard:achievements → ZADD score=points member=charId
leaderboard:wealth → ZADD score=gold member=charId

# Rate limiting
ratelimit:{userId}:{endpoint} → counter               TTL: window duration

# Active PVP queue
pvp:queue:1v1 → sorted set (score=rating, member=charId)
pvp:queue:3v3 → sorted set (score=rating, member=charId+teamId)

# BullMQ job queues (managed by BullMQ internally)
bull:resolve-run:*
bull:marketplace-buy:*
bull:pvp-resolve:*
bull:resolve-craft:*
bull:resolve-gathering:*

6. Game Systems — Server

6.1 Simulation Engine (Combat Resolution)

The simulation engine is the core of Delve. It runs entirely on the server with no real-time client involvement.

#![allow(unused)]
fn main() {
// crates/workers/src/simulation/engine.rs

use rand::SeedableRng;
use rand_chacha::ChaCha8Rng;

pub struct SimulationContext {
    pub run: Run,
    pub party: Vec<CharacterSnapshot>,  // character stats + gear + queue at run start
    pub quest: QuestDefinition,
    pub rng: ChaCha8Rng,                // deterministic seeded RNG
    pub log: RunLogBuilder,
}

pub fn resolve_run(ctx: &mut SimulationContext) -> RunResult {
    for encounter in &ctx.quest.encounters {
        let result = resolve_encounter(ctx, encounter);
        ctx.log.add_encounter(&result);

        if result.outcome == EncounterOutcome::PartyWipe {
            return RunResult {
                status: RunStatus::Failed,
                log: ctx.log.build(),
                failed_at: Some(encounter.index),
                rewards: None,
            };
        }
    }

    let loot = roll_loot(ctx);
    let xp = calculate_xp(ctx);
    RunResult {
        status: RunStatus::Completed,
        log: ctx.log.build(),
        failed_at: None,
        rewards: Some(RunRewards { loot, xp }),
    }
}
}

Deterministic RNG: Each run is seeded with a ChaCha8Rng initialized from a seed stored in the run record. This means any run can be replayed identically for debugging or dispute resolution. The seed is derived from blake3::hash(run_id + started_at). ChaCha8 is fast and produces identical output across platforms — critical for deterministic simulation.

Encounter Resolution Loop:

  1. Sort all participants by initiative (Speed + weapon speed modifier + d100 roll)
  2. For each round (max 50 rounds per encounter):
    • For each participant in initiative order:
      • Evaluate skill queue: find first skill whose conditions are met and resources available
      • Roll d100 against success chance (derived from attacker stats vs. defender stats)
      • Apply effects: damage, healing, conditions, resource cost
      • Check for death/incapacitation
    • Tick conditions (poison damage, buff/debuff duration)
    • Check encounter end conditions
  3. Log all rolls and outcomes

6.2 Economy Worker

The economy worker handles marketplace transactions with serialized processing to prevent race conditions.

Marketplace Buy Flow:
1. API validates buyer has enough gold
2. API enqueues "marketplace.buy" job (NOT direct DB update)
3. Economy worker (single instance) processes:
   a. BEGIN TRANSACTION
   b. Verify listing still active (SELECT FOR UPDATE)
   c. Verify buyer gold >= price (SELECT FOR UPDATE on buyer character)
   d. Transfer gold: buyer -= price, seller += (price - 10% tax)
   e. Transfer item: update item.owner_id, item.location = 'mail'
   f. Create mail record for seller (gold received notification)
   g. Update listing status = 'sold'
   h. COMMIT
4. Insert notification records for buyer ("item purchased") and seller ("item sold")

6.3 PVP Match Resolution

Arena matches resolve instantly (no wait timer) using the same simulation engine as PvE, but with stat normalization applied.

PVP Flow:
1. Player enters arena queue → added to Redis sorted set by rating
2. Matchmaker (runs every 5 seconds):
   a. Scan queue for viable matches (rating within ±150, expanding over time)
   b. Pop matched players from queue
   c. Enqueue "pvp.resolve" job (immediate, no delay)
3. PVP Worker resolves match:
   a. Snapshot both characters with PVP stat normalization
   b. Run simulation engine (same as PvE but PVP-specific encounter rules)
   c. Calculate ELO changes
   d. Write match result + rating updates
   e. Insert notification records for both players
4. Both players discover result via polling (PVP poll interval: 10s) or push notification

6.4 Scheduled Jobs

JobScheduleDescription
daily-reset00:00 UTCReset daily bounties, first-run bonus, faction quest counts
weekly-resetMonday 00:00 UTCRotate weekly challenge, reset raid token caps
auction-expiryEvery 5 minExpire stale marketplace listings, return items via mail
rested-bonus-tickEvery 1 hourIncrement rested bonus for offline characters
season-transitionManual triggerEnd current season, archive ratings, distribute rewards
guild-buff-expiryEvery 1 minExpire guild buffs past their duration
mail-cleanupDailyDelete read mail older than 30 days
pvp-matchmakerEvery 5 secScan PVP queue and create matches

7. Game Systems — Client

7.1 Skill Queue Builder

The skill queue builder is the most complex client-side UI. Players drag-and-drop skills into an ordered list and configure optional conditions.

┌─────────────────────────────────────────────┐
│ Skill Queue: "Boss Rush Build"        [Save]│
├─────────────────────────────────────────────┤
│ 1. [🗡️ Power Strike]     always             │
│ 2. [🛡️ Shield Wall]      if HP < 50%       │
│ 3. [⚡ Cleave]            if enemies > 2    │
│ 4. [❤️ Second Wind]       if HP < 30%       │
│ 5. [🗡️ Execute]           if target HP < 20%│
│ 6. [🗡️ Basic Attack]      always (fallback) │
├─────────────────────────────────────────────┤
│ Available Skills:  [Drag to add]            │
│ [Whirlwind] [Taunt] [Parry] [Charge] ...   │
└─────────────────────────────────────────────┘

Condition types (predefined, not free-form):

  • always — default, no condition
  • if_hp_below(%) — self HP threshold
  • if_hp_above(%)
  • if_target_hp_below(%)
  • if_enemy_count_above(n)
  • if_enemy_count_below(n)
  • if_ally_hp_below(%) — any ally below threshold
  • if_resource_above(type, n) — e.g., “if Fury > 50”
  • if_resource_below(type, n)
  • if_has_condition(condition) — if affected by specific status
  • if_target_has_condition(condition)

The client validates the queue locally (correct number of slots, skills owned, conditions valid) and sends it to the server for authoritative validation on run start.

7.2 Run Replay Viewer

After a run completes, the client renders the server-generated run_log as a detailed timeline.

┌─────────────────────────────────────────────┐
│ Run Complete: Goblin Warren (Normal)        │
│ Result: ✅ Success  |  Duration: 32 min     │
│ XP: +450  |  Gold: +120  |  Items: 3       │
├─────────────────────────────────────────────┤
│                                             │
│ ▼ Encounter 1/5: Goblin Scouts (Combat)    │
│   Round 1:                                  │
│     You use Power Strike → Hit (rolled 34   │
│     vs 72% chance) → 18 damage to Goblin A  │
│     Goblin A attacks → Miss (rolled 88 vs   │
│     45% chance)                              │
│   Round 2: ...                              │
│   Result: Victory (2 rounds)                │
│                                             │
│ ▶ Encounter 2/5: Trapped Hallway (Trap)    │
│ ▶ Encounter 3/5: Fork in the Road (Choice) │
│ ▶ Encounter 4/5: Goblin Chieftain (Combat) │
│ ▶ Encounter 5/5: Treasure Room (Loot)      │
│                                             │
├─────────────────────────────────────────────┤
│ Loot: [Goblin Blade (Uncommon)] [Health     │
│ Potion x3] [12 Rough Leather]              │
│                                [Collect All]│
└─────────────────────────────────────────────┘

7.3 Activity Dashboard

The main game screen shows all concurrent activities at a glance:

┌─────────────────────────────────────────────┐
│ 🏰 Active Activities                        │
├─────────────────────────────────────────────┤
│ ⚔️ Dungeon Run: Goblin Warren     02:15:33 │
│ 🔨 Crafting: Iron Longsword         00:12:45│
│ ⛏️ Mining: Copper Vein (Tier 1)     01:45:00│
│ 📦 Marketplace: 3 active listings           │
│ 🎯 Arena Queue: Searching...               │
├─────────────────────────────────────────────┤
│ 📬 1 new mail  |  🔔 2 new notifications    │
└─────────────────────────────────────────────┘

8. Polling & Notifications

8.1 Why Polling, Not WebSockets

Delve is an async idle game. The fastest meaningful game event is a PVP match (resolved in seconds), and the slowest is a raid (12 hours). There is no real-time combat, no live player movement, no twitch gameplay. The client needs updates, not a live stream.

WebSockets add significant complexity for negligible benefit in this context:

  • Persistent connection state to manage on the server (memory per connection, reconnect logic, heartbeats)
  • Dedicated WebSocket server processes to scale independently
  • Connection lifecycle management on mobile (background/foreground transitions)
  • Missed-event recovery when connections drop

Polling via TanStack Query is simpler, stateless, and works identically whether the player is on desktop, mobile, or just opened the app after 8 hours offline. The server remains a pure REST API with no connection state.

8.2 Notification System

Workers write notification records to the database when events complete. The client polls for them.

CREATE TABLE notifications (
    id              UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    character_id    UUID REFERENCES characters(id) ON DELETE CASCADE,
    type            TEXT NOT NULL,       -- run_complete, craft_complete, item_sold, etc.
    title           TEXT NOT NULL,
    body            TEXT,
    data            JSONB,              -- { runId, itemId, etc. } for deep linking
    is_read         BOOLEAN DEFAULT false,
    created_at      TIMESTAMPTZ DEFAULT now()
);

CREATE INDEX idx_notifications_unread
    ON notifications(character_id, created_at DESC)
    WHERE is_read = false;
GET /api/characters/:id/notifications?since={timestamp}
→ Returns unread notifications since last poll

POST /api/characters/:id/notifications/read
Body: { ids: [...] }
→ Marks notifications as read

8.3 Push Notifications (Mobile)

When a worker creates a notification record, it also checks whether to send a push notification. Push is sent when:

  • The player has push enabled for that notification type
  • The player’s last API request was > 5 minutes ago (likely offline/backgrounded)

Push notifications are delivered via FCM (Android) and APNs (iOS) through Capacitor’s push plugin.

Notification events (user-configurable):

  • Run completed
  • Crafting completed
  • Gathering expedition completed
  • Marketplace item sold
  • Raid lobby starting in 15 min / 5 min / now
  • Mail received
  • Guild war declared

Never sent (per design doc anti-burnout philosophy):

  • “Come back!” re-engagement nags
  • Daily streak reminders
  • “Your friends are playing” social pressure
  • Limited-time urgency notifications

8.4 Polling Impact on Server Load

At 10,000 concurrent players polling every 30s, that’s ~333 requests/second to the notification endpoint. This is a trivial load for an API server — it’s a single indexed query (WHERE character_id = $1 AND is_read = false AND created_at > $2). For comparison, a typical Node.js server handles 5,000–10,000 simple requests/second.

At 100,000 concurrent players: ~3,333 req/s. Still manageable with 2-3 API server instances. The notification query hits an index and returns a handful of rows — it’s one of the cheapest possible database operations.


9. Chat — Discord Integration

9.1 Why Discord, Not In-Game Chat

Building a real-time chat system requires WebSockets, persistent connections, message storage, moderation tools, spam filtering, mute/block systems, and mobile notification integration. Discord already does all of this better than we could build, and the Delve community will already be on Discord.

9.2 Integration Approach

Discord is the primary social layer. The game links to it but does not embed it.

In-game integration points:

  • Guild creation flow prompts the guild leader to link a Discord server
  • Guild detail page shows a “Join Discord” button that opens the linked invite
  • Party/raid lobby page shows a “Coordinate on Discord” link
  • LFG (looking for group) happens in a dedicated Discord channel, not in-game
  • Trade chat happens in a Discord channel

Server-side integration (Discord bot, optional):

  • Bot posts to a #notifications channel when server events happen (season starts, maintenance, patch notes)
  • Bot can optionally post run results or achievements to a guild’s Discord channel (if guild links their server and enables it)
  • Account linking: players can link their Discord account via OAuth2 for bot features

9.3 What This Eliminates

Removed ComponentComplexity Saved
WebSocket server processNo persistent connections, no connection state management
Chat message storageNo chat tables, no message history, no Redis pub/sub
Chat moderationNo profanity filter, no mute/ban system, no reporting UI
Presence systemNo online/offline tracking, no heartbeats
NATS message busWorkers write to DB directly, no pub/sub needed
Chat UI componentsNo message input, no channel switching, no emoji picker

This reduces the server to a pure stateless REST API, which is dramatically simpler to build, deploy, debug, and scale.


10. Mobile Wrapping

10.1 Capacitor Configuration

Capacitor wraps the SvelteKit SPA as a native iOS and Android app.

Native plugins used:
├── @capacitor/push-notifications  — FCM/APNs integration
├── @capacitor/haptics             — tactile feedback for loot drops, crits
├── @capacitor/app                 — app state (foreground/background detection)
├── @capacitor/status-bar          — immersive game UI
├── @capacitor/splash-screen       — branded loading screen
├── @capacitor/browser             — external links (terms, support, Discord)
└── @capacitor/preferences         — local key-value storage (settings, cached auth)

10.2 Mobile-Specific Adaptations

ConcernImplementation
App lifecycleDetect foreground → resume polling + refetch stale queries. Background → pause polling (push notifications still arrive).
OfflineShow cached data via TanStack Query persistence. Queue-able actions (queue edits) stored locally, synced on reconnect.
Deep linksdelve://character/{id}, delve://guild/{id}, delve://quest/{id} for sharing
App Store complianceAll purchases routed through Stripe web checkout (linked from app). No in-app purchase SDK to avoid 30% platform cut. Patron status synced via server.
PerformanceLazy-load routes. Limit PixiJS animations on low-end devices (detect via navigator.deviceMemory).
Safe areasCSS env(safe-area-inset-*) for notch/dynamic island handling
Splash + iconsGenerated via @capacitor/assets from a single source SVG

10.3 Build Pipeline

Web Build:
  pnpm build → SvelteKit static adapter → dist/

iOS:
  npx cap sync ios → Xcode project updated
  xcodebuild → .ipa
  Distribute via App Store Connect (or TestFlight for beta)

Android:
  npx cap sync android → Gradle project updated
  ./gradlew assembleRelease → .aab
  Distribute via Google Play Console (or internal testing track)

CI/CD:
  GitHub Actions:
    - On push to main: build web, run tests, deploy to staging
    - On tag (v*): build web + iOS + Android, deploy to production
    - iOS builds via Xcode Cloud or self-hosted Mac runner
    - Android builds via standard Linux runner

11. Infrastructure & DevOps

11.1 Deployment Architecture

Production Environment:

┌─────────────────────────────────────────────┐
│         CDN (Cloudflare Pages)              │
│         Static SPA assets                   │
└─────────────────────────────────────────────┘

┌─────────────────────────────────────────────┐
│            Caddy (Reverse Proxy)            │
│         TLS termination, /api → API         │
└──────────────────┬──────────────────────────┘
                   │
          ┌────────┴────────┐
          │   API Servers   │
          │   (2 replicas)  │
          └────────┬────────┘
                   │
     ┌─────────────┼─────────────┐
     ▼             ▼             ▼
┌─────────┐  ┌──────────┐  ┌──────────────┐
│Simulation│  │ Economy  │  │ PVP/Crafting │
│Workers(N)│  │Worker(1) │  │  Workers     │
└─────────┘  └──────────┘  └──────────────┘
     │             │             │
     └─────────────┼─────────────┘
                   │
          ┌────────┼────────┐
          ▼        ▼        ▼
     PostgreSQL  Redis   Backblaze B2

11.2 Environment Strategy

EnvironmentPurposeInfrastructure
LocalDevelopmentDocker Compose (all services)
StagingPre-production testingSingle node, real DB, seeded test data
ProductionLive gameMulti-node, replicated DB, Redis cluster

11.3 Database Operations

  • Migrations: Drizzle-kit generates SQL migration files, applied via CI before deployment.
  • Backups: PostgreSQL WAL archiving to S3 for point-in-time recovery. Daily full backups retained 30 days.
  • Connection pooling: PgBouncer in transaction mode between API/workers and PostgreSQL.

11.4 Monitoring & Alerting

MetricAlert Threshold
API response time p95> 500ms
Simulation worker queue depth> 1000 pending jobs
Error rate> 1% of requests
Database connections> 80% pool utilization
Redis memory> 80% capacity
Disk space> 85% utilization
Notification poll latency p95> 100ms

12. Security

12.1 Authentication & Authorization

  • Password hashing: Argon2id with recommended parameters
  • Sessions: Opaque session tokens stored in Redis, 30-day expiry, refreshed on use
  • CSRF: SameSite=Strict cookies + origin header validation
  • OAuth2: Optional social login (Google, Discord) via standard OAuth2 flow
  • Authorization: Every API call validates that the authenticated user owns the character being acted upon. No cross-user access.

12.2 Anti-Cheat

Because the game is server-authoritative, traditional client-side cheats are not possible. The main attack vectors are:

VectorMitigation
API manipulationAll inputs validated server-side. Skill queue validated against owned skills. Gear validated against owned items. Gold amounts verified in transactions.
Race conditionsEconomy worker serialized. SELECT FOR UPDATE on critical resources. Idempotency keys on purchase/trade endpoints.
Automation / bottingRate limiting on all endpoints. CAPTCHA on account creation. Behavioral analysis on marketplace patterns (future).
Multi-accountingSingle email per account. IP-based rate limiting on account creation. Marketplace patterns flagged for review.
Time manipulationAll timers are server-side. completesAt timestamps are authoritative. Client countdown is display-only.

12.3 Data Protection

  • Encryption at rest: PostgreSQL with disk encryption. Redis with TLS.
  • Encryption in transit: TLS everywhere (HTTPS, internal service communication).
  • PII minimization: Only email stored. No real names, addresses, or payment details (payments handled by Stripe).
  • GDPR/CCPA: Account deletion endpoint that cascades to all character data. Data export endpoint for portability.
  • Input sanitization: All user-provided strings (character names, guild names, mail messages) sanitized against XSS.

13. Performance Targets

13.1 Client

MetricTarget
Initial load (LCP)< 2s on 4G
Bundle size (gzipped)< 150KB initial, < 500KB total with lazy routes
Time to interactive< 3s on mid-range mobile
Frame rate (UI transitions)60fps
Memory usage< 100MB on mobile

13.2 Server

MetricTarget
API response time p50< 50ms
API response time p95< 200ms
Notification poll response< 30ms (indexed query, tiny result set)
Simulation throughput100+ concurrent run resolutions per worker
Marketplace transaction throughput1000+ transactions/minute
Target concurrent players (initial)10,000
Target concurrent players (scaled)100,000+

13.3 Scalability Path

Phase 1 (Launch): Single PostgreSQL instance, 2 API servers, 2 simulation workers, 1 economy worker. Supports ~10K concurrent players.

Phase 2 (Growth): Read replicas for PostgreSQL, Redis cluster, 4+ simulation workers, horizontal API scaling. Supports ~50K concurrent players.

Phase 3 (Scale): Database sharding by character ID range (if needed), dedicated PVP cluster, CDN for all static game data, regional API deployments for latency. Supports 100K+ concurrent players.

Without WebSocket servers, scaling is much simpler — every API server is stateless and interchangeable. No sticky sessions, no connection affinity, no need to coordinate which server holds which player’s connection.


Appendix A: Data-Driven Design

All game content (species, classes, items, skills, conditions, factions, etc.) is defined in TOML data files and referenced by string ID. See features/data-driven-architecture.md for the full design. Only engine-structural concepts are Rust enums.

Game Data Registry

#![allow(unused)]
fn main() {
// crates/game/src/registry.rs
// Loaded once at startup, shared via Axum state. All game content lives here.

pub struct GameData {
    pub species: HashMap<String, SpeciesDef>,
    pub classes: HashMap<String, ClassDef>,
    pub backgrounds: HashMap<String, BackgroundDef>,
    pub weapon_types: HashMap<String, WeaponTypeDef>,
    pub equipment_slots: IndexMap<String, EquipmentSlotDef>, // ordered
    pub rarities: Vec<RarityDef>,                            // ordered by tier
    pub resources: HashMap<String, ResourceDef>,
    pub conditions: HashMap<String, ConditionDef>,
    pub skills: HashMap<String, SkillDef>,
    pub item_templates: HashMap<String, ItemTemplateDef>,
    pub creatures: HashMap<String, CreatureDef>,
    pub quests: HashMap<String, QuestDef>,
    pub factions: HashMap<String, FactionDef>,
    pub reputation_tiers: Vec<ReputationTierDef>,
    pub loot_tables: HashMap<String, LootTableDef>,
    pub recipes: HashMap<String, RecipeDef>,
    pub achievements: HashMap<String, AchievementDef>,
}

impl GameData {
    pub fn load(data_dir: &Path) -> Result<Self, GameDataError>;
    pub fn validate(&self) -> Result<(), GameDataError>; // cross-reference check
}
}

Data-Driven IDs (game content — stored as TEXT in Postgres)

#![allow(unused)]
fn main() {
// crates/types/src/ids.rs
// Validated newtype wrappers over String. The inner value is a key into GameData.

macro_rules! data_id {
    ($name:ident) => {
        #[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize, sqlx::Type)]
        #[sqlx(transparent)]
        pub struct $name(String);

        impl $name {
            pub fn as_str(&self) -> &str { &self.0 }
            /// Unchecked construction — only use when loading from DB (already validated)
            pub fn from_db(s: String) -> Self { Self(s) }
        }
    };
}

data_id!(SpeciesId);
data_id!(ClassId);
data_id!(SubclassId);
data_id!(BackgroundId);
data_id!(WeaponTypeId);
data_id!(SlotId);
data_id!(RarityId);
data_id!(ResourceId);
data_id!(ConditionId);
data_id!(SkillId);
data_id!(ItemTemplateId);
data_id!(CreatureId);
data_id!(QuestId);
data_id!(FactionId);
data_id!(RecipeId);
data_id!(AchievementId);
data_id!(LootTableId);
}

Character (uses data IDs, not enums)

#![allow(unused)]
fn main() {
// crates/types/src/character.rs

#[derive(Debug, Clone, Serialize, Deserialize, FromRow)]
pub struct Character {
    pub id: Uuid,
    pub user_id: Uuid,
    pub name: String,
    pub species: SpeciesId,      // TEXT column — e.g., "ironborn"
    pub class: ClassId,          // TEXT column — e.g., "vanguard"
    pub subclass: Option<SubclassId>,
    pub background: BackgroundId,
    pub level: i16,
    pub xp: i32,
    pub gold: i64,
    pub might: i16,
    pub logic: i16,
    pub speed: i16,
    pub presence: i16,
    pub fortitude: i16,
    pub luck: i16,
}
}

Engine-Structural Enums (code, not data)

#![allow(unused)]
fn main() {
// These remain as Rust enums — they control code branching, not content.

/// Where an item is stored — each variant has different rules and UI.
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(tag = "type", rename_all = "snake_case")]
pub enum ItemLocation {
    Equipped { slot: String },  // slot is a data ID (e.g., "main_hand")
    Backpack { index: u16 },
    Bank { index: u16 },
    Mail { mail_id: Uuid },
    Listed { listing_id: Uuid },
}

/// Run state machine — finite set of states with enforced transitions.
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
pub enum RunStatus { InProgress, Completed, Failed }

/// Encounter dispatch — each variant calls a different resolver function.
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
pub enum EncounterType { Combat, Trap, Decision, Hazard, Rest, Puzzle }

/// Queue condition evaluation — each variant has different evaluation logic.
/// The parameters (resource ID, condition ID) are data references.
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(tag = "kind", rename_all = "snake_case")]
pub enum QueueCondition {
    Always,
    IfHpBelow { threshold: u8 },
    IfHpAbove { threshold: u8 },
    IfTargetHpBelow { threshold: u8 },
    IfEnemyCountAbove { count: u8 },
    IfEnemyCountBelow { count: u8 },
    IfAllyHpBelow { threshold: u8 },
    IfResourceAbove { resource: String, amount: u16 },  // resource is a data ID
    IfResourceBelow { resource: String, amount: u16 },
    IfHasCondition { condition: String },                // condition is a data ID
    IfTargetHasCondition { condition: String },
}
}

Client/Server Type Sharing

Since the backend is Rust and the frontend is TypeScript, types are not shared at the language level. The API contract is the source of truth:

  • OpenAPI spec: The API server exports an OpenAPI schema (via utoipa crate), and the client generates TS types from it (via openapi-typescript).
  • Or: A types.ts file in the client is manually maintained to match the API.
  • Game data: The client fetches data definitions (species list, class list, rarity colors, etc.) via GET /api/game-data which returns the full registry for UI rendering.

Appendix B: API Route Summary

MethodPathDescription
Auth
POST/api/auth/registerCreate account
POST/api/auth/loginLogin, returns session
POST/api/auth/logoutDestroy session
Characters
GET/api/charactersList user’s characters
POST/api/charactersCreate character
GET/api/characters/:idGet character details
DELETE/api/characters/:idDelete character
PUT/api/characters/:id/skill-queueSave skill queue
GET/api/characters/:id/skill-queuesList saved queues
Equipment
GET/api/characters/:id/inventoryGet backpack + equipped
POST/api/characters/:id/equipEquip item
POST/api/characters/:id/unequipUnequip item
POST/api/characters/:id/salvageSalvage items
Quests & Runs
GET/api/quest-boardGet available quests for character
POST/api/runsStart a dungeon run
GET/api/runs/:idGet run status + results
GET/api/characters/:id/runsRun history
Crafting
GET/api/characters/:id/recipesKnown recipes
POST/api/crafting/startStart crafting job
GET/api/characters/:id/craftingActive crafting jobs
Gathering
POST/api/gathering/startStart expedition
GET/api/characters/:id/gatheringActive expeditions
Marketplace
GET/api/marketplaceSearch listings
POST/api/marketplace/listCreate listing
POST/api/marketplace/buy/:idBuy listing
DELETE/api/marketplace/:idCancel listing
Mail
GET/api/characters/:id/mailGet mailbox
POST/api/mail/sendSend mail
POST/api/mail/:id/collectCollect attachments
Guilds
POST/api/guildsCreate guild
GET/api/guilds/:idGuild details
POST/api/guilds/:id/joinRequest to join
POST/api/guilds/:id/inviteInvite player
PUT/api/guilds/:id/settingsUpdate guild settings
POST/api/guilds/:id/buffActivate guild buff
PVP
POST/api/pvp/queueEnter arena queue
DELETE/api/pvp/queueLeave arena queue
GET/api/pvp/historyMatch history
GET/api/pvp/leaderboard/:bracketLeaderboard
Factions
GET/api/characters/:id/reputationAll faction standings
GET/api/factions/:id/vendorFaction vendor inventory
Social
GET/api/characters/:id/friendsFriends list
POST/api/friends/addSend friend request
POST/api/friends/accept/:idAccept request
Parties
POST/api/partiesCreate party
POST/api/parties/:id/joinJoin party
POST/api/parties/:id/readyMark ready
GET/api/parties/:idParty details
Seasons & Dailies
GET/api/characters/:id/dailiesDaily progress
GET/api/characters/:id/weekliesWeekly progress
GET/api/seasons/currentCurrent season info
GET/api/characters/:id/season-progressSeason track progress
Notifications
GET/api/characters/:id/notificationsUnread notifications (polled)
POST/api/characters/:id/notifications/readMark notifications as read
Achievements
GET/api/characters/:id/achievementsEarned achievements
GET/api/characters/:id/bestiaryBestiary progress

Delve — Hosting & Infrastructure Plan

Table of Contents

  1. Hosting Philosophy
  2. Phased Infrastructure
  3. Phase 1 — Solo Dev / Alpha
  4. Phase 2 — Closed Beta (500–2,000 players)
  5. Phase 3 — Launch (2,000–10,000 players)
  6. Phase 4 — Growth (10,000–50,000 players)
  7. Phase 5 — Scale (50,000+ players)
  8. Service-by-Service Breakdown
  9. Cost vs. Revenue Analysis
  10. Domain, DNS & CDN
  11. Backups & Disaster Recovery
  12. Local Development
  13. CI/CD Pipeline
  14. Monitoring Stack
  15. Decision Log

1. Hosting Philosophy

Delve is an indie project with an ethical monetization model ($3/mo subscriptions, no whales). Infrastructure costs must stay well below revenue at every stage. This means:

  • No Kubernetes until it’s actually needed. K8s adds operational overhead that doesn’t pay off until you have multiple engineers and dozens of services. A single VPS running Docker Compose can handle thousands of concurrent players for Delve’s async workload.
  • No managed cloud databases at small scale. A self-hosted PostgreSQL on a dedicated VPS is 5-10x cheaper than AWS RDS or equivalent, and fine when you’re the only operator.
  • Graduate infrastructure with player count. Every upgrade should be a response to measured bottlenecks, not anticipated ones.
  • Prefer value VPS providers. Hetzner, OVH, and Vultr offer 3-5x the compute-per-dollar compared to AWS/GCP/Azure for baseline infrastructure.
  • Use managed services only where the operational cost of self-hosting exceeds the price difference. Email delivery, push notifications, and payment processing are always managed. Databases and app servers are self-hosted until scale demands otherwise.

2. Phased Infrastructure

PhasePlayersMonthly CostInfrastructure
1. Solo Dev / Alpha1–50~$10–25Single VPS
2. Closed Beta500–2,000~$50–1002 VPS + managed DB option
3. Launch2,000–10,000~$150–3503-4 VPS, dedicated DB server
4. Growth10,000–50,000~$500–1,500Multi-server, read replicas, Redis cluster
5. Scale50,000+~$2,000–5,000+Managed K8s, multi-region

3. Phase 1 — Solo Dev / Alpha

Goal: Get the game running, playable, testable. You and a handful of testers.

Infrastructure

Single VPS (Hetzner CX32 or equivalent)
├── 4 vCPU, 8 GB RAM, 80 GB NVMe
├── Docker Compose runs everything:
│   ├── Caddy (reverse proxy + auto TLS)
│   ├── delve-api (Rust binary)
│   ├── delve-workers (Rust binary — simulation, economy, crafting, pvp)
│   ├── PostgreSQL 16
│   └── Redis 7 (Valkey)
├── SvelteKit SPA served by Caddy as static files
└── Cost: ~€8/mo ($9/mo) on Hetzner Cloud

Provider: Hetzner Cloud

SpecValue
PlanCX32 (shared vCPU)
CPU4 vCPU
RAM8 GB
Disk80 GB NVMe
Transfer20 TB/mo
LocationFalkenstein, DE (or Ashburn, VA for US)
Cost€7.59/mo (~$8.50)

Why Hetzner: Best price-to-performance for European/US hosting. Their ARM options (CAX line) are even cheaper if the stack supports it (Rust cross-compiles to aarch64 trivially, PostgreSQL + Redis run fine on ARM).

What Runs Where

Everything on one box. Docker Compose with a single docker-compose.yml. PostgreSQL data on a persistent volume. Caddy handles TLS via Let’s Encrypt.

Backups

  • PostgreSQL: Daily pg_dump to Hetzner’s 20GB backup space (free with server) or to a Backblaze B2 bucket ($0.005/GB/mo)
  • Schedule: cron job at 04:00 UTC

Total Phase 1 Cost

ServiceMonthly Cost
Hetzner CX32$9
Domain (.com)~$1 (amortized)
Backblaze B2 (backups)$0.10
Email (Resend free tier)$0
Total~$10/mo

4. Phase 2 — Closed Beta (500–2,000 players)

Goal: Real players, real load. Validate the game systems, economy, and multiplayer features. Start collecting subscription revenue.

Infrastructure

VPS 1 — Application (Hetzner CX42)
├── 8 vCPU, 16 GB RAM, 160 GB NVMe
├── Docker Compose:
│   ├── Caddy
│   ├── delve-api
│   ├── delve-workers (×2 containers)
│   ├── delve-workers --scheduler (×1)
│   └── Redis 7
└── Cost: ~€16/mo ($18/mo)

VPS 2 — Database (Hetzner CX32)
├── 4 vCPU, 8 GB RAM, 80 GB NVMe
├── PostgreSQL 16 (dedicated, not sharing CPU with app)
├── Automated WAL backups to B2
└── Cost: ~€8/mo ($9/mo)

Why Split the Database

PostgreSQL performance degrades when it competes for CPU and I/O with the application. Isolating it on a dedicated VPS is the highest-impact scaling move at this stage, and it costs only $9/mo.

Push Notifications

At this phase, mobile testers need push notifications.

ServiceFree TierPaid
Firebase Cloud Messaging (FCM)Unlimited Android + web pushFree
APNs (via Firebase)Unlimited iOS pushFree (Apple Developer Program $99/yr already required)

FCM is free at any scale. The only cost is the Apple Developer Program membership ($99/yr) required to publish to iOS.

Payments

Stripe for subscription billing and one-time purchases. Stripe processes payment on the web (not via in-app purchase), so no App Store / Play Store commission on subscriptions.

ServiceCost
Stripe2.9% + $0.30 per transaction

At $3/mo subscription: Stripe takes ~$0.39, you keep ~$2.61 per subscriber.

Email

Transactional email for account verification, password reset, subscription receipts.

ServiceFree TierAfter Free
Resend3,000 emails/mo$20/mo for 50K
Postmark100 emails/mo$15/mo for 10K

Resend’s free tier covers beta easily. Upgrade to paid at launch.

Total Phase 2 Cost

ServiceMonthly Cost
Hetzner CX42 (app)$18
Hetzner CX32 (db)$9
Backblaze B2$0.50
Domain + DNS$1
Apple Developer$8 (amortized)
Stripe feesVariable
Email (Resend free)$0
Total~$37/mo (before Stripe)

Revenue at This Phase

If 500 beta players, 15% subscribe: 75 × $2.61 net = ~$196/mo. Comfortably profitable on infrastructure.


5. Phase 3 — Launch (2,000–10,000 players)

Goal: Public launch. Stable, performant, ready for organic growth.

Infrastructure

VPS 1 — API (Hetzner CX42)
├── 8 vCPU, 16 GB RAM, 160 GB NVMe
├── Caddy (reverse proxy)
├── delve-api (×2 containers, load balanced by Caddy)
└── Cost: ~€16/mo ($18/mo)

VPS 2 — Workers (Hetzner CX42)
├── 8 vCPU, 16 GB RAM, 160 GB NVMe
├── delve-workers (×4 containers)
├── delve-workers --scheduler (×1)
└── Cost: ~€16/mo ($18/mo)

VPS 3 — Database (Hetzner CX42)
├── 8 vCPU, 16 GB RAM, 160 GB NVMe
├── PostgreSQL 16 (primary)
├── PgBouncer (connection pooling)
├── Automated WAL archiving to B2
└── Cost: ~€16/mo ($18/mo)

VPS 4 — Redis + Monitoring (Hetzner CX32)
├── 4 vCPU, 8 GB RAM, 80 GB NVMe
├── Redis 7 (dedicated, persistent)
├── Prometheus + Grafana + Loki (monitoring stack)
└── Cost: ~€8/mo ($9/mo)

CDN — Cloudflare (Free plan)
├── Static SPA assets, game data JSON
├── DDoS protection
└── Cost: $0 (free plan is sufficient)

Why 4 Servers

ServerBottleneck it addresses
APIHandles all REST polling traffic. Isolated so poll load doesn’t compete with simulation CPU. Rust’s efficiency means a CX42 handles this easily.
WorkersSimulation is CPU-intensive. Isolated so a spike in dungeon completions doesn’t lag the API.
DatabasePostgreSQL needs dedicated I/O. Shared CPU causes query latency spikes.
Redis + MonitoringRedis needs stable memory. Monitoring (Prometheus, Grafana) is a nice-to-have that shouldn’t compete with game systems.

Object Storage

Run replay logs (JSONB stored in DB for now, but if they get large):

ServiceCost
Backblaze B2$0.005/GB/mo storage, $0.01/GB egress
Hetzner Object Storage€0.0065/GB/mo

At 10K players with ~50KB per run log and 3 runs/day average: ~1.5 GB/day = ~45 GB/mo. Cost: ~$0.25/mo on B2. Negligible.

Total Phase 3 Cost

ServiceMonthly Cost
Hetzner CX42 (API)$18
Hetzner CX42 (workers)$18
Hetzner CX42 (database)$18
Hetzner CX32 (Redis + monitoring)$9
Cloudflare (CDN)$0
Backblaze B2$2
Resend (email)$20
Apple Developer$8
Domain + DNS$1
Sentry (error tracking, free tier)$0
Total~$94/mo

Revenue at This Phase

If 5,000 active players, 15% subscribe: 750 × $2.61 = ~$1,958/mo. Plus one-time purchases (~$0.50 ARPU across all players): +$2,500 cumulative.

Infrastructure is ~6% of subscription revenue. Very healthy margin.


6. Phase 4 — Growth (10,000–50,000 players)

Goal: Handle sustained growth. Start introducing redundancy for uptime guarantees.

Infrastructure

Load Balancer — Hetzner Load Balancer
├── Routes /api/* to API pool
├── Health checks, automatic failover
└── Cost: €6/mo

API Pool (2× Hetzner CX42)
├── 8 vCPU, 16 GB RAM each
├── delve-api + Caddy per node
└── Cost: 2 × €16 = €32/mo

Worker Pool (3× Hetzner CX42)
├── delve-workers (distributed via Redis job queue)
├── Economy queue consumed serially by one instance
├── delve-workers --scheduler on one designated node
└── Cost: 3 × €16 = €48/mo

Database — Primary + Read Replica
├── Primary: Hetzner CX52 (16 vCPU, 32 GB RAM)
│   ├── PostgreSQL 16 + PgBouncer
│   └── Cost: €36/mo
├── Read Replica: Hetzner CX42 (8 vCPU, 16 GB RAM)
│   ├── Streaming replication, serves read-heavy queries
│   │   (leaderboards, marketplace search, profile lookups)
│   └── Cost: €16/mo
└── Total: €52/mo

Redis — Hetzner CX42
├── 16 GB RAM, persistent, Sentinel for failover (or Valkey cluster)
└── Cost: €16/mo

Monitoring — Hetzner CX32
├── Prometheus, Grafana, Loki, Alertmanager
├── Sentry (cloud, Team plan for higher limits)
└── Cost: €8/mo + $26/mo Sentry

At this scale, marketplace search benefits from a dedicated search engine:

ServiceHostingCost
MeilisearchSelf-hosted on worker VPS$0 (already have spare capacity)
Meilisearch CloudManaged$30/mo (if self-hosting is too much operational burden)

Total Phase 4 Cost

ServiceMonthly Cost
Hetzner Load Balancer$7
API servers (2×)$36
Worker servers (3×)$54
Database primary$40
Database replica$18
Redis$18
Monitoring VPS$9
Sentry Team$26
Cloudflare Pro$20
Backblaze B2$5
Resend$20
Apple Developer$8
Domain$1
Total~$262/mo

Revenue at This Phase

If 25,000 active players, 15% subscribe: 3,750 × $2.61 = ~$9,788/mo. Infrastructure is ~3% of subscription revenue.

At this point you’re making real money and could afford managed services or an ops hire if needed.


7. Phase 5 — Scale (50,000+ players)

Goal: Professional-grade infrastructure. Consider managed Kubernetes, multi-region, and a dedicated ops approach.

When to Move to Kubernetes

Move to K8s when at least two of these are true:

  • More than one person is deploying and operating infrastructure
  • You need auto-scaling (traffic is spiky, not steady)
  • You’re managing 15+ containers across 10+ servers and Docker Compose is unwieldy
  • You need zero-downtime rolling deployments across multiple server pools

Infrastructure

Kubernetes Cluster (Hetzner Cloud or CIVO)
├── Control plane (managed by provider)
├── Node pool — API: 3× CX42 (auto-scaling 2-5)
├── Node pool — Workers: 4× CX42 (auto-scaling 2-8)
└── Estimated: €150-350/mo for nodes

Managed PostgreSQL (Hetzner Managed DB or Neon)
├── Primary: 16 vCPU, 64 GB RAM
├── 2 read replicas
├── Automated backups, point-in-time recovery
├── Connection pooling (PgBouncer built-in)
└── Estimated: €150-300/mo

Managed Redis (Upstash or self-hosted Valkey cluster)
├── 3-node cluster for HA
├── 32 GB total memory
└── Estimated: €50-100/mo

Multi-Region Consideration:
├── If majority US players: US primary + EU edge CDN
├── If global: US primary + EU secondary with DB replication
└── Add ~50-100% to compute costs for second region

Total Phase 5 Cost (Estimated)

ServiceMonthly Cost
Kubernetes nodes$300–500
Managed PostgreSQL$200–350
Managed Redis$60–120
Monitoring (Grafana Cloud or self-hosted)$50–100
Cloudflare Pro$20
Object storage$15
Email (Resend or Postmark)$40
Sentry Business$80
Push notifications$0 (FCM free)
Total~$800–1,300/mo

Revenue at This Phase

If 50,000 active players, 15% subscribe: 7,500 × $2.61 = ~$19,575/mo. If 100,000 active players: ~$39,150/mo.

Infrastructure at 2-5% of revenue. Very healthy.


8. Service-by-Service Breakdown

PostgreSQL

PhaseSetupCost
1–2Single instance on shared/dedicated VPS$0–9
3Dedicated VPS, PgBouncer, WAL backups$18
4Primary + read replica, PgBouncer$58
5Managed, primary + 2 replicas$200–350

Key configuration:

  • shared_buffers: 25% of RAM
  • effective_cache_size: 75% of RAM
  • work_mem: 64MB (for marketplace queries, leaderboard aggregation)
  • max_connections: 200 (with PgBouncer in front, actual app connections pool at ~20 per API instance)
  • WAL level: replica (for streaming replication readiness from day 1)

Redis

PhaseSetupCost
1–2Shared VPS, appendonly persistence$0
3Dedicated VPS$9
4Dedicated VPS, Sentinel$18
5Cluster or managed$60–120

Memory estimation at 50K players:

  • Sessions: ~50K × 0.5KB = 25MB
  • Leaderboards: ~10 boards × 50K entries × 0.1KB = 50MB
  • Job queue: ~10K pending × 1KB = 10MB
  • PVP queues: negligible
  • Rate limiting: ~50K counters × 0.1KB = 5MB
  • Total: ~90MB — Redis memory is not a concern until extreme scale

Caddy / Load Balancer

PhaseSetup
1–3Caddy on the API VPS (reverse proxy + auto TLS)
4+Hetzner Load Balancer ($7/mo) in front of Caddy instances

Caddy handles:

  • Automatic HTTPS via Let’s Encrypt
  • HTTP/2
  • Static file serving (SPA bundle)
  • Gzip/brotli compression

Job Queue

The custom Redis-backed job queue runs in-process on worker binaries. No separate infrastructure. Job types and their expected volumes:

Job TypeTriggerVolume (10K players)
resolve-runRun timer completes~30K/day
resolve-craftCraft timer completes~15K/day
resolve-gatheringExpedition completes~10K/day
marketplace-buyPlayer purchases listing~5K/day
auction-expiryEvery 5 min (batch)288/day
pvp-resolveMatch found~3K/day
daily-reset00:00 UTC1/day
weekly-resetMonday 00:00 UTC1/week
mail-delivery1 hour after send~2K/day
guild-buff-expiryEvery 1 min (batch)1,440/day

9. Cost vs. Revenue Analysis

Revenue Model (from monetization doc)

  • Subscription: $3/mo, ~$2.61 net after Stripe fees
  • Target subscription rate: 15% of active players
  • One-time purchases: ~$0.50 ARPU lifetime average

Break-Even Table

Active PlayersSubscribers (15%)Subscription RevenueInfra CostMargin
50075$196/mo$37/mo$159
2,000300$783/mo$60/mo$723
5,000750$1,958/mo$94/mo$1,864
10,0001,500$3,915/mo$150/mo$3,765
25,0003,750$9,788/mo$262/mo$9,526
50,0007,500$19,575/mo$1,000/mo$18,575
100,00015,000$39,150/mo$2,500/mo$36,650

Infrastructure stays at 2-6% of revenue across all phases. The async, server-resolved nature of Delve means the compute cost per player is very low compared to real-time multiplayer games.

Break-Even Point

At $10/mo infrastructure (Phase 1), you need 4 subscribers to break even on hosting. That’s ~27 active players at 15% subscription rate. The game is profitable on infrastructure almost immediately once anyone is paying.

The real costs are development time (your time), not infrastructure.


10. Domain, DNS & CDN

Domain

Register delve.game or similar via Cloudflare Registrar (at-cost pricing, no markup).

DNS

Cloudflare DNS (free):

  • delve.game → Cloudflare CDN → origin server (static SPA)
  • api.delve.game → origin server (REST API, proxied through Cloudflare is fine — no WebSocket concerns)

CDN

Cloudflare free plan:

  • Cache the SPA shell (index.html, JS, CSS, images)
  • Cache static game data files (item templates, skill definitions exported as JSON)
  • DDoS protection (useful once the game has any visibility)
  • Edge compression (Brotli)

Since there are no WebSockets, all traffic can be proxied through Cloudflare from day one — free DDoS protection and caching for the SPA assets. API traffic proxied through Cloudflare adds ~10-20ms latency but gains DDoS protection, which is worth it.

At Phase 4+, Cloudflare Pro ($20/mo) adds:

  • Better DDoS mitigation
  • WAF rules
  • Cache analytics

11. Backups & Disaster Recovery

Backup Strategy

DataMethodFrequencyRetentionStorage
PostgreSQLpg_dump (Phase 1–2), WAL archiving (Phase 3+)Daily full + continuous WAL30 days full, 7 days WALBackblaze B2
RedisRDB snapshotsEvery 6 hours7 daysLocal + B2
Run logsStored in PostgreSQL (JSONB)Covered by DB backupSame as DBSame as DB
Application codeGit repositoryEvery pushInfiniteGitHub
Docker imagesContainer registryEvery deploy30 versionsGitHub Container Registry (free for public, 500MB free for private)
Secrets/configEncrypted in repo or secrets managerEvery changeInfiniteGit (encrypted) or Doppler/Infisical

Disaster Recovery

ScenarioRecovery
App server diesDeploy new VPS from Docker image (10 min). Stateless — no data loss.
Database server diesProvision new VPS, restore from latest B2 backup + WAL replay. RPO: minutes. RTO: 30–60 min.
Redis diesProvision new VPS, restore from RDB snapshot. Sessions regenerate on next login. Leaderboards rebuild from DB. RPO: 6 hours. RTO: 15 min.
Complete datacenter failureRestore all from B2 backups to a different Hetzner datacenter (or different provider entirely). RTO: 2-4 hours.
Corrupt database (bad migration, bug)Point-in-time recovery from WAL archive. Restore to any moment before corruption.

Backup Testing

Monthly: restore the latest PostgreSQL backup to a temporary VPS and run a basic health check query. Automate this in CI. Untested backups are not backups.


12. Local Development

Docker Compose (dev)

# docker-compose.yml (development)
services:
  postgres:
    image: postgres:16-alpine
    ports: ["5432:5432"]
    environment:
      POSTGRES_DB: delve
      POSTGRES_USER: delve
      POSTGRES_PASSWORD: devpassword
    volumes:
      - pgdata:/var/lib/postgresql/data

  redis:
    image: valkey/valkey:7-alpine
    ports: ["6379:6379"]

  mailpit:
    image: axllent/mailpit
    ports: ["8025:8025", "1025:1025"]
    # Catches all outgoing email in dev — accessible at localhost:8025

volumes:
  pgdata:

The Rust API server, workers, and SvelteKit dev server run directly on the host (not in containers) for fast iteration. They connect to the containerized dependencies.

# Terminal 1: Start dependencies
docker compose up -d

# Terminal 2: API server (with cargo-watch for auto-rebuild)
cargo watch -x 'run --bin api'

# Terminal 3: Workers (with cargo-watch)
cargo watch -x 'run --bin workers'

# Terminal 4: Client (SvelteKit dev server)
pnpm --filter client dev

Rust build times: Initial full build will take 1-3 minutes. Incremental rebuilds via cargo-watch are typically 5-15 seconds. Use cargo-chef in the Docker multi-stage build to cache dependency compilation separately from application code.

Seed Data

A seed binary (cargo run --bin seed) populates the dev database with:

  • Test user accounts (free, patron, admin)
  • Characters at various levels with gear
  • Active marketplace listings
  • Guild with members
  • In-progress runs, crafts, and expeditions

13. CI/CD Pipeline

GitHub Actions

On Pull Request:
  ├── cargo fmt --check (formatting)
  ├── cargo clippy (linting)
  ├── cargo test (unit + integration tests against Docker Compose services)
  ├── cargo sqlx prepare --check (verify query cache is up to date)
  ├── Client: pnpm lint + pnpm check + pnpm build
  └── Build check: cargo build --release (ensure it compiles)

On Push to main:
  ├── All PR checks
  ├── Build Docker images (delve-api, delve-workers) via cargo-chef multi-stage
  ├── Build SvelteKit SPA
  ├── Push images to GitHub Container Registry
  ├── Deploy to staging (auto)
  └── Smoke test against staging

On Git Tag (v*):
  ├── All main checks
  ├── Build + push production Docker images
  ├── Deploy to production (manual approval gate)
  ├── Build iOS (Xcode Cloud or self-hosted Mac runner)
  ├── Build Android (.aab)
  ├── Upload to TestFlight / Play Console internal track
  └── Tag container images with version

Deployment (Phase 1–4)

Simple SSH-based deployment. No need for fancy orchestration:

# deploy.sh (run from CI or manually)
ssh deploy@app-server "
  cd /opt/delve &&
  docker compose pull &&
  docker compose up -d --remove-orphans
"

ssh deploy@worker-server "
  cd /opt/delve &&
  docker compose pull &&
  docker compose up -d --remove-orphans
"

Database migrations run as a separate step before app deployment:

ssh deploy@app-server "
  cd /opt/delve &&
  docker compose run --rm api sqlx migrate run
"

Deployment (Phase 5 — Kubernetes)

Helm charts or Kustomize manifests. Rolling deployments with readiness probes. Migrations as init containers or pre-deploy jobs.


14. Monitoring Stack

Phase 1–2: Minimal

  • Uptime: UptimeRobot (free, 50 monitors) — ping API endpoint every 5 min
  • Errors: Sentry free tier (5K events/mo)
  • Logs: docker compose logs — review manually

Phase 3+: Full Stack

All self-hosted on the monitoring VPS:

Prometheus
├── Scrapes API server metrics (request rate, latency, error rate)
├── Scrapes worker metrics (queue depth, job duration, failure rate)
├── Scrapes PostgreSQL (pg_exporter: connections, query time, replication lag)
├── Scrapes Redis (redis_exporter: memory, commands/sec, keyspace)
├── Scrapes Node exporter (CPU, RAM, disk, network per VPS)
└── Retention: 30 days local

Grafana
├── Dashboards:
│   ├── Game Overview: active players, runs/hour, marketplace volume
│   ├── API Performance: request rate, p50/p95/p99 latency, error rate
│   ├── Worker Health: queue depths, processing time, failure rate
│   ├── Database: query latency, connections, replication lag
│   ├── Redis: memory usage, commands/sec, hit rate
│   └── Infrastructure: CPU, RAM, disk, network per server
└── Alerts → Discord webhook (or email)

Loki
├── Aggregates structured JSON logs from all services (via tracing + tracing-subscriber)
├── Queryable from Grafana
└── Retention: 14 days

Alertmanager
├── Routes alerts to Discord channel
├── Key alerts:
│   ├── API p95 > 500ms for 5 min
│   ├── Any worker queue > 1000 pending for 10 min
│   ├── PostgreSQL replication lag > 30s
│   ├── Any server disk > 85%
│   ├── Any server CPU > 90% sustained 10 min
│   └── Error rate > 1% for 5 min
└── Silence/snooze via Grafana UI

Application Metrics (exposed via Prometheus client)

#![allow(unused)]
fn main() {
// Key metrics (via metrics + metrics-exporter-prometheus crates):

// API server:
http_request_duration_seconds    // histogram, labeled by route + method
http_requests_total              // counter, labeled by route + status
notification_poll_duration_ms    // histogram — track polling endpoint performance

// Workers:
simulation_runs_resolved_total   // counter
simulation_run_duration_seconds  // histogram
job_queue_depth                  // gauge, labeled by queue name
job_processing_duration_seconds  // histogram, labeled by job type
job_failures_total               // counter, labeled by job type

// Business metrics:
runs_started_total               // counter
marketplace_transactions_total   // counter
subscriptions_active             // gauge (query from DB, cached)
}

15. Decision Log

Key hosting decisions and the reasoning behind them. Update this as decisions change.

DecisionChosenAlternatives ConsideredWhy
Backend languageRustTypeScript/Node.js, Go, Python, C#Best performance for CPU-bound simulation engine. Strong type system. Single binary deploys (~10-20MB Docker images). No GC pauses.
API frameworkAxumActix-web, Rocket, WarpTokio-native, ergonomic extractors, tower middleware ecosystem. Most active Rust web framework.
Client-server communicationREST + pollingWebSockets, SSE, long pollingGame is async — players wait minutes to hours. Polling every 30-60s is adequate. Eliminates persistent connection management entirely. Server stays stateless.
ChatDiscord (external)In-game WebSocket chatCommunity already lives on Discord. Eliminates real-time messaging system, chat storage, moderation tools, presence tracking. Massive complexity reduction.
Primary hosting providerHetzner CloudAWS, DigitalOcean, Vultr, OVH3-5x cheaper than AWS for equivalent specs. Reliable. EU + US datacenters. ARM options for future savings.
Container orchestration (Phase 1–4)Docker ComposeKubernetes, Nomad, bare metalK8s is overkill for <10 containers on <10 servers. Docker Compose is simple, well-understood, and sufficient.
DatabaseSelf-hosted PostgreSQLNeon, Supabase, PlanetScale, AWS RDSSelf-hosted is $9–40/mo vs. $50–200/mo managed for equivalent specs. Acceptable risk for a single operator. Move to managed at Phase 5.
CDNCloudflare (free)Bunny CDN, Fastly, AWS CloudFrontFree tier is generous. DDoS protection included. Upgrade to Pro at Phase 4 ($20/mo).
Object storageBackblaze B2AWS S3, Hetzner Object Storage, Cloudflare R2Cheapest. S3-compatible API. Free egress via Cloudflare bandwidth alliance.
EmailResendPostmark, SendGrid, SESGood free tier (3K/mo). Simple API. Scales cheaply.
Push notificationsFirebase (FCM)OneSignal, PusherFree at any scale. Direct integration with Capacitor.
PaymentsStripe (web checkout)In-app purchase (Apple/Google)Avoids 30% platform commission. Web checkout is compliant if not selling digital goods consumed within the app (subscriptions for server-side speed are defensible).
MonitoringSelf-hosted Prometheus/GrafanaDatadog, New Relic, Grafana CloudFree. Full control. Datadog would cost $100+/mo for equivalent coverage.
Error trackingSentryBugsnag, self-hostedBest free tier. Rust + JS SDKs. Essential for client + server error visibility.
Secrets managementEnvironment variables (Phase 1–3), Infisical (Phase 4+)Doppler, HashiCorp Vault, AWS Secrets ManagerEnv vars are fine while it’s one person deploying. Move to a proper secrets manager when there are multiple operators.
App Store payments strategyWeb checkout via StripeNative in-app purchaseApple/Google take 30% (or 15% for small business). At $3/mo, that’s $0.45–0.90 per sub lost. Web checkout keeps the full margin minus Stripe’s 2.9%+$0.30. Requires careful compliance with store policies.

Delve — Feature Implementation Plan

Features are ordered sequentially — each builds on the ones before it. Implement in order.

Foundation

#FeatureDescriptionKey Deps
00Project FoundationCargo workspace, DB, Docker, CI, SvelteKit skeleton
01AuthenticationRegistration, login, sessions, rate limiting00
02Character CreationSpecies, classes, backgrounds, attribute point-buy01

Core Game Loop

#FeatureDescriptionKey Deps
03Items & InventoryGear templates, random bonuses, equip/unequip, salvage02
04Character ProgressionLeveling, feats, subclasses, weapon proficiency, Paragon02, 03
05Skill QueueQueue builder, conditions, validation, multiple saved queues04
06Combat Engined100 system, simulation engine, encounters, loot resolution05, 03
07Quests & RunsQuest board, run lifecycle, worker resolution, rewards06

Secondary Systems

#FeatureDescriptionKey Deps
08Crafting & Gathering5 crafting + 4 gathering professions, idle timers03
09Economy & MarketplaceAuction house, mail, NPC vendors, gold sinks03
10Guilds & SocialGuilds, friends, parties, raid lobbies02, 09
11PVP SystemArena, matchmaking, stat normalization, ELO, seasons06, 05
12Factions & Reputation7 factions, rep tiers, conflict pairs, vendors07

Engagement & Polish

#FeatureDescriptionKey Deps
13NotificationsPolling notifications, push (FCM/APNs), preferences00, 01
14Dailies, Weeklies & SeasonsDaily bounties, weekly challenges, seasonal events07, 04
15Achievements & CollectionsAchievements, bestiary, leaderboards, titles07+
16MonetizationPatron subscription, purchases, Stripe integration01, 07, 08
17Gear Enhancement & Reforging+1 to +5 upgrades, re-roll random bonuses03, 08

Distribution

#FeatureDescriptionKey Deps
18Mobile WrappingCapacitor iOS/Android, push, deep links, app store13, all UI

Implementation Notes

  • Features 00-07 constitute the MVP — a playable game loop. Prioritize these.
  • Features 08-12 add depth. Can be built in parallel by multiple contributors.
  • Features 13-17 are engagement/monetization layers. Feature 13 (notifications) should be wired in early even if other engagement features come later.
  • Feature 18 (mobile) can begin as soon as the client UI is stable, but app store submission should wait until the core loop is solid.
  • Each feature file lists its own technical tasks and tests. Tasks within a feature are ordered but can sometimes be parallelized where noted.
  • Data-Driven Architecture — READ THIS FIRST. All game content (species, classes, items, conditions, etc.) is defined in TOML data files and referenced by string ID. No Rust enums for game content. No Postgres enums. Adding new content = add a TOML file, restart server.

Data-Driven Architecture

Principle

Adding new game content should never require recompilation. Species, classes, items, skills, factions, status effects — all of it is defined in data files (TOML), loaded at server startup, and validated at load time. The database stores string IDs that reference data definitions, not Rust enums.

This means:

  • Adding a 10th species = add a TOML file, restart server
  • Adding a new status effect = add it to conditions.toml, restart server
  • Adding a new weapon type = add a TOML file, restart server
  • No code changes, no recompilation, no database migration

What Is Data (String IDs)

Everything that describes “what exists in the game world” is defined in TOML files under data/ and referenced by string ID throughout the codebase and database.

CategoryExample IDsDefined In
Species"ironborn", "verdani", "kharren"data/species/*.toml
Classes"vanguard", "shade", "arcanist"data/classes/*.toml
Subclasses"bulwark", "assassin", "evoker"data/classes/*.toml (nested)
Backgrounds"soldier", "scholar", "merchant"data/backgrounds/*.toml
Weapon Types"sword", "axe", "bow", "staff"data/weapon_types/*.toml
Equipment Slots"main_hand", "head", "ring_1"data/equipment_slots.toml
Rarity Tiers"common", "rare", "legendary"data/rarities.toml
Resource Types"stamina", "mana", "fury"data/resources.toml
Status Effects"poisoned", "stunned", "hasted"data/conditions/*.toml
Skills"power_strike", "fireball"data/skills/*.toml
Item Templates"iron_longsword", "leather_cap"data/items/**/*.toml
Creatures"goblin_scout", "cave_troll"data/creatures/*.toml
Quests"goblin_warren", "deep_mines"data/quests/**/*.toml
Factions"iron_compact", "shadow_court"data/factions/*.toml
Reputation Tiers"hostile", "friendly", "exalted"data/factions/reputation_tiers.toml
Crafting Professions"blacksmithing", "alchemy"data/crafting/professions.toml
Gathering Professions"mining", "herbalism"data/gathering/professions.toml
Recipes"iron_longsword_recipe"data/crafting/recipes/*.toml
Achievements"first_blood", "dungeon_crawler"data/achievements/*.toml
Loot Tables"goblin_bounty_t1"data/loot_tables/*.toml
Bonus Property Pools"offensive", "defensive"data/bonus_pools.toml

Database Columns

All of these are stored as TEXT in PostgreSQL. The column species on the characters table is TEXT NOT NULL, not a Postgres enum. This means adding a new species never requires a migration.

-- YES: plain text, validated by the application
CREATE TABLE characters (
    species     TEXT NOT NULL,  -- validated against data/species/ at runtime
    class       TEXT NOT NULL,  -- validated against data/classes/ at runtime
    background  TEXT NOT NULL,  -- validated against data/backgrounds/ at runtime
    ...
);

-- NO: Postgres enums require ALTER TYPE migrations to add values
-- CREATE TYPE species AS ENUM ('ironborn', 'verdani', ...);

Rust Types

Instead of Rust enums with hardcoded variants, game content IDs are wrapped in validated newtypes:

#![allow(unused)]
fn main() {
/// A validated reference to a species defined in data/species/*.toml
/// The inner String is guaranteed to be a valid species ID at construction time.
#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize, sqlx::Type)]
#[sqlx(transparent)]
pub struct SpeciesId(String);

impl SpeciesId {
    /// Create a SpeciesId, validating it exists in the game data registry.
    pub fn new(id: &str, registry: &GameData) -> Result<Self, GameDataError> {
        if registry.species.contains_key(id) {
            Ok(Self(id.to_string()))
        } else {
            Err(GameDataError::UnknownSpecies(id.to_string()))
        }
    }

    pub fn as_str(&self) -> &str { &self.0 }
}

// Same pattern for ClassId, BackgroundId, WeaponTypeId, SlotId,
// RarityId, ResourceTypeId, ConditionId, FactionId, SkillId, etc.
}

Data Registry

All game data is loaded into a GameData struct at startup and shared via Axum state:

#![allow(unused)]
fn main() {
pub struct GameData {
    pub species: HashMap<String, SpeciesDef>,
    pub classes: HashMap<String, ClassDef>,
    pub backgrounds: HashMap<String, BackgroundDef>,
    pub weapon_types: HashMap<String, WeaponTypeDef>,
    pub equipment_slots: HashMap<String, EquipmentSlotDef>,
    pub rarities: Vec<RarityDef>,  // ordered by tier (common first)
    pub resources: HashMap<String, ResourceDef>,
    pub conditions: HashMap<String, ConditionDef>,
    pub skills: HashMap<String, SkillDef>,
    pub item_templates: HashMap<String, ItemTemplateDef>,
    pub creatures: HashMap<String, CreatureDef>,
    pub quests: HashMap<String, QuestDef>,
    pub factions: HashMap<String, FactionDef>,
    pub reputation_tiers: Vec<ReputationTierDef>,  // ordered by threshold
    pub loot_tables: HashMap<String, LootTableDef>,
    pub recipes: HashMap<String, RecipeDef>,
    pub achievements: HashMap<String, AchievementDef>,
    pub bonus_pools: HashMap<String, BonusPoolDef>,
}

impl GameData {
    /// Load all data files from the data/ directory and validate cross-references.
    pub fn load(data_dir: &Path) -> Result<Self, GameDataError> {
        let data = Self { /* load each category */ };
        data.validate()?;  // check all cross-references
        Ok(data)
    }

    /// Validate that all cross-references between data files are valid.
    /// e.g., a class's `primary_resource` must reference a valid resource ID,
    /// a quest's `encounters.enemy_ids` must reference valid creature IDs, etc.
    fn validate(&self) -> Result<(), GameDataError> { /* ... */ }
}
}

Cross-Reference Validation

At startup, the GameData::validate() method checks every cross-reference:

  • Every class’s primary_resource is a valid resource ID
  • Every class’s starting_skills are valid skill IDs
  • Every species’s attribute_bonuses reference valid attribute names
  • Every item template’s slot is a valid equipment slot ID
  • Every item template’s weapon_type (if weapon) is a valid weapon type ID
  • Every skill’s resource_cost.type is a valid resource ID
  • Every skill’s conditions_applied are valid condition IDs
  • Every quest encounter’s enemy_ids are valid creature IDs
  • Every quest’s loot_table is a valid loot table ID
  • Every recipe’s materials reference valid item template IDs
  • Every recipe’s result_item_template_id is a valid item template ID
  • Every faction’s conflict_pair (if set) is a valid faction ID
  • Every loot table entry’s template_id is a valid item template ID

If any validation fails, the server refuses to start with a clear error message naming the broken reference. This catches data errors at deploy time, not at player-action time.

What Is Code (Rust Enums)

Things that define how the engine works — not what content exists — remain as Rust enums. These change only when the engine’s behavior changes, which is a code change anyway.

CategoryEnumWhy It’s Code
Item storage locationsItemLocation (Equipped, Backpack, Bank, Mail, Listed)Each variant has different capacity rules, UI sections, transfer logic
Run state machineRunStatus (InProgress, Completed, Failed)Finite states with transitions enforced by the worker
Encounter dispatchEncounterType (Combat, Trap, Decision, Hazard, Rest, Puzzle)Each dispatches to a completely different resolver function
Queue condition evaluationQueueConditionKind (IfHpBelow, IfEnemyCountAbove, etc.)Each has different evaluation logic in the combat engine
Achievement criteria kindsCriteriaKind (KillCount, ReachLevel, CraftCount, etc.)Each has different progress tracking and check logic
Notification typesNotificationType (RunComplete, ItemSold, etc.)Each has different payload structure and routing

Important: Condition Definitions vs. Condition Evaluation

The definitions of status effects (Poisoned does 5 damage/round, lasts 3 rounds) are data-driven — they live in data/conditions/*.toml. But the evaluation logic for queue conditions (“if my HP is below X”) is code, because each condition type requires different logic to evaluate:

#![allow(unused)]
fn main() {
// CODE: how to evaluate a queue condition (engine logic)
pub enum QueueConditionKind {
    Always,
    IfHpBelow,
    IfHpAbove,
    IfTargetHpBelow,
    IfEnemyCountAbove,
    IfEnemyCountBelow,
    IfAllyHpBelow,
    IfResourceAbove,
    IfResourceBelow,
    IfHasCondition,      // the condition ID is a data reference
    IfTargetHasCondition, // the condition ID is a data reference
}

// DATA: what "poisoned" actually does (loaded from TOML)
// data/conditions/poisoned.toml
// [poisoned]
// name = "Poisoned"
// damage_per_round = 5
// duration_rounds = 3
// damage_type = "poison"
// stackable = false
}

Data File Format Examples

Species Definition

# data/species/ironborn.toml
[ironborn]
name = "Ironborn"
description = "Stout mountain-dwelling folk..."
attribute_bonuses = { fortitude = 2, might = 1 }

[ironborn.species_skill]
id = "ironborn_resilience"
name = "Ironborn Resilience"
description = "Reduce incoming physical damage by 5%"
effect = { type = "damage_reduction", subtype = "physical", value = 0.05 }

Condition Definition

# data/conditions/poisoned.toml
[poisoned]
name = "Poisoned"
description = "Taking poison damage each round"
category = "debuff"
damage_per_round = 5
damage_type = "poison"
default_duration = 3
stackable = false
icon = "poison"

[stunned]
name = "Stunned"
description = "Cannot act this round"
category = "debuff"
skip_turn = true
default_duration = 1
stackable = false
icon = "stun"

Equipment Slot Definition

# data/equipment_slots.toml
[[slots]]
id = "main_hand"
name = "Main Hand"
accepts = ["weapon"]
required = false

[[slots]]
id = "off_hand"
name = "Off Hand"
accepts = ["weapon", "shield"]
required = false
blocked_by = "two_handed"  # if main_hand has a two-handed weapon

[[slots]]
id = "head"
name = "Head"
accepts = ["armor_head"]
required = false

# ... etc for all 11 slots

Rarity Definition

# data/rarities.toml
[[rarities]]
id = "common"
name = "Common"
color = "#ffffff"
tier = 0
bonus_count = 0
has_signature = false
salvage_material = "common_fragment"
salvage_quantity = 2

[[rarities]]
id = "rare"
name = "Rare"
color = "#0070dd"
tier = 2
bonus_count = [1, 2]  # 1-2 random bonuses
has_signature = true
salvage_material = "rare_core"
salvage_quantity = 1

[[rarities]]
id = "legendary"
name = "Legendary"
color = "#ff8000"
tier = 4
bonus_count = 3
has_signature = true
has_gear_skill = true
salvage_material = "legendary_spark"
salvage_quantity = 1

Resource Definition

# data/resources.toml
[[resources]]
id = "stamina"
name = "Stamina"
max_base = 100
regen_per_round = 10
regen_on_rest = 50
color = "#4CAF50"
used_by_classes = ["vanguard", "pathfinder", "berserker"]

[[resources]]
id = "mana"
name = "Mana"
max_base = 80
regen_per_round = 5
regen_on_rest = 30
color = "#2196F3"
used_by_classes = ["arcanist", "hexbinder"]

[[resources]]
id = "fury"
name = "Fury"
max_base = 0  # starts at 0, builds during combat
regen_per_round = 0
gain_on_hit = 15
gain_on_take_damage = 10
color = "#F44336"
used_by_classes = ["berserker"]

Migration Strategy for Existing Feature Docs

The feature docs (00-18) reference hardcoded enums in several places. The principle going forward:

  1. Never define a Rust enum for game content. Use String / newtype wrapper validated against the GameData registry.
  2. Never use sqlx::Type on game content. Use TEXT columns in Postgres. The #[sqlx(transparent)] derive on the newtype wrapper handles serialization.
  3. Define all game content in data/ TOML files. Validate cross-references at startup.
  4. Feature 00 now includes the GameData registry as part of the foundation — it’s loaded before the API server starts accepting requests.
  5. Tests use a test GameData fixture loaded from a test_data/ directory with minimal content (1-2 of each type) rather than the full game data set.

Feature 00: Project Foundation

Overview

Set up the Rust Cargo workspace, database infrastructure, Docker Compose development environment, and CI pipeline. This is the skeleton that every subsequent feature builds on — no game logic yet, just the scaffolding to build, run, test, and deploy.

Technical Tasks

1. Initialize Cargo Workspace

  • Create root Cargo.toml with workspace members
  • Create crate stubs:
    • crates/api — binary, depends on db, types, game, jobs
    • crates/workers — binary, depends on db, types, game, jobs
    • crates/game — library
    • crates/db — library
    • crates/types — library
    • crates/jobs — library
  • Add shared dependencies to workspace Cargo.toml:
    • tokio (async runtime)
    • serde, serde_json (serialization)
    • sqlx (database, with postgres, runtime-tokio, tls-rustls features)
    • redis (with tokio-comp feature)
    • uuid (with v4, serde features)
    • chrono (timestamps, with serde feature)
    • tracing, tracing-subscriber (logging)
    • thiserror, anyhow (error handling)
  • Verify cargo build succeeds with empty crates
  • Verify cargo test runs (no tests yet, but harness works)

2. API Server Skeleton (crates/api)

  • Add Axum dependencies: axum, tower, tower-http (cors, tracing, compression)
  • Create main.rs with:
    • Tokio runtime initialization
    • Tracing subscriber setup (JSON format for structured logging)
    • Axum router with a health check endpoint: GET /api/health{ "status": "ok" }
    • Graceful shutdown on SIGTERM/SIGINT
  • Create AppState struct holding:
    • PgPool (SQLx connection pool)
    • redis::Client (Redis connection)
  • Wire AppState into Axum via Extension or State
  • Create src/error.rs — unified error type that converts to Axum responses with appropriate HTTP status codes
  • Create src/middleware/ directory with placeholder modules

3. Worker Binary Skeleton (crates/workers)

  • Create main.rs with:
    • Tokio runtime initialization
    • Tracing subscriber setup
    • CLI argument parsing (e.g., --scheduler flag) via clap
    • Placeholder job processing loop: poll Redis, log “no jobs”, sleep
    • Graceful shutdown

4. Database Setup (crates/db)

  • Add SQLx CLI as a dev dependency or document cargo install sqlx-cli
  • Create migrations/ directory
  • Create initial migration 0001_create_extensions.sql:
    • CREATE EXTENSION IF NOT EXISTS "pgcrypto"; (for gen_random_uuid())
  • Create src/lib.rs:
    • create_pool(database_url: &str) -> PgPool function
    • run_migrations(pool: &PgPool) function
  • Create src/models/mod.rs — empty, will hold row types
  • Create src/queries/mod.rs — empty, will hold query functions

5. Job Queue Foundation (crates/jobs)

  • Create Redis-backed delayed job queue:
    • enqueue(queue: &str, payload: &[u8], delay: Duration) — adds job to Redis sorted set with score = now + delay
    • enqueue_immediate(queue: &str, payload: &[u8]) — adds with score = now
    • poll(queue: &str) -> Option<Job>ZPOPMIN where score <= now
    • ack(job_id: &str) — remove from processing set
    • fail(job_id: &str, error: &str) — move to dead letter queue
  • Job struct: { id: String, queue: String, payload: Vec<u8>, enqueued_at: DateTime, attempts: u32 }
  • Use Redis ZADD/ZPOPMIN with timestamps as scores for delayed execution
  • Add retry logic: on failure, re-enqueue with exponential backoff (max 3 retries)

6. Docker Compose Development Environment

  • Create docker-compose.yml:
    • PostgreSQL 16 Alpine (port 5432, volume for persistence)
    • Valkey 7 Alpine (port 6379)
    • Mailpit (ports 8025 web UI, 1025 SMTP)
  • Create .env.example with:
    • DATABASE_URL=postgres://delve:devpassword@localhost:5432/delve
    • REDIS_URL=redis://localhost:6379
    • SMTP_HOST=localhost
    • SMTP_PORT=1025
  • Add .env to .gitignore

7. Configuration Management

  • Create crates/api/src/config.rs:
    • Load config from environment variables (with dotenvy for .env files in dev)
    • Struct: Config { database_url, redis_url, host, port, smtp_host, smtp_port }
    • Validate required fields on startup, panic with clear error if missing

8. CI Pipeline

  • Create .github/workflows/ci.yml:
    • Trigger on PR and push to main
    • Steps: cargo fmt --check, cargo clippy, cargo test, cargo build --release
    • Use actions-rs/toolchain or dtolnay/rust-toolchain
    • Cache cargo registry and target directory via Swatinem/rust-cache
    • Start PostgreSQL and Redis services for integration tests

9. Dockerfile

  • Create multi-stage Dockerfile:
    • Stage 1: cargo-chef to cache dependency compilation
    • Stage 2: Build release binaries
    • Stage 3: FROM debian:bookworm-slim (or Alpine) — copy binaries, set entrypoint
  • Produce two targets: delve-api and delve-workers
  • Verify docker build succeeds and images are < 50MB

10. SvelteKit Client Skeleton

  • Initialize SvelteKit project in client/ directory:
    • pnpm create svelte@latest client (skeleton project, TypeScript)
    • Install: tailwindcss, @tanstack/svelte-query, @tanstack/query-sync-storage-persister
    • Configure Tailwind with design token stubs (colors for rarity tiers, etc.)
    • Configure SvelteKit static adapter (SPA mode)
    • Configure Vite proxy: /apihttp://localhost:3000 in dev
  • Create root layout (+layout.svelte):
    • QueryClientProvider wrapper
    • Placeholder navigation shell
  • Create GET /api/health query to verify client↔server connectivity
  • Create lib/api/client.ts — base fetch wrapper with auth header injection

Tests

Unit Tests

  • crates/jobs: Test enqueue + poll returns job after delay has elapsed
  • crates/jobs: Test poll returns None when delay hasn’t elapsed
  • crates/jobs: Test ack removes job from processing set
  • crates/jobs: Test fail with retry re-enqueues with backoff
  • crates/jobs: Test fail after max retries moves to dead letter queue
  • crates/db: Test create_pool connects to test database
  • crates/db: Test run_migrations applies migrations without error
  • crates/api/config: Test config loads from env vars
  • crates/api/config: Test config panics on missing required fields

Integration Tests

  • API server starts and GET /api/health returns 200 with { "status": "ok" }
  • API server connects to PostgreSQL (pool creation succeeds)
  • API server connects to Redis (ping succeeds)
  • Worker binary starts and exits cleanly on SIGTERM
  • Job queue round-trip: enqueue → poll → ack (against real Redis)
  • Migrations run cleanly on a fresh database

Client Tests

  • SvelteKit builds without errors (pnpm build)
  • Health check query hits the API and receives a response (dev proxy test)

Feature 01: Authentication

Overview

User registration, login, logout, and session management. This is the gateway to every other feature — no game actions are possible without an authenticated user. Sessions are stored in Redis with opaque tokens. Passwords are hashed with Argon2id.

Dependencies

  • Feature 00 (Project Foundation)

Technical Tasks

1. Users Table Migration

  • Create migration 0002_create_users.sql:
    CREATE TABLE users (
        id              UUID PRIMARY KEY DEFAULT gen_random_uuid(),
        email           TEXT UNIQUE NOT NULL,
        password_hash   TEXT NOT NULL,
        patron_tier     SMALLINT DEFAULT 0,
        patron_expires  TIMESTAMPTZ,
        character_slots SMALLINT DEFAULT 2,
        bank_slots      SMALLINT DEFAULT 50,
        marketplace_slots SMALLINT DEFAULT 10,
        created_at      TIMESTAMPTZ DEFAULT now(),
        last_login      TIMESTAMPTZ
    );
    

2. User Model & Queries (crates/db)

  • Create src/models/user.rsUser struct with FromRow derive
  • Create src/queries/users.rs:
    • create_user(pool, email, password_hash) -> User
    • find_user_by_email(pool, email) -> Option<User>
    • find_user_by_id(pool, id) -> Option<User>
    • update_last_login(pool, id)

3. Password Hashing (crates/api)

  • Add argon2 crate dependency
  • Create src/auth/password.rs:
    • hash_password(password: &str) -> String — Argon2id with recommended params
    • verify_password(password: &str, hash: &str) -> bool

4. Session Management

  • Create src/auth/session.rs:
    • create_session(redis, user_id) -> String — generate random 32-byte token (hex-encoded), store in Redis with 30-day TTL as session:{token} → { user_id, expires_at }
    • validate_session(redis, token) -> Option<UserId> — lookup in Redis, return user_id if valid
    • destroy_session(redis, token) — delete from Redis
    • refresh_session(redis, token) — reset TTL to 30 days on each use

5. Auth Middleware

  • Create src/middleware/auth.rs:
    • Axum extractor AuthUser that reads Authorization: Bearer {token} header (or cookie)
    • Validates session via Redis
    • Returns 401 Unauthorized if missing or invalid
    • Populates AuthUser { user_id: Uuid } for downstream handlers

6. Auth Routes (crates/api)

  • Create src/routes/auth.rs:
    • POST /api/auth/register:
      • Validate: email format, password length (8-128 chars)
      • Check email not already taken (409 Conflict)
      • Hash password
      • Create user record
      • Create session
      • Return { token, user: { id, email } }
    • POST /api/auth/login:
      • Find user by email (401 if not found)
      • Verify password (401 if wrong)
      • Update last_login
      • Create session
      • Return { token, user: { id, email } }
    • POST /api/auth/logout:
      • Requires auth middleware
      • Destroy session
      • Return 204 No Content
    • GET /api/auth/me:
      • Requires auth middleware
      • Return current user info { id, email, patron_tier, character_slots }

7. Rate Limiting

  • Create src/middleware/rate_limit.rs:
    • Redis-based rate limiter using INCR + EXPIRE
    • Per-IP rate limiting for auth endpoints (10 req/min for register, 20 req/min for login)
    • Per-user rate limiting for authenticated endpoints (100 req/min default)
    • Return 429 Too Many Requests with Retry-After header when exceeded

8. Input Validation

  • Add validator crate
  • Create request structs with validation derives:
    • RegisterRequest { email: String, password: String } — email format, password length
    • LoginRequest { email: String, password: String }
  • Create ValidatedJson<T> Axum extractor that validates before passing to handler

9. Client Auth (client/)

  • Create lib/api/auth.ts:
    • register(email, password) — POST to /api/auth/register
    • login(email, password) — POST to /api/auth/login
    • logout() — POST to /api/auth/logout
    • getMe() — GET to /api/auth/me
  • Create lib/stores/auth.ts:
    • Svelte store holding current user + token
    • Persist token to localStorage
    • Auto-inject token into all API requests via the base fetch wrapper
  • Create auth pages:
    • routes/(auth)/login/+page.svelte — login form
    • routes/(auth)/register/+page.svelte — registration form
  • Create auth guard: redirect to /login if not authenticated when accessing (game) routes

Tests

Unit Tests

  • password::hash_password produces a valid Argon2id hash
  • password::verify_password returns true for correct password
  • password::verify_password returns false for wrong password
  • session::create_session stores a key in Redis with correct TTL
  • session::validate_session returns user_id for valid token
  • session::validate_session returns None for expired/invalid token
  • session::destroy_session removes the key from Redis
  • RegisterRequest validation rejects invalid email formats
  • RegisterRequest validation rejects passwords shorter than 8 chars
  • RegisterRequest validation accepts valid input

Integration Tests

  • POST /api/auth/register with valid data → 200, returns token + user
  • POST /api/auth/register with duplicate email → 409
  • POST /api/auth/register with invalid email → 422
  • POST /api/auth/register with short password → 422
  • POST /api/auth/login with correct credentials → 200, returns token
  • POST /api/auth/login with wrong password → 401
  • POST /api/auth/login with non-existent email → 401
  • GET /api/auth/me with valid token → 200, returns user
  • GET /api/auth/me without token → 401
  • POST /api/auth/logout destroys session (subsequent /me returns 401)
  • Rate limiter returns 429 after exceeding limit
  • Session persists across server restart (stored in Redis, not memory)

Feature 02: Character Creation

Overview

Players create characters by choosing a species, class, background, and distributing attribute points. Each user can have up to 2 characters for free (up to 6 with purchased slots). Characters are the core identity — all subsequent features operate on a selected character.

Dependencies

  • Feature 01 (Authentication)

Technical Tasks

1. Static Game Data — Species, Classes, Backgrounds

  • Create data/species/ directory with TOML files defining all 9 species:
    • Each species: name, description, attribute_bonuses (e.g., { might: 2, fortitude: 1 }), species_skill (name, description, passive effect)
    • Species: Ironborn, Verdani, Kharren, Sylphari, Thornkin, Ashenmere, Glimkin, Vexari, Ferathi
  • Create data/classes/ directory with TOML files defining all 9 classes:
    • Each class: name, description, primary_resource (stamina/mana/fury/etc.), starting_skills (list of skill IDs), subclasses (3 per class, with name + description — details deferred to Feature 04)
    • Classes: Vanguard, Shade, Arcanist, Warden, Pathfinder, Berserker, Songweaver, Oathblade, Hexbinder
  • Create data/backgrounds/ directory with TOML files defining all 10 backgrounds:
    • Each background: name, description, attribute_bonus (+1 to one attribute), passive_perk (name, effect description)
  • Create crates/game/src/data.rs:
    • Load functions: load_species(), load_classes(), load_backgrounds()
    • Use once_cell::sync::Lazy for global static access
    • Validate data on load (no missing references, attribute bonuses sum correctly)

2. Type Definitions (crates/types)

  • Create src/character.rs:
    • Species enum (9 variants) with Serialize/Deserialize/sqlx::Type
    • Class enum (9 variants)
    • Background enum (10 variants)
    • Attributes struct: { might, logic, speed, presence, fortitude, luck } — all u8
    • Character struct with all fields matching the DB schema
  • Create src/ids.rs:
    • CharacterId(Uuid) newtype with Serialize/Deserialize/FromRow support
    • UserId(Uuid) newtype

3. Characters Table Migration

  • Create migration 0003_create_characters.sql:
    • Full characters table with all columns from the technical architecture schema
    • Indexes on user_id and name
    • Check constraint: attributes between 1 and 99
    • Unique constraint on name

4. Character Model & Queries (crates/db)

  • Create src/models/character.rsCharacter struct with FromRow
  • Create src/queries/characters.rs:
    • create_character(pool, params) -> Character
    • find_characters_by_user(pool, user_id) -> Vec<Character>
    • find_character_by_id(pool, id) -> Option<Character>
    • find_character_by_name(pool, name) -> Option<Character>
    • delete_character(pool, id)
    • count_characters_by_user(pool, user_id) -> i64

5. Character Creation Validation (crates/game)

  • Create src/character_creation.rs:
    • validate_attributes(attributes: &Attributes, species: Species) -> Result<()>:
      • Base points: each attribute starts at 5, player distributes 40 points
      • Range: each base attribute 5–15 (before species bonuses)
      • Total distributed must equal 40
      • After species bonuses, final values must be 1–99
    • validate_name(name: &str) -> Result<()>:
      • Length: 2–24 characters
      • Allowed: alphanumeric + spaces + hyphens + apostrophes
      • No leading/trailing whitespace
      • No consecutive spaces
      • Profanity filter (basic word list — can be expanded later)
    • calculate_starting_attributes(base: &Attributes, species: Species, background: Background) -> Attributes:
      • Apply species bonuses
      • Apply background bonus (+1 to one attribute)
    • get_starting_equipment(class: Class) -> Vec<String>:
      • Return list of item template IDs for starting gear (deferred to Feature 05, return empty for now)

6. Character Routes (crates/api)

  • Create src/routes/characters.rs:
    • GET /api/characters:
      • Auth required
      • Return all characters owned by the authenticated user
      • Include: id, name, species, class, level, gold (summary view)
    • POST /api/characters:
      • Auth required
      • Body: { name, species, class, background, attributes: { might, logic, speed, presence, fortitude, luck } }
      • Validate user hasn’t exceeded character slot limit
      • Validate name uniqueness
      • Validate name format
      • Validate attribute distribution
      • Calculate final attributes (base + species + background bonuses)
      • Create character record
      • Return full character object
    • GET /api/characters/:id:
      • Auth required
      • Validate character belongs to authenticated user
      • Return full character details including all attributes, skills, gold, level, etc.
    • DELETE /api/characters/:id:
      • Auth required
      • Validate character belongs to authenticated user
      • Soft delete or hard delete (hard delete for now — cascade will handle related data)
      • Return 204

7. Character Ownership Middleware

  • Create src/middleware/character.rs:
    • Axum extractor CharacterOwner(Character):
      • Reads :id path parameter
      • Loads character from DB
      • Verifies character.user_id == auth_user.user_id
      • Returns 404 if character not found or not owned by user
    • This extractor will be reused by every endpoint that operates on a character

8. Client — Character Selection & Creation

  • Create routes/(game)/+page.svelte:
    • Character selection screen (list of user’s characters)
    • “Create New Character” button (disabled if at slot limit)
    • Selecting a character sets it as active in the Svelte store
  • Create routes/(game)/create-character/+page.svelte:
    • Step 1: Choose species (cards showing name, description, bonuses, species skill)
    • Step 2: Choose class (cards showing name, description, resource type, starting skills)
    • Step 3: Choose background (cards showing name, bonus, perk)
    • Step 4: Distribute attributes (point-buy UI with +/- buttons, live preview of final stats with bonuses)
    • Step 5: Choose name (text input with validation feedback)
    • Step 6: Review & confirm
  • Create lib/types/character.ts — TypeScript types matching the Rust character types
  • Create lib/api/queries/characters.ts — TanStack Query hooks for character CRUD

Tests

Unit Tests

  • validate_attributes: accepts valid 40-point distribution
  • validate_attributes: rejects total != 40
  • validate_attributes: rejects individual attribute < 5 or > 15
  • validate_attributes: correctly applies species bonuses
  • validate_name: accepts “Aldric the Bold”
  • validate_name: rejects empty string
  • validate_name: rejects names > 24 chars
  • validate_name: rejects names with special characters (e.g., <script>)
  • validate_name: rejects names with consecutive spaces
  • calculate_starting_attributes: correctly sums base + species + background
  • calculate_starting_attributes: Ironborn gets +2 Fortitude, +1 Might
  • Game data loading: all 9 species load without error
  • Game data loading: all 9 classes load without error
  • Game data loading: all 10 backgrounds load without error

Integration Tests

  • POST /api/characters with valid data → 201, character created with correct attributes
  • POST /api/characters with duplicate name → 409
  • POST /api/characters when at slot limit → 403 with clear error message
  • POST /api/characters with invalid attribute total → 422
  • POST /api/characters with invalid species → 422
  • GET /api/characters returns only characters owned by authenticated user
  • GET /api/characters/:id for own character → 200
  • GET /api/characters/:id for another user’s character → 404
  • DELETE /api/characters/:id for own character → 204, character gone
  • DELETE /api/characters/:id for another user’s character → 404
  • Character count correctly limits creation per user

Feature 03: Items & Inventory

Overview

The item system: gear templates, item instances with random properties, inventory management (backpack, equipped slots, bank), equipping/unequipping, and salvaging. This must be in place before combat or quests, since characters need gear to do anything.

Dependencies

  • Feature 02 (Character Creation)

Technical Tasks

1. Static Game Data — Item Templates

  • Create data/items/ directory with TOML files organized by category:
    • weapons/swords.toml, weapons/axes.toml, weapons/daggers.toml, weapons/bows.toml, weapons/staves.toml, weapons/wands.toml, weapons/shields.toml
    • armor/heavy.toml, armor/medium.toml, armor/light.toml
    • accessories/rings.toml, accessories/amulets.toml, accessories/cloaks.toml, accessories/belts.toml
    • consumables/potions.toml, consumables/scrolls.toml, consumables/supplies.toml
    • materials/crafting.toml (placeholder — filled in Feature 09)
  • Define item template struct:
    name, item_type, subtype, slot, rarity, level_req,
    base_stats: { damage?, armor?, evasion?, speed? },
    signature_effect? (for Rare+),
    skill_granted? (for Legendary/Artifact weapons)
    
  • Start with Tier 1 (level 1-10) items — enough to test the full system. Higher tiers added later.
  • Create crates/game/src/items.rs:
    • load_item_templates()HashMap<String, ItemTemplate>
    • ItemTemplate struct
    • EquipmentSlot enum: MainHand, OffHand, Head, Chest, Hands, Feet, Cloak, Ring1, Ring2, Amulet, Belt

2. Random Bonus Property System (crates/game)

  • Create src/item_generation.rs:
    • Define bonus property pools:
      • Offensive: bonus damage, crit chance, attack speed, armor penetration
      • Defensive: bonus armor, evasion, HP, damage reduction
      • Attribute: +might, +logic, +speed, +presence, +fortitude, +luck
      • Resource: +max resource, +resource regen
      • Utility: +gold find, +XP gain, +crafting speed
    • Define potency tiers: Minor, Standard, Major, Grand
    • generate_item(template_id: &str, rng: &mut impl Rng) -> Item:
      • Common: base stats only
      • Uncommon: base stats + 1 random bonus
      • Rare: base + signature effect + 1-2 random bonuses
      • Very Rare: base + signature + 2-3 random bonuses
      • Legendary: base + signature + 3 random bonuses + gear skill
      • Artifact: hand-defined (no random generation)
    • Bonus selection uses weighted random from the appropriate pool

3. Item & Inventory Tables Migration

  • Create migration 0004_create_items.sql:
    • items table: id, owner_id, template_id, rarity, enhancement, bonus_properties (JSONB), location, slot_index, created_at
    • Index on (owner_id), (owner_id, location)
    • artifacts table: template_id (PK), held_by, acquired_at

4. Item Model & Queries (crates/db)

  • Create src/models/item.rs:
    • Item struct with FromRow
    • ItemLocation enum serialized as text
    • BonusProperty struct (for JSONB deserialization)
  • Create src/queries/items.rs:
    • create_item(pool, owner_id, template_id, rarity, bonuses, location) -> Item
    • find_items_by_owner(pool, owner_id) -> Vec<Item>
    • find_items_by_location(pool, owner_id, location) -> Vec<Item>
    • find_equipped_items(pool, owner_id) -> Vec<Item>
    • find_item_by_id(pool, id) -> Option<Item>
    • update_item_location(pool, item_id, new_location, slot_index)
    • delete_item(pool, item_id)
    • count_items_in_location(pool, owner_id, location) -> i64

5. Equip/Unequip Logic (crates/game)

  • Create src/equipment.rs:
    • can_equip(character: &Character, item: &Item, slot: EquipmentSlot) -> Result<()>:
      • Check level requirement
      • Check class restrictions (if any)
      • Check slot compatibility (e.g., can’t put a sword in head slot)
      • Check two-handed weapon rules (main hand + off hand)
    • get_equipped_stats(items: &[Item]) -> EquippedStats:
      • Sum all base stats + bonus properties from equipped items
      • Return aggregated damage, armor, evasion, attribute bonuses, etc.

6. Salvage System (crates/game)

  • Create src/salvage.rs:
    • salvage_item(item: &Item) -> Vec<SalvageMaterial>:
      • Returns materials based on rarity (NOT level — per design doc)
      • Common → Common Fragments
      • Uncommon → Uncommon Shards
      • Rare → Rare Cores
      • Very Rare → Prismatic Essences
      • Legendary → Legendary Sparks
    • Material quantities scale with rarity, not item level

7. Inventory Routes (crates/api)

  • Create src/routes/inventory.rs:
    • GET /api/characters/:id/inventory:
      • Return all items grouped by location: { equipped: [], backpack: [], bank: [] }
      • Each item includes resolved template data (name, base stats) merged with instance data (bonuses, enhancement)
    • POST /api/characters/:id/equip:
      • Body: { item_id, slot }
      • Validate ownership, slot compatibility, level requirement
      • If slot already occupied, swap to backpack
      • Update item locations in DB
    • POST /api/characters/:id/unequip:
      • Body: { slot }
      • Move equipped item to backpack
      • Check backpack isn’t full
    • POST /api/characters/:id/salvage:
      • Body: { item_ids: [uuid] }
      • Validate all items owned and in backpack/bank
      • Cannot salvage equipped items
      • Delete items, grant materials (materials are items in backpack with type: material)
      • Return list of materials gained
    • POST /api/characters/:id/move-item:
      • Body: { item_id, to_location, to_index? }
      • Move between backpack ↔ bank
      • Validate capacity limits

8. Starting Equipment

  • Update character creation (Feature 02) to grant starting gear:
    • Each class gets a weapon + basic armor appropriate to their archetype
    • Items are Common rarity, level 1
    • Created as item instances and placed in equipped slots

9. Client — Inventory UI

  • Create routes/(game)/inventory/+page.svelte:
    • Equipment panel: visual grid of 11 gear slots (character paper doll layout)
    • Backpack panel: grid of items with drag-and-drop support
    • Bank panel: accessible tab, grid layout
    • Item tooltip on hover/tap: name, rarity color, base stats, bonus properties, level req, slot
    • Equip: drag from backpack to slot, or right-click → “Equip”
    • Unequip: click equipped item → “Unequip”
    • Salvage: select multiple items → “Salvage” button with confirmation
  • Create lib/types/item.ts — TypeScript types for items
  • Create lib/components/inventory/ItemTooltip.svelte — reusable tooltip component
  • Create lib/components/inventory/ItemGrid.svelte — reusable grid component

Tests

Unit Tests

  • generate_item: Common items have no bonus properties
  • generate_item: Rare items have signature effect + 1-2 bonuses
  • generate_item: Legendary items have 3 bonuses + gear skill reference
  • generate_item: deterministic with seeded RNG (same seed → same item)
  • can_equip: accepts valid weapon in main hand
  • can_equip: rejects item below level requirement
  • can_equip: rejects sword in head slot
  • can_equip: handles two-handed weapon (clears off-hand)
  • get_equipped_stats: correctly sums stats from multiple items
  • get_equipped_stats: includes bonus properties
  • salvage_item: Common → correct Common Fragments count
  • salvage_item: Rare → Rare Cores (not affected by item level)
  • Item template loading: all templates load without error, no missing references

Integration Tests

  • GET /api/characters/:id/inventory returns equipped + backpack + bank items
  • POST /api/characters/:id/equip moves item from backpack to slot
  • POST /api/characters/:id/equip swaps existing equipped item to backpack
  • POST /api/characters/:id/equip rejects item not owned by character
  • POST /api/characters/:id/unequip moves item to backpack
  • POST /api/characters/:id/unequip fails when backpack is full
  • POST /api/characters/:id/salvage deletes items and returns materials
  • POST /api/characters/:id/salvage rejects equipped items
  • POST /api/characters/:id/move-item moves item between backpack and bank
  • Character creation grants starting equipment in correct slots
  • Inventory respects backpack capacity limit (default 30 slots)
  • Bank respects bank capacity limit (default 50 slots, upgradeable)

Feature 04: Character Progression

Overview

Leveling (1-50), XP curves, attribute growth per level, subclass selection at level 10, feat selection at milestone levels, non-combat skill advancement, weapon proficiency tracking, and the Paragon system for post-50 horizontal progression.

Dependencies

  • Feature 02 (Character Creation)
  • Feature 03 (Items & Inventory) — for weapon proficiency tracking by weapon type

Technical Tasks

1. Static Game Data — Progression Tables

  • Create data/progression/:
    • xp_table.toml: XP required per level (1-50), designed for 8-12 months of regular play
    • attribute_growth.toml: attribute points gained per level (per design doc milestones)
    • feats.toml: all selectable feats with name, description, prerequisites, effects
    • subclasses.toml: 3 subclasses per class (27 total) with name, description, bonus_skills, passive_effects
  • Create data/skills/:
    • class_skills.toml: starting skills per class + skills unlocked at levels 5, 10, 15, 20, 25, 30
    • species_skills.toml: one unique passive skill per species
    • weapon_skills.toml: 10 skills per weapon type, unlocked at proficiency milestones (10, 20, 30, 40, 50, 60, 70, 80, 90, 100)

2. Progression Logic (crates/game)

  • Create src/progression.rs:
    • xp_for_level(level: u16) -> u64: lookup from XP table
    • check_level_up(current_level: u16, current_xp: u64) -> Option<LevelUpResult>:
      • If XP >= threshold, return new level + attribute points earned + any unlocks
      • Handle multi-level-up (if enough XP for several levels at once)
    • LevelUpResult: new_level, attribute_points, feat_slot_unlocked (bool), skills_unlocked, subclass_eligible (bool)
    • apply_level_up(character: &mut Character, result: &LevelUpResult):
      • Increment level, reduce XP by threshold, apply attribute points
  • Create src/feats.rs:
    • Feat selection rules: slots at levels 5, 12, 20, 28, 35, 42, 48
    • can_select_feat(character: &Character, feat_id: &str) -> Result<()>:
      • Check character has an open feat slot
      • Check prerequisites met (level, class, attribute minimums)
      • Check feat not already selected
    • apply_feat(character: &mut Character, feat_id: &str):
      • Add to character’s feat list

3. Weapon Proficiency (crates/game)

  • Create src/weapon_proficiency.rs:
    • WeaponType enum: Sword, Axe, Dagger, Bow, Staff, Wand, Shield, Mace, Spear
    • gain_proficiency(current: u16, amount: u16) -> u16: capped at 100
    • skills_unlocked_at(proficiency: u16) -> Vec<String>: return skill IDs unlocked at current proficiency
    • Proficiency gained from using the weapon in combat (calculated during simulation)

4. Non-Combat Skills (crates/game)

  • Create src/noncombat_skills.rs:
    • 12 skills: Athletics, Acrobatics, Stealth, Perception, Arcana, Nature, Religion, Persuasion, Deception, Intimidation, Medicine, Survival
    • Skills are 0-100, improved through encounter checks
    • check_skill(skill_value: u16, difficulty: u16, rng: &mut impl Rng) -> SkillCheckResult:
      • d100 roll vs. (skill_value + attribute_modifier)
      • Returns success/failure + margin

5. Subclass System

  • Create src/subclass.rs:
    • can_choose_subclass(character: &Character) -> bool: level >= 10 and subclass is None
    • valid_subclasses(class: Class) -> Vec<SubclassInfo>: returns 3 options for the class
    • apply_subclass(character: &mut Character, subclass_id: &str) -> Result<()>:
      • Validate character is eligible
      • Validate subclass belongs to character’s class
      • Set subclass (permanent, cannot be changed)
      • Grant subclass starting skills

6. Paragon System (crates/game)

  • Create src/paragon.rs:
    • Post-level-50 horizontal progression
    • Paragon XP required per level (uncapped, escalating)
    • Each paragon level grants a small bonus (e.g., +1 to a chosen attribute, +1% to a stat)
    • gain_paragon_xp(character: &mut Character, xp: u64): check for paragon level up
    • Paragon bonuses are marginal — depth, not power

7. Database Migrations

  • Create migration 0005_create_progression.sql:
    • weapon_proficiencies table: character_id, weapon_type, proficiency (PK: character_id + weapon_type)
    • skill_queues table: id, character_id, name, is_active, slots (JSONB), created_at (index on character_id)

8. Progression Queries (crates/db)

  • Create src/queries/progression.rs:
    • get_weapon_proficiencies(pool, character_id) -> Vec<WeaponProficiency>
    • update_weapon_proficiency(pool, character_id, weapon_type, new_value)
    • update_character_level(pool, character_id, new_level, new_xp, attribute_updates)
    • set_subclass(pool, character_id, subclass)
    • add_feat(pool, character_id, feat_id)

9. Progression Routes (crates/api)

  • Create src/routes/progression.rs (or extend characters.rs):
    • GET /api/characters/:id/progression:
      • Return: level, xp, xp_to_next, feats, subclass, weapon_proficiencies, non-combat skills, paragon_level
    • POST /api/characters/:id/choose-subclass:
      • Body: { subclass_id }
      • Validate eligibility, apply permanently
    • POST /api/characters/:id/choose-feat:
      • Body: { feat_id }
      • Validate feat slot available, prerequisites met
    • POST /api/characters/:id/allocate-attributes:
      • Body: { might: 1, speed: 1 } (unspent points from leveling)
      • Validate character has unspent points

10. Client — Character Sheet

  • Create routes/(game)/character/+page.svelte:
    • Character overview: name, species, class, subclass, level, XP bar
    • Attributes panel: all 6 attributes with base + bonus breakdown
    • Feats panel: selected feats + available slots with “Choose Feat” UI
    • Weapon proficiencies: bar chart per weapon type (0-100)
    • Non-combat skills: list with values
    • Subclass selection modal (appears at level 10 if unchosen)

Tests

Unit Tests

  • xp_for_level: returns correct XP for levels 1, 10, 25, 50
  • check_level_up: returns None when XP insufficient
  • check_level_up: returns correct result for single level up
  • check_level_up: handles multi-level-up correctly
  • can_select_feat: accepts valid feat selection
  • can_select_feat: rejects feat already selected
  • can_select_feat: rejects when no feat slot available
  • can_select_feat: rejects when prerequisites not met
  • can_choose_subclass: true at level 10 with no subclass
  • can_choose_subclass: false at level 9
  • can_choose_subclass: false when subclass already chosen
  • valid_subclasses: returns exactly 3 for each class
  • gain_proficiency: caps at 100
  • skills_unlocked_at: returns correct skills at proficiency milestones
  • check_skill: d100 against skill value produces expected pass/fail distribution (statistical test with seeded RNG)
  • Paragon XP escalation: each level requires more than the last

Integration Tests

  • GET /api/characters/:id/progression returns all progression data
  • POST /api/characters/:id/choose-subclass permanently sets subclass
  • POST /api/characters/:id/choose-subclass second call → 409 (already chosen)
  • POST /api/characters/:id/choose-feat adds feat to character
  • POST /api/characters/:id/choose-feat at limit → 409
  • POST /api/characters/:id/allocate-attributes distributes unspent points
  • POST /api/characters/:id/allocate-attributes rejects if no unspent points
  • Weapon proficiency persists across requests

Feature 05: Skill Queue

Overview

The skill queue is Delve’s core strategic system. Players build an ordered list of 6-10 combat skills with optional conditions. The server executes this queue during combat simulation. This feature covers building, saving, validating, and managing multiple named queues.

Dependencies

  • Feature 04 (Character Progression) — for skill unlocks and weapon proficiency

Technical Tasks

1. Static Game Data — Skills

  • Flesh out data/skills/ TOML files (started in Feature 04) with full combat skill details:
    • Per skill: id, name, description, type (attack/heal/buff/debuff/utility), resource_cost (type + amount), cooldown (rounds), base_damage/healing, success_modifier, initiative_modifier, target_type (single/aoe/self/ally), conditions_applied, weapon_type_required
    • Weapon skills: 10 per weapon type (sword, axe, dagger, bow, staff, wand, shield, mace, spear)
    • Class skills: 8-12 per class, unlocked at level milestones
    • Species skills: 1 passive per species (not queued — applied automatically)
    • Gear skills: defined on Legendary/Artifact weapon templates (not in skills data — on item templates)

2. Skill Queue Types (crates/types)

  • Create src/skill.rs:
    • SkillQueueSlot { skill_id: String, condition: QueueCondition }
    • QueueCondition enum with all condition variants:
      • Always
      • IfHpBelow { threshold: u8 }
      • IfHpAbove { threshold: u8 }
      • IfTargetHpBelow { threshold: u8 }
      • IfEnemyCountAbove { count: u8 }
      • IfEnemyCountBelow { count: u8 }
      • IfAllyHpBelow { threshold: u8 }
      • IfResourceAbove { resource: ResourceType, amount: u16 }
      • IfResourceBelow { resource: ResourceType, amount: u16 }
      • IfHasCondition { condition: StatusEffect }
      • IfTargetHasCondition { condition: StatusEffect }
    • ResourceType enum: Stamina, Momentum, Mana, Devotion, Focus, Fury, Resonance, Zeal, Essence

3. Skill Queue Validation (crates/game)

  • Create src/skill_queue.rs:
    • validate_queue(character: &Character, slots: &[SkillQueueSlot], proficiencies: &[WeaponProficiency], equipped: &[Item]) -> Result<()>:
      • Queue length: 1-10 slots (minimum 1, maximum 10)
      • Every skill_id must be known by the character (from class, weapon proficiency, or equipped gear)
      • Weapon skills require the matching weapon type equipped
      • Conditions must reference valid resource types for the character’s class
      • Thresholds must be in valid ranges (0-100 for HP%, valid amounts for resources)
      • Must have at least one Always condition or the queue may never fire
    • get_available_skills(character: &Character, proficiencies: &[WeaponProficiency], equipped: &[Item]) -> Vec<SkillInfo>:
      • Return all skills the character can use based on class, weapon proficiency, and gear
      • Used by the client to populate the skill picker

4. Skill Queue Database Operations

  • Already created skill_queues table in Feature 04 migration
  • Create src/queries/skill_queues.rs:
    • create_skill_queue(pool, character_id, name, slots_json) -> SkillQueue
    • find_skill_queues(pool, character_id) -> Vec<SkillQueue>
    • find_active_queue(pool, character_id) -> Option<SkillQueue>
    • update_skill_queue(pool, id, name?, slots_json?)
    • set_active_queue(pool, character_id, queue_id) — deactivates all others, activates this one
    • delete_skill_queue(pool, id)

5. Skill Queue Routes (crates/api)

  • Create src/routes/skill_queues.rs:
    • GET /api/characters/:id/skill-queues:
      • Return all saved queues for the character (each with name, is_active, slots)
    • POST /api/characters/:id/skill-queues:
      • Body: { name, slots: [{ skill_id, condition }] }
      • Validate queue (all skills owned, conditions valid)
      • Save to DB
      • Return created queue
    • PUT /api/characters/:id/skill-queues/:queue_id:
      • Update name and/or slots
      • Re-validate if slots changed
    • DELETE /api/characters/:id/skill-queues/:queue_id:
      • Cannot delete the active queue (must activate another first)
    • POST /api/characters/:id/skill-queues/:queue_id/activate:
      • Set as active queue (used for the next run)
    • GET /api/characters/:id/available-skills:
      • Return all skills the character can currently use (for the queue builder UI)

6. Client — Skill Queue Builder

  • Create routes/(game)/character/skill-queue/+page.svelte:
    • Queue selector: dropdown of saved queues, “New Queue” button
    • Queue builder:
      • Ordered list of skill slots (drag-and-drop reordering)
      • Each slot shows: skill icon/name + condition dropdown
      • “Add Skill” button opens skill picker
      • Skill picker: filterable list of available skills grouped by source (class, weapon, gear)
      • Condition editor: dropdown per slot with type + threshold input
    • Save/rename/delete queue buttons
    • “Set Active” button
    • Validation feedback: highlight invalid slots, show error messages
  • Create lib/components/character/SkillQueueBuilder.svelte
  • Create lib/components/character/SkillPicker.svelte
  • Create lib/components/character/ConditionEditor.svelte

Tests

Unit Tests

  • validate_queue: accepts valid queue with all skills owned
  • validate_queue: rejects empty queue
  • validate_queue: rejects queue > 10 slots
  • validate_queue: rejects skill not owned by character
  • validate_queue: rejects weapon skill without matching weapon equipped
  • validate_queue: rejects invalid condition threshold (e.g., HP > 100%)
  • validate_queue: warns (but allows) queue with no Always fallback
  • get_available_skills: returns class skills for character’s class
  • get_available_skills: returns weapon skills up to current proficiency
  • get_available_skills: returns gear skills from equipped Legendary weapon
  • get_available_skills: doesn’t return skills for unequipped weapon types
  • QueueCondition serialization round-trips correctly (serde JSON)

Integration Tests

  • GET /api/characters/:id/skill-queues returns empty list for new character
  • POST /api/characters/:id/skill-queues creates queue and returns it
  • POST /api/characters/:id/skill-queues with invalid skill → 422
  • PUT /api/characters/:id/skill-queues/:id updates name and slots
  • POST /api/characters/:id/skill-queues/:id/activate sets active flag
  • Only one queue is active at a time (activating one deactivates others)
  • DELETE on active queue → 409
  • GET /api/characters/:id/available-skills returns skills based on class + proficiency + gear
  • Queue slots JSONB round-trips correctly (stored and retrieved identically)

Feature 06: Combat Engine

Overview

The heart of Delve: the server-side simulation engine that resolves combat encounters. Uses d100 percentile dice, processes skill queues round-by-round in initiative order, applies damage/healing/conditions, and produces a detailed log of every action and roll. This is a pure game logic feature — no API routes yet (that’s Feature 07).

Dependencies

  • Feature 05 (Skill Queue) — for skill definitions and queue validation
  • Feature 03 (Items & Inventory) — for equipped gear stats

Technical Tasks

1. Static Game Data — Creatures

  • Create data/creatures/ directory with TOML files:
    • Organized by zone/theme: goblins.toml, undead.toml, beasts.toml, etc.
    • Per creature: id, name, level, hp, attributes (might/logic/speed/presence/fortitude/luck), armor, evasion, skills (ordered list — creature’s own “queue”), loot_table_id, xp_reward
    • Start with 15-20 creatures for levels 1-10 (enough to test the engine)
    • Boss creatures: higher stats, multi-phase (phase 2 activates at HP threshold with new skill list)

2. Combat Types (crates/types)

  • Create src/combat.rs:
    • CombatState: tracks all participants, HP, resources, active conditions, round number
    • Participant: id, name, is_player, hp, max_hp, resources, attributes, armor, evasion, skill_queue, active_conditions, initiative_roll
    • CombatAction: the result of a single skill execution (actor, target, skill, roll, hit, damage, healing, conditions applied)
    • RoundLog: list of actions + condition tick results for one round
    • EncounterLog: list of rounds + outcome for one encounter
    • RunLog: list of encounter logs + final status
    • EncounterOutcome: Victory, Survived, PartyWipe, Fled
    • RunStatus: Completed, Failed
    • StatusEffect enum: Poisoned, Bleeding, Burning, Stunned, Blinded, Slowed, Weakened, Shielded, Regenerating, Empowered, Hasted, etc.
    • Condition: effect type, duration (rounds remaining), source_id, potency

3. d100 Roll System (crates/game)

  • Create src/combat/rolls.rs:
    • roll_d100(rng: &mut impl Rng) -> u8: returns 1-100
    • calculate_hit_chance(attacker: &Participant, defender: &Participant, skill: &SkillDef) -> u8:
      • Base: 50% + (attacker relevant attribute - defender relevant attribute) + skill success_modifier
      • Clamp to 5-95 (before crit/fail rules)
    • is_critical(roll: u8, luck: u8) -> bool: roll <= 5 (modified by luck)
    • is_critical_fail(roll: u8, luck: u8) -> bool: roll >= 96 (modified by luck)
    • calculate_damage(base_damage: (u16, u16), attacker: &Participant, defender: &Participant, is_crit: bool, rng: &mut impl Rng) -> u32:
      • Roll between base damage range
      • Add might modifier (for physical) or logic modifier (for magic)
      • Subtract defender armor (physical) or resistance (magic)
      • Critical: double damage
      • Floor at 1 (always deal at least 1 damage)

4. Initiative System (crates/game)

  • Create src/combat/initiative.rs:
    • roll_initiative(participant: &Participant, rng: &mut impl Rng) -> u16:
      • Base: Speed attribute + weapon speed modifier
      • Add d100 roll
      • Lower total = faster (acts first)
    • sort_by_initiative(participants: &mut [Participant]):
      • Sort ascending (lowest initiative acts first)

5. Condition System (crates/game)

  • Create src/combat/conditions.rs:
    • apply_condition(target: &mut Participant, condition: Condition):
      • Add to active conditions (or refresh duration if already present)
    • tick_conditions(participant: &mut Participant, log: &mut Vec<ConditionTick>):
      • For each active condition:
        • Apply per-round effect (poison damage, regen healing, etc.)
        • Decrement duration
        • Remove if expired
      • Log all effects
    • has_condition(participant: &Participant, effect: StatusEffect) -> bool
    • Condition effects:
      • Poisoned: X damage per round
      • Bleeding: X damage per round, reduced healing
      • Burning: X fire damage per round
      • Stunned: skip next action
      • Blinded: -30% hit chance
      • Slowed: +50 initiative (acts later)
      • Weakened: -25% damage
      • Shielded: absorb X damage before HP loss
      • Regenerating: heal X per round
      • Empowered: +25% damage
      • Hasted: -25 initiative (acts sooner)

6. Skill Queue Execution (crates/game)

  • Create src/combat/execution.rs:
    • evaluate_queue(participant: &Participant, combat_state: &CombatState) -> Option<&SkillQueueSlot>:
      • Iterate queue in order
      • For each slot, evaluate condition against current combat state
      • Return first skill whose condition is met AND resource cost can be paid
      • Return None if no valid skill found (participant passes turn)
    • execute_skill(actor: &mut Participant, target: &mut Participant, skill: &SkillDef, rng: &mut impl Rng) -> CombatAction:
      • Deduct resource cost from actor
      • Roll d100 for hit
      • Calculate damage/healing if hit
      • Apply conditions if hit
      • Handle AoE (apply to multiple targets)
      • Return CombatAction log entry
    • select_target(actor: &Participant, skill: &SkillDef, combat_state: &CombatState) -> Option<ParticipantId>:
      • Single target attack: target enemy with lowest HP
      • AoE: all enemies
      • Self: the actor
      • Ally heal: ally with lowest HP

7. Encounter Resolution (crates/game)

  • Create src/combat/encounter.rs:
    • resolve_combat_encounter(players: Vec<Participant>, enemies: Vec<Participant>, rng: &mut impl Rng) -> EncounterLog:
      • Roll initiative for all participants
      • Loop rounds (max 50 per encounter):
        1. For each participant in initiative order:
          • If dead/stunned, skip
          • Evaluate skill queue → get skill
          • Select target
          • Execute skill
          • Log action
        2. Tick conditions on all participants
        3. Check end conditions:
          • All enemies dead → Victory
          • All players dead → PartyWipe
          • Round limit reached → draw (treated as Victory with reduced rewards)
      • Return EncounterLog with all rounds and outcome

8. Non-Combat Encounter Handlers (crates/game)

  • Create src/combat/encounters_noncombat.rs:
    • resolve_trap(party: &[CharacterSnapshot], trap: &TrapDef, rng: &mut impl Rng) -> EncounterLog:
      • Skill check (Perception to detect, Acrobatics/Athletics to avoid)
      • Failure: party takes damage
    • resolve_decision(party: &[CharacterSnapshot], decision: &DecisionDef, rng: &mut impl Rng) -> EncounterLog:
      • Auto-pick based on highest relevant skill in party
      • Each choice leads to different outcomes (bonus loot, skip encounters, etc.)
    • resolve_hazard(party: &[CharacterSnapshot], hazard: &HazardDef, rng: &mut impl Rng) -> EncounterLog:
      • Environmental damage, skill checks to mitigate
    • resolve_rest_point(party: &mut [Participant]) -> EncounterLog:
      • Restore HP by 25%, restore some resources
    • resolve_puzzle(party: &[CharacterSnapshot], puzzle: &PuzzleDef, rng: &mut impl Rng) -> EncounterLog:
      • Logic/Arcana/Perception checks, success grants bonus

9. Full Run Simulation (crates/game)

  • Create src/simulation.rs:
    • SimulationContext: run record, party snapshots, quest definition, seeded RNG, log builder
    • resolve_run(ctx: &mut SimulationContext) -> RunResult:
      • For each encounter in quest:
        • Create participants from party snapshots + encounter enemies
        • Dispatch to appropriate resolver (combat, trap, decision, etc.)
        • Record encounter log
        • If party wipe → return Failed
        • Carry forward HP/resource state between encounters
      • All encounters survived → calculate rewards (XP, gold, loot)
      • Return RunResult with status, full log, and rewards
    • ChaCha8Rng seeded from blake3::hash(run_id + started_at) for deterministic replay

10. Loot Resolution (crates/game)

  • Create src/loot.rs:
    • roll_loot(quest: &QuestDefinition, difficulty: Difficulty, encounters_completed: usize, rng: &mut impl Rng) -> Vec<GeneratedItem>:
      • Reference quest’s loot table
      • Roll for each encounter’s loot drop (chance based on difficulty)
      • Generate items via item_generation::generate_item
      • Bonus chest for completing all encounters
    • Loot tables defined in data/loot_tables/ TOML files:
      • Each table: list of { template_id, weight, rarity_weights: { common: 60, uncommon: 30, rare: 10 } }

Tests

Unit Tests

  • roll_d100: always returns 1-100 (fuzz with 10,000 rolls)
  • calculate_hit_chance: 50% base when attacker/defender attributes equal
  • calculate_hit_chance: higher attacker stat → higher chance
  • calculate_hit_chance: clamped to 5-95 range
  • is_critical: roll of 3 is critical, roll of 50 is not
  • is_critical_fail: roll of 98 is critical fail
  • calculate_damage: critical doubles damage
  • calculate_damage: armor reduces damage
  • calculate_damage: minimum 1 damage
  • roll_initiative: lower speed → higher initiative value (slower)
  • sort_by_initiative: sorts fastest first
  • apply_condition: adds condition to participant
  • apply_condition: refreshes duration if already present
  • tick_conditions: poison deals damage each round
  • tick_conditions: removes expired conditions
  • tick_conditions: stunned participant is flagged
  • evaluate_queue: returns first matching skill
  • evaluate_queue: skips skills whose conditions aren’t met
  • evaluate_queue: skips skills when resource cost can’t be paid
  • evaluate_queue: returns None when nothing matches
  • execute_skill: deducts resource cost
  • execute_skill: applies conditions on hit
  • execute_skill: AoE hits all enemies
  • resolve_combat_encounter: party wins when all enemies die
  • resolve_combat_encounter: party wipe when all players die
  • resolve_combat_encounter: respects 50-round limit
  • resolve_combat_encounter: initiative order is respected
  • resolve_combat_encounter: deterministic with same seed (run twice → identical log)
  • resolve_trap: Perception check succeeds/fails correctly
  • resolve_rest_point: restores HP by 25%
  • resolve_run: processes all encounters in sequence
  • resolve_run: stops on party wipe
  • resolve_run: carries HP state between encounters
  • roll_loot: higher difficulty → better rarity distribution
  • roll_loot: deterministic with seeded RNG

Integration Tests

  • (None — this is pure game logic with no DB or API. All tests are unit tests.)
  • Full simulation test: create a party with known stats vs. known enemies, run simulation with fixed seed, assert exact sequence of events in the log

Feature 07: Quests & Dungeon Runs

Overview

The core gameplay loop: browse the quest board, start a run (which consumes real time), and review the results when it completes. This feature connects the combat engine (Feature 06) to the API and job queue, making the game actually playable.

Dependencies

  • Feature 06 (Combat Engine)
  • Feature 05 (Skill Queue) — active queue used for the run
  • Feature 03 (Items & Inventory) — equipped gear snapshot, loot rewards

Technical Tasks

1. Static Game Data — Quests

  • Create data/quests/ directory:
    • bounties/ — short quests (1-3 encounters, 15-45 min)
    • questlines/ — medium quests (5-8 encounters, 1-3 hours)
    • dungeon_crawls/ — long quests (10-20 encounters, 3-8 hours)
    • Per quest: id, name, type, level_range, base_duration_secs, encounters (ordered list), loot_table, difficulty_options, description, zone
    • Each encounter: type (combat/trap/decision/hazard/rest/puzzle), enemy_ids (for combat), difficulty_class (for skill checks), description
    • Start with 10-15 quests covering levels 1-10

2. Quest Board Logic (crates/game)

  • Create src/quest_board.rs:
    • generate_quest_board(character_level: u16, zone: Option<&str>, rng: &mut impl Rng) -> Vec<QuestBoardEntry>:
      • Return 6-10 level-appropriate quests
      • Mix of bounties, questlines, and dungeon crawls
      • Refreshes every 6 hours (timestamp-seeded for consistency)
    • QuestBoardEntry: quest_id, name, type, difficulty, estimated_duration, encounter_count, level_range, recommended_attributes
    • calculate_run_duration(quest: &QuestDefinition, difficulty: Difficulty, is_patron: bool) -> Duration:
      • Base duration from quest data
      • Multiply by difficulty modifier (Trivial 0.5x, Normal 1x, Hard 1.5x, Deadly 2x)
      • Patron: multiply by 0.667 (50% faster = 2/3 time)

3. Run Management — Database

  • Create migration 0006_create_runs.sql:
    • runs table: id, character_id, quest_id, difficulty, status (in_progress/completed/failed), skill_queue (JSONB snapshot), loadout (JSONB snapshot), supplies (JSONB snapshot), party_id, started_at, completes_at, completed_at, run_log (JSONB), rewards (JSONB)
    • Indexes: character_id, status WHERE in_progress, completes_at WHERE in_progress

4. Run Queries (crates/db)

  • Create src/queries/runs.rs:
    • create_run(pool, params) -> Run
    • find_active_run(pool, character_id) -> Option<Run>
    • find_run_by_id(pool, id) -> Option<Run>
    • find_runs_by_character(pool, character_id, limit, offset) -> Vec<Run>
    • complete_run(pool, run_id, status, run_log, rewards)

5. Run Start Flow (crates/api)

  • Create src/routes/runs.rs:
    • GET /api/quest-board?character_id=:
      • Generate quest board for character’s level
      • Return list of available quests with details
    • POST /api/runs:
      • Body: { character_id, quest_id, difficulty }
      • Validations:
        • Character not already in a run
        • Character meets quest level requirements
        • Character has an active skill queue
        • Character has gear equipped (at minimum a weapon)
      • Snapshot the character’s current state:
        • Skill queue (copied, not referenced — changes after start don’t affect the run)
        • Equipped gear (stats frozen at start time)
        • Supplies (deducted from inventory at start)
      • Calculate completes_at timestamp
      • Create run record (status: in_progress)
      • Enqueue delayed job: resolve-run with delay = duration
      • Return { run_id, completes_at }

6. Run Resolution Worker (crates/workers)

  • Create src/simulation_worker.rs:
    • Register job handler for resolve-run queue
    • On job received:
      1. Load run record from DB
      2. Load character snapshot + quest definition
      3. Build SimulationContext with seeded RNG
      4. Call resolve_run() from the game crate
      5. Write results to DB:
        • Update run: status, completed_at, run_log (JSONB), rewards
        • If success: grant XP, gold, loot items to character
        • Update weapon proficiency (based on weapon used)
        • Check for level up, apply if needed
      6. Create notification record (Feature 14)
      7. If character has push enabled, send push notification

7. Run Results & History (crates/api)

  • Extend src/routes/runs.rs:
    • GET /api/runs/:id:
      • Return run details: status, quest info, timestamps
      • If completed: include run_log, rewards, failure analysis (if failed)
    • GET /api/characters/:id/runs:
      • Paginated run history
      • Summary view: quest name, difficulty, status, rewards, date
    • POST /api/runs/:id/collect:
      • Collect loot rewards from a completed run
      • Move items from run rewards into character’s backpack
      • Grant XP and gold to character
      • Idempotent (can’t collect twice)

8. Supplies System

  • Define supply items in data/items/consumables/supplies.toml:
    • Rations (restore HP during rest encounters)
    • Torches (improve Perception in dark encounters)
    • Healing Potions (emergency heal — auto-used when HP < 20%)
    • Antidotes (cure poison)
    • Repair Kits (prevent gear durability loss)
  • POST /api/runs deducts selected supplies from inventory at run start
  • Supplies affect encounter resolution (checked during simulation)

9. Client — Quest Board & Runs

  • Create routes/(game)/quest-board/+page.svelte:
    • Quest board: list of available quests as cards
    • Each card: quest name, type badge, difficulty selector, encounter count, estimated duration, level range, reward preview
    • “Start Run” button per quest → confirmation modal showing:
      • Active skill queue summary
      • Equipped gear summary
      • Supply selection (optional)
      • Estimated completion time
  • Create routes/(game)/runs/+page.svelte:
    • Active run panel (if any): quest name, progress bar to completesAt, countdown timer
    • Run history: paginated list of past runs
  • Create routes/(game)/runs/[id]/+page.svelte:
    • Run result detail page
    • Encounter-by-encounter timeline (collapsible)
    • Each encounter: rounds, actions, rolls, outcomes (the Run Replay Viewer from the tech architecture)
    • Loot display with “Collect All” button
    • If failed: failure analysis (which encounter, what went wrong)
  • Wire polling: active run status polls every 60s; on timer expiry, immediate refetch

Tests

Unit Tests

  • generate_quest_board: returns level-appropriate quests
  • generate_quest_board: includes mix of quest types
  • generate_quest_board: deterministic for same time window + seed
  • calculate_run_duration: Patron gets 2/3 time
  • calculate_run_duration: difficulty modifier applied correctly

Integration Tests

  • GET /api/quest-board returns quests appropriate to character level
  • POST /api/runs creates run with correct completes_at timestamp
  • POST /api/runs snapshots skill queue and loadout
  • POST /api/runs deducts supplies from inventory
  • POST /api/runs rejects if character already in a run
  • POST /api/runs rejects if no active skill queue
  • POST /api/runs rejects if quest level too high
  • GET /api/runs/:id returns in_progress run with completes_at
  • Worker resolves run and updates DB with results and log
  • Worker grants XP and gold to character on successful run
  • Worker creates loot items in character’s rewards
  • Worker updates weapon proficiency after run
  • Worker triggers level-up if XP threshold reached
  • POST /api/runs/:id/collect moves loot to backpack and grants XP/gold
  • POST /api/runs/:id/collect second call → 409 (already collected)
  • GET /api/characters/:id/runs returns paginated history
  • Full end-to-end: create character → equip gear → set queue → start run → worker resolves → collect loot → verify character state updated

Feature 08: Crafting & Gathering

Overview

Two parallel idle activity systems: gathering expeditions (send character to mine/herb/log/skin for 1-12 hours) and crafting (combine materials into items over 15 min-12 hours). Both run concurrently with dungeon runs. Crafting has 5 professions, gathering has 4. Each has a skill level (1-100) that unlocks higher-tier content.

Dependencies

  • Feature 03 (Items & Inventory) — materials are items, crafted items go to backpack
  • Feature 00 (Job Queue) — delayed jobs for completion timers

Technical Tasks

1. Static Game Data

  • Create data/gathering/:
    • mining.toml: 5 tiers of mining nodes (Copper→Iron→Steel→Mithril→Adamantine), zones where they’re found, yield per tier, skill requirement per tier
    • herbalism.toml: 5 tiers of herbs
    • logging.toml: 5 tiers of wood
    • skinning.toml: 5 tiers of leather/hide
    • Each tier: required skill level, expedition durations (1/3/6/12 hours), yield range, rare material chance
  • Create data/crafting/:
    • blacksmithing.toml: recipes for weapons and heavy armor
    • alchemy.toml: recipes for potions, elixirs, antidotes
    • enchanting.toml: recipes for enchantments (applied to gear)
    • cooking.toml: recipes for food buffs
    • jewelcrafting.toml: recipes for rings and amulets
    • Per recipe: id, name, profession, skill_req, materials (list of material_id + quantity), result_item_template_id, result_rarity, crafting_time_secs, critical_bonus (what happens on critical craft)

2. Database Migrations

  • Create migration 0007_create_crafting.sql:
    • crafting_proficiencies: character_id, profession, skill_level (PK: character_id + profession)
    • crafting_jobs: id, character_id, recipe_id, status, started_at, completes_at, result_item_id, is_critical
    • gathering_expeditions: id, character_id, profession, zone, tier, status, started_at, completes_at, yields (JSONB)
    • known_recipes: character_id, recipe_id, learned_at (PK: character_id + recipe_id)
    • Indexes on character_id for all tables

3. Gathering Logic (crates/game)

  • Create src/gathering.rs:
    • can_start_expedition(character_proficiency: u16, tier: u8) -> bool
    • calculate_expedition_duration(tier: u8, hours: u8, is_patron: bool) -> Duration
    • resolve_expedition(profession: &str, tier: u8, skill_level: u16, rng: &mut impl Rng) -> ExpeditionResult:
      • Calculate material yields (base + skill bonus)
      • Roll for rare materials (5% base, +0.1% per skill level)
      • Calculate skill XP gained
    • ExpeditionResult: materials (vec of id + quantity), skill_xp, rare_finds

4. Crafting Logic (crates/game)

  • Create src/crafting.rs:
    • can_craft(character: &Character, recipe: &Recipe, inventory: &[Item]) -> Result<()>:
      • Check profession skill level meets requirement
      • Check all materials available in inventory
      • Check recipe is known
    • calculate_craft_duration(recipe: &Recipe, is_patron: bool) -> Duration
    • resolve_craft(recipe: &Recipe, skill_level: u16, rng: &mut impl Rng) -> CraftResult:
      • Generate result item via item_generation::generate_item
      • Roll for critical craft: 5% base + 0.15% per skill level (max 20%)
      • Critical: bump rarity by one tier (e.g., Rare → Very Rare)
      • Calculate skill XP gained
    • CraftResult: item (GeneratedItem), is_critical, skill_xp

5. Queries (crates/db)

  • Create src/queries/crafting.rs:
    • get_crafting_proficiencies(pool, character_id) -> Vec<CraftingProficiency>
    • update_crafting_proficiency(pool, character_id, profession, new_level)
    • get_known_recipes(pool, character_id) -> Vec<String> (recipe IDs)
    • learn_recipe(pool, character_id, recipe_id)
    • create_crafting_job(pool, params) -> CraftingJob
    • find_active_crafting_jobs(pool, character_id) -> Vec<CraftingJob>
    • complete_crafting_job(pool, job_id, result_item_id, is_critical)
    • create_gathering_expedition(pool, params) -> GatheringExpedition
    • find_active_expeditions(pool, character_id) -> Vec<GatheringExpedition>
    • complete_expedition(pool, expedition_id, yields_json)

6. Crafting & Gathering Workers (crates/workers)

  • Create src/crafting_worker.rs:
    • Register handler for resolve-craft queue
    • On job: load crafting job, resolve craft, create result item, update proficiency, complete job, create notification
  • Create src/gathering_worker.rs:
    • Register handler for resolve-gathering queue
    • On job: load expedition, resolve expedition, create material items in backpack, update proficiency, complete expedition, create notification

7. API Routes (crates/api)

  • Create src/routes/crafting.rs:
    • GET /api/characters/:id/crafting/proficiencies: all profession levels
    • GET /api/characters/:id/crafting/recipes: known recipes with craftability status (has materials?)
    • POST /api/crafting/start:
      • Body: { character_id, recipe_id }
      • Validate: known recipe, has materials, meets skill level
      • Deduct materials from inventory
      • Create crafting job, enqueue delayed job
      • Return { job_id, completes_at }
    • GET /api/characters/:id/crafting/active: list active crafting jobs with timers
    • POST /api/crafting/:job_id/collect: collect completed craft result
  • Create src/routes/gathering.rs:
    • GET /api/characters/:id/gathering/proficiencies: all gathering profession levels
    • POST /api/gathering/start:
      • Body: { character_id, profession, zone, tier, duration_hours }
      • Validate: meets skill level for tier
      • Create expedition, enqueue delayed job
      • Return { expedition_id, completes_at }
    • GET /api/characters/:id/gathering/active: list active expeditions with timers
    • POST /api/gathering/:id/collect: collect expedition yields

8. Client — Crafting & Gathering UI

  • Create routes/(game)/crafting/+page.svelte:
    • Profession tabs (Blacksmithing, Alchemy, Enchanting, Cooking, Jewelcrafting)
    • Recipe browser: filterable list, shows materials needed, craftable indicator
    • Active crafting jobs with countdown timers
    • “Craft” button → confirmation with material cost
  • Create routes/(game)/gathering/+page.svelte:
    • Profession tabs (Mining, Herbalism, Logging, Skinning)
    • Tier selection per profession with skill level gates
    • Duration selector (1h, 3h, 6h, 12h)
    • Active expeditions with countdown timers
    • “Collect” button when done

Tests

Unit Tests

  • can_start_expedition: accepts when skill level sufficient
  • can_start_expedition: rejects when skill level too low for tier
  • resolve_expedition: returns materials in correct quantity range
  • resolve_expedition: rare material chance scales with skill level
  • can_craft: accepts with correct materials and skill
  • can_craft: rejects missing materials
  • can_craft: rejects insufficient skill level
  • resolve_craft: generates item with correct rarity
  • resolve_craft: critical craft bumps rarity by one tier
  • resolve_craft: critical chance increases with skill level
  • calculate_craft_duration: Patron gets 2/3 duration
  • calculate_expedition_duration: Patron gets 2/3 duration

Integration Tests

  • POST /api/crafting/start deducts materials, creates job, returns completes_at
  • POST /api/crafting/start rejects when materials insufficient
  • Craft worker completes job and creates item in character inventory
  • Craft worker updates profession skill level
  • POST /api/crafting/:id/collect returns crafted item
  • POST /api/gathering/start creates expedition with correct duration
  • Gathering worker completes expedition and creates material items
  • POST /api/gathering/:id/collect returns expedition yields
  • Multiple activities run concurrently (run + craft + gather)
  • Crafting and gathering activities don’t block dungeon runs

Feature 09: Economy & Marketplace

Overview

The player economy: gold as primary currency, the auction house marketplace for player-to-player trading, NPC vendors, the mail system for item/gold transfers, and gold sinks to prevent inflation. All marketplace transactions are serialized through the economy worker to prevent race conditions.

Dependencies

  • Feature 03 (Items & Inventory) — items to trade
  • Feature 01 (Authentication) — user accounts for mail

Technical Tasks

1. Database Migrations

  • Create migration 0008_create_economy.sql:
    • marketplace_listings: id, seller_id, item_id, price, listing_fee, status (active/sold/expired/cancelled), listed_at, expires_at (48h), sold_to, sold_at
    • Indexes: status WHERE active, expires_at WHERE active, seller_id
    • mail: id, sender_id (nullable — system mail), recipient_id, subject, body, gold_amount, item_ids (UUID[]), is_read, deliverable_at, sent_at, expires_at
    • Index: recipient_id

2. Economy Rules (crates/game)

  • Create src/economy.rs:
    • Constants:
      • LISTING_FEE_RATE: f64 = 0.05 (5% of list price, deducted upfront)
      • SALE_TAX_RATE: f64 = 0.10 (10% of sale price, deducted from proceeds)
      • MAIL_GOLD_FEE_RATE: f64 = 0.05 (5% fee on gold transfers via mail)
      • LISTING_DURATION: Duration = 48 hours
      • MAIL_DELIVERY_DELAY: Duration = 1 hour
      • MAIL_EXPIRY: Duration = 30 days
    • calculate_listing_fee(price: u64) -> u64
    • calculate_sale_proceeds(price: u64) -> u64: price - sale tax
    • calculate_mail_gold_fee(amount: u64) -> u64
    • NPC vendor pricing:
      • npc_sell_price(item: &Item) -> u64: base value by rarity tier
      • npc_buy_price(item: &Item, background: Background) -> u64: 50-70% of sell value (some backgrounds get better rates)

3. Marketplace Queries (crates/db)

  • Create src/queries/marketplace.rs:
    • create_listing(pool, seller_id, item_id, price, listing_fee) -> Listing
    • find_active_listings(pool, filters: MarketplaceFilters, limit, offset) -> Vec<Listing>:
      • Filters: item_type, rarity, level_range, price_range, name search
    • find_listing_by_id(pool, id) -> Option<Listing>
    • find_listings_by_seller(pool, seller_id) -> Vec<Listing>
    • complete_sale(pool, listing_id, buyer_id) — used by economy worker
    • cancel_listing(pool, listing_id) — return item to seller
    • expire_listings(pool) -> Vec<Listing> — find all WHERE expires_at < now AND status = active

4. Mail Queries (crates/db)

  • Create src/queries/mail.rs:
    • send_mail(pool, sender_id, recipient_id, subject, body, gold, item_ids) -> Mail
    • find_mail_for_character(pool, character_id) -> Vec<Mail>: WHERE deliverable_at <= now
    • find_mail_by_id(pool, id) -> Option<Mail>
    • mark_read(pool, mail_id)
    • collect_mail_attachments(pool, mail_id) — move items/gold to character
    • delete_expired_mail(pool) -> u64 — delete WHERE expires_at < now AND is_read

5. Economy Worker (crates/workers)

  • Create src/economy_worker.rs:
    • Single-consumer queue — only one instance processes the marketplace-buy queue to prevent race conditions
    • handle_marketplace_buy(job):
      1. BEGIN TRANSACTION
      2. Load listing (SELECT FOR UPDATE) — verify still active
      3. Load buyer character (SELECT FOR UPDATE) — verify gold >= price
      4. Deduct gold from buyer
      5. Add sale proceeds (price - 10% tax) to seller’s gold
      6. Transfer item ownership to buyer (set location to ‘mail’)
      7. Create mail to buyer with purchased item
      8. Create mail to seller with gold notification
      9. Update listing status to ‘sold’
      10. COMMIT
    • handle_auction_expiry():
      • Run every 5 minutes via scheduler
      • Find all expired active listings
      • Return items to sellers via mail
      • Update listing status to ‘expired’

6. Marketplace Routes (crates/api)

  • Create src/routes/marketplace.rs:
    • GET /api/marketplace:
      • Query params: type, rarity, level_min, level_max, price_min, price_max, search, page
      • Return paginated listings with item details
    • POST /api/marketplace/list:
      • Body: { character_id, item_id, price }
      • Validate: item owned, in backpack/bank, not equipped, price > 0
      • Check seller has available listing slots (default 10, up to 30 with purchases)
      • Deduct listing fee (5% of price) from seller’s gold
      • Move item to ‘listed’ location
      • Create listing record
    • POST /api/marketplace/buy/:listing_id:
      • Body: { character_id }
      • Validate: buyer has enough gold, listing is active, buyer != seller
      • Do NOT directly modify gold — enqueue marketplace-buy job
      • Return { status: "processing" } (buyer sees result on next poll)
    • DELETE /api/marketplace/:listing_id:
      • Cancel own listing, return item to backpack
      • Listing fee is NOT refunded

7. Mail Routes (crates/api)

  • Create src/routes/mail.rs:
    • GET /api/characters/:id/mail:
      • Return delivered mail (deliverable_at <= now)
      • Include: sender name, subject, body, gold amount, item summaries, is_read, sent_at
    • POST /api/mail/send:
      • Body: { sender_id, recipient_name, subject, body, gold_amount?, item_ids? }
      • Validate: sender owns items, has enough gold + transfer fee
      • Deduct gold + fee from sender, remove items from inventory
      • Create mail with deliverable_at = now + 1 hour
    • POST /api/mail/:id/collect:
      • Move attached items to character’s backpack
      • Add gold to character’s balance
      • Mark as collected (prevent double collection)

8. NPC Vendor Routes (crates/api)

  • Add to src/routes/inventory.rs (or new file):
    • POST /api/characters/:id/sell-to-vendor:
      • Body: { item_ids: [uuid] }
      • Calculate NPC price per item, add gold to character, delete items
    • NPC buy is handled via faction vendors (Feature 13)

9. Client — Marketplace & Mail

  • Create routes/(game)/marketplace/+page.svelte:
    • Search/filter bar: item type, rarity, level, price range, text search
    • Listing grid: item card with name, rarity color, stats preview, price, time remaining
    • Buy flow: click listing → confirmation modal → POST buy → show “Processing…” → poll for result
    • Sell flow: select item from inventory → set price → list
    • My Listings tab: active listings with cancel button
  • Create routes/(game)/mail/+page.svelte (or sidebar panel):
    • Inbox list: sender, subject, gold/item indicators, read status
    • Mail detail: body, attachments, “Collect” button
    • Compose: recipient name autocomplete, subject, body, attach gold/items

Tests

Unit Tests

  • calculate_listing_fee: 5% of 1000 = 50
  • calculate_sale_proceeds: 1000 - 10% = 900
  • calculate_mail_gold_fee: 5% of 500 = 25
  • npc_sell_price: scales by rarity tier
  • npc_buy_price: returns 50-70% of sell price

Integration Tests

  • POST /api/marketplace/list creates listing, deducts fee, moves item
  • POST /api/marketplace/list rejects equipped item
  • POST /api/marketplace/list rejects when insufficient gold for fee
  • POST /api/marketplace/list rejects when at listing slot limit
  • GET /api/marketplace returns active listings with filters
  • POST /api/marketplace/buy/:id enqueues job, economy worker transfers gold/item
  • Economy worker: buyer gold decreases, seller gold increases by correct amounts
  • Economy worker: item transferred to buyer via mail
  • POST /api/marketplace/buy/:id on already-sold listing → 409
  • DELETE /api/marketplace/:id returns item to seller, no fee refund
  • Auction expiry: expired listings return items to seller via mail
  • POST /api/mail/send with gold deducts gold + fee, creates deliverable mail
  • POST /api/mail/send with items removes items from sender inventory
  • GET /api/characters/:id/mail only returns mail where deliverable_at <= now
  • POST /api/mail/:id/collect moves items/gold to character
  • POST /api/mail/:id/collect twice → 409
  • Concurrent buy attempts on same listing: only one succeeds (economy worker serialization)
  • POST /api/characters/:id/sell-to-vendor grants gold and deletes items

Feature 10: Guilds & Social

Overview

Guilds (persistent groups up to 200 members with ranks, bank, leveling, and buffs), friends list, party formation for group content, and timed raid lobbies. Chat is handled externally via Discord — this feature covers the in-game social structures only.

Dependencies

  • Feature 02 (Character Creation)
  • Feature 09 (Economy) — guild bank, gold costs

Technical Tasks

1. Database Migrations

  • Create migration 0009_create_social.sql:
    • guilds: id, name (unique), tag (unique, 2-4 chars), leader_id, level, xp, bank_gold, active_buff, buff_expires, max_members, discord_invite_url, created_at
    • guild_members: guild_id, character_id (PK), rank (leader/officer/member/recruit), joined_at
    • Index: guild_members(character_id)
    • friends: character_id, friend_id (PK), status (pending/accepted), created_at
    • parties: id, leader_id, type (duo/standard/raid), max_size, status (forming/ready/in_run/completed), quest_id, scheduled_at, created_at
    • party_members: party_id, character_id (PK), role (tank/healer/dps/support), ready (bool)

2. Guild Logic (crates/game)

  • Create src/guilds.rs:
    • GUILD_CREATION_COST: u64 = 10_000 (gold)
    • guild_max_members(guild_level: u16) -> u16: starts at 50, increases with level
    • guild_xp_for_level(level: u16) -> u64: XP required for next guild level
    • guild_buff_options() -> Vec<GuildBuff>:
      • +10% XP for 24 hours
      • +10% gold for 24 hours
      • -10% crafting time for 24 hours
      • Only one buff active at a time
    • guild_buff_cost(buff: &GuildBuff) -> u64: gold cost from guild bank

3. Guild Queries (crates/db)

  • Create src/queries/guilds.rs:
    • create_guild(pool, name, tag, leader_id) -> Guild
    • find_guild_by_id(pool, id) -> Option<Guild>
    • find_guild_by_name(pool, name) -> Option<Guild>
    • find_guild_members(pool, guild_id) -> Vec<GuildMember>
    • find_character_guild(pool, character_id) -> Option<(Guild, GuildMember)>
    • add_member(pool, guild_id, character_id, rank)
    • remove_member(pool, guild_id, character_id)
    • update_member_rank(pool, guild_id, character_id, new_rank)
    • update_guild_settings(pool, guild_id, discord_url?)
    • activate_guild_buff(pool, guild_id, buff, expires_at, cost)
    • add_guild_xp(pool, guild_id, xp)

4. Party Queries (crates/db)

  • Create src/queries/parties.rs:
    • create_party(pool, leader_id, type, quest_id?, scheduled_at?) -> Party
    • find_party_by_id(pool, id) -> Option<Party>
    • find_character_party(pool, character_id) -> Option<Party>
    • add_party_member(pool, party_id, character_id, role)
    • remove_party_member(pool, party_id, character_id)
    • set_member_ready(pool, party_id, character_id, ready)
    • check_all_ready(pool, party_id) -> bool
    • update_party_status(pool, party_id, status)

5. Guild Routes (crates/api)

  • Create src/routes/guilds.rs:
    • POST /api/guilds:
      • Body: { character_id, name, tag }
      • Validate: name/tag unique, character not in guild, has 10K gold
      • Deduct gold, create guild, add creator as leader
    • GET /api/guilds/:id:
      • Public info: name, tag, level, member count, leader name
    • GET /api/guilds/:id/members:
      • Member list with names, ranks, last active
    • POST /api/guilds/:id/join:
      • Body: { character_id }
      • Add as recruit (open join — no invite required for now)
      • Validate: not already in a guild, guild not full
    • POST /api/guilds/:id/leave:
      • Remove from guild. Leader cannot leave (must transfer leadership first)
    • POST /api/guilds/:id/invite:
      • Body: { character_name } — officer+ only
    • PUT /api/guilds/:id/settings:
      • Body: { discord_invite_url? } — leader/officer only
    • POST /api/guilds/:id/promote:
      • Body: { character_id, new_rank } — leader only
    • POST /api/guilds/:id/kick:
      • Body: { character_id } — officer+ only, cannot kick higher rank
    • POST /api/guilds/:id/buff:
      • Body: { buff_id } — officer+ only, deducts from guild bank
    • POST /api/guilds/:id/bank/deposit:
      • Body: { character_id, amount } — deposit gold to guild bank
    • POST /api/guilds/:id/transfer-leadership:
      • Body: { new_leader_id } — leader only

6. Friends Routes (crates/api)

  • Create src/routes/social.rs:
    • GET /api/characters/:id/friends:
      • Return friends list with status (pending/accepted), names, levels
    • POST /api/friends/add:
      • Body: { character_id, friend_name }
      • Create pending friend request
    • POST /api/friends/accept/:friend_character_id:
      • Accept pending request (creates reciprocal entry)
    • DELETE /api/friends/:friend_character_id:
      • Remove friend (both directions)

7. Party Routes (crates/api)

  • Create src/routes/parties.rs:
    • POST /api/parties:
      • Body: { leader_id, type, quest_id?, scheduled_at? }
      • Create party, add leader
    • GET /api/parties/:id:
      • Party info: members, roles, ready status, quest, schedule
    • POST /api/parties/:id/join:
      • Body: { character_id, role }
      • Validate: party not full, correct type limits (duo=2, standard=4, raid=8)
    • POST /api/parties/:id/leave:
      • Remove from party. If leader leaves, disband.
    • POST /api/parties/:id/ready:
      • Body: { character_id } — toggle ready status
    • POST /api/parties/:id/start:
      • Leader only, all members must be ready
      • Start group run (uses Feature 07 run system with party_id)

8. Client — Guild & Social UI

  • Create routes/(game)/guild/+page.svelte:
    • Guild overview: name, tag, level, XP bar, member count
    • Member list: name, rank, last active, promote/kick actions
    • Guild bank: current gold, deposit button
    • Active buff display with “Activate Buff” selector
    • Discord link button
    • Settings (for officers+): Discord URL
  • Create routes/(game)/social/+page.svelte:
    • Friends tab: friends list, add friend input, pending requests
    • Parties tab: current party, create party, join party
  • Create party lobby view for group content coordination

Tests

Unit Tests

  • guild_max_members: 50 at level 1, scales correctly
  • guild_buff_cost: returns correct costs per buff type
  • Guild rank hierarchy: leader > officer > member > recruit

Integration Tests

  • POST /api/guilds creates guild, deducts 10K gold
  • POST /api/guilds rejects when already in a guild
  • POST /api/guilds rejects duplicate name/tag
  • POST /api/guilds/:id/join adds as recruit
  • POST /api/guilds/:id/join rejects when guild full
  • POST /api/guilds/:id/leave removes member
  • POST /api/guilds/:id/leave by leader → 409
  • POST /api/guilds/:id/promote changes rank
  • POST /api/guilds/:id/kick removes member (officer+)
  • POST /api/guilds/:id/kick rejects kicking higher rank
  • POST /api/guilds/:id/buff activates buff, deducts from bank
  • POST /api/guilds/:id/buff rejects when buff already active
  • POST /api/guilds/:id/bank/deposit adds gold to guild bank
  • POST /api/guilds/:id/transfer-leadership changes leader
  • POST /api/friends/add creates pending request
  • POST /api/friends/accept creates mutual friendship
  • DELETE /api/friends/:id removes both directions
  • POST /api/parties creates party with leader
  • POST /api/parties/:id/join adds member up to max
  • POST /api/parties/:id/start starts group run when all ready
  • POST /api/parties/:id/start rejects when not all ready

Feature 11: PVP System

Overview

Arena PVP with instant resolution (no wait timer), ELO-based matchmaking, stat normalization for fairness, 1v1 and 3v3 brackets, seasonal ratings with soft resets, and leaderboards. PVP matches use the same combat engine as PvE but with normalized stats.

Dependencies

  • Feature 06 (Combat Engine) — same simulation engine with PVP rules
  • Feature 05 (Skill Queue) — players use their configured queues

Technical Tasks

1. Database Migrations

  • Create migration 0010_create_pvp.sql:
    • pvp_ratings: character_id, bracket (‘1v1’/‘3v3’), rating (default 1000), season, wins, losses (PK: character_id + bracket + season)
    • pvp_matches: id, bracket, season, team_a (UUID[]), team_b (UUID[]), winner (‘a’/‘b’/‘draw’), match_log (JSONB), rating_changes (JSONB), resolved_at

2. PVP Stat Normalization (crates/game)

  • Create src/pvp.rs:
    • normalize_character(character: &CharacterSnapshot) -> PvpParticipant:
      • Normalize all base attributes to a baseline (e.g., 30 per attribute)
      • Keep weapon type and skill queue (strategy matters)
      • Keep gear enchantments/effects (effects matter, raw stats don’t)
      • Strip raw stat bonuses from gear
      • Set all participants to same HP pool
    • This ensures Patron speed bonus has zero PVP impact (arena resolves instantly)
    • Higher-level characters have more skills available (real advantage) but not stat advantage

3. ELO Matchmaking (crates/game)

  • Create src/pvp_matchmaking.rs:
    • calculate_elo_change(winner_rating: i32, loser_rating: i32) -> (i32, i32):
      • Standard ELO formula with K-factor 32
      • Winner gains, loser loses (different amounts based on rating gap)
    • is_viable_match(rating_a: i32, rating_b: i32, wait_seconds: u64) -> bool:
      • Start with ±150 rating window
      • Expand by 50 per 30 seconds of waiting
      • Max window: ±500

4. PVP Queue (Redis)

  • PVP queue stored in Redis sorted set: pvp:queue:{bracket} with score = rating
  • join_queue(redis, character_id, bracket, rating): ZADD
  • leave_queue(redis, character_id, bracket): ZREM
  • find_match(redis, bracket) -> Option<(CharId, CharId)>:
    • Scan sorted set for viable matches
    • Pop both matched players atomically

5. PVP Worker (crates/workers)

  • Create src/pvp_worker.rs:
    • Matchmaker (runs every 5 seconds via scheduler):
      • Call find_match for each bracket
      • For each match found: enqueue pvp-resolve job (immediate)
    • Match resolver (handles pvp-resolve queue):
      1. Load both characters’ snapshots
      2. Normalize stats
      3. Run combat simulation (same engine, PVP encounter rules)
      4. Determine winner
      5. Calculate ELO changes
      6. Write match result + rating updates to DB
      7. Create notifications for both players

6. PVP Seasons (crates/game)

  • Create src/pvp_seasons.rs:
    • Season duration: ~3 months
    • soft_reset_rating(current: i32) -> i32: compress toward 1000 (e.g., new = 1000 + (current - 1000) / 2)
    • Season rewards based on final rating tier:
      • Bronze (< 1200): title
      • Silver (1200-1499): title + portrait frame
      • Gold (1500-1799): title + portrait + materials
      • Diamond (1800+): title + portrait + exclusive seasonal item

7. PVP Routes (crates/api)

  • Create src/routes/pvp.rs:
    • POST /api/pvp/queue:
      • Body: { character_id, bracket }
      • Validate: character has active skill queue, has gear, not already in queue
      • Add to Redis PVP queue
      • Return { status: "queued" }
    • DELETE /api/pvp/queue:
      • Body: { character_id, bracket }
      • Remove from queue
    • GET /api/pvp/queue/status?character_id=:
      • Return: in_queue (bool), match_found (bool), match_id (if found)
      • Polled every 10 seconds by client
    • GET /api/pvp/history?character_id=:
      • Paginated match history: opponent, result, rating change, date
    • GET /api/pvp/leaderboard/:bracket:
      • Top 100 by rating from Redis sorted set
      • Include: rank, character name, rating, wins, losses
    • GET /api/pvp/ratings?character_id=:
      • Current ratings for all brackets + season

8. Client — PVP UI

  • Create routes/(game)/pvp/+page.svelte:
    • Bracket selector (1v1, 3v3)
    • Current rating, rank, W/L record
    • “Enter Queue” / “Leave Queue” button
    • Queue status indicator with polling (10s interval)
    • Match result modal when match completes
  • Create routes/(game)/pvp/history/+page.svelte:
    • Match history list with replay viewer (same as PvE run viewer)
  • Create routes/(game)/pvp/leaderboard/+page.svelte:
    • Top 100 table per bracket
    • Highlight current player’s rank

Tests

Unit Tests

  • normalize_character: all attributes set to baseline
  • normalize_character: gear effects preserved, raw stats stripped
  • normalize_character: HP pool equalized
  • calculate_elo_change: higher rated player gains less from beating lower rated
  • calculate_elo_change: lower rated player gains more from upset
  • calculate_elo_change: sum of changes is approximately zero
  • is_viable_match: accepts ±150 at 0 seconds wait
  • is_viable_match: rejects ±200 at 0 seconds, accepts at 30 seconds
  • soft_reset_rating: compresses 1500 → 1250, 500 → 750
  • PVP combat simulation: deterministic with same seed
  • PVP combat simulation: stat normalization means level 10 vs level 50 is fair on raw stats

Integration Tests

  • POST /api/pvp/queue adds to Redis sorted set
  • DELETE /api/pvp/queue removes from Redis
  • POST /api/pvp/queue rejects without active skill queue
  • Matchmaker finds viable match and enqueues resolution
  • PVP worker resolves match, writes result, updates ratings
  • GET /api/pvp/queue/status shows match_found after resolution
  • GET /api/pvp/history returns match results
  • GET /api/pvp/leaderboard/1v1 returns top 100 sorted by rating
  • GET /api/pvp/ratings returns current season ratings
  • Concurrent queue joins: two players with close ratings → matched within 10 seconds

Feature 12: Factions & Reputation

Overview

Seven factions with a reputation system ranging from Hostile (-3000) to Exalted (21000+). Three conflict pairs where gaining reputation with one faction loses 50% with its opposite. Faction vendors sell exclusive recipes, consumables, and enchantments at reputation tiers. Daily faction quests provide the primary rep grind.

Dependencies

  • Feature 07 (Quests & Runs) — faction quests use the run system
  • Feature 03 (Items & Inventory) — faction vendor items

Technical Tasks

1. Static Game Data — Factions

  • Create data/factions/:
    • factions.toml: all 7 factions with:
      • id, name, description, zone, conflict_pair (opposing faction ID or null)
      • Factions: Iron Compact, Shadow Court, Arcane Conclave, Primal Circle, Order of the Dawn, Covenant of Dusk, Merchant Consortium
      • Conflict pairs: Iron Compact ↔ Shadow Court, Arcane Conclave ↔ Primal Circle, Order of the Dawn ↔ Covenant of Dusk. Merchant Consortium has no conflict.
    • reputation_tiers.toml: tier thresholds
      • Hostile: < -1000
      • Unfriendly: -1000 to -1
      • Neutral: 0 to 2999
      • Friendly: 3000 to 5999
      • Honored: 6000 to 11999
      • Revered: 12000 to 20999
      • Exalted: 21000+
    • faction_vendors/ — per faction TOML with items available at each rep tier
    • faction_quests/ — 3 daily quests per faction (templates, generated dynamically)
    • exalted_passives.toml: one unique passive ability per faction at Exalted

2. Reputation Logic (crates/game)

  • Create src/factions.rs:
    • gain_reputation(character_rep: &mut HashMap<String, i32>, faction_id: &str, amount: i32):
      • Add amount to faction
      • If faction has a conflict pair, subtract 50% from opposing faction
      • Clamp: minimum -3000, no maximum
    • get_reputation_tier(rep: i32) -> ReputationTier
    • can_access_vendor_tier(rep: i32, required_tier: ReputationTier) -> bool
    • get_exalted_passive(faction_id: &str) -> Option<PassiveEffect>: only if Exalted

3. Database — Already Exists

  • character_reputation table was defined in the base schema (Feature 02 migration area)
  • If not yet created, add migration 0011_create_reputation.sql:
    • character_reputation: character_id, faction_id, reputation (default 0), PK: character_id + faction_id

4. Reputation Queries (crates/db)

  • Create src/queries/reputation.rs:
    • get_all_reputation(pool, character_id) -> Vec<(String, i32)>
    • get_faction_reputation(pool, character_id, faction_id) -> i32
    • update_reputation(pool, character_id, faction_id, new_value)
    • batch_update_reputation(pool, character_id, changes: Vec<(String, i32)>) — for conflict pair updates

5. Faction Quest Generation (crates/game)

  • Create src/faction_quests.rs:
    • generate_daily_faction_quests(character: &Character, faction_id: &str, date: NaiveDate) -> Vec<FactionQuest>:
      • 3 quests per faction per day
      • Seeded by character_id + faction_id + date (deterministic per day)
      • Quest types: bounties themed to the faction’s identity
      • Requires Friendly rep to access faction quests
    • Each quest grants: reputation (150-250 per quest), gold, XP, chance at faction-specific materials

6. Faction Routes (crates/api)

  • Create src/routes/factions.rs:
    • GET /api/characters/:id/reputation:
      • Return all 7 faction standings with tier names
    • GET /api/factions/:faction_id/vendor?character_id=:
      • Return items available to buy based on character’s rep tier
      • Each item: name, cost (gold or faction tokens), rep requirement
    • POST /api/factions/:faction_id/vendor/buy:
      • Body: { character_id, item_template_id }
      • Validate rep tier, deduct cost, create item
    • GET /api/factions/:faction_id/quests?character_id=:
      • Return today’s 3 faction quests (if Friendly+)
      • Include completion status
    • POST /api/factions/:faction_id/quests/:quest_id/start:
      • Start faction quest as a run (uses Feature 07 run system)
      • On completion, grant rep (plus conflict pair penalty)

7. Update Run Completion for Reputation

  • In the simulation worker (Feature 07), after resolving a faction quest run:
    • Call gain_reputation with appropriate amounts
    • Handle conflict pair rep loss
    • Check for tier-up events (Friendly → Honored, etc.)
    • Create notification on tier change

8. Client — Factions UI

  • Create routes/(game)/factions/+page.svelte:
    • Faction list: 7 factions with current rep bar, tier badge, conflict pair indicator
    • Faction detail panel: description, current tier perks, progress to next tier
    • Vendor tab: items purchasable at current tier
    • Daily quests tab: 3 quests per day (if Friendly+)
    • Exalted passive display (if earned)

Tests

Unit Tests

  • gain_reputation: adds correct amount to faction
  • gain_reputation: subtracts 50% from conflict pair
  • gain_reputation: Merchant Consortium has no conflict penalty
  • gain_reputation: clamps at -3000 minimum
  • get_reputation_tier: correct tier at boundaries (2999 = Neutral, 3000 = Friendly)
  • generate_daily_faction_quests: returns 3 quests
  • generate_daily_faction_quests: same character + date → same quests (deterministic)
  • generate_daily_faction_quests: different date → different quests

Integration Tests

  • GET /api/characters/:id/reputation returns all 7 factions with rep values
  • GET /api/factions/:id/vendor returns items appropriate to character’s rep tier
  • POST /api/factions/:id/vendor/buy at sufficient rep → creates item, deducts cost
  • POST /api/factions/:id/vendor/buy at insufficient rep → 403
  • GET /api/factions/:id/quests returns daily quests when Friendly+
  • GET /api/factions/:id/quests returns empty when below Friendly
  • Completing a faction quest grants reputation and applies conflict penalty
  • Reputation tier change creates a notification

Feature 13: Notifications & Push

Overview

The in-game notification system that replaces WebSockets. Workers write notification records to the database when events complete. The client polls for them. Mobile push notifications are sent via FCM/APNs when the player appears to be offline.

Dependencies

  • Feature 00 (Project Foundation) — Redis, database
  • Feature 01 (Authentication) — user sessions

Technical Tasks

1. Database Migration

  • Create migration 0012_create_notifications.sql:
    • notifications: id, character_id, type, title, body, data (JSONB for deep linking), is_read, created_at
    • Index: (character_id, created_at DESC) WHERE is_read = false
    • push_tokens: user_id, platform (‘ios’/‘android’/‘web’), token, created_at, updated_at
    • Index: user_id
    • notification_preferences: character_id, notification_type, in_app (bool), push (bool)
    • PK: character_id + notification_type

2. Notification Types (crates/types)

  • Create src/notification.rs:
    • NotificationType enum:
      • RunComplete
      • CraftComplete
      • GatheringComplete
      • ItemSold
      • MailReceived
      • PvpMatchComplete
      • RaidLobbyStarting
      • GuildWarDeclared
      • ReputationTierUp
      • LevelUp
      • AchievementEarned
    • Notification struct: id, character_id, notification_type, title, body, data (serde_json::Value), is_read, created_at

3. Notification Service (crates/db or shared)

  • Create src/queries/notifications.rs:
    • create_notification(pool, character_id, type, title, body, data) -> Notification
    • get_unread_notifications(pool, character_id, since: Option<DateTime>) -> Vec<Notification>
    • mark_read(pool, notification_ids: &[Uuid])
    • mark_all_read(pool, character_id)
    • delete_old_notifications(pool, older_than: DateTime) — cleanup, 30-day retention
    • get_notification_preferences(pool, character_id) -> Vec<NotificationPreference>
    • update_notification_preference(pool, character_id, type, in_app, push)

4. Push Notification Service

  • Create crates/api/src/push.rs (or shared crate):
    • should_send_push(pool, redis, character_id, notification_type) -> bool:
      • Check push preference enabled for this type
      • Check last API request from this user was > 5 minutes ago (likely offline)
    • send_push(token: &str, platform: &str, title: &str, body: &str, data: &Value):
      • FCM for Android (via HTTP v1 API)
      • APNs for iOS (via a]pns2 crate or HTTP/2 directly)
    • register_push_token(pool, user_id, platform, token)
    • unregister_push_token(pool, user_id, platform)

5. Integrate Notifications into Workers

  • Update all workers to create notifications on event completion:
    • Simulation worker (Feature 07): RunComplete + LevelUp if applicable
    • Crafting worker (Feature 08): CraftComplete
    • Gathering worker (Feature 08): GatheringComplete
    • Economy worker (Feature 09): ItemSold, MailReceived
    • PVP worker (Feature 11): PvpMatchComplete
    • After creating notification, check if push should be sent

6. Notification Routes (crates/api)

  • Create src/routes/notifications.rs:
    • GET /api/characters/:id/notifications?since=:
      • Return unread notifications since timestamp
      • Ordered by created_at DESC
      • Limit 50 per request
    • POST /api/characters/:id/notifications/read:
      • Body: { ids: [uuid] }
      • Mark specified notifications as read
    • POST /api/characters/:id/notifications/read-all:
      • Mark all as read
    • GET /api/characters/:id/notification-preferences:
      • Return per-type in_app + push settings
    • PUT /api/characters/:id/notification-preferences:
      • Body: { type, in_app, push }
      • Update preference

7. Push Token Registration Routes

  • Add to auth or settings routes:
    • POST /api/push/register:
      • Body: { platform, token }
      • Register push token for authenticated user
    • DELETE /api/push/unregister:
      • Body: { platform }
      • Remove push token

8. Scheduled Cleanup

  • Add to scheduler worker:
    • cleanup-notifications: daily, delete notifications older than 30 days
    • cleanup-read-notifications: daily, delete read notifications older than 7 days

9. Client — Notifications

  • Create notification bell component in the main nav:
    • Badge showing unread count
    • Dropdown panel listing recent notifications
    • Click notification → navigate to relevant screen (run result, mail, PVP result)
  • Polling: GET /api/characters/:id/notifications every 30 seconds
  • Create routes/(game)/settings/notifications/+page.svelte:
    • Per-type toggles for in-app and push notifications
  • Mobile (Capacitor):
    • Register push token on app start via @capacitor/push-notifications
    • Handle push tap → deep link to relevant content

Tests

Unit Tests

  • should_send_push: returns true when push enabled and user offline > 5 min
  • should_send_push: returns false when push disabled for type
  • should_send_push: returns false when user recently active
  • NotificationType serializes/deserializes correctly

Integration Tests

  • GET /api/characters/:id/notifications returns unread notifications
  • GET /api/characters/:id/notifications?since= filters by timestamp
  • POST /api/characters/:id/notifications/read marks as read
  • Subsequent GET excludes read notifications
  • POST /api/characters/:id/notifications/read-all clears all
  • Run completion creates RunComplete notification
  • Craft completion creates CraftComplete notification
  • Item sold creates ItemSold notification
  • Notification preferences are respected (disabled type → no notification created for in-app)
  • Push token registration and unregistration work
  • Cleanup job deletes old notifications

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 + date
    • weekly_tracking: character_id, week_start (date), challenge_completed (bool), raid_tokens_earned (int) — PK: character_id + week_start
    • season_progress: character_id, season_id, track (‘free’/‘premium’), tier_reached (smallint), xp (int) — PK: character_id + season_id
    • seasons: 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 = 3
    • generate_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 done
    • roll_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) -> DailyTracking
    • update_daily_tracking(pool, character_id, date, updates)
    • get_or_create_weekly_tracking(pool, character_id, week_start) -> WeeklyTracking
    • update_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_tracking rows are created per-day on first access
    • weekly-reset (Monday 00:00 UTC): same pattern for weekly_tracking
    • rested-bonus-tick (every 1 hour): update rested_bonus for characters inactive > 24h
    • season-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 bounties
  • generate_daily_bounties: deterministic per date
  • check_bounty_chest_eligible: true when 3/3, false otherwise
  • generate_weekly_challenge: deterministic per week
  • generate_weekly_challenge: different each week
  • calculate_rested_bonus: 0% at 0 hours
  • calculate_rested_bonus: 25% at 24 hours
  • calculate_rested_bonus: 50% at 72+ hours
  • calculate_rested_bonus: linear interpolation between thresholds
  • consume_rested_bonus: depletes bonus proportionally
  • calculate_season_xp: returns correct XP per activity type
  • check_tier_up: returns tier-up when XP sufficient
  • check_tier_up: returns None when insufficient

Integration Tests

  • GET /api/characters/:id/dailies returns 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

Feature 15: Achievements & Collections

Overview

Long-term completionist goals: achievements across all game systems (combat, crafting, social, exploration, PVP, collection), the bestiary (creature catalog), item catalog, recipe collection, titles, and leaderboards. Achievements grant points, titles, and cosmetic rewards.

Dependencies

  • Feature 07 (Quests & Runs) — combat and exploration achievements
  • Feature 08 (Crafting & Gathering) — crafting achievements
  • Feature 11 (PVP) — PVP achievements and leaderboards
  • Feature 10 (Guilds) — social achievements

Technical Tasks

1. Static Game Data — Achievements

  • Create data/achievements/:
    • combat.toml: First Blood, Dungeon Crawler (all dungeons), Deadly Survivor (complete Deadly), etc.
    • progression.toml: level milestones, Paragon milestones, full feat selection
    • crafting.toml: First Craft, Master Blacksmith (skill 100), Grand Master (all 100), Critical Crafter (10 crits)
    • social.toml: Guilded (join guild), Raid Ready (first raid), Social Butterfly (10 friends)
    • exploration.toml: Explorer (all regions), Lore Hunter, Cartographer
    • pvp.toml: First Duel, Gladiator (Gold rating), Legend (Diamond)
    • collection.toml: Bestiary Complete, Fashionista (25 cosmetics), Title Collector (10 titles)
    • Per achievement: id, name, description, category, points, reward (title?, portrait_frame?, gold?, materials?), criteria (structured conditions)

2. Achievement Tracking Types (crates/types)

  • Create src/achievement.rs:
    • AchievementCriteria enum:
      • KillCount { creature_id: Option<String>, count: u32 } — kill N creatures (or specific type)
      • DungeonComplete { dungeon_id: Option<String>, difficulty: Option<Difficulty> }
      • CraftCount { profession: Option<String>, count: u32 }
      • ReachLevel { level: u16 }
      • ReachProficiency { weapon_type: String, level: u16 }
      • ReachReputation { faction_id: String, tier: ReputationTier }
      • PvpRating { bracket: String, rating: i32 }
      • FriendCount { count: u32 }
      • GuildAction { action: String } — join, create, etc.
      • CollectionCount { collection: String, count: u32 }
    • Achievement: id, name, description, category, points, reward, criteria

3. Database Migration

  • Create migration 0014_create_achievements.sql:
    • character_achievements: character_id, achievement_id, earned_at — PK: character_id + achievement_id
    • character_bestiary: character_id, creature_id, kills, first_killed — PK: character_id + creature_id
    • character_titles: character_id, title_id, earned_at, is_active — PK: character_id + title_id

4. Achievement Engine (crates/game)

  • Create src/achievements.rs:
    • check_achievements(character: &Character, event: &GameEvent, state: &AchievementState) -> Vec<String>:
      • Given a game event (kill, craft, level up, etc.), check all relevant achievements
      • Return IDs of newly earned achievements
    • GameEvent enum:
      • CreatureKilled { creature_id: String }
      • RunCompleted { quest_id: String, difficulty: Difficulty }
      • ItemCrafted { profession: String }
      • LevelReached { level: u16 }
      • ProficiencyReached { weapon_type: String, level: u16 }
      • ReputationChanged { faction_id: String, new_rep: i32 }
      • PvpMatchCompleted { bracket: String, new_rating: i32 }
      • FriendAdded { total_friends: u32 }
      • GuildJoined / GuildCreated
    • AchievementState: set of already-earned achievement IDs (to avoid re-checking)

5. Bestiary Tracking

  • Create src/bestiary.rs:
    • record_kill(character_id: Uuid, creature_id: &str):
      • Increment kill count
      • If first kill, record timestamp
    • get_bestiary_completion(character_id: Uuid) -> BestiaryProgress:
      • Total creatures encountered / total creatures in game
      • Per-region completion percentage

6. Queries (crates/db)

  • Create src/queries/achievements.rs:
    • get_earned_achievements(pool, character_id) -> Vec<CharacterAchievement>
    • grant_achievement(pool, character_id, achievement_id)
    • get_achievement_points(pool, character_id) -> u32
    • get_bestiary(pool, character_id) -> Vec<BestiaryEntry>
    • upsert_bestiary_entry(pool, character_id, creature_id, kills_delta)
    • get_active_title(pool, character_id) -> Option<String>
    • set_active_title(pool, character_id, title_id)
    • get_earned_titles(pool, character_id) -> Vec<Title>

7. Integrate Achievement Checks into Workers

  • After every significant game event, call check_achievements:
    • Simulation worker: after each encounter (CreatureKilled), after run (RunCompleted, LevelReached)
    • Crafting worker: after craft (ItemCrafted)
    • PVP worker: after match (PvpMatchCompleted)
    • Reputation updates: after rep change (ReputationChanged)
    • Social actions: on friend add, guild join/create
  • For each newly earned achievement:
    • Grant achievement record
    • Grant reward (title, gold, materials)
    • Create notification (AchievementEarned)
  • Update bestiary after combat encounters (record creature kills)

8. Leaderboard System

  • Redis sorted sets for leaderboards (already defined in tech architecture):
    • leaderboard:pvp:1v1:season:{n} — rating
    • leaderboard:pvp:3v3:season:{n} — rating
    • leaderboard:achievements — total points
    • leaderboard:wealth — gold
  • Update leaderboards when relevant data changes:
    • PVP: after match resolution
    • Achievements: after achievement granted
    • Wealth: after gold change (debounced — update every 5 minutes via scheduler)

9. API Routes (crates/api)

  • Create src/routes/achievements.rs:
    • GET /api/characters/:id/achievements:
      • Return earned achievements with timestamps + total points
      • Include unearned achievements as “locked” entries with descriptions (progression visibility)
    • GET /api/characters/:id/bestiary:
      • Return creature entries: name, kills, first killed, completion percentage
    • GET /api/characters/:id/titles:
      • Return earned titles, active title
    • POST /api/characters/:id/titles/set:
      • Body: { title_id }
      • Set active title (displayed on profile)
    • GET /api/leaderboards/:type:
      • Query params: page, bracket (for PVP)
      • Return top 100 + requesting player’s rank
    • GET /api/characters/:id/showcase:
      • Return selected 5 achievements for profile display
    • PUT /api/characters/:id/showcase:
      • Body: { achievement_ids: [5 max] }

10. Client — Achievements UI

  • Create routes/(game)/achievements/+page.svelte:
    • Category tabs: Combat, Progression, Crafting, Social, Exploration, PVP, Collection
    • Achievement cards: name, description, progress bar (if trackable), earned/locked indicator, points, reward preview
    • Total achievement points prominently displayed
  • Create routes/(game)/bestiary/+page.svelte:
    • Grid of creature entries (unlocked show art + stats, locked show silhouette)
    • Regional filters
    • Completion percentage
  • Create routes/(game)/leaderboards/+page.svelte:
    • Leaderboard tabs: PVP, Achievements, Wealth, Dungeon Speed, Weekly
    • Top 100 table with rank, name, score
    • “Your Rank” indicator
  • Create routes/(game)/profile/+page.svelte:
    • Character card: name, level, class, active title
    • Achievement showcase (5 selected)
    • Key stats: total achievements, bestiary %, PVP rating

Tests

Unit Tests

  • check_achievements: CreatureKilled event triggers “First Blood” when first kill
  • check_achievements: doesn’t re-trigger already-earned achievements
  • check_achievements: LevelReached(10) triggers level 10 achievement
  • check_achievements: multiple achievements can trigger from one event
  • record_kill: increments count, first kill sets timestamp
  • get_bestiary_completion: correct percentage calculation

Integration Tests

  • Run completion triggers relevant combat achievements
  • Achievement grant creates notification
  • Achievement grant adds points to leaderboard
  • GET /api/characters/:id/achievements returns earned + locked achievements
  • GET /api/characters/:id/bestiary returns entries after combat
  • GET /api/leaderboards/achievements returns sorted by points
  • POST /api/characters/:id/titles/set changes active title
  • PUT /api/characters/:id/showcase saves 5 achievement selections
  • Bestiary entry created after first encounter with creature
  • Kill count increments across multiple runs

Feature 16: Monetization

Overview

Patron subscription ($3/mo or $30/yr) for 50% faster time-based activities and premium seasonal track, plus small permanent purchases (character slots, storage upgrades, name changes). All payments via Stripe web checkout. No in-app purchase SDK — avoids the 30% platform cut.

Dependencies

  • Feature 01 (Authentication) — user accounts with patron_tier
  • Feature 07 (Quests & Runs) — patron speed bonus applied to run duration
  • Feature 08 (Crafting & Gathering) — patron speed bonus on crafts/expeditions
  • Feature 14 (Seasons) — premium track access

Technical Tasks

1. Stripe Integration

  • Add Stripe Rust SDK or use HTTP API directly via reqwest
  • Create crates/api/src/payments.rs:
    • create_checkout_session(user_id, product: ProductType) -> String (checkout URL):
      • Products:
        • Patron Monthly ($3.00)
        • Patron Annual ($30.00)
        • Character Slot ($2.00)
        • Bank Space +25 ($1.00)
        • Material Bank +50 ($1.00)
        • Marketplace Slots +5 ($1.00)
        • Name Change ($1.00)
        • Appearance Reset ($1.00)
      • Create Stripe Checkout Session with success/cancel URLs
      • For subscriptions: create Stripe Subscription with appropriate price ID
    • handle_webhook(payload, signature) -> Result<()>:
      • Verify Stripe signature
      • Handle events:
        • checkout.session.completed → fulfill purchase
        • invoice.paid → renew subscription
        • customer.subscription.deleted → expire subscription
        • customer.subscription.updated → handle plan changes

2. Purchase Fulfillment

  • Create src/payments/fulfill.rs:
    • fulfill_patron_subscription(user_id, plan, expires_at):
      • Set patron_tier = 1, patron_expires = expires_at on user
      • All time calculations now check patron status
    • fulfill_character_slot(user_id):
      • Increment character_slots (max 6)
    • fulfill_bank_space(user_id):
      • Increment bank_slots by 25 (max 150 = 50 base + 4 purchases)
    • fulfill_marketplace_slots(user_id):
      • Increment marketplace_slots by 5 (max 30 = 10 base + 4 purchases)
    • fulfill_name_change(character_id, new_name):
      • Validate new name, update character
    • fulfill_appearance_reset(character_id):
      • Reset appearance fields (future — appearance is just a portrait for now)

3. Patron Speed Bonus Integration

  • Ensure all duration calculations check user.patron_tier:
    • calculate_run_duration (Feature 07): ×0.667 if patron
    • calculate_craft_duration (Feature 08): ×0.667 if patron
    • calculate_expedition_duration (Feature 08): ×0.667 if patron
    • Death recovery timer: ×0.667 if patron
  • These are already parameterized — just need to pass is_patron correctly

4. Subscription Expiry Check

  • Add to scheduler worker:
    • check-patron-expiry (daily): find users where patron_expires < now() and patron_tier > 0
    • Set patron_tier = 0 for expired subscriptions
    • Active runs/crafts continue at original speed (snapshot at start) — only new activities use free-tier timing

5. Spending Transparency

  • Create migration 0015_create_purchases.sql:
    • purchase_history: id, user_id, product_type, amount_cents, stripe_session_id, created_at
    • Index: user_id

6. API Routes (crates/api)

  • Create src/routes/payments.rs:
    • POST /api/payments/checkout:
      • Body: { product } (e.g., “patron_monthly”, “character_slot”)
      • Validate: user eligible (e.g., not already at max slots)
      • Create Stripe checkout session
      • Return { checkout_url }
    • POST /api/payments/webhook:
      • No auth (Stripe calls this directly)
      • Verify webhook signature
      • Fulfill purchase
    • GET /api/payments/history:
      • Return user’s purchase history (amount, product, date)
    • GET /api/payments/patron-status:
      • Return: is_patron, expires_at, plan_type
    • POST /api/payments/cancel-subscription:
      • Cancel Stripe subscription (takes effect at period end)
      • No “are you sure?” hoops — instant cancellation

7. Client — Subscription & Purchases

  • Create routes/(game)/settings/subscription/+page.svelte:
    • Current status: Free / Patron (with expiry date)
    • Subscribe button → opens Stripe checkout in browser
    • Cancel button → instant cancellation with confirmation
    • What you get: clear comparison table (free vs patron)
  • Create routes/(game)/settings/purchases/+page.svelte:
    • Available purchases with current limits (e.g., “3/6 character slots”)
    • Buy buttons → Stripe checkout
    • Purchase history
    • Total lifetime spend display (transparency per design doc)
  • Stripe checkout opens via @capacitor/browser on mobile (external browser, not in-app webview)

Tests

Unit Tests

  • Duration calculations: patron gets 2/3 duration (parameterized across all activity types)
  • Duration calculations: free player gets full duration
  • fulfill_character_slot: increments correctly, respects max of 6
  • fulfill_bank_space: increments by 25, respects max of 150
  • fulfill_marketplace_slots: increments by 5, respects max of 30

Integration Tests

  • POST /api/payments/checkout returns valid Stripe checkout URL
  • Stripe webhook checkout.session.completed for subscription → user becomes patron
  • Stripe webhook invoice.paid for renewal → patron_expires extended
  • Stripe webhook customer.subscription.deleted → patron expires at period end
  • Patron expiry check sets patron_tier = 0 after expiration
  • POST /api/payments/checkout for character slot → slot count increases after webhook
  • POST /api/payments/checkout for character slot at max → 409
  • GET /api/payments/history returns purchase records
  • POST /api/payments/cancel-subscription cancels in Stripe
  • New run started after becoming patron uses reduced duration
  • Run started before patron expires continues at patron speed

Feature 17: Gear Enhancement & Reforging

Overview

Endgame item progression: enhancement (+1 to +5 upgrades that increase base stats) and reforging (re-roll random bonus properties on Rare+ items). Both are material and gold sinks that give max-level players long-term goals without adding power creep.

Dependencies

  • Feature 03 (Items & Inventory) — gear with bonus properties
  • Feature 08 (Crafting) — crafting materials used as enhancement/reforge inputs
  • Feature 09 (Economy) — gold sinks

Technical Tasks

1. Enhancement Logic (crates/game)

  • Create src/enhancement.rs:
    • Enhancement levels: +1 through +5
    • Per level: material cost, gold cost, success chance
      • +1: 5 Uncommon Shards, 500 gold, 100% success
      • +2: 10 Uncommon Shards + 2 Rare Cores, 2000 gold, 80% success
      • +3: 5 Rare Cores, 5000 gold, 60% success
      • +4: 10 Rare Cores + 2 Prismatic Essences, 15000 gold, 40% success
      • +5: 5 Prismatic Essences + 1 Legendary Spark, 50000 gold, 20% success
    • Failure: item stays at current level (no downgrade), materials consumed
    • enhance_item(item: &Item, target_level: u8, rng: &mut impl Rng) -> EnhanceResult:
      • Check current enhancement < target
      • Roll success chance
      • Return Success(new_level) or Failure(current_level)
    • enhancement_stat_bonus(base_stat: u16, level: u8) -> u16:
      • +5% per level to base damage/armor/evasion

2. Reforging Logic (crates/game)

  • Create src/reforging.rs:
    • Only available for Rare+ items (they have random bonus properties)
    • reforge_cost(rarity: Rarity) -> ReforgeCost:
      • Rare: 3 Rare Cores + 1000 gold
      • Very Rare: 5 Rare Cores + 2 Prismatic Essences + 5000 gold
      • Legendary: 3 Prismatic Essences + 1 Legendary Spark + 20000 gold
    • reforge_item(item: &mut Item, rng: &mut impl Rng) -> Vec<BonusProperty>:
      • Re-roll ALL random bonus properties (keep count, re-roll values and types)
      • Signature effect is NOT re-rolled (it’s fixed per template)
      • Return new bonus properties

3. API Routes (crates/api)

  • Add to src/routes/inventory.rs:
    • POST /api/characters/:id/enhance:
      • Body: { item_id }
      • Validate: item owned, enhancement < 5, has materials + gold
      • Deduct materials and gold
      • Roll enhancement
      • Return { success, new_enhancement_level }
    • POST /api/characters/:id/reforge:
      • Body: { item_id }
      • Validate: item owned, Rare+ rarity, has materials + gold
      • Deduct materials and gold
      • Re-roll bonuses
      • Return { new_bonus_properties }

4. Client — Enhancement & Reforging UI

  • Add to inventory screen:
    • “Enhance” button on eligible items → modal showing cost, success chance, current level
    • “Reforge” button on Rare+ items → modal showing cost, current bonuses, warning about random results
    • Enhancement level displayed on item: “+3 Iron Longsword”
    • Visual indicator of enhancement level (glow effect or badge)

Tests

Unit Tests

  • enhance_item: +1 always succeeds (100%)
  • enhance_item: +5 has 20% success rate (statistical test with seeded RNG)
  • enhance_item: failure doesn’t downgrade
  • enhancement_stat_bonus: +5 at level 3 = +15% bonus
  • reforge_item: keeps same number of bonus properties
  • reforge_item: can produce different properties than original
  • reforge_item: deterministic with seeded RNG
  • reforge_cost: correct per rarity tier

Integration Tests

  • POST /api/characters/:id/enhance deducts materials and gold
  • POST /api/characters/:id/enhance on max (+5) → 409
  • POST /api/characters/:id/enhance with insufficient materials → 422
  • POST /api/characters/:id/reforge re-rolls bonuses, deducts cost
  • POST /api/characters/:id/reforge on Common item → 422
  • Enhanced item stats correctly increased in equipment calculations

Feature 18: Mobile Wrapping & Deployment

Overview

Wrap the SvelteKit SPA in Capacitor for iOS and Android distribution. Configure push notifications, deep links, app lifecycle handling, safe area layout, and the build/release pipeline for app stores.

Dependencies

  • Feature 13 (Notifications) — push notification integration
  • All client UI features complete (or sufficiently built)

Technical Tasks

1. Capacitor Setup

  • Install Capacitor in the client project:
    • npm install @capacitor/core @capacitor/cli
    • npx cap init delve com.delve.game
    • npx cap add ios
    • npx cap add android
  • Configure capacitor.config.ts:
    • server.url pointing to production API
    • plugins configuration for each native plugin

2. Native Plugin Integration

  • Install and configure plugins:
    • @capacitor/push-notifications — FCM (Android) + APNs (iOS)
    • @capacitor/haptics — tactile feedback for loot drops, crits, level ups
    • @capacitor/app — foreground/background detection
    • @capacitor/status-bar — immersive UI (dark status bar, game theme)
    • @capacitor/splash-screen — branded loading screen
    • @capacitor/browser — external links (Stripe checkout, Discord, support)
    • @capacitor/preferences — local key-value storage (cached auth token, settings)

3. Push Notification Flow

  • Create lib/push.ts:
    • On app start: request push permission
    • On token received: POST /api/push/register { platform, token }
    • On token refresh: re-register
    • On notification received (foreground): show in-app toast
    • On notification tapped (background): deep link to relevant screen
  • Configure FCM:
    • Create Firebase project, add Android app
    • Download google-services.jsonandroid/app/
  • Configure APNs:
    • Enable Push Notifications capability in Xcode
    • Create APNs key in Apple Developer portal
    • Upload key to Firebase for FCM→APNs bridging

4. App Lifecycle Handling

  • Create lib/lifecycle.ts:
    • On appStateChange to background:
      • Pause TanStack Query polling (no network requests while backgrounded)
      • Save current state to Preferences (cached auth, last viewed screen)
    • On appStateChange to foreground:
      • Resume polling
      • Invalidate stale queries (refetch character state, notifications)
      • Check for session validity
    • On app resume after long background:
      • Full state refresh

5. Deep Linking

  • Configure URL scheme: delve://
  • Routes:
    • delve://character/{id} → character sheet
    • delve://run/{id} → run result
    • delve://guild/{id} → guild page
    • delve://marketplace → marketplace
    • delve://pvp → PVP arena
  • Configure iOS Universal Links and Android App Links for web→app handoff
  • Push notification payloads include deep link URLs

6. Responsive & Mobile Polish

  • Audit all screens for mobile breakpoint (< 640px):
    • Bottom tab navigation instead of sidebar
    • Stacked panels instead of side-by-side
    • Touch-friendly tap targets (minimum 44px)
    • Drag-and-drop (skill queue, inventory) works with touch via pointer events
    • Item tooltips trigger on tap-and-hold, dismiss on tap elsewhere
  • Safe area handling:
    • env(safe-area-inset-top) for status bar
    • env(safe-area-inset-bottom) for home indicator / gesture bar
  • Keyboard handling:
    • Search inputs in marketplace, friend name, mail compose
    • Viewport resize on keyboard open (prevent content hidden behind keyboard)

7. App Store Assets

  • Generate app icons and splash screens via @capacitor/assets:
    • Source: single 1024x1024 icon SVG/PNG
    • Outputs: all required iOS and Android icon sizes
    • Splash screen: centered logo on brand color background
  • Prepare store metadata:
    • App name: “Delve”
    • Short description (30 chars)
    • Full description (4000 chars)
    • Keywords
    • Screenshots (6.7“ iPhone, 12.9“ iPad, phone + tablet Android)
    • Privacy policy URL
    • Support URL

8. Build Pipeline

  • iOS:
    • pnpm buildnpx cap sync ios
    • Build via Xcode Cloud or self-hosted Mac runner
    • Signing: automatic with App Store Connect API key
    • Distribute: TestFlight (beta), App Store (production)
  • Android:
    • pnpm buildnpx cap sync android
    • Build via Gradle: ./gradlew bundleRelease.aab
    • Signing: upload key in Play Console
    • Distribute: internal testing (beta), production track
  • CI integration:
    • Add mobile build steps to the v* tag pipeline
    • Cache Gradle and CocoaPods dependencies

9. App Store Compliance

  • Payment handling:
    • All purchases via Stripe web checkout (opens in external browser)
    • No in-app purchase SDK
    • App description clearly states “subscription managed via web”
    • Monitor Apple/Google policy changes on external payment links
  • Privacy:
    • App Privacy Details (Apple): email address collected for account
    • Data Safety (Google Play): email collected, no tracking
  • Age rating: fantasy violence (text-based, no graphic content), in-app purchases

Tests

Manual Tests (mobile builds require manual QA)

  • App launches on iOS simulator and Android emulator
  • Push notification permission prompt appears on first launch
  • Push notification received when run completes (app backgrounded)
  • Tapping push notification opens correct screen
  • App resumes from background and refreshes data
  • All screens render correctly at mobile breakpoint
  • Safe areas respected on notch/dynamic island devices
  • Drag-and-drop works with touch (skill queue, inventory)
  • Stripe checkout opens in external browser and returns to app
  • Deep links open correct screens
  • App works offline (shows cached data, queues actions)

Automated Tests

  • Capacitor build succeeds for iOS (npx cap sync ios → Xcode build)
  • Capacitor build succeeds for Android (npx cap sync android → Gradle build)
  • All client unit tests pass in the Capacitor web view context
  • Deep link routing resolves to correct pages