Overview
The Duel Arena is a server-authoritative PvP system where players challenge each other to combat with customizable rules and stakes. Inspired by Old School RuneScape’s Duel Arena, it provides a safe environment for player-vs-player combat with economic stakes. Key Features:- 6 dedicated duel arenas with automatic pooling
- 10 combat rule toggles (no ranged, no food, etc.)
- 11 equipment slot restrictions
- Item staking with anti-scam protections
- 3-2-1 countdown before combat
- Forfeit mechanics with rule enforcement
- Comprehensive audit logging
Duel Flow
1. Challenge Phase
Players must be in the Duel Arena zone to initiate challenges:- Both players must be within 15 tiles of each other
- Neither player can be in an existing duel
- Challenge expires after 30 seconds (50 ticks)
- Challenger: Sees “Challenge sent” notification
- Target: Receives DuelChallengeModal with Accept/Decline buttons
- Chat: Red clickable message “PlayerA wishes to duel with you”
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 (freeze at spawn points)
- No Forfeit (fight to the death)
- Fun Weapons (cosmetic items allowed)
- Head, Cape, Amulet, Weapon, Body, Shield, Legs, Gloves, Boots, Ring, Ammo
noForfeit + noMovementis invalid (prevents softlocks)- Both players must accept before proceeding
3. Stakes Screen
Players stake items from their inventory: Staking Mechanics:- Left-click inventory item: Stake 1
- Right-click: Context menu (Stake 1, 5, 10, All)
- Click staked item: Remove from stakes
- Maximum 28 staked items per player
- Acceptance resets when either player modifies stakes
- Warning banner when opponent modifies stakes
- Value imbalance warning (>50% difference, >10k gp)
- Staked items are locked (cannot be dropped or traded)
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)
- Both players’ acceptance status
“This is your final chance to review before the duel begins!”Both players must accept to proceed to countdown.
5. Countdown Phase
Arena Reservation:- System reserves one of 6 available arenas
- Returns “No arena available” if all arenas occupied
- Players teleported to arena spawn points (north/south)
- Facing each other automatically
- Disabled equipment slots are unequipped
- 3-2-1-FIGHT overlay with color-coded numbers
- Players frozen during countdown (cannot move)
- Countdown runs on server tick (1 second per tick)
6. Fighting Phase
Combat Begins:- Players can attack each other
- Rules are enforced server-side
- Arena walls prevent escape (collision-based)
- DuelHUD displays opponent health and active rules
- Click forfeit pillar in arena (if allowed)
- Confirmation required (click twice)
- Instant loss, opponent wins all stakes
- 30-second reconnection timer (50 ticks)
- Auto-forfeit if player doesn’t reconnect
- Instant loss if
noForfeitrule active
7. Resolution
Death:- Loser’s health reaches 0
- 8-tick delay (4.8 seconds) for death animation
- Winner receives all stakes
- Both players restored to full health
- Both teleported to duel arena lobby
- Forfeiting player loses immediately
- Same stake transfer and teleportation
- Victory trophy (🏆) or defeat skull (💀)
- Items won/lost with gold values
- Total value summary
Server Architecture
DuelSystem
Location:packages/server/src/systems/DuelSystem/index.ts
Main orchestrator for duel sessions (1,609 lines):
PendingDuelManager
Location:packages/server/src/systems/DuelSystem/PendingDuelManager.ts
Manages challenge requests before duel sessions begin:
- 30-second expiration timer
- Distance validation (15 tiles max)
- Disconnect cleanup
- Prevents duplicate challenges
ArenaPoolManager
Location:packages/server/src/systems/DuelSystem/ArenaPoolManager.ts
Manages 6 duel arenas with automatic pooling:
Arena Layout:
- 2×3 grid of rectangular arenas
- Each arena: 20 tiles wide × 24 tiles long
- 4-tile gap between arenas
- Base coordinates: (70, 0, 90)
- Registers wall collision on initialization
- Blocks perimeter ring OUTSIDE arena bounds
- Players can walk to visual wall but not through it
- Uses
CollisionFlag.BLOCKEDin collision matrix
DuelSessionManager
Location:packages/server/src/systems/DuelSystem/DuelSessionManager.ts
CRUD operations for duel sessions:
DuelCombatResolver
Location:packages/server/src/systems/DuelSystem/DuelCombatResolver.ts
Handles duel outcomes and stake transfers:
- Set session state to FINISHED
- Transfer loser’s stakes to winner
- Restore both players to full health
- Teleport to lobby (different spawn points for winner/loser)
- Emit
duel:completedevent - Audit log for economic tracking
- Clean up session and release arena
Client UI Components
DuelPanel
Location:packages/client/src/game/panels/DuelPanel/
Main duel interface with screen switching:
Screens:
RulesScreen.tsx- Rules and equipment negotiationStakesScreen.tsx- Item staking with inventoryConfirmScreen.tsx- Final read-only review
- Rules screen: 450px width
- Stakes screen: 650px width (3 panels)
- Confirm screen: 520px width (2 columns)
DuelHUD
Location:packages/client/src/game/panels/DuelPanel/DuelHUD.tsx
In-combat overlay showing:
- Opponent health bar (large, prominent)
- Active rule indicators with icons
- Forfeit button (if allowed)
- Disconnect status with countdown
DuelCountdown
Location:packages/client/src/game/panels/DuelPanel/DuelCountdown.tsx
Full-screen countdown overlay:
- Large centered number (200px font)
- Color-coded: 3=red, 2=orange, 1=yellow, 0=green
- Expanding ring pulse effect
- “FIGHT!” display on 0
- Auto-hides after fight starts
DuelResultModal
Location:packages/client/src/game/panels/DuelPanel/DuelResultModal.tsx
Post-duel result display:
- Victory trophy (🏆) or defeat skull (💀)
- Animated entrance (icon pop, title slide)
- Items won/lost with gold values
- Total value summary
- Forfeit indicator
Configuration
Timing Constants
Location:packages/server/src/systems/DuelSystem/config.ts
All timing values in game ticks (600ms each):
Distance Constants
Arena Configuration
Spawn Locations
State Machine
The duel system uses an exhaustive state machine:Network Events
Server → Client
Client → Server
Security Features
Server-Authoritative
All duel logic runs on the server:- Client cannot modify rules, stakes, or outcomes
- Arena bounds enforced via collision matrix
- Stake transfers use database transactions
- Rate limiting on all duel operations
Anti-Scam Protections
- Acceptance Reset: Any modification resets both players’ acceptance
- Opponent Modified Banner: Warning when opponent changes stakes
- Value Imbalance Warning: Alert when risking >50% more than opponent
- Duplicate Slot Prevention: Cannot stake same inventory slot twice
- Read-Only Confirmation: Final screen is non-editable
Audit Logging
Location:packages/server/src/systems/ServerNetwork/services/AuditLogger.ts
All duel events are logged:
Testing
Unit Tests
Location:packages/server/src/systems/DuelSystem/__tests__/
Comprehensive test coverage:
- DuelSystem.test.ts (1,066 lines) - Full state machine testing
- ArenaPoolManager.test.ts (233 lines) - Arena pooling
- PendingDuelManager.test.ts (456 lines) - Challenge management
Integration with Other Systems
Combat System
Location:packages/shared/src/systems/shared/combat/CombatSystem.ts
The combat system checks duel rules before allowing actions:
Death System
Location:packages/shared/src/systems/shared/death/PlayerDeathSystem.ts
Death handling differs for duel deaths:
Inventory System
Staked items are locked during duels:Manifest Configuration
Duel Arena Config
Location:manifests/duel-arenas.json
Centralized configuration for arena layout and zones:
- 6 arenas arranged in a 2×3 grid
- Each arena is 16×16 tiles
- Spawn points positioned 4 tiles from center (north/south)
- 4 trapdoor positions per arena (forfeit pillars)
- Lobby area: 60×30 tiles at (250, 295)
- Hospital area: 20×15 tiles at (210, 295)
Rule Definitions
Equipment Slot Labels
Error Codes
Performance Considerations
Arena Pooling
- 6 arenas support up to 6 concurrent duels
- Arena reservation is O(n) where n=6 (negligible)
- Arena release is O(1) by arena ID or O(n) by duel ID
Session Management
- Player-to-session mapping uses
Map<string, string>for O(1) lookups - Session cleanup runs every 17 ticks (~10 seconds)
- Expired sessions (>30 minutes in setup) are auto-cancelled
Collision Matrix
- Arena walls registered once on initialization
- Uses existing collision system (no performance overhead)
- Wall collision is bitmask-based (very fast)
OSRS Accuracy
The duel system faithfully recreates OSRS mechanics:| Feature | OSRS Behavior | Hyperscape Implementation |
|---|---|---|
| Tick Rate | 600ms (0.6s) | ✅ Matches exactly |
| Challenge Timeout | 30 seconds | ✅ 50 ticks = 30s |
| Countdown | 3-2-1-FIGHT | ✅ 1 second per tick |
| Death Animation | ~5 seconds | ✅ 8 ticks = 4.8s |
| Arena Walls | Collision-based | ✅ CollisionMatrix |
| Forfeit Pillars | Clickable objects | ✅ Implemented |
| Stake Locking | Items locked | ✅ Server-enforced |
| Health Restoration | Full HP after duel | ✅ Both players |
| No Death Penalty | No items lost | ✅ Stakes only |
Future Enhancements
Potential additions (not yet implemented):- Ranked Duels: ELO rating system
- Tournament Mode: Bracket-style competitions
- Spectator Mode: Watch ongoing duels
- Duel History: Track wins/losses
- Leaderboards: Top duelists
- Custom Arenas: Player-created arena layouts
- Obstacles: Arena hazards (OSRS had this)
Related Documentation
Combat System
Core combat mechanics used in duels
Death System
How death is handled differently in duels
Inventory System
Item staking and inventory locking
Collision System
Arena wall collision implementation