Guides

Player Killing (PK) with open-source tools

Implementing a Player Killing (PK) system requires balancing technical enforcement with gameplay fairness. This guide focuses on the architecture of PK flags, level-restricted engagement, and state-driven anti-griefing measures for a production MUD environment.

6 to 10 hours6 steps
Player Killing (PK) with open-source tools hero illustration
1

Define PK Status and Persistent Flags

Add a bitmask or boolean to the player structure to track PK participation. This must be saved to the player file (pfile) to prevent players from toggling status to avoid consequences.

#define PLR_PK (1 << 10)

void do_pk_toggle(CHAR_DATA *ch, char *argument) {
    if (IS_SET(ch->act, PLR_PK)) {
        send_to_char("You are already a PKer.\n\r", ch);
        return;
    }
    SET_BIT(ch->act, PLR_PK);
    save_char_obj(ch);
    send_to_char("You are now flagged for PK.\n\r", ch);
}

⚠ Common Pitfalls

  • Allowing players to toggle PK status while in combat
  • Failing to save the flag, allowing a logout/login to reset status
2

Implement Level-Range Engagement Logic

To prevent 'newbie-slaying,' modify the combat initiation function to check the level difference between the attacker and the target. A common standard is +/- 5 to 10 levels.

bool can_attack(CHAR_DATA *ch, CHAR_DATA *victim) {
    if (!IS_SET(ch->act, PLR_PK) || !IS_SET(victim->act, PLR_PK)) return FALSE;
    if (abs(ch->level - victim->level) > 10) {
        send_to_char("Level difference is too great.\n\r", ch);
        return FALSE;
    }
    return TRUE;
}

⚠ Common Pitfalls

  • Hard-coding level limits which may need tuning as the player base scales
  • Ignoring group/party combat where a high-level player might 'tank' for a low-level PKer
3

Enforce Room-Based PK Restrictions

Integrate room flags into the attack check. Define ROOM_SAFE for towns/newbie areas and ROOM_BATTLEFIELD for areas where level-range checks are ignored.

if (IS_SET(ch->in_room->room_flags, ROOM_SAFE)) {
    send_to_char("A mystical force prevents your violence here.\n\r", ch);
    return FALSE;
}
if (IS_SET(ch->in_room->room_flags, ROOM_CHAOTIC)) {
    return TRUE; // Ignore level checks in chaotic zones
}

⚠ Common Pitfalls

  • Players 'border hopping' between safe and PK rooms to avoid death (ping-ponging)
  • Forgetting to flag critical quest rooms as safe
4

Develop the Combat Timer (Anti-Quit)

Apply a 'combat pulse' or timer to players. While active, the player cannot logout, use 'recall' spells, or enter ROOM_SAFE areas. This ensures players must survive the encounter or flee.

void update_combat_timer(CHAR_DATA *ch) {
    ch->pcdata->pk_timer = 120; // 2 minutes of real time
}

// In do_quit command
if (ch->pcdata->pk_timer > 0) {
    send_to_char("You are too agitated to quit!\n\r", ch);
    return;
}

⚠ Common Pitfalls

  • Timers being too short, allowing players to quit during a chase
  • Not refreshing the timer when a player is hit, only when they attack
5

Handle PK Death and Corpse Mechanics

Modify the death function to differentiate between Mob-Death and PK-Death. Implement specific loot rules, such as allowing the killer to take a limited number of items or a percentage of gold.

void handle_pk_death(CHAR_DATA *victim, CHAR_DATA *killer) {
    OBJ_DATA *corpse = create_object(get_obj_index(OBJ_VNUM_CORPSE), 0);
    corpse->owner = str_dup(victim->name);
    corpse->killer = str_dup(killer->name);
    // Logic to move inventory to corpse
    log_printf("PK: %s killed by %s at room %d", victim->name, killer->name, victim->in_room->vnum);
}

⚠ Common Pitfalls

  • Item duplication bugs during inventory transfer
  • Allowing killers to loot 'No-Drop' or quest-essential items
6

Implement PK Logging and Auditing

Automate the logging of every PK kill to a dedicated file or database. Include timestamps, levels, and room VNUMs. This is essential for resolving griefing disputes and balancing classes.

⚠ Common Pitfalls

  • Incomplete logs that don't show who initiated the fight
  • Log files growing excessively large without rotation

What you built

A robust PK system is defined by its edge-case handling—specifically combat timers and room transitions. Once the core engagement logic is stable, focus on community-facing features like PK ladders or bounty systems to incentivize healthy competition.