AMX Mod X Project Organization

SkillDev tools

Best practices for organizing large AMX Mod X projects with multiple plugins sharing entities, weapons, events, and other definitions. Use when creating mod-scale projects that need consistent namespace patterns and shared constants.

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 AMX Mod X Project Organization 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/project/SKILL.md and read by ahel’s review.

Best practices for large projects with multiple plugins sharing definitions.


Project File Structure

mymod/
├── assets/
│   └── addons/
│       └── amxmodx/
│           └── configs/
│               └── assets/
│                   └── mymod.json       # Asset library
├── src/
│   ├── include/
│   │   ├── mymod_const.inc              # Shared constants (entities, events, etc.)
│   │   ├── mymod_internal.inc           # Internal macros (not for external use)
│   │   └── mymod.inc                    # Public API for external plugins
│   └── scripts/
│       ├── core/
│       │   ├── core.sma                 # Main mod plugin
│       │   └── gamerules.sma
│       ├── entities/
│       │   ├── projectile.sma
│       │   └── corpse.sma
│       ├── weapons/
│       │   ├── base.sma                 # Base weapon class
│       │   ├── rifle.sma
│       │   └── pistol.sma
│       ├── player-roles/
│       │   ├── base.sma
│       │   └── survivor.sma
│       └── features/
│           └── infection.sma
└── README.md

API References

Projects typically utilize amxxpack for dependency management and build automation, configured via .amxxpack.json.

Standard Paths

  • AMX Mod X Includes: ./.compiler/include
  • Third-party Libraries: ./.thirdparty

Documentation Resources

Refer to the following resources within amxx-modding-kit for implementation details:

  • README.md files: Module overviews, usage guides, and architectural documentation.
  • .inc files: Located in the include/ directory; contains function signatures, constants, and technical API specifications.

Include File Organization

Constants File (mymod_const.inc)

#if defined _mymod_const_included
  #endinput
#endif
#define _mymod_const_included

/*--------------------------------[ Title ]--------------------------------*/

stock const MYTMOD_TITLE[] = "My Mod";
stock const MYMOD_VERSION[] = "1.0.0";

/*--------------------------------[ Libraries ]--------------------------------*/

stock const MyMod_Library_Core[] = "mymod";
stock const MyMod_Library_Gamerules[] = "mymod_gamerules";
stock const MyMod_Library_Infection[] = "mymod_infection";

/*--------------------------------[ Asset Library ]--------------------------------*/

stock const MyMod_AssetLibrary[] = "mymod";

/*--------------------------------[ Assets ]--------------------------------*/

stock const MyMod_Asset_Player_Model_Survivor[] = "player.survivor.model";
stock const MyMod_Asset_Player_Model_Infected[] = "player.infected.model";
stock const MyMod_Asset_Player_Sound_Hit[] = "player.sounds.hit";
stock const MyMod_Asset_Weapon_Rifle_Model_View[] = "weapons.rifle.models.view";
stock const MyMod_Asset_Weapon_Rifle_Model_Player[] = "weapons.rifle.models.player";
stock const MyMod_Asset_Weapon_Rifle_Model_World[] = "weapons.rifle.models.world";

/*--------------------------------[ Entities ]--------------------------------*/

stock const MyMod_Entity_Projectile[] = "mm_projectile";
stock const MyMod_Entity_Corpse[] = "mm_corpse";
stock const MyMod_Entity_WeaponBox[] = "weaponbox";

/*--------------------------------[ Entity Members ]--------------------------------*/

stock const MyMod_Entity_Projectile_Member_flDamage[] = "flDamage";
stock const MyMod_Entity_Projectile_Member_flSpeed[] = "flSpeed";
stock const MyMod_Entity_Projectile_Member_pTarget[] = "pTarget";

/*--------------------------------[ Entity Methods ]--------------------------------*/

stock const MyMod_Entity_Projectile_Method_Launch[] = "Launch";
stock const MyMod_Entity_Projectile_Method_Explode[] = "Explode";

/*--------------------------------[ Weapons ]--------------------------------*/

stock const MyMod_Weapon_Base[] = "mymod/v100/weapon_base";
stock const MyMod_Weapon_Rifle[] = "mymod/v100/weapon_rifle";
stock const MyMod_Weapon_Pistol[] = "mymod/v100/weapon_pistol";

/*--------------------------------[ Weapon Members ]--------------------------------*/

stock const MyMod_Weapon_Base_Member_flWeight[] = "flWeight";
stock const MyMod_Weapon_Rifle_Member_flChargeTime[] = "flChargeTime";
stock const MyMod_Weapon_Rifle_Member_bSilenced[] = "bSilenced";

/*--------------------------------[ Weapon Methods ]--------------------------------*/

stock const MyMod_Weapon_Rifle_Method_ToggleSilencer[] = "ToggleSilencer";

/*--------------------------------[ Player Roles ]--------------------------------*/

stock const MyMod_PlayerRole_Base[] = "mymod-base";
stock const MyMod_PlayerRole_Survivor[] = "mymod-survivor";
stock const MyMod_PlayerRole_Infected[] = "mymod-infected";

/*--------------------------------[ Role Members ]--------------------------------*/

stock const MyMod_PlayerRole_Base_Member_flSpeed[] = "flSpeed";
stock const MyMod_PlayerRole_Survivor_Member_iKills[] = "iKills";

/*--------------------------------[ Role Methods ]--------------------------------*/

stock const MyMod_PlayerRole_Base_Method_GetMaxSpeed[] = "GetMaxSpeed";
stock const MyMod_PlayerRole_Base_Method_GetMaxHealth[] = "GetMaxHealth";

/*--------------------------------[ Events ]--------------------------------*/

stock const MyMod_Event_PlayerInfected[] = "mymod-player-infected";
stock const MyMod_Event_RoundStarted[] = "mymod-round-started";
stock const MyMod_Event_ConfigLoaded[] = "mymod-config-loaded";

/*--------------------------------[ State Contexts ]--------------------------------*/

stock const MyMod_StateContext_Infection[] = "mymod-infection";

/*--------------------------------[ Shops ]--------------------------------*/

stock const MyMod_Shop_Main[] = "mymod";
stock const MyMod_Shop_Item_Medkit[] = "mm-medkit";
stock const MyMod_Shop_Item_Armor[] = "mm-armor";

/*--------------------------------[ Enums ]--------------------------------*/

enum MyMod_Team {
  MyMod_Team_Unassigned = 0,
  MyMod_Team_Survivors,
  MyMod_Team_Infected,
  MyMod_Team_Spectators
};

enum MyMod_InfectionState {
  MyMod_InfectionState_None,
  MyMod_InfectionState_Infected,
  MyMod_InfectionState_Transformed
};

enum {
  MyMod_WeaponId_Rifle = 3,
  MyMod_WeaponId_Pistol,
  MyMod_WeaponId_Grenade
};

/*--------------------------------[ Dictionary ]--------------------------------*/

stock const MyMod_Dictionary[] = "mymod.txt";
stock const MyMod_DictionaryKey_RoundStart[] = "MM_ROUND_START";

Internal Macros File (mymod_internal.inc)

#if defined _mymod_internal_included
  #endinput
#endif
#define _mymod_internal_included

#include <mymod_const>

/*--------------------------------[ Common Macros ]--------------------------------*/

#if !defined IS_PLAYER
  #define IS_PLAYER(%1) (%1 >= 1 && %1 <= MaxClients)
#endif

#if !defined BIT
  #define BIT(%1) (1 << (%1))
#endif

/*--------------------------------[ CVar & Command Macros ]--------------------------------*/

#define CVAR(%1) "mymod_" + %1
#define COMMAND(%1) "mymod_" + %1

/*--------------------------------[ Plugin Registration Macros ]--------------------------------*/

#define PLUGIN_NAME(%1) "[My Mod] " + %1
#define ENTITY_PLUGIN(%1) "[Entity] My Mod " + #%1
#define WEAPON_PLUGIN(%1) "[Weapon] My Mod " + #%1
#define ROLE_PLUGIN(%1) "[Role] My Mod " + #%1
#define FEATURE_PLUGIN(%1) "[Feature] My Mod " + #%1

/*--------------------------------[ Namespace Macros ]--------------------------------*/

#define NAMESPACE(%1) MyMod_%1
#define NAMESPACE_FIELD<%1>(%2) NAMESPACE(%1)_%2

/*--------------------------------[ Library Shortcuts ]--------------------------------*/

#define LIBRARY(%1) NAMESPACE_FIELD<Library>(%1)

/*--------------------------------[ Asset Shortcuts ]--------------------------------*/

#define ASSET_LIBRARY NAMESPACE(AssetLibrary)
#define ASSET(%1) NAMESPACE_FIELD<Asset>(%1)

/*--------------------------------[ Entity Shortcuts ]--------------------------------*/

#define ENTITY(%1) NAMESPACE_FIELD<Entity>(%1)
#define ENTITY_DATA<%1>(%2,%3) ENTITY(%2)_%1_%3
#define ENTITY_METHOD<%1>(%2) ENTITY_DATA<Method>(%1,%2)
#define ENTITY_MEMBER<%1>(%2) ENTITY_DATA<Member>(%1,%2)

/*--------------------------------[ Weapon Shortcuts ]--------------------------------*/

#define WEAPON(%1) NAMESPACE_FIELD<Weapon>(%1)
#define WEAPON_DATA<%1>(%2,%3) WEAPON(%2)_%1_%3
#define WEAPON_METHOD<%1>(%2) WEAPON_DATA<Method>(%1,%2)
#define WEAPON_MEMBER<%1>(%2) WEAPON_DATA<Member>(%1,%2)

/*--------------------------------[ Player Role Shortcuts ]--------------------------------*/

#define PLAYER_ROLE(%1) NAMESPACE_FIELD<PlayerRole>(%1)
#define PLAYER_ROLE_DATA<%1>(%2,%3) PLAYER_ROLE(%2)_%1_%3
#define PLAYER_ROLE_METHOD<%1>(%2) PLAYER_ROLE_DATA<Method>(%1,%2)
#define PLAYER_ROLE_MEMBER<%1>(%2) PLAYER_ROLE_DATA<Member>(%1,%2)

/*--------------------------------[ Event Shortcuts ]--------------------------------*/

#define EVENT(%1) NAMESPACE_FIELD<Event>(%1)

/*--------------------------------[ State Shortcuts ]--------------------------------*/

#define STATE_CONTEXT(%1) NAMESPACE_FIELD<StateContext>(%1)

/*--------------------------------[ Shop Shortcuts ]--------------------------------*/

#define SHOP(%1) NAMESPACE_FIELD<Shop>(%1)
#define SHOP_ITEM(%1) NAMESPACE_FIELD<Shop_Item>(%1)

/*--------------------------------[ Dictionary Shortcuts ]--------------------------------*/

#define DICTIONARY NAMESPACE(Dictionary)
#define DICTIONARY_KEY(%1) NAMESPACE_FIELD<DictionaryKey>(%1)

Core Plugin vs Game Rules

Core Plugin (core.sma)

The core plugin prepares the game for the mod. It contains static logic that doesn't depend on game state, events, or conditions.

Must Do:

  • Define library - Register mod library with register_library() so other plugins can check if mod is loaded
  • Register version cvar - Create version cvar with FCVAR_SERVER flag and hook changes to prevent modification
  • Customize game name - Hook FM_GetGameDescription to display mod name instead of base game
  • Load configuration - Execute mod config files in plugin_cfg() and emit event when loaded

Should Do (If Needed):

  • Block unwanted entities - Use CE_RegisterNullClass() to disable game entities that conflict with your mod (e.g., armoury_entity, hostage_entity, func_buyzone)
  • Block messages - Hook messages to suppress default game notifications (win messages, radio, etc.)
  • Block client commands - Register and block commands that shouldn't work in your mod (e.g., radio1, buy)
  • Validate required modules - Check for required libraries with LibraryExists() and set_fail_state() if missing
  • Load common resources - Load asset libraries and precache shared resources used across multiple plugins

Game Rules (gamerules.sma)

The game rules plugin defines dynamic gameplay logic that depends on game state, entity state, and conditions.

Typical Responsibilities:

  • Win/lose conditions - Check when team wins, round ends, game ends
  • Spawn logic - Control what happens when players spawn, what equipment they get
  • Round flow - Handle round start, round end, intermission
  • Team balance - Manage team assignment, auto-balance
  • Player death handling - What happens when player dies (drop items, respawn timer, etc.)
  • Score tracking - Track kills, objectives, team scores
  • Game mode states - Manage game phases (warmup, active, overtime, etc.)

Key Difference

AspectCore PluginGame Rules
Logic typeStatic, unconditionalDynamic, conditional
Depends onNothing (runs always)Game state, entity state
PurposePrepare game environmentDefine gameplay behavior
ExampleBlock armoury_entityGive weapons on spawn

Should NOT be in either:

  • Entity implementations → entities/*.sma
  • Weapon implementations → weapons/*.sma
  • Feature-specific logic → features/*.sma

Plugin Independence (Best Practice)

Entities, weapons, and roles should avoid direct dependencies on gamerules to remain reusable and work independently.

Recommended Approach

┌─────────────────┐     forwards/events     ┌─────────────────┐
│   Game Rules    │ ───────────────────────>│ Entity/Weapon   │
│                 │                         │                 │
│ (state owner)   │<─────────────────────── │ (subscriber)    │
└─────────────────┘   subscribe via events  └─────────────────┘

Instead of:

// ❌ Direct gamerules dependency - breaks if gamerules not loaded
@Weapon_PrimaryAttack(const this) {
  if (GameRules_GetState() == GameState_Warmup) return;  // Direct call
  // ...
}

Use events/forwards:

// ✅ Subscribe to state changes - works without gamerules
new bool:g_bCanAttack = true;

public plugin_init() {
  // Subscribe to game state changes (if gamerules exists)
  CustomEvent_Subscribe(EVENT(GameStateChanged), "OnGameStateChanged");
}

public OnGameStateChanged(GameState:iNewState) {
  g_bCanAttack = (iNewState != GameState_Warmup);
}

@Weapon_PrimaryAttack(const this) {
  if (!g_bCanAttack) return;  // Uses local state
  // ...
}

When Direct Calls Are Acceptable

Direct gamerules calls are fine when the entity is part of gamerules logic:

  • Spawner entities that configure game rules
  • Trigger entities that end rounds
  • Objective entities that track game progress
  • Initialization entities that set gamerules variables
// ✅ OK - entity IS part of gamerules
@TriggerRescue_Touch(const this, const pPlayer) {
  if (!IS_PLAYER(pPlayer)) return;

  GameRules_DispatchWin(TEAM_CT);  // Direct call is appropriate here
}

Benefits

ApproachWithout GamerulesWith Gamerules
Direct calls❌ Crashes/fails✅ Works
Events/forwards✅ Works (default behavior)✅ Works (custom behavior)

This pattern makes entities and weapons portable across different mods or usable in standalone testing.


Core Plugin Structure

Main Mod Plugin (core.sma)

#pragma semicolon 1

#include <amxmodx>
#include <amxmisc>
#include <fakemeta>

#include <api_assets>
#include <api_custom_entities>

#include <mymod_internal>

/*--------------------------------[ Forward Pointers ]--------------------------------*/

new g_pfwConfigLoaded;

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

public plugin_precache() {
  // Load asset library
  Asset_Library_Load(ASSET_LIBRARY);

  // Nullify unwanted CS entities
  CE_RegisterNullClass("armoury_entity");
  CE_RegisterNullClass("weapon_shield");
  CE_RegisterNullClass("game_player_equip");

  // Register version cvar with change hook
  hook_cvar_change(create_cvar(CVAR("version"), MYMOD_VERSION, FCVAR_SERVER), "CvarHook_Version");
}

public plugin_init() {
  register_plugin(MYTMOD_TITLE, MYMOD_VERSION, "Author");

  // Check required libraries
  if (!LibraryExists(LIBRARY(Gamerules), LibType_Library)) {
    set_fail_state("Gamerules library is required!");
  }

  // Create forward
  g_pfwConfigLoaded = CreateMultiForward("MyMod_OnConfigLoaded", ET_IGNORE);

  // Hook game description
  register_forward(FM_GetGameDescription, "FMHook_GetGameDescription");

  // Register inline message hooks
  register_message(get_user_msgid("SendAudio"), "Message_SendAudio");
  register_message(get_user_msgid("TextMsg"), "Message_TextMsg");
}

public plugin_cfg() {
  new szConfigDir[32]; get_configsdir(szConfigDir, charsmax(szConfigDir));
  new szMapName[64]; get_mapname(szMapName, charsmax(szMapName));

  // Execute main config, then map-specific config
  server_cmd("exec %s/mymod.cfg", szConfigDir);
  server_cmd("exec %s/mymod/%s.cfg", szConfigDir, szMapName);
  server_exec();

  // Notify other plugins
  ExecuteForward(g_pfwConfigLoaded);
}

public plugin_natives() {
  register_library(LIBRARY(Core));
}

/*--------------------------------[ Hooks ]--------------------------------*/

public CvarHook_Version(const pCvar) {
  set_pcvar_string(pCvar, MYMOD_VERSION);
}

public FMHook_GetGameDescription() {
  static szGameName[32];
  format(szGameName, charsmax(szGameName), "%s %s", MYTMOD_TITLE, MYMOD_VERSION);
  forward_return(FMV_STRING, szGameName);

  return FMRES_SUPERCEDE;
}

public Message_SendAudio() {
  static szAudio[16]; get_msg_arg_string(2, szAudio, charsmax(szAudio));

  // Block radio messages
  if (equal(szAudio, "%!MRAD_", 7)) return PLUGIN_HANDLED;

  return PLUGIN_CONTINUE;
}

public Message_TextMsg() {
  static szMessage[32]; get_msg_arg_string(2, szMessage, charsmax(szMessage));

  // Block default win messages
  if (equal(szMessage, "#Terrorists_Win")) return PLUGIN_HANDLED;
  if (equal(szMessage, "#CTs_Win")) return PLUGIN_HANDLED;
  if (equal(szMessage, "#Round_Draw")) return PLUGIN_HANDLED;

  return PLUGIN_CONTINUE;
}

Local Shortcut Macros

Internal macros like ENTITY_METHOD<Projectile>(Launch) and WEAPON_MEMBER<Rifle>(bSilenced) use non-standard MACRO<>() syntax that breaks syntax highlighting. To avoid this, define local shortcut macros at the top of each plugin file.

Rule: Never use MACRO<>() patterns directly in plugin code. Always define local shortcuts (METHOD, MEMBER) at the top of the file and use those instead.

Custom Entities

#pragma semicolon 1

#include <amxmodx>

#include <api_custom_entities>

#include <mymod_internal>

// Local shortcut macros for this entity
#define ENTITY_NAME ENTITY(Projectile)
#define METHOD ENTITY_METHOD<Projectile>
#define MEMBER ENTITY_MEMBER<Projectile>

/*--------------------------------[ Assets ]--------------------------------*/

new const g_szModel[] = "models/mymod/projectile.mdl";

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

public plugin_precache() {
  precache_model(g_szModel);

  CE_RegisterClass(ENTITY_NAME);
  CE_ImplementClassMethod(ENTITY_NAME, CE_Method_Create, "@Entity_Create");
  CE_ImplementClassMethod(ENTITY_NAME, CE_Method_Spawn, "@Entity_Spawn");
  CE_ImplementClassMethod(ENTITY_NAME, CE_Method_Touch, "@Entity_Touch");

  // ✅ CORRECT: METHOD(Launch) expands cleanly
  CE_RegisterClassMethod(ENTITY_NAME, METHOD(Launch), "@Entity_Launch", CE_Type_Cell);
}

public plugin_init() {
  register_plugin(ENTITY_PLUGIN(Projectile), MYMOD_VERSION, "Author");
}

/*--------------------------------[ Methods ]--------------------------------*/

@Entity_Create(const this) {
  CE_CallBaseMethod();

  CE_SetMemberString(this, CE_Member_szModel, g_szModel);

  // ✅ CORRECT: MEMBER(flDamage) instead of ENTITY_MEMBER<Projectile>(flDamage)
  CE_SetMember(this, MEMBER(flDamage), 50.0);
  CE_SetMember(this, MEMBER(flSpeed), 1000.0);
}

@Entity_Spawn(const this) {
  CE_CallBaseMethod();

  set_pev(this, pev_movetype, MOVETYPE_FLY);
  set_pev(this, pev_solid, SOLID_BBOX);
}

@Entity_Touch(const this, const pTarget) {
  CE_CallBaseMethod(pTarget);

  static Float:flDamage; flDamage = CE_GetMember(this, MEMBER(flDamage));
  static pOwner; pOwner = pev(this, pev_owner);

  if (IS_PLAYER(pTarget)) {
    ExecuteHamB(Ham_TakeDamage, pTarget, this, pOwner, flDamage, DMG_GENERIC);
  }

  // ✅ Call custom method via shortcut
  CE_CallMethod(this, METHOD(Explode));
}

@Entity_Launch(const this, const pTarget) {
  // Launch logic...
}

Custom Weapons

#pragma semicolon 1

#include <amxmodx>

#include <api_custom_weapons>

#include <mymod_internal>

// Local shortcut macros for this weapon
#define WEAPON_NAME WEAPON(Rifle)
#define METHOD WEAPON_METHOD<Rifle>
#define MEMBER WEAPON_MEMBER<Rifle>

/*--------------------------------[ Assets ]--------------------------------*/

new const g_szModelV[] = "models/mymod/v_rifle.mdl";
new const g_szModelP[] = "models/mymod/p_rifle.mdl";
new const g_szModelW[] = "models/mymod/w_rifle.mdl";

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

public plugin_precache() {
  precache_model(g_szModelV);
  precache_model(g_szModelP);
  precache_model(g_szModelW);

  CW_RegisterClass(WEAPON_NAME, "weapon_ak47");
  CW_ImplementClassMethod(WEAPON_NAME, CW_Method_Create, "@Weapon_Create");
  CW_ImplementClassMethod(WEAPON_NAME, CW_Method_Deploy, "@Weapon_Deploy");
  CW_ImplementClassMethod(WEAPON_NAME, CW_Method_PrimaryAttack, "@Weapon_PrimaryAttack");

  // ✅ CORRECT: METHOD(ToggleSilencer) expands cleanly
  CW_RegisterClassMethod(WEAPON_NAME, METHOD(ToggleSilencer), "@Weapon_ToggleSilencer", CW_Type_Cell);
}

public plugin_init() {
  register_plugin(WEAPON_PLUGIN(Rifle), MYMOD_VERSION, "Author");
}

/*--------------------------------[ Methods ]--------------------------------*/

@Weapon_Create(const this) {
  CW_CallBaseMethod();

  CW_SetMemberString(this, CW_Member_szModel, g_szModelW);
  CW_SetMember(this, CW_Member_iId, MyMod_WeaponId_Rifle);

  // ✅ CORRECT: MEMBER(bSilenced) instead of WEAPON_MEMBER<Rifle>(bSilenced)
  CW_SetMember(this, MEMBER(bSilenced), false);
  CW_SetMember(this, MEMBER(flChargeTime), 0.0);
}

@Weapon_Deploy(const this) {
  CW_CallBaseMethod();

  CW_CallNativeMethod(this, CW_Method_DefaultDeploy, g_szModelV, g_szModelP, 0, "rifle");
}

@Weapon_PrimaryAttack(const this) {
  CW_CallBaseMethod();

  if (bool:CW_GetMember(this, MEMBER(bSilenced))) {
    // Silenced fire logic...
  }
}

@Weapon_ToggleSilencer(const this) {
  // ✅ Toggle using shortcut member
  CW_SetMember(this, MEMBER(bSilenced), !bool:CW_GetMember(this, MEMBER(bSilenced)));
}

Player Roles

#pragma semicolon 1

#include <amxmodx>

#include <api_player_roles>
#include <api_player_model>

#include <mymod_internal>

// Local shortcut macros for this role
#define ROLE PLAYER_ROLE(Base)
#define METHOD PLAYER_ROLE_METHOD<Base>
#define MEMBER PLAYER_ROLE_MEMBER<Base>

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

public plugin_precache() {
  PlayerRole_Register(ROLE);

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

  // ✅ CORRECT: METHOD(GetMaxSpeed) expands cleanly
  PlayerRole_RegisterVirtualMethod(ROLE, METHOD(GetMaxSpeed), "@Role_GetMaxSpeed");
  PlayerRole_RegisterVirtualMethod(ROLE, METHOD(GetMaxHealth), "@Role_GetMaxHealth");
}

public plugin_init() {
  register_plugin(ROLE_PLUGIN(Base), MYMOD_VERSION, "Author");
}

/*--------------------------------[ Methods ]--------------------------------*/

@Role_Assign(const pPlayer) {
  PlayerRole_This_CallBaseMethod();

  // ✅ CORRECT: MEMBER(flSpeed) instead of PLAYER_ROLE_MEMBER<Base>(flSpeed)
  PlayerRole_This_SetMember(MEMBER(flSpeed), 250.0);
}

@Role_Unassign(const pPlayer) {
  PlayerRole_This_CallBaseMethod();

  PlayerModel_Reset(pPlayer);
}

Float:@Role_GetMaxSpeed(const pPlayer) {
  return PlayerRole_This_GetMember(MEMBER(flSpeed));
}

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

Summary

APILocal DefinesUsage in Code
Custom Entities#define METHOD ENTITY_METHOD<EntityName>METHOD(Launch)
#define MEMBER ENTITY_MEMBER<EntityName>MEMBER(flDamage)
Custom Weapons#define METHOD WEAPON_METHOD<WeaponName>METHOD(ToggleSilencer)
#define MEMBER WEAPON_MEMBER<WeaponName>MEMBER(bSilenced)
Player Roles#define METHOD PLAYER_ROLE_METHOD<RoleName>METHOD(GetMaxSpeed)
#define MEMBER PLAYER_ROLE_MEMBER<RoleName>MEMBER(flSpeed)

Important: The MACRO<>() syntax is only valid inside macro definitions (in mymod_internal.inc). In plugin code, always use local shortcuts or fully expanded constant names.


Macro Expansion Reference

// ENTITY(Projectile) expands to:
// -> NAMESPACE_FIELD<Entity>(Projectile)
// -> NAMESPACE(Entity)_Projectile
// -> MyMod_Entity_Projectile

Shortened here. Read the whole file on GitHub.

Signals

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