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)