원클릭으로
amxx-modding-kit-api-states
Guide for States API usage implementing state machines with transitions, guards, and lifecycle hooks.
Codex 또는 Claude로 설치 이 Prompt를 복사해 Codex, Claude 또는 다른 어시스턴트에 붙여 넣으면 Skill 페이지를 검토하고 설치를 진행할 수 있습니다.
메뉴
Guide for States API usage implementing state machines with transitions, guards, and lifecycle hooks.
Codex 또는 Claude로 설치 이 Prompt를 복사해 Codex, Claude 또는 다른 어시스턴트에 붙여 넣으면 Skill 페이지를 검토하고 설치를 진행할 수 있습니다.
SOC 직업 분류 기준
Guide for implementing custom weapons using OOP-style patterns in AMX Mod X. Use when creating new weapons or extending existing ones with the Custom Weapons API.
This skill is describing how to use AMXX Modding Kit for AMX Mod X plugin development.
Helps with AMX Mod X (Pawn) coding conventions and best practices.
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.
Guide for Assets API usage managing models, sounds, and resources from JSON configuration files.
Guide for implementing custom entities using OOP-style patterns in AMX Mod X. Use when creating projectiles, pickups, NPCs, or any custom game entity with the Custom Entities API.
| name | amxx-modding-kit-api-states |
| description | Guide for States API usage implementing state machines with transitions, guards, and lifecycle hooks. |
State machine implementation for managing entity and player states with transitions, guards, enter/exit hooks, and timed state changes.
For complete API documentation, see README.md.
enum HealthState {
HealthState_Healthy = 0,
HealthState_Injured,
HealthState_Critical,
HealthState_Dead
};
#define STATE_CONTEXT_HEALTH "myplugin.health"
public plugin_precache() {
// Register context with initial state
State_Context_Register(STATE_CONTEXT_HEALTH, HealthState_Healthy);
}
public plugin_precache() {
State_Context_Register(STATE_CONTEXT_HEALTH, HealthState_Healthy);
// Enter hooks - called when entering state
State_Context_RegisterEnterHook(STATE_CONTEXT_HEALTH, HealthState_Healthy, "@Health_Healthy_Enter");
State_Context_RegisterEnterHook(STATE_CONTEXT_HEALTH, HealthState_Injured, "@Health_Injured_Enter");
State_Context_RegisterEnterHook(STATE_CONTEXT_HEALTH, HealthState_Critical, "@Health_Critical_Enter");
// Exit hooks - called when leaving state
State_Context_RegisterExitHook(STATE_CONTEXT_HEALTH, HealthState_Critical, "@Health_Critical_Exit");
}
Called on specific state-to-state transition:
public plugin_precache() {
// ...
// Called when transitioning from Injured to Critical
State_Context_RegisterTransitionHook(
STATE_CONTEXT_HEALTH,
HealthState_Injured,
HealthState_Critical,
"@Health_Injured_To_Critical"
);
}
@Health_Injured_To_Critical(const StateManager:this) {
static pPlayer; pPlayer = State_Manager_GetUserToken(this);
client_print(pPlayer, print_center, "Warning: Condition worsening!");
}
Called on any state change:
public plugin_precache() {
State_Context_RegisterChangeHook(STATE_CONTEXT_HEALTH, "@Health_Changed");
}
@Health_Changed(const StateManager:this) {
static pPlayer; pPlayer = State_Manager_GetUserToken(this);
static HealthState:iNewState; iNewState = State_Manager_GetState(this);
// Update HUD, play sound, etc.
UpdateHealthHUD(pPlayer, iNewState);
}
Validate state changes before they happen:
public plugin_precache() {
State_Context_RegisterChangeGuard(STATE_CONTEXT_HEALTH, "@Health_CanChange");
}
bool:@Health_CanChange(const StateManager:this, any:iOldState, any:iNewState) {
static pPlayer; pPlayer = State_Manager_GetUserToken(this);
// Can't become healthy if poisoned
if (iNewState == HealthState_Healthy && IsPlayerPoisoned(pPlayer)) {
return false;
}
return true;
}
new StateManager:g_rgpPlayerStateManagers[MAX_PLAYERS + 1] = { StateManager_Invalid, ... };
public client_connect(pPlayer) {
// Create manager with player as user token
g_rgpPlayerStateManagers[pPlayer] = State_Manager_Create(STATE_CONTEXT_HEALTH, pPlayer);
}
public client_disconnected(pPlayer) {
if (g_rgpPlayerStateManagers[pPlayer] != StateManager_Invalid) {
State_Manager_Destroy(g_rgpPlayerStateManagers[pPlayer]);
g_rgpPlayerStateManagers[pPlayer] = StateManager_Invalid;
}
}
// Set state immediately
State_Manager_SetState(g_rgpPlayerStateManagers[pPlayer], HealthState_Injured);
// Transition to state after delay
State_Manager_SetState(g_rgpPlayerStateManagers[pPlayer], HealthState_Critical, 5.0);
// Force transition even during another transition
State_Manager_SetState(g_rgpPlayerStateManagers[pPlayer], HealthState_Dead, _, true);
// Reset to initial state (HealthState_Healthy)
State_Manager_ResetState(g_rgpPlayerStateManagers[pPlayer]);
new HealthState:iState = State_Manager_GetState(g_rgpPlayerStateManagers[pPlayer]);
switch (iState) {
case HealthState_Healthy: { /* ... */ }
case HealthState_Injured: { /* ... */ }
case HealthState_Critical: { /* ... */ }
case HealthState_Dead: { /* ... */ }
}
@Health_Healthy_Enter(const StateManager:this) {
static pPlayer; pPlayer = State_Manager_GetUserToken(this);
client_print(pPlayer, print_center, "You are healthy!");
// Clear any negative effects
ClearHealthEffects(pPlayer);
}
@Health_Injured_Enter(const StateManager:this) {
static pPlayer; pPlayer = State_Manager_GetUserToken(this);
client_print(pPlayer, print_center, "You are injured. Be careful!");
// Apply visual effect
ApplyInjuredEffect(pPlayer);
}
@Health_Critical_Enter(const StateManager:this) {
static pPlayer; pPlayer = State_Manager_GetUserToken(this);
client_print(pPlayer, print_center, "CRITICAL! Find a medkit!");
// Apply urgent effects
ApplyCriticalEffect(pPlayer);
StartHeartbeatSound(pPlayer);
}
@Health_Critical_Exit(const StateManager:this) {
static pPlayer; pPlayer = State_Manager_GetUserToken(this);
// Remove critical effects
StopHeartbeatSound(pPlayer);
ClearCriticalEffect(pPlayer);
client_print(pPlayer, print_center, "Condition stabilizing...");
}
@Player_TakeDamage_Post(const pPlayer) {
UpdateHealthState(pPlayer);
}
@Player_Healed(const pPlayer) {
UpdateHealthState(pPlayer);
}
UpdateHealthState(const pPlayer) {
static StateManager:pManager; pManager = g_rgpPlayerStateManagers[pPlayer];
if (pManager == StateManager_Invalid) return;
static Float:flHealth; pev(pPlayer, pev_health, flHealth);
if (flHealth <= 0.0) {
State_Manager_SetState(pManager, HealthState_Dead);
} else if (flHealth < 20.0) {
State_Manager_SetState(pManager, HealthState_Critical);
} else if (flHealth < 50.0) {
State_Manager_SetState(pManager, HealthState_Injured);
} else {
State_Manager_SetState(pManager, HealthState_Healthy);
}
}
enum InfectionState {
InfectionState_None = 0,
InfectionState_Infected,
InfectionState_Transforming,
InfectionState_Zombie
};
#define STATE_CONTEXT_INFECTION "myplugin.infection"
public plugin_precache() {
State_Context_Register(STATE_CONTEXT_INFECTION, InfectionState_None);
State_Context_RegisterEnterHook(STATE_CONTEXT_INFECTION, InfectionState_Infected, "@Infection_Infected_Enter");
State_Context_RegisterEnterHook(STATE_CONTEXT_INFECTION, InfectionState_Transforming, "@Infection_Transforming_Enter");
State_Context_RegisterEnterHook(STATE_CONTEXT_INFECTION, InfectionState_Zombie, "@Infection_Zombie_Enter");
State_Context_RegisterChangeGuard(STATE_CONTEXT_INFECTION, "@Infection_CanChange");
}
// When player is bitten
InfectPlayer(const pPlayer) {
new StateManager:pManager = g_rgpPlayerInfectionState[pPlayer];
// Start infection, transform after 10 seconds
State_Manager_SetState(pManager, InfectionState_Infected);
State_Manager_SetState(pManager, InfectionState_Transforming, 10.0);
}
@Infection_Transforming_Enter(const StateManager:this) {
static pPlayer; pPlayer = State_Manager_GetUserToken(this);
// Schedule final transformation
State_Manager_SetState(this, InfectionState_Zombie, 5.0);
client_print(pPlayer, print_center, "Transformation beginning...");
}
@Infection_Zombie_Enter(const StateManager:this) {
static pPlayer; pPlayer = State_Manager_GetUserToken(this);
// Complete transformation
PlayerRole_Player_AssignRole(pPlayer, ROLE_ZOMBIE);
}
public HamHook_Player_Spawn_Post(const pPlayer) {
if (!is_user_alive(pPlayer)) return HAM_IGNORED;
// Reset health state
State_Manager_ResetState(g_rgpPlayerStateManagers[pPlayer]);
// Reset infection state
State_Manager_ResetState(g_rgpPlayerInfectionState[pPlayer]);
return HAM_HANDLED;
}
plugin_precacheclient_connectclient_disconnectedState_Manager_GetUserToken