Player Roles API

SkillDev tools

Guide for Player Roles API usage implementing OOP-style player role management with inheritance, groups, and custom methods.

Available today. Use it from your connected AI after setup.

Connect ahel once, and every AI you use reads what you have installed.

Then ask your AI: use the Player Roles API skill

What this skill tells your AI

The instructions your AI receives, as published by hedgefog/amxx-modding-kit in .agents/skills/amxx-modding-kit/api/player-roles/SKILL.md and read by ahel’s review.

OOP-style system for defining, assigning, and managing player roles with inheritance, groups, and custom methods/members.

For complete API documentation, see README.md.


Naming Conventions

Role and Group Constants

Use #define with ROLE_ and ROLE_GROUP_ prefixes:

#define ROLE_SURVIVOR "survivor"
#define ROLE_ZOMBIE "zombie"
#define ROLE_FAST_ZOMBIE "fast_zombie"

#define ROLE_GROUP_SPECIES "species"
#define ROLE_GROUP_CLASS "class"

Member and Method Constants

new const m_flPower[] = "flPower";
new const m_szVariant[] = "szVariant";

new const Growl[] = "Growl";
new const GetSpeed[] = "GetSpeed";

Role Registration

Basic Registration

public plugin_precache() {
  // Register standalone roles
  PlayerRole_Register(ROLE_SURVIVOR);
  PlayerRole_Register(ROLE_ZOMBIE);
}

Registration with Inheritance

public plugin_precache() {
  // Base zombie role
  PlayerRole_Register(ROLE_ZOMBIE);

  // Specialized zombies inherit from base
  PlayerRole_Register(ROLE_FAST_ZOMBIE, ROLE_ZOMBIE);
  PlayerRole_Register(ROLE_TANK_ZOMBIE, ROLE_ZOMBIE);
  PlayerRole_Register(ROLE_POISON_ZOMBIE, ROLE_ZOMBIE);
}

Method Implementation

public plugin_precache() {
  PlayerRole_Register(ROLE_ZOMBIE);

  // Implement native methods
  PlayerRole_ImplementMethod(ROLE_ZOMBIE, PlayerRole_Method_Assign, "@Zombie_Assign");
  PlayerRole_ImplementMethod(ROLE_ZOMBIE, PlayerRole_Method_Unassign, "@Zombie_Unassign");

  // Register custom methods
  PlayerRole_RegisterMethod(ROLE_ZOMBIE, Growl, "@Zombie_Growl");
  PlayerRole_RegisterVirtualMethod(ROLE_ZOMBIE, GetSpeed, "@Zombie_GetSpeed");
}

Method Implementations

Assign Method

@Zombie_Assign(const pPlayer) {
  // Call base method if inheriting
  PlayerRole_This_CallBaseMethod();

  // Initialize role members
  PlayerRole_This_SetMember(m_flPower, 100.0);
  PlayerRole_This_SetMemberString(m_szVariant, "standard");

  // Apply role effects
  PlayerModel_Set(pPlayer, g_szZombieModel);
  PlayerModel_Update(pPlayer);

  client_print(pPlayer, print_chat, "You are now a zombie!");
}

Unassign Method

@Zombie_Unassign(const pPlayer) {
  PlayerRole_This_CallBaseMethod();

  // Remove role effects
  PlayerModel_Reset(pPlayer);

  client_print(pPlayer, print_chat, "You are no longer a zombie.");
}

Custom Method

@Zombie_Growl(const pPlayer) {
  emit_sound(pPlayer, CHAN_VOICE, g_szGrowlSound, VOL_NORM, ATTN_NORM, 0, PITCH_NORM);
  client_print(pPlayer, print_center, "Grrrrrrr!");
}

Float:@Zombie_GetSpeed(const pPlayer) {
  return 280.0;
}

Role Assignment

Basic Assignment

// Assign role to player
PlayerRole_Player_AssignRole(pPlayer, ROLE_ZOMBIE);

// Unassign role
PlayerRole_Player_UnassignRole(pPlayer, ROLE_ZOMBIE);

// Unassign all roles
PlayerRole_Player_UnassignRoles(pPlayer);

Assignment with Groups

Groups enforce mutual exclusivity - only one role per group:

// Assign role in specific group
PlayerRole_Player_AssignRole(pPlayer, ROLE_ZOMBIE, ROLE_GROUP_SPECIES);

// Later, assigning different role in same group auto-unassigns previous
PlayerRole_Player_AssignRole(pPlayer, ROLE_SURVIVOR, ROLE_GROUP_SPECIES);
// Zombie is automatically unassigned

// Unassign all roles in a group
PlayerRole_Player_UnassignRoleGroup(pPlayer, ROLE_GROUP_SPECIES);

Inheritance Auto-Exclusivity

Roles with same parent are mutually exclusive:

// Assign FastZombie (inherits from Zombie)
PlayerRole_Player_AssignRole(pPlayer, ROLE_FAST_ZOMBIE);

// Assign TankZombie - FastZombie is automatically unassigned
// (both inherit from Zombie)
PlayerRole_Player_AssignRole(pPlayer, ROLE_TANK_ZOMBIE);

Role Queries

Check Role Assignment

// Check if player has role (includes inheritance)
if (PlayerRole_Player_HasRole(pPlayer, ROLE_ZOMBIE)) {
  // Player has Zombie, FastZombie, TankZombie, etc.
}

// Check exact role (no inheritance check)
if (PlayerRole_Player_HasExactRole(pPlayer, ROLE_FAST_ZOMBIE)) {
  // Player has exactly FastZombie
}

Check Role Group

if (PlayerRole_Player_HasRoleGroup(pPlayer, ROLE_GROUP_SPECIES)) {
  new szRole[PLAYER_ROLE_MAX_LENGTH];
  PlayerRole_Player_GetRoleByGroup(pPlayer, ROLE_GROUP_SPECIES, szRole, charsmax(szRole));

  client_print(pPlayer, print_chat, "Your species role: %s", szRole);
}

Role Members

Set Members

// From within role method (uses This_ variant)
@Zombie_Assign(const pPlayer) {
  PlayerRole_This_SetMember(m_flPower, 100.0);
  PlayerRole_This_SetMemberString(m_szVariant, "alpha");
}

// From outside role method
PlayerRole_Player_SetMember(pPlayer, ROLE_ZOMBIE, m_flPower, 150.0);
PlayerRole_Player_SetMemberString(pPlayer, ROLE_ZOMBIE, m_szVariant, "beta");

Get Members

// From within role method
new Float:flPower = PlayerRole_This_GetMember(m_flPower);

// From outside
new Float:flPower = PlayerRole_Player_GetMember(pPlayer, ROLE_ZOMBIE, m_flPower);

new szVariant[32];
PlayerRole_Player_GetMemberString(pPlayer, ROLE_ZOMBIE, m_szVariant, szVariant, charsmax(szVariant));

Calling Methods

Call Custom Methods

// Call method if player has role
if (PlayerRole_Player_HasRole(pPlayer, ROLE_ZOMBIE)) {
  PlayerRole_Player_CallMethod(pPlayer, ROLE_ZOMBIE, Growl);

  new Float:flSpeed = PlayerRole_Player_CallMethod(pPlayer, ROLE_ZOMBIE, GetSpeed);
}

Call Base Method (In Inherited Roles)

@FastZombie_Assign(const pPlayer) {
  // Call parent (Zombie) Assign method first
  PlayerRole_This_CallBaseMethod();

  // Then add FastZombie-specific logic
  PlayerRole_This_SetMember(m_flSpeedBonus, 50.0);
}

Common Patterns

Spawn-Based Role Assignment

public HamHook_Player_Spawn_Post(const pPlayer) {
  if (!is_user_alive(pPlayer)) return HAM_IGNORED;

  // Assign role based on team
  switch (get_user_team(pPlayer)) {
    case 1: PlayerRole_Player_AssignRole(pPlayer, ROLE_SURVIVOR, ROLE_GROUP_SPECIES);
    case 2: PlayerRole_Player_AssignRole(pPlayer, ROLE_ZOMBIE, ROLE_GROUP_SPECIES);
  }

  return HAM_HANDLED;
}

Role-Based Speed

public HamHook_Player_GetMaxSpeed(const pPlayer) {
  if (PlayerRole_Player_HasRole(pPlayer, ROLE_ZOMBIE)) {
    new Float:flSpeed = PlayerRole_Player_CallMethod(pPlayer, ROLE_ZOMBIE, GetSpeed);
    SetHamReturnFloat(flSpeed);
    return HAM_OVERRIDE;
  }

  return HAM_IGNORED;
}

Reset on Disconnect

public client_disconnected(pPlayer) {
  PlayerRole_Player_UnassignRoles(pPlayer);
}

Complete Role Plugin Structure

#pragma semicolon 1

#include <amxmodx>

#include <api_player_roles>

/*--------------------------------[ Constants ]--------------------------------*/

#define ROLE "Test"
#define GetMaxSpeed "GetMaxSpeed"
#define GetMaxHealth "GetMaxHealth"

/*--------------------------------[ Plugin Initialization ]--------------------------------*/

public plugin_precache() {
  PlayerRole_Register(ROLE);

  PlayerRole_ImplementMethod(ROLE, PlayerRole_Method_Assign, "@Role_Assign");
  PlayerRole_ImplementMethod(ROLE, PlayerRole_Method_Unassign, "@Role_Unassign");

  PlayerRole_RegisterVirtualMethod(ROLE, GetMaxSpeed, "@Role_GetMaxSpeed");
  PlayerRole_RegisterVirtualMethod(ROLE, GetMaxHealth, "@Role_GetMaxHealth");
}

public plugin_init() {
  register_plugin("[Role] Test", "1.0.0", "Author");
}
/*--------------------------------[ Methods ]--------------------------------*/

@Role_Assign(const pPlayer) {}

@Role_Unassign(const pPlayer) {}

Float:@Role_GetMaxSpeed(const pPlayer) {
  return 250.0;
}

Float:@Role_GetMaxHealth(const pPlayer) {
  return 100.0;
}

Best Practices Checklist

  • Register roles in plugin_precache
  • Use inheritance for shared behavior
  • Use groups for mutual exclusivity
  • Use This_ variants inside role methods
  • Call PlayerRole_This_CallBaseMethod() in inherited roles
  • Reset roles on player disconnect
  • Define constants with #define ROLE_ prefix

Signals

GitHub stars
32
Forks
4
Last commit
Aug 2026
Advanced
Catalog kind
skill
Gateway key
amxx-modding-kit-api-player-roles
Source
github.com/hedgefog/amxx-modding-kit