PvP (Player vs Player) with open-source tools
This guide outlines the technical implementation of a structured PvP framework for a MUD, focusing on state management, consent-based dueling, and automated ranking systems. It assumes an existing turn-based or round-based combat engine is already in place.

Define PvP State and Room Flags
Modify the player data structure to include a 'pvp_status' enum (OFF, SEEKING, DUELING, AGGRESSIVE) and the room structure to include 'room_flags' (SAFE, ARENA, OPEN_PVP). This allows the combat engine to check legality before any damage packet is processed.
typedef enum { PVP_NONE, PVP_CONSENT, PVP_OPEN } pvp_type_t;
bool is_combat_legal(char_data *ch, char_data *victim) {
if (IS_SET(ch->in_room->room_flags, ROOM_SAFE)) return false;
if (ch->pvp_status == PVP_NONE && !IS_SET(ch->in_room->room_flags, ROOM_ARENA)) return false;
return true;
}⚠ Common Pitfalls
- •Forgetting to check room flags during area-of-effect (AoE) spells, leading to accidental 'flagging' of peaceful players.
- •Inconsistent state when a player disconnects during an active PvP flag.
Implement the Duel Handshake Protocol
Create a command sequence that requires mutual consent to prevent griefing. The 'challenge' command should set a temporary 'pending_duel' pointer on the target, which expires after a set timeout (e.g., 60 seconds).
def do_challenge(self, target_name):
target = self.world.find_player(target_name)
if not target:
self.send("Player not found.")
return
target.pending_duel = self
target.send(f"{self.name} has challenged you to a duel. Type 'accept {self.name}' to begin.")
self.send(f"Challenge sent to {target.name}.")⚠ Common Pitfalls
- •Allowing multiple pending challenges to stack, which can be used to spam a player's screen during combat.
Develop the ELO Ranking Logic
Integrate an ELO calculation post-combat. When a duel concludes, update the 'pvp_rating' field for both the winner and loser. Use a K-factor (typically 32) to determine the volatility of rating changes.
function calculateElo(winnerRating, loserRating) {
const K = 32;
const expectedWinner = 1 / (1 + Math.pow(10, (loserRating - winnerRating) / 400));
const ratingChange = Math.round(K * (1 - expectedWinner));
return ratingChange;
}⚠ Common Pitfalls
- •Rating inflation caused by 'farming' low-level alts. Implement a minimum level requirement or daily cap on rating gains from the same opponent.
Construct Combat Log Buffers
To facilitate balance and dispute resolution, implement a circular buffer that stores the last 50 combat events (damage, misses, spell effects) for every PvP encounter. This buffer should be dumpable to a file or a 'review' command upon combat conclusion.
⚠ Common Pitfalls
- •Memory leaks if buffers are not cleared when players log out.
- •Excessive disk I/O if logs are written to flat files for every single hit; use an in-memory buffer instead.
Apply Escape and Tether Restrictions
Prevent 'fleeing' or 'recalling' during active PvP. Implement a 'combat_timer' that resets every time a player deals or receives damage. While this timer is active, movement commands to exit the zone or teleportation spells should be disabled.
void do_flee(char_data *ch) {
if (ch->pvp_timer > 0) {
send_to_char("You are too focused on combat to flee properly!\n", ch);
return;
}
// Standard flee logic here
}⚠ Common Pitfalls
- •Players using 'quit' or 'force-close' to escape. Implement a 'ghost' system where the player character remains in the world for 30 seconds if they disconnect during PvP.
Automated Tournament Bracketing
Create a global controller that handles tournament registration. It should sort players by ELO, generate a power-of-two bracket, and automatically teleport pairs into 'ARENA' flagged rooms when their match is called.
⚠ Common Pitfalls
- •Handling 'no-shows' where one player enters the arena and the other is AFK. Implement a 2-minute disqualification timer.
What you built
A successful MUD PvP system requires strict state management to separate willing participants from roleplayers or questers. By implementing robust handshakes, ELO-based matchmaking, and anti-escape mechanics, developers can foster a competitive environment that minimizes toxicity and maximizes mechanical balance.