Duel Arena System
The Duel Arena allows players to engage in player-versus-player combat with customizable rules and optional item stakes. The system is OSRS-accurate with a complete state machine for challenge, negotiation, and combat.Duel Arena code lives in
packages/server/src/systems/DuelSystem/ with client UI in packages/client/src/game/panels/DuelPanel/.Duel Flow
1. Challenge
Players initiate duels by walking to their opponent and sending a challenge:- Must be in Duel Arena lobby zone
- Cannot challenge yourself
- Cannot challenge if already in a duel
- 30-second timeout for acceptance
- Cancels if players move >15 tiles apart
- Clickable red chat message: “Player wishes to duel with you.”
- DuelChallengeModal shows challenger name and combat level
- Accept/Decline buttons
2. Rules Screen
Both players negotiate combat rules and equipment restrictions: Combat Rules (10 toggles):- No Ranged
- No Melee
- No Magic
- No Special Attack
- No Prayer
- No Potions
- No Food
- No Movement
- No Forfeit
- Fun Weapons (future)
- Head, Cape, Amulet, Weapon, Body, Shield, Legs, Gloves, Boots, Ring, Ammo
- Either player can toggle rules
- Toggling resets both players’ acceptance
- Both must accept to proceed to Stakes
3. Stakes Screen
Players stake items from their inventory: Staking:- Left-click inventory item: stake 1
- Right-click: context menu for quantity (1, 5, 10, All)
- Click staked item to remove from stakes
- Staked items show with gold border in inventory
- Value imbalance warnings (>50% difference, >10k gp)
- Opponent modification warnings
- Total value display for each player
- Acceptance resets when stakes change
- Both players must accept to proceed to Confirmation
4. Confirmation Screen
Final read-only review before combat: Displays:- Active rules summary
- Disabled equipment summary
- “If You Win, You Receive:” (opponent’s stakes)
- “If You Lose, They Receive:” (your stakes)
- Total values in gold
- Both players must accept to start countdown
- No modifications allowed on this screen
5. Countdown
3-2-1-FIGHT countdown with teleportation:- Players teleported to arena spawn points
- Restricted equipment automatically unequipped
- 3-2-1 countdown displayed (1 second per tick)
- Players frozen during countdown
- “FIGHT!” displayed when combat begins
6. Fighting
Active combat with rule enforcement and real-time health synchronization: Combat AI Improvements:- 2H Sword Attack Timing: DuelCombatAI attacks every weapon-speed cycle (no re-engagement delay)
- First Tick Attack: Seeds first tick to attack immediately since startCombat() has no auto-attack
- Health Bar Sync: Inline HP sync in handleEntityDamaged + updateContestantHp before broadcasts
- Teleport Handling: Health restore with quiet parameter skips visual events during fight-start HP sync
- Countdown Display: CountdownOverlay stays mounted 2.5s into FIGHTING phase with fade-out animation
canUseRanged(playerId)canUseMelee(playerId)canUseMagic(playerId)canUseSpecialAttack(playerId)canUsePrayer(playerId)canUsePotions(playerId)canEatFood(playerId)canMove(playerId)canForfeit(playerId)
- Opponent health bar at top center
- Active rule indicators
- Forfeit button (if allowed)
- Disconnect status with countdown
- Opponent’s health reaches 0
- Opponent forfeits (if allowed)
- Opponent disconnects for 30 seconds
7. Result
Duel resolution and stake transfer with proper cleanup:endCycle()chains cleanup→delay→new cycle via .finally()- INTER_CYCLE_DELAY_MS ensures proper cleanup before next cycle
- Cleanup always teleports both agents to lobby
- Prevents stale avatars stuck in arena between cycles
- Victory trophy (🏆) or defeat skull (💀)
- Items won/lost with gold values
- Total value summary
- Forfeit indicator if applicable
Arena System
Arena Pool
6 arenas arranged in a 2×3 grid:- Automatic reservation when duel confirmed
- Fence posts and rails (replaced solid walls for better visibility)
- Flattened terrain for fair combat via terrain flat zones
- Forfeit pillars (if forfeit allowed)
- Released when duel ends
- Lit torches at all 4 corners with fire particles
- Procedural stone tile floor texture (unique per arena)
Terrain Flat Zone Registration (commits b8f56e81, 7a60135)
The duel arena system registers flat zones with the terrain system to prevent players from sinking into arena floors:- Flat zones were removed from the terrain system
getHeightAt()returned raw procedural terrain height instead of floor-level height- Grass was growing through floor surfaces
- DuelArenaVisualsSystem registers flat zones during
start()for all 8 floor areas - TerrainSystem stores flat zones in a spatial index (terrain tiles for O(1) lookup)
- Height queries (
getHeightAt()) check flat zones first before procedural terrain - Terrain mesh is carved under floors to prevent grass/vegetation clipping
- Players spawn at the correct floor-level height (procedural + 0.4m offset)
height: Procedural terrain height + 0.4m (where players stand)blendRadius: 1.0m smooth transition to surrounding terraincarveInset: 1.0m inset from zone edges to preserve blend padding
- 6 duel arenas (20m × 24m each)
- Lobby floor (40m × 25m)
- Hospital floor (30m × 25m)
Visual Enhancements
Lit Torches
Each arena has 4 lit torches at the fence corners:- PointLights with flicker animation
- Fire particles using “torch” glow preset
- Tight particle spread (0.08) for concentrated flame effect
- Preset-aware particle respawn system
Procedural Stone Tile Texture
Arena floors use canvas-generated sandstone tile patterns:- OSRS medieval aesthetic
- Grout lines between tiles
- Color variation for natural stone look
- Speckle noise for texture detail
- Unique texture per arena (seeded by arena ID)
Spawn Points
Each arena has 2 spawn points (north and south):Arena Bounds
Movement is restricted to arena bounds:CollisionMatrix to prevent escape.
Server Architecture
DuelSystem
Main orchestrator for the duel state machine:DuelSessionManager
Handles session CRUD operations:PendingDuelManager
Tracks challenge requests with timeouts:ArenaPoolManager
Manages arena reservation and collision:DuelCombatResolver
Handles combat resolution and stake transfers:DuelCombatAI
Tick-based combat AI for streaming duels with trash talk system: Location:packages/server/src/arena/DuelCombatAI.ts
- Removes redundant manual attack-speed tracking from DuelCombatAI
- Combat system’s auto-attack loop already drives attack cadence
- AI only re-engages when combat drops or target changes
- Fixes 2H sword attack timing issues (slow weapons were silently dropping attacks)
TWO_HAND_SWORD:
- Fires once per threshold per fight (prevents spam)
- Compares previous vs current HP to detect threshold crossings
- Tracks fired thresholds in
firedOwnThresholdsandfiredOpponentThresholdssets - 8-second cooldown between messages (
TRASH_TALK_COOLDOWN_MS)
Ambient Periodic Taunts
Random taunts every 15-25 ticks:- Scheduled via tick counter with randomized intervals
- Adds personality to prolonged fights
- Respects 8-second cooldown between all messages
LLM-Generated Taunts
Uses agent character bio/style via TEXT_SMALL model:- 30-token limit for overhead chat bubble
- 3-second LLM timeout with scripted fallback
- Temperature 0.9 for creative, varied responses
- Fire-and-forget (never blocks combat tick loop)
- In-flight flag prevents overlapping LLM calls
- Uses scripted taunt pools when LLM unavailable
- Ensures trash talk works without LLM access
- Used when LLM call fails or times out
Integration with DuelOrchestrator
- DuelOrchestrator drives AI ticks via
externalTick() - Runs every 600ms (game tick duration)
- Synchronized with combat system tick cadence
- Stats logged on AI stop (attacks, heals, damage dealt)
Social System Update
CHAT_MESSAGE action now allowed during combat:Duel Session Structure
Network Protocol
Client → Server
Server → Client
Configuration
Timing Constants
All timing values use game ticks (600ms each):Distance Constants
Arena Configuration
Spawn Locations
Rule Enforcement
The DuelSystem provides rule enforcement APIs for other systems:Combat System Integration
Food System Integration
Movement System Integration
Disconnect Handling
During Setup (RULES/STAKES/CONFIRMING)
Immediate cancellation:- Duel cancelled
- Stakes returned to both players
- Arena released (if reserved)
- Opponent notified
During Combat (FIGHTING)
30-second grace period:- Instant loss on disconnect (can’t forfeit, so disconnect = loss)
Death Handling
When a player dies during a duel:- Winner receives loser’s stakes
- Both players restored to full health
- Winner teleported to LOBBY_SPAWN_WINNER
- Loser teleported to LOBBY_SPAWN_LOSER
- Arena released
- Session deleted
OSRS-Accurate: Players don’t actually die in duels. Health is restored after combat ends.
Stake Transfer
Stakes are transferred atomically when duel ends:- Server-authoritative stake validation
- Atomic database transactions
- Audit logging for economic tracking
- Prevents item duplication exploits
Testing
Comprehensive test coverage for all duel functionality:Unit Tests
DuelSystem.test.ts (1,066 lines):- Challenge creation and validation
- State transitions through all screens
- Rule toggling and validation
- Equipment restriction toggling
- Stake operations (add/remove)
- Combat outcomes (death, forfeit)
- Disconnect handling
- Error cases and edge conditions
- Challenge creation and validation
- Acceptance and decline
- Expiration cleanup
- Distance-based cancellation
- Player disconnect cleanup
- Arena initialization (6 arenas)
- Reservation and release
- Spawn point and bounds retrieval
- Pool exhaustion handling
- Grid layout validation
Integration Tests
- Full duel flow from challenge to result
- Rule enforcement during combat
- Stake transfer verification
- Disconnect/reconnect scenarios
UI Components
DuelPanel
Main duel interface with screen switching:RulesScreen- Rules and equipment negotiationStakesScreen- Item staking with three panels (my stakes, opponent stakes, inventory)ConfirmScreen- Final read-only review
DuelChallengeModal
Incoming challenge popup:DuelCountdown
Full-screen countdown overlay:- Large centered countdown number
- Color-coded stages (red → orange → yellow → green)
- Expanding ring pulse effect
- “FIGHT!” display on 0
DuelHUD
In-combat overlay:- Opponent health bar with color coding
- Active rule indicators
- Forfeit button (if allowed)
- Disconnect status with countdown
DuelResultModal
Post-duel result display:- Animated entrance with icon pop
- Victory trophy or defeat skull
- Items won/lost with gold values
- Total value summary
Audit Logging
All duel outcomes are logged for economic tracking:- Duel completion (winner, loser, stakes transferred)
- Duel cancellation (if stakes were involved)
- Large stake transfers (≥1M gold value)
Related Documentation
- Combat System - Combat mechanics and damage formulas
- Inventory System - Item staking and transfers
- Movement System - Arena bounds and pathfinding
- Death System - Death handling and respawning