| name | amxmodx-basics |
| description | Helps with AMX Mod X (Pawn) coding conventions and best practices. |
AMX Mod X (Pawn) Code Style Guide
This document provides an overview of coding conventions for AMX Mod X projects. Each topic is covered in detail in its own file.
Core Conventions
| Category | Description |
|---|
| Basics | Syntax, basics |
| Code Style | File structure, formatting, braces, spacing, plugin registration |
| Naming Conventions | Hungarian notation, variable prefixes, naming patterns |
| Constants & Enums | Define constants, enums, TASKID constants |
| Macros | Common macros, IS_PLAYER, patterns to avoid |
| Function Declarations | Return types, @ prefix, static variables |
| Validations | FM_NULLENT, entity checks, player validation, early returns |
API Patterns
| Category | Description |
|---|
| Hooks | Ham, FakeMeta, ReAPI, Event, Message hooks and handles |
| Forwards | CreateMultiForward, ExecuteForward, pre/post patterns |
| Natives | Native registration and implementation |
| Callbacks | Tasks, SQL queries, CVar queries |
| Menus | Menu creation, callbacks, and patterns |
| Commands | Client, server, and console commands |
| CVars | CVar creation, binding, and change hooks |
Performance & Data
| Category | Description |
|---|
| Optimizations | Native call reduction, dynamic hooks, model path caching |
| Data Structures | Arrays, Tries, entity access, strings |
Quick Reference: Best Practices Summary
Code Style
- Always use
#pragma semicolon 1 at file start
- Use Hungarian notation for all variable names
- Use K&R brace style (opening brace on same line)
- Pass plugin info directly to
register_plugin() - avoid macros
- Group hooks and functions with section comments
Constants & Validation
- Use
FM_NULLENT instead of -1 or 0 for null entity checks
- Always check
FM_NULLENT after entity creation before processing
- Return
FM_NULLENT not 0 for failures - 0 is worldspawn
- Return early for invalid conditions
Macros
- Don't redefine macros - use shared definitions from includes
- Never use
MACRO()_Suffix patterns in code - only in macro definitions
Function Declarations
- Use
@ prefix only for OOP-like methods: @{EntityName}_{MethodName}
- Never add
public keyword to @ prefixed functions
- Use
const prefix for all handle arguments
- Use
const &this for "this" argument in OOP-like methods
- Use static variables in frequently called class methods
- Declare and assign static on same line using semicolon separator
Hooks
- Ham hooks must return
HAM_* constants
- FakeMeta hooks must return
FMRES_* constants
- ReAPI hooks must return
HC_* constants
- Message hooks must return
PLUGIN_* constants
- Hook handle variables:
g_pfwham (Ham), g_pfwfm (FakeMeta)
- Inline
get_user_msgid when only used once in register_message
Forwards
- Forward names use
LibraryName_OnSomething - not Fw_ prefix
- Multi-forward handle variables use
g_pfw prefix
Natives & Callbacks
- Native implementations use
Native_ prefix with const for arguments
- Task callbacks use
Task_ prefix with offset in task ID
- SQL callbacks use
Callback_SQLQuery_{Name} prefix
Menus
- Menu callbacks use
Callback_Menu_{Name} prefix
- Use enum for menu items to avoid index mistakes
- Destroy dynamic menus in callback with
menu_destroy
Commands & CVars
- Command handlers use
Command_ prefix, server commands use ServerCommand_
- Use
register_concmd for admin commands that should work from RCON
- Avoid
client_cmd - use engclient_cmd for server-side execution
- Use
create_cvar instead of deprecated register_cvar
- Use
bind_pcvar_* instead of get_pcvar_* for cvar access
Optimizations
- Minimize native calls in hot paths
- Use single global
g_pTrace - never create trace handles per-call
- Register high-frequency hooks dynamically
- Use
xs_vec_set instead of xs_vec_copy for vector initialization
- Cache model index with static inside function, not in separate global
Naming Conventions
- Sound arrays use
g_rgsz prefix with g_i*Num counter
- Message IDs use
gmsg prefix (without underscore)
- Player arrays use
g_rg*[MAX_PLAYERS + 1] with type prefix
- Don't use
id for players - use pPlayer
- Don't use
index for entities - use pEntity
Data Structures
- Always free dynamic handles -
ArrayDestroy, TrieDestroy in plugin_end()