2
0
mirror of https://github.com/rehlds/reapi.git synced 2024-12-28 07:35:31 +03:00

API upgrade: 15 new natives (#297)

* 15 natives addition
* Added DECAL_ indexes
* Improve documentation
* Added player null option on rg_create_weaponbox + code style fixes
This commit is contained in:
Francisco Muñoz 2023-11-28 09:50:27 -03:00 committed by GitHub
parent bf8b9bd48a
commit 4430205522
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 921 additions and 46 deletions

View File

@ -1375,54 +1375,54 @@ enum InfoMapBuyParam
enum GameEventType
{
EVENT_INVALID = 0,
EVENT_WEAPON_FIRED, // tell bots the player is attack (argumens: 1 = attacker, 2 = NULL)
EVENT_WEAPON_FIRED_ON_EMPTY, // tell bots the player is attack without clip ammo (argumens: 1 = attacker, 2 = NULL)
EVENT_WEAPON_RELOADED, // tell bots the player is reloading his weapon (argumens: 1 = reloader, 2 = NULL)
EVENT_WEAPON_FIRED, // tell bots the player is attack (argumens: 1 = attacker, 2 = NULL)
EVENT_WEAPON_FIRED_ON_EMPTY, // tell bots the player is attack without clip ammo (argumens: 1 = attacker, 2 = NULL)
EVENT_WEAPON_RELOADED, // tell bots the player is reloading his weapon (argumens: 1 = reloader, 2 = NULL)
EVENT_HE_GRENADE_EXPLODED, // tell bots the HE grenade is exploded (argumens: 1 = grenade thrower, 2 = NULL)
EVENT_FLASHBANG_GRENADE_EXPLODED, // tell bots the flashbang grenade is exploded (argumens: 1 = grenade thrower, 2 = explosion origin)
EVENT_SMOKE_GRENADE_EXPLODED, // tell bots the smoke grenade is exploded (argumens: 1 = grenade thrower, 2 = NULL)
EVENT_HE_GRENADE_EXPLODED, // tell bots the HE grenade is exploded (argumens: 1 = grenade thrower, 2 = NULL)
EVENT_FLASHBANG_GRENADE_EXPLODED, // tell bots the flashbang grenade is exploded (argumens: 1 = grenade thrower, 2 = explosion origin)
EVENT_SMOKE_GRENADE_EXPLODED, // tell bots the smoke grenade is exploded (argumens: 1 = grenade thrower, 2 = NULL)
EVENT_GRENADE_BOUNCED,
EVENT_BEING_SHOT_AT,
EVENT_PLAYER_BLINDED_BY_FLASHBANG, // tell bots the player is flashed (argumens: 1 = flashed player, 2 = NULL)
EVENT_PLAYER_FOOTSTEP, // tell bots the player is running (argumens: 1 = runner, 2 = NULL)
EVENT_PLAYER_JUMPED, // tell bots the player is jumped (argumens: 1 = jumper, 2 = NULL)
EVENT_PLAYER_DIED, // tell bots the player is killed (argumens: 1 = victim, 2 = killer)
EVENT_PLAYER_LANDED_FROM_HEIGHT, // tell bots the player is fell with some damage (argumens: 1 = felled player, 2 = NULL)
EVENT_PLAYER_TOOK_DAMAGE, // tell bots the player is take damage (argumens: 1 = victim, 2 = attacker)
EVENT_HOSTAGE_DAMAGED, // tell bots the player has injured a hostage (argumens: 1 = hostage, 2 = injurer)
EVENT_HOSTAGE_KILLED, // tell bots the player has killed a hostage (argumens: 1 = hostage, 2 = killer)
EVENT_PLAYER_BLINDED_BY_FLASHBANG, // tell bots the player is flashed (argumens: 1 = flashed player, 2 = NULL)
EVENT_PLAYER_FOOTSTEP, // tell bots the player is running (argumens: 1 = runner, 2 = NULL)
EVENT_PLAYER_JUMPED, // tell bots the player is jumped (argumens: 1 = jumper, 2 = NULL)
EVENT_PLAYER_DIED, // tell bots the player is killed (argumens: 1 = victim, 2 = killer)
EVENT_PLAYER_LANDED_FROM_HEIGHT, // tell bots the player is fell with some damage (argumens: 1 = felled player, 2 = NULL)
EVENT_PLAYER_TOOK_DAMAGE, // tell bots the player is take damage (argumens: 1 = victim, 2 = attacker)
EVENT_HOSTAGE_DAMAGED, // tell bots the player has injured a hostage (argumens: 1 = hostage, 2 = injurer)
EVENT_HOSTAGE_KILLED, // tell bots the player has killed a hostage (argumens: 1 = hostage, 2 = killer)
EVENT_DOOR, // tell bots the door is moving (argumens: 1 = door, 2 = NULL)
EVENT_BREAK_GLASS, // tell bots the glass has break (argumens: 1 = glass, 2 = NULL)
EVENT_BREAK_WOOD, // tell bots the wood has break (argumens: 1 = wood, 2 = NULL)
EVENT_BREAK_METAL, // tell bots the metal/computer has break (argumens: 1 = metal/computer, 2 = NULL)
EVENT_BREAK_FLESH, // tell bots the flesh has break (argumens: 1 = flesh, 2 = NULL)
EVENT_BREAK_CONCRETE, // tell bots the concrete has break (argumens: 1 = concrete, 2 = NULL)
EVENT_DOOR, // tell bots the door is moving (argumens: 1 = door, 2 = NULL)
EVENT_BREAK_GLASS, // tell bots the glass has break (argumens: 1 = glass, 2 = NULL)
EVENT_BREAK_WOOD, // tell bots the wood has break (argumens: 1 = wood, 2 = NULL)
EVENT_BREAK_METAL, // tell bots the metal/computer has break (argumens: 1 = metal/computer, 2 = NULL)
EVENT_BREAK_FLESH, // tell bots the flesh has break (argumens: 1 = flesh, 2 = NULL)
EVENT_BREAK_CONCRETE, // tell bots the concrete has break (argumens: 1 = concrete, 2 = NULL)
EVENT_BOMB_PLANTED, // tell bots the bomb has been planted (argumens: 1 = planter, 2 = NULL)
EVENT_BOMB_DROPPED, // tell bots the bomb has been dropped (argumens: 1 = NULL, 2 = NULL)
EVENT_BOMB_PICKED_UP, // let the bots hear the bomb pickup (argumens: 1 = player that pickup c4, 2 = NULL)
EVENT_BOMB_BEEP, // let the bots hear the bomb beeping (argumens: 1 = c4, 2 = NULL)
EVENT_BOMB_DEFUSING, // tell the bots someone has started defusing (argumens: 1 = defuser, 2 = NULL)
EVENT_BOMB_DEFUSE_ABORTED, // tell the bots someone has aborted defusing (argumens: 1 = NULL, 2 = NULL)
EVENT_BOMB_DEFUSED, // tell the bots the bomb is defused (argumens: 1 = defuser, 2 = NULL)
EVENT_BOMB_EXPLODED, // let the bots hear the bomb exploding (argumens: 1 = NULL, 2 = NULL)
EVENT_BOMB_PLANTED, // tell bots the bomb has been planted (argumens: 1 = planter, 2 = NULL)
EVENT_BOMB_DROPPED, // tell bots the bomb has been dropped (argumens: 1 = NULL, 2 = NULL)
EVENT_BOMB_PICKED_UP, // let the bots hear the bomb pickup (argumens: 1 = player that pickup c4, 2 = NULL)
EVENT_BOMB_BEEP, // let the bots hear the bomb beeping (argumens: 1 = c4, 2 = NULL)
EVENT_BOMB_DEFUSING, // tell the bots someone has started defusing (argumens: 1 = defuser, 2 = NULL)
EVENT_BOMB_DEFUSE_ABORTED, // tell the bots someone has aborted defusing (argumens: 1 = NULL, 2 = NULL)
EVENT_BOMB_DEFUSED, // tell the bots the bomb is defused (argumens: 1 = defuser, 2 = NULL)
EVENT_BOMB_EXPLODED, // let the bots hear the bomb exploding (argumens: 1 = NULL, 2 = NULL)
EVENT_HOSTAGE_USED, // tell bots the hostage is used (argumens: 1 = user, 2 = NULL)
EVENT_HOSTAGE_RESCUED, // tell bots the hostage is rescued (argumens: 1 = rescuer (CBasePlayer *), 2 = hostage (CHostage *))
EVENT_ALL_HOSTAGES_RESCUED, // tell bots the all hostages are rescued (argumens: 1 = NULL, 2 = NULL)
EVENT_HOSTAGE_USED, // tell bots the hostage is used (argumens: 1 = user, 2 = NULL)
EVENT_HOSTAGE_RESCUED, // tell bots the hostage is rescued (argumens: 1 = rescuer (CBasePlayer *), 2 = hostage (CHostage *))
EVENT_ALL_HOSTAGES_RESCUED, // tell bots the all hostages are rescued (argumens: 1 = NULL, 2 = NULL)
EVENT_VIP_ESCAPED, // tell bots the VIP is escaped (argumens: 1 = NULL, 2 = NULL)
EVENT_VIP_ASSASSINATED, // tell bots the VIP is assassinated (argumens: 1 = NULL, 2 = NULL)
EVENT_TERRORISTS_WIN, // tell bots the terrorists won the round (argumens: 1 = NULL, 2 = NULL)
EVENT_CTS_WIN, // tell bots the CTs won the round (argumens: 1 = NULL, 2 = NULL)
EVENT_ROUND_DRAW, // tell bots the round was a draw (argumens: 1 = NULL, 2 = NULL)
EVENT_ROUND_WIN, // tell carreer the round was a win (argumens: 1 = NULL, 2 = NULL)
EVENT_ROUND_LOSS, // tell carreer the round was a loss (argumens: 1 = NULL, 2 = NULL)
EVENT_ROUND_START, // tell bots the round was started (when freeze period is expired) (argumens: 1 = NULL, 2 = NULL)
EVENT_PLAYER_SPAWNED, // tell bots the player is spawned (argumens: 1 = spawned player, 2 = NULL)
EVENT_VIP_ESCAPED, // tell bots the VIP is escaped (argumens: 1 = NULL, 2 = NULL)
EVENT_VIP_ASSASSINATED, // tell bots the VIP is assassinated (argumens: 1 = NULL, 2 = NULL)
EVENT_TERRORISTS_WIN, // tell bots the terrorists won the round (argumens: 1 = NULL, 2 = NULL)
EVENT_CTS_WIN, // tell bots the CTs won the round (argumens: 1 = NULL, 2 = NULL)
EVENT_ROUND_DRAW, // tell bots the round was a draw (argumens: 1 = NULL, 2 = NULL)
EVENT_ROUND_WIN, // tell carreer the round was a win (argumens: 1 = NULL, 2 = NULL)
EVENT_ROUND_LOSS, // tell carreer the round was a loss (argumens: 1 = NULL, 2 = NULL)
EVENT_ROUND_START, // tell bots the round was started (when freeze period is expired) (argumens: 1 = NULL, 2 = NULL)
EVENT_PLAYER_SPAWNED, // tell bots the player is spawned (argumens: 1 = spawned player, 2 = NULL)
EVENT_CLIENT_CORPSE_SPAWNED,
EVENT_BUY_TIME_START,
EVENT_PLAYER_LEFT_BUY_ZONE,
@ -1471,12 +1471,12 @@ enum GameEventType
EVENT_RADIO_ENEMY_DOWN,
EVENT_END_RADIO,
EVENT_NEW_MATCH, // tell bots the game is new (argumens: 1 = NULL, 2 = NULL)
EVENT_PLAYER_CHANGED_TEAM, // tell bots the player is switch his team (also called from ClientPutInServer()) (argumens: 1 = switcher, 2 = NULL)
EVENT_BULLET_IMPACT, // tell bots the player is shoot at wall (argumens: 1 = shooter, 2 = shoot trace end position)
EVENT_GAME_COMMENCE, // tell bots the game is commencing (argumens: 1 = NULL, 2 = NULL)
EVENT_WEAPON_ZOOMED, // tell bots the player is switch weapon zoom (argumens: 1 = zoom switcher, 2 = NULL)
EVENT_HOSTAGE_CALLED_FOR_HELP, // tell bots the hostage is talking (argumens: 1 = listener, 2 = NULL)
EVENT_NEW_MATCH, // tell bots the game is new (argumens: 1 = NULL, 2 = NULL)
EVENT_PLAYER_CHANGED_TEAM, // tell bots the player is switch his team (also called from ClientPutInServer()) (argumens: 1 = switcher, 2 = NULL)
EVENT_BULLET_IMPACT, // tell bots the player is shoot at wall (argumens: 1 = shooter, 2 = shoot trace end position)
EVENT_GAME_COMMENCE, // tell bots the game is commencing (argumens: 1 = NULL, 2 = NULL)
EVENT_WEAPON_ZOOMED, // tell bots the player is switch weapon zoom (argumens: 1 = zoom switcher, 2 = NULL)
EVENT_HOSTAGE_CALLED_FOR_HELP, // tell bots the hostage is talking (argumens: 1 = listener, 2 = NULL)
NUM_GAME_EVENTS,
};
@ -1490,3 +1490,52 @@ enum SecondaryAtkState
WEAPON_SECONDARY_ATTACK_SET,
WEAPON_SECONDARY_ATTACK_BLOCK
};
/**
* Decal list for rg_decal_trace
*/
enum Decal
{
DECAL_GUNSHOT1 = 0,
DECAL_GUNSHOT2,
DECAL_GUNSHOT3,
DECAL_GUNSHOT4,
DECAL_GUNSHOT5,
DECAL_LAMBDA1,
DECAL_LAMBDA2,
DECAL_LAMBDA3,
DECAL_LAMBDA4,
DECAL_LAMBDA5,
DECAL_LAMBDA6,
DECAL_SCORCH1,
DECAL_SCORCH2,
DECAL_BLOOD1,
DECAL_BLOOD2,
DECAL_BLOOD3,
DECAL_BLOOD4,
DECAL_BLOOD5,
DECAL_BLOOD6,
DECAL_YBLOOD1,
DECAL_YBLOOD2,
DECAL_YBLOOD3,
DECAL_YBLOOD4,
DECAL_YBLOOD5,
DECAL_YBLOOD6,
DECAL_GLASSBREAK1,
DECAL_GLASSBREAK2,
DECAL_GLASSBREAK3,
DECAL_BIGSHOT1,
DECAL_BIGSHOT2,
DECAL_BIGSHOT3,
DECAL_BIGSHOT4,
DECAL_BIGSHOT5,
DECAL_SPIT1,
DECAL_SPIT2,
DECAL_BPROOF1, // Bulletproof glass decal
DECAL_GARGSTOMP1, // Gargantua stomp crack
DECAL_SMALLSCORCH1, // Small scorch mark
DECAL_SMALLSCORCH2, // Small scorch mark
DECAL_SMALLSCORCH3, // Small scorch mark
DECAL_MOMMABIRTH, // Big momma birth splatter
DECAL_MOMMASPLAT,
};

View File

@ -1008,3 +1008,190 @@ native rg_spawn_head_gib(const index);
* @noreturn
*/
native rg_spawn_random_gibs(const index, const cGibs, const bool:bHuman = true);
/*
* Spawn a grenade (HEGrenade, Flashbang, SmokeGrenade, or C4)
*
* @param weaponId WEAPON_HEGRENADE, WEAPON_SMOKEGRENADE, WEAPON_FLASHBANG or WEAPON_C4
* @param pevOwner Grenade owner
* @param vecSrc Grenade spawn position
* @param vecThrow Grenade velocity vector
* @param time Grenade explosion time
* @param iTeam Grenade team, see TEAM_* constants
* @param usEvent Event index related to grenade (returned value of precache_event)
*
* @return Entity index on success, AMX_NULLENT (-1) otherwise
*/
native rg_spawn_grenade(WeaponIdType:weaponId, pevOwner, Float:vecSrc[3], Float:vecThrow[3], Float:time, TeamName:iTeam, usEvent = 0);
/*
* Spawn a weaponbox entity with its properties
*
* @param pItem Weapon entity index to attach
* @param pPlayerOwner Player index to remove pItem entity (0 = no weapon owner)
* @param modelName Model name ("models/w_*.mdl")
* @param origin Weaponbox origin position
* @param angles Weaponbox angles
* @param velocity Weaponbox initial velocity vector
* @param lifeTime Time to stay in world (< 0.0 = use mp_item_staytime cvar value)
* @param packAmmo Set if ammo should be removed from weapon owner
*
* @return Weaponbox ent index on success, AMX_NULLENT (-1) otherwise
*/
native rg_create_weaponbox(const pItem, const pPlayerOwner, const modelName[], Float:origin[3], Float:angles[3], Float:velocity[3], Float:lifeTime, bool:packAmmo);
/*
* Removes an entity using gamedll's UTIL_Remove function, which sets a frame delay to ensure its removal.
*
* @param pEntity Entity index to remove
*
* @return 1 on success, 0 otherwise
*/
native rg_remove_entity(const pEntity);
/*
* Creates a Decal in world based on a traceresult.
*
* @param ptr Traceresult pointer, use Fakemeta's create_tr2 to instantiate one
* @param decalNumber Number of decal to spray, see DECAL_ constants on cssdk_const.inc
*
* @noreturn
*/
native rg_decal_trace(const ptr, Decal:decalNumber);
/*
* Emits a sound based on a traceresult simulating a bullet hit (metal, wood, concrete, etc.).
* @note Used mostly on trace attacks (bullets, knife).
*
* @param ptr Traceresult pointer, use Fakemeta's create_tr2 to instantiate one
* @param vecSrc Start position
* @param vecEnd End position, must match ptr's vecEndPos member
* @param iBulletType Bullet type, see BULLET_* constants in cssdk_const.inc
*
* @noreturn
*/
native rg_emit_texture_sound(const ptr, Float:vecSrc[3], Float:vecEnd[3], Bullet:iBulletType);
/*
* Generates an ammo slot in game's logic
* @note To see a visual effect, WeaponList message should be sent using the custom ammo name,
* where ammo icon HUD will be the one listed in "sprites/weapon_<name>.txt" file.
*
* @param szAmmoname Ammo name to create.
*
* @note Maximum ammo index is 31, after that every ammo instantiation will start from 1 overriding existing ones.
* @return New ammo index. If name already exists, will return the matched index from memory.
*/
native rg_add_ammo_registry(const szAmmoname[]);
/*
* Deploys a weapon attached to a player using the CBasePlayerWeapon::DefaultDeploy function.
*
* @param entity Weapon to deploy. Must be attached to a player.
* @param szViewModel Weapon view model name ("models/v_*.mdl")
* @param szWeaponModel Weapon world model bame ("models/p_*.mdl")
* @param iAnim Weapon view model animation to play (often "deploy", use HLMV to see anim index)
* @param szAnimExt Player anim extension name to assign. Examples: "carbine", "shotgun", "knife", etc.
* Use HLMV on a player model to see animext names.
* @param skiplocal If 0, weapon animation will be forced to play on client ignoring active client prediction.
*
* @return 1 on successful weapon deploy, 0 otherwise.
*/
native rg_weapon_deploy(const entity, const szViewModel[], const szWeaponModel[], iAnim, const szAnimExt[], skiplocal = 0);
/*
* Reloads a weapon or a player's active weapon using the CBasePlayerWeapon::DefaultReload function.
*
* @param entity Weapon to reload (> MaxClients) OR player index to reload his current active weapon (>= 1 & <= MaxClients).
* @param iClipSize Weapon max clip to check. 0 = weapon max clip stored in ItemInfo
* @param iAnim Weapon view model animation to play (often "reload", use HLMV to see anim index)
* @param fDelay Player reload duration before clip refill.
*
* @return 1 on successful weapon reload, 0 otherwise.
*/
native rg_weapon_reload(const entity, iClipSize, iAnim, Float:fDelay);
/*
* Forces shotgun reload thinking on a weapon or a player's active weapon using the CBasePlayerWeapon::DefaultShotgunReload function.
*
* @param entity Weapon to reload (> MaxClients) OR player index to reload his current active weapon (>= 1 & <= MaxClients).
* @param iAnim Weapon view model "insert" animation to play (use HLMV to see anim index)
* @param iStartAnim Weapon view model "start reload" animation to play (use HLMV to see anim index)
* @param fDelay Delay between each buckshot inserted
* @param fStartDelay Delay before buckshots insertion starts
* @param pszReloadSound1 Sound to play on every insertion
* @param pszReloadSound2 Another sound to play on every insertion
*
* @note This is used inside weapon's Reload function and is often called every frame player is pressing IN_RELOAD button.
* @return 1 while weapon not in delay and with ammo remaining to load, 0 otherwise.
*/
native rg_weapon_shotgun_reload(const entity, iAnim, iStartAnim, Float:fDelay, Float:fStartDelay, const pszReloadSound1[] = "", const pszReloadSound2[] = "");
/*
* Sends a weapon animation using the CBasePlayerWeapon::SendWeaponAnim function.
*
* @param entity Weapon to send animation on owner (> MaxClients) OR player index to send animation (>= 1 & <= MaxClients).
* @param iAnim Weapon view model animation to play (use HLMV to see anim index)
* @param skiplocal If 0, weapon animation will be forced to play on client ignoring active client prediction.
*
* @noreturn
*/
native rg_weapon_send_animation(const entity, iAnim, skiplocal = 0);
/*
* Emits a "recoil" effect on weapon's player using the CBasePlayerWeapon::KickBack function.
*
* @param entity Weapon to reload (> MaxClients) OR player index to reload his current active weapon (>= 1 & <= MaxClients).
* @param up_base Minimum vertical punchangle
* @param lateral_base Minimum horizontal punchangle
* @param up_modifier Vertical punchangle units to multiply to m_iShotsFired member
* @param lateral_modifier Horizontal punchangle units to multiply to m_iShotsFired member
* @param up_max Maximum vertical punchangle
* @param lateral_max Maximum horizontal punchangle
* @param direction_change Probability to change punchangle orientation (positive or negative). 0 = 100% (1/1), 1 = 50% (1/2), 2 = 33.3% (1/3), ...
*
* @noreturn
*/
native rg_weapon_kickback(const entity, Float:up_base, Float:lateral_base, Float:up_modifier, Float:lateral_modifier, Float:up_max, Float:lateral_max, direction_change);
/*
* Switches player current weapon into the best one on its inventory using the CHalfLifeMultiplay::GetNextBestWeapon function.
*
* @param player Player index.
* @param currentWeapon Current player active weapon. 0 = retrieve from m_pActiveItem member
*
* @note Weapon selection is based on weapon's Weight attribute from ItemInfo structure.
* @return 1 if weapon was found and switched to, 0 otherwise
*/
native rg_switch_best_weapon(const player, const currentWeapon = 0);
/*
* Disappear a player from the world. Used when VIP reaches escape zone. Basically a silent kill.
*
* @param player Player index.
*
* @noreturn
*/
native rg_disappear(const player);
/*
* Sets player current Observer mode.
* @note Player must be a valid observer (m_afPhysicsFlags & PFLAG_OBSERVER).
*
* @param player Player index.
* @param mode Observer mode, see OBS_* constants in cssdk_const.inc
*
* @noreturn
*/
native rg_set_observer_mode(const player, const mode);
/*
* Emits a death notice (logs, DeathMsg event, win conditions check)
*
* @param pVictim Player index.
* @param pKiller Killer entity.
* @param pevInflictor Inflictor entity. 0 = world
*
* @noreturn
*/
native rg_death_notice(const pVictim, const pKiller, const pevInflictor);

View File

@ -40,6 +40,10 @@ public:
{
return m_value != 0;
}
operator unsigned short() const
{
return (unsigned short)m_value;
}
operator CBaseEntity*() const
{
if (m_value < 0)
@ -78,6 +82,14 @@ public:
{
return static_cast<PLAYER_ANIM>(m_value);
}
operator WeaponIdType() const
{
return static_cast<WeaponIdType>(m_value);
}
operator TraceResult *() const
{
return reinterpret_cast<TraceResult *>(m_value);
}
Vector& vector() const
{
return operator Vector&();

View File

@ -2612,6 +2612,617 @@ cell AMX_NATIVE_CALL rg_spawn_random_gibs(AMX* amx, cell* params)
return TRUE;
}
/*
* Spawn a grenade (HEGrenade, Flashbang, SmokeGrenade, or C4)
*
* @param weaponId WEAPON_HEGRENADE, WEAPON_SMOKEGRENADE, WEAPON_FLASHBANG or WEAPON_C4
* @param pevOwner Grenade owner
* @param vecSrc Grenade spawn position
* @param vecThrow Grenade velocity vector
* @param time Grenade explosion time
* @param iTeam Grenade team, see TEAM_* constants
* @param usEvent Event index related to grenade (returned value of precache_event)
*
* @return Entity index on success, AMX_NULLENT (-1) otherwise
*/
cell AMX_NATIVE_CALL rg_spawn_grenade(AMX* amx, cell* params)
{
enum args_e { arg_count, arg_weapon_id, arg_index, arg_origin, arg_velocity, arg_time, arg_team, arg_event };
CHECK_ISPLAYER(arg_index);
CBasePlayer *pPlayer = UTIL_PlayerByIndex(params[arg_index]);
CHECK_CONNECTED(pPlayer, arg_index);
CAmxArgs args(amx, params);
CGrenade *pBomb = g_ReGameFuncs->SpawnGrenade(args[arg_weapon_id],
pPlayer->pev,
args[arg_origin],
args[arg_velocity],
args[arg_time],
args[arg_team],
args[arg_event]);
// Sanity check anyway
if (pBomb)
return indexOfPDataAmx(pBomb);
return AMX_NULLENT;
}
/*
* Spawn a weaponbox entity with its properties
*
* @param pItem Weapon entity index to attach
* @param pPlayerOwner Player index to remove pItem entity (0 = no weapon owner)
* @param modelName Model name ("models/w_*.mdl")
* @param origin Weaponbox origin position
* @param angles Weaponbox angles
* @param velocity Weaponbox initial velocity vector
* @param lifeTime Time to stay in world (< 0.0 = use mp_item_staytime cvar value)
* @param packAmmo Set if ammo should be removed from weapon owner
*
* @return Weaponbox ent index on success, AMX_NULLENT (-1) otherwise
*/
cell AMX_NATIVE_CALL rg_create_weaponbox(AMX* amx, cell* params)
{
enum args_e { arg_count, arg_item, arg_player, arg_modelname, arg_origin, arg_angles, arg_velocity, arg_lifetime, arg_packammo };
CHECK_ISENTITY(arg_item);
CBasePlayerItem *pItem = getPrivate<CBasePlayerItem>(params[arg_item]);
if (unlikely(pItem == nullptr))
{
AMXX_LogError(amx, AMX_ERR_NATIVE, "%s: invalid or uninitialized entity", __FUNCTION__);
return FALSE;
}
CBasePlayer *pPlayer = nullptr;
if (params[arg_player] != 0)
{
CHECK_ISPLAYER(arg_player);
pPlayer = getPrivate<CBasePlayer>(params[arg_player]);
CHECK_CONNECTED(pPlayer, arg_player);
}
CAmxArgs args(amx, params);
char modelStr[MAX_PATH];
const char *modelName = getAmxString(amx, params[arg_modelname], modelStr);
CWeaponBox *pBox = g_ReGameFuncs->CreateWeaponBox(pItem, pPlayer, modelName, args[arg_origin], args[arg_angles], args[arg_velocity], args[arg_lifetime], args[arg_packammo]);
if (pBox)
return indexOfPDataAmx(pBox);
return AMX_NULLENT;
}
/*
* Removes an entity using gamedll's UTIL_Remove function, which sets a frame delay to ensure its removal.
*
* @param pEntity Entity index to remove
*
* @return 1 on success, 0 otherwise
*/
cell AMX_NATIVE_CALL rg_remove_entity(AMX* amx, cell* params)
{
enum args_e { arg_count, arg_entity };
CHECK_ISENTITY(arg_entity);
auto pEntity = getPrivate<CBaseEntity>(params[arg_entity]);
if (!pEntity || (pEntity->pev->flags & FL_KILLME) != 0)
{
return FALSE;
}
g_ReGameFuncs->UTIL_Remove(pEntity);
if ((pEntity->pev->flags & FL_KILLME) != 0)
{
return TRUE;
}
return FALSE;
}
/*
* Creates a Decal in world based on a traceresult.
*
* @param ptr Traceresult pointer, use Fakemeta's create_tr2 to instantiate one
* @param decalNumber Number of decal to spray, see DECAL_ constants on cssdk_const.inc
*
* @noreturn
*/
cell AMX_NATIVE_CALL rg_decal_trace(AMX* amx, cell* params)
{
enum args_e { arg_count, arg_trace, arg_decal };
CAmxArgs args(amx, params);
g_ReGameFuncs->UTIL_DecalTrace(args[arg_trace], args[arg_decal]);
return TRUE;
}
/*
* Emits a sound based on a traceresult simulating a bullet hit (metal, wood, concrete, etc.).
* @note Used mostly on trace attacks (bullets, knife).
*
* @param ptr Traceresult pointer, use Fakemeta's create_tr2 to instantiate one
* @param vecSrc Start position
* @param vecEnd End position, must match ptr's vecEndPos member
* @param iBulletType Bullet type, see BULLET_* constants in cssdk_const.inc
*
* @noreturn
*/
cell AMX_NATIVE_CALL rg_emit_texture_sound(AMX* amx, cell* params)
{
enum args_e { arg_count, arg_trace, arg_start, arg_end, arg_bullet_type };
CAmxArgs args(amx, params);
g_ReGameFuncs->TextureTypePlaySound(args[arg_trace], args[arg_start], args[arg_end], args[arg_bullet_type]);
return TRUE;
}
/*
* Generates an ammo slot in game's logic
* @note To see a visual effect, WeaponList message should be sent using the custom ammo name,
* where ammo icon HUD will be the one listed in "sprites/weapon_<name>.txt" file.
*
* @param szAmmoname Ammo name to create.
*
* @note Maximum ammo index is 31, after that every ammo instantiation will start from 1 overriding existing ones.
* @return New ammo index. If name already exists, will return the matched index from memory.
*/
cell AMX_NATIVE_CALL rg_add_ammo_registry(AMX* amx, cell* params)
{
enum args_e { arg_count, arg_ammoname };
char ammonamebuf[190];
string_t ammoname = getAmxStringAlloc(amx, params[arg_ammoname], ammonamebuf);
if (!ammonamebuf || ammonamebuf[0] == '\0')
{
AMXX_LogError(amx, AMX_ERR_NATIVE, "%s: empty ammo name", __FUNCTION__);
return FALSE;
}
return (cell)g_ReGameFuncs->AddAmmoNameToAmmoRegistry(STRING(ammoname));
}
/*
* Deploys a weapon attached to a player using the CBasePlayerWeapon::DefaultDeploy function.
*
* @param entity Weapon to deploy. Must be attached to a player.
* @param szViewModel Weapon view model name ("models/v_*.mdl")
* @param szWeaponModel Weapon world model bame ("models/p_*.mdl")
* @param iAnim Weapon view model animation to play (often "deploy", use HLMV to see anim index)
* @param szAnimExt Player anim extension name to assign. Examples: "carbine", "shotgun", "knife", etc.
* Use HLMV on a player model to see animext names.
* @param skiplocal If 0, weapon animation will be forced to play on client ignoring active client prediction.
*
* @return 1 on successful weapon deploy, 0 otherwise.
*/
cell AMX_NATIVE_CALL rg_weapon_deploy(AMX* amx, cell* params)
{
enum args_e { arg_count, arg_weapon, arg_viewmodel, arg_weaponmodel, arg_anim, arg_animextension, arg_skiplocal };
CHECK_ISENTITY(arg_weapon);
CBasePlayerWeapon *pWeapon = getPrivate<CBasePlayerWeapon>(params[arg_weapon]);
if (unlikely(pWeapon == nullptr))
{
AMXX_LogError(amx, AMX_ERR_NATIVE, "%s: invalid or uninitialized entity", __FUNCTION__);
return FALSE;
}
if (!pWeapon->IsWeapon())
{
AMXX_LogError(amx, AMX_ERR_NATIVE, "%s: #%d entity is not a weapon.", __FUNCTION__, indexOfEdict(pWeapon->pev));
return FALSE;
}
CCSPlayerWeapon *pCSWeapon = pWeapon->CSPlayerWeapon();
if (unlikely(pCSWeapon == nullptr))
{
AMXX_LogError(amx, AMX_ERR_NATIVE, "%s: invalid or uninitialized m_pEntity.", __FUNCTION__);
return FALSE;
}
char viewmodelbuffer[MAX_PATH], weaponmodelbuffer[MAX_PATH], animextbuffer[32];
getAmxString(amx, params[arg_viewmodel], viewmodelbuffer);
getAmxString(amx, params[arg_weaponmodel], weaponmodelbuffer);
getAmxString(amx, params[arg_animextension], animextbuffer);
return pCSWeapon->DefaultDeploy(viewmodelbuffer, weaponmodelbuffer, (int)params[arg_anim], animextbuffer, (int)params[arg_skiplocal]) ? TRUE : FALSE;
}
/*
* Reloads a weapon or a player's active weapon using the CBasePlayerWeapon::DefaultReload function.
*
* @param entity Weapon to reload (> MaxPlayers) OR player index to reload his current active weapon (>= 1 & <= MaxPlayers).
* @param iClipSize Weapon max clip to check. 0 = weapon max clip stored in ItemInfo
* @param iAnim Weapon view model animation to play (often "reload", use HLMV to see anim index)
* @param fDelay Player reload duration before clip refill.
*
* @return 1 on successful weapon reload, 0 otherwise.
*/
cell AMX_NATIVE_CALL rg_weapon_reload(AMX* amx, cell* params)
{
enum args_e { arg_count, arg_weapon, arg_clipsize, arg_anim, arg_delay };
CBasePlayerWeapon *pWeapon;
if (params[arg_weapon] > 0 && params[arg_weapon] <= gpGlobals->maxClients)
{
CHECK_ISPLAYER(arg_weapon);
CBasePlayer *pPlayer = UTIL_PlayerByIndex(params[arg_weapon]);
CHECK_CONNECTED(pPlayer, arg_weapon);
if (!pPlayer->IsAlive())
{
AMXX_LogError(amx, AMX_ERR_NATIVE, "%s: player %d not alive", __FUNCTION__, params[arg_weapon]);
return FALSE;
}
pWeapon = static_cast<CBasePlayerWeapon *>(pPlayer->m_pActiveItem);
}
else
{
CHECK_ISENTITY(arg_weapon);
pWeapon = getPrivate<CBasePlayerWeapon>(params[arg_weapon]);
}
if (unlikely(pWeapon == nullptr))
{
AMXX_LogError(amx, AMX_ERR_NATIVE, "%s: invalid or uninitialized entity", __FUNCTION__);
return FALSE;
}
if (!pWeapon->IsWeapon())
{
AMXX_LogError(amx, AMX_ERR_NATIVE, "%s: #%d entity is not a weapon.", __FUNCTION__, indexOfEdict(pWeapon->pev));
return FALSE;
}
CCSPlayerWeapon *pCSWeapon = pWeapon->CSPlayerWeapon();
if (unlikely(pCSWeapon == nullptr))
{
AMXX_LogError(amx, AMX_ERR_NATIVE, "%s: invalid or uninitialized m_pEntity.", __FUNCTION__);
return FALSE;
}
CAmxArgs args(amx, params);
int clipsize = args[arg_clipsize];
if (clipsize <= 0)
clipsize = pWeapon->CSPlayerItem()->m_ItemInfo.iMaxClip;
return pCSWeapon->DefaultReload(clipsize, args[arg_anim], args[arg_delay]) ? TRUE : FALSE;
}
/*
* Forces shotgun reload thinking on a weapon or a player's active weapon using the CBasePlayerWeapon::DefaultShotgunReload function.
*
* @param entity Weapon to reload (> MaxClients) OR player index to reload his current active weapon (>= 1 & <= MaxClients).
* @param iAnim Weapon view model "insert" animation to play (use HLMV to see anim index)
* @param iStartAnim Weapon view model "start reload" animation to play (use HLMV to see anim index)
* @param fDelay Delay between each buckshot inserted
* @param fStartDelay Delay before buckshots insertion starts
* @param pszReloadSound1 Sound to play on every insertion
* @param pszReloadSound2 Another sound to play on every insertion
*
* @note This is used inside weapon's Reload function and is often called every frame player is pressing IN_RELOAD button.
* @return 1 while weapon not in delay and with ammo remaining to load, 0 otherwise.
*/
cell AMX_NATIVE_CALL rg_weapon_shotgun_reload(AMX* amx, cell* params)
{
enum args_e { arg_count, arg_weapon, arg_anim, arg_startanim, arg_delay, arg_startdelay, arg_reloadsound1, arg_reloadsound2 };
CBasePlayerWeapon *pWeapon;
if (params[arg_weapon] > 0 && params[arg_weapon] <= gpGlobals->maxClients)
{
CHECK_ISPLAYER(arg_weapon);
CBasePlayer *pPlayer = UTIL_PlayerByIndex(params[arg_weapon]);
CHECK_CONNECTED(pPlayer, arg_weapon);
if (!pPlayer->IsAlive())
{
AMXX_LogError(amx, AMX_ERR_NATIVE, "%s: player %d not alive", __FUNCTION__, params[arg_weapon]);
return FALSE;
}
pWeapon = static_cast<CBasePlayerWeapon *>(pPlayer->m_pActiveItem);
}
else
{
CHECK_ISENTITY(arg_weapon);
pWeapon = getPrivate<CBasePlayerWeapon>(params[arg_weapon]);
}
if (unlikely(pWeapon == nullptr))
{
AMXX_LogError(amx, AMX_ERR_NATIVE, "%s: invalid or uninitialized entity", __FUNCTION__);
return FALSE;
}
if (!pWeapon->IsWeapon())
{
AMXX_LogError(amx, AMX_ERR_NATIVE, "%s: #%d entity is not a weapon.", __FUNCTION__, indexOfEdict(pWeapon->pev));
return FALSE;
}
CCSPlayerWeapon *pCSWeapon = pWeapon->CSPlayerWeapon();
if (unlikely(pCSWeapon == nullptr))
{
AMXX_LogError(amx, AMX_ERR_NATIVE, "%s: invalid or uninitialized m_pEntity.", __FUNCTION__);
return FALSE;
}
CAmxArgs args(amx, params);
char sound1buffer[MAX_PATH], sound2buffer[MAX_PATH];
const char *reloadsound1 = getAmxString(amx, params[arg_reloadsound1], sound1buffer);
const char *reloadsound2 = getAmxString(amx, params[arg_reloadsound2], sound2buffer);
return pCSWeapon->DefaultShotgunReload(args[arg_anim], args[arg_startanim], args[arg_delay], args[arg_startdelay], reloadsound1, reloadsound2) ? TRUE : FALSE;
}
/*
* Sends a weapon animation using the CBasePlayerWeapon::SendWeaponAnim function.
*
* @param entity Weapon to send animation on owner (> MaxClients) OR player index to send animation (>= 1 & <= MaxClients).
* @param iAnim Weapon view model animation to play (use HLMV to see anim index)
* @param skiplocal If 0, weapon animation will be forced to play on client ignoring active client prediction.
*
* @noreturn
*/
cell AMX_NATIVE_CALL rg_weapon_send_animation(AMX* amx, cell* params)
{
enum args_e { arg_count, arg_weapon, arg_anim, arg_skiplocal };
CBasePlayerWeapon *pWeapon;
if (params[arg_weapon] > 0 && params[arg_weapon] <= gpGlobals->maxClients)
{
CHECK_ISPLAYER(arg_weapon);
CBasePlayer *pPlayer = UTIL_PlayerByIndex(params[arg_weapon]);
CHECK_CONNECTED(pPlayer, arg_weapon);
if (!pPlayer->IsAlive())
{
AMXX_LogError(amx, AMX_ERR_NATIVE, "%s: player %d not alive", __FUNCTION__, params[arg_weapon]);
return FALSE;
}
pWeapon = static_cast<CBasePlayerWeapon *>(pPlayer->m_pActiveItem);
}
else
{
CHECK_ISENTITY(arg_weapon);
pWeapon = getPrivate<CBasePlayerWeapon>(params[arg_weapon]);
}
if (unlikely(pWeapon == nullptr))
{
AMXX_LogError(amx, AMX_ERR_NATIVE, "%s: invalid or uninitialized entity", __FUNCTION__);
return FALSE;
}
if (!pWeapon->IsWeapon())
{
AMXX_LogError(amx, AMX_ERR_NATIVE, "%s: #%d entity is not a weapon.", __FUNCTION__, indexOfEdict(pWeapon->pev));
return FALSE;
}
CCSPlayerWeapon *pCSWeapon = pWeapon->CSPlayerWeapon();
if (unlikely(pCSWeapon == nullptr))
{
AMXX_LogError(amx, AMX_ERR_NATIVE, "%s: invalid or uninitialized m_pEntity.", __FUNCTION__);
return FALSE;
}
CAmxArgs args(amx, params);
pCSWeapon->SendWeaponAnim(args[arg_anim], args[arg_skiplocal]);
return TRUE;
}
/*
* Emits a "recoil" effect on weapon's player using the CBasePlayerWeapon::KickBack function.
*
* @param entity Weapon to reload (> MaxClients) OR player index to reload his current active weapon (>= 1 & <= MaxClients).
* @param up_base Minimum vertical punchangle
* @param lateral_base Minimum horizontal punchangle
* @param up_modifier Vertical punchangle units to multiply to m_iShotsFired member
* @param lateral_modifier Horizontal punchangle units to multiply to m_iShotsFired member
* @param up_max Maximum vertical punchangle
* @param lateral_max Maximum horizontal punchangle
* @param direction_change Probability to change punchangle orientation (positive or negative). 0 = 100% (1/1), 1 = 50% (1/2), 2 = 33.3% (1/3), ...
*
* @noreturn
*/
cell AMX_NATIVE_CALL rg_weapon_kickback(AMX* amx, cell* params)
{
enum args_e { arg_count, arg_weapon, arg_up_base, arg_lateral_base, arg_up_modifier, arg_lateral_modifier, arg_up_max, arg_lateral_max, arg_direction_change };
CBasePlayerWeapon *pWeapon;
if (params[arg_weapon] > 0 && params[arg_weapon] <= gpGlobals->maxClients)
{
CHECK_ISPLAYER(arg_weapon);
CBasePlayer *pPlayer = UTIL_PlayerByIndex(params[arg_weapon]);
CHECK_CONNECTED(pPlayer, arg_weapon);
if (!pPlayer->IsAlive())
{
AMXX_LogError(amx, AMX_ERR_NATIVE, "%s: player %d not alive", __FUNCTION__, params[arg_weapon]);
return FALSE;
}
pWeapon = static_cast<CBasePlayerWeapon *>(pPlayer->m_pActiveItem);
}
else
{
CHECK_ISENTITY(arg_weapon);
pWeapon = getPrivate<CBasePlayerWeapon>(params[arg_weapon]);
}
if (unlikely(pWeapon == nullptr)) {
AMXX_LogError(amx, AMX_ERR_NATIVE, "%s: invalid or uninitialized entity", __FUNCTION__);
return FALSE;
}
if (!pWeapon->IsWeapon())
{
AMXX_LogError(amx, AMX_ERR_NATIVE, "%s: #%d entity is not a weapon.", __FUNCTION__, indexOfEdict(pWeapon->pev));
return FALSE;
}
CCSPlayerWeapon *pCSWeapon = pWeapon->CSPlayerWeapon();
if (unlikely(pCSWeapon == nullptr))
{
AMXX_LogError(amx, AMX_ERR_NATIVE, "%s: invalid or uninitialized m_pEntity.", __FUNCTION__);
return FALSE;
}
CAmxArgs args(amx, params);
pCSWeapon->KickBack(args[arg_up_base], args[arg_lateral_base], args[arg_up_modifier], args[arg_lateral_modifier], args[arg_up_max], args[arg_lateral_max], args[arg_direction_change]);
return TRUE;
}
/*
* Switches player current weapon into the best one on its inventory using the CHalfLifeMultiplay::GetNextBestWeapon function.
*
* @param player Player index.
* @param currentWeapon Current player active weapon. 0 = retrieve from m_pActiveItem member
*
* @note Weapon selection is based on weapon's Weight attribute from ItemInfo structure.
* @return 1 if weapon was found and switched to, 0 otherwise
*/
cell AMX_NATIVE_CALL rg_switch_best_weapon(AMX* amx, cell* params)
{
enum args_e { arg_count, arg_index, arg_weapon };
CHECK_GAMERULES();
CHECK_ISPLAYER(arg_index);
CBasePlayer *pPlayer = UTIL_PlayerByIndex(params[arg_index]);
CHECK_CONNECTED(pPlayer, arg_index);
if (!pPlayer->IsAlive())
return FALSE;
CBasePlayerWeapon *pWeapon;
if (params[arg_weapon] != 0)
{
CHECK_ISENTITY(arg_weapon);
pWeapon = getPrivate<CBasePlayerWeapon>(params[arg_weapon]);
if (unlikely(pWeapon == nullptr)) {
AMXX_LogError(amx, AMX_ERR_NATIVE, "%s: invalid or uninitialized entity", __FUNCTION__);
return FALSE;
}
if (!pWeapon->IsWeapon()) {
AMXX_LogError(amx, AMX_ERR_NATIVE, "%s: #%d entity is not a weapon.", __FUNCTION__, indexOfEdict(pWeapon->pev));
return FALSE;
}
}
else
{
pWeapon = static_cast<CBasePlayerWeapon *>(pPlayer->m_pActiveItem);
if (unlikely(pWeapon == nullptr)) {
AMXX_LogError(amx, AMX_ERR_NATIVE, "%s: player %d has invalid m_pActiveItem", __FUNCTION__, params[arg_index]);
return FALSE;
}
}
return CSGameRules()->GetNextBestWeapon(pPlayer, pWeapon);
}
/*
* Disappear a player from the world. Used when VIP reaches escape zone. Basically a silent kill.
*
* @param player Player index.
*
* @noreturn
*/
cell AMX_NATIVE_CALL rg_disappear(AMX* amx, cell* params)
{
enum args_e { arg_count, arg_index };
CHECK_ISPLAYER(arg_index)
CBasePlayer *pPlayer = UTIL_PlayerByIndex(params[arg_index]);
CHECK_CONNECTED(pPlayer, arg_index);
pPlayer->CSPlayer()->Disappear();
return TRUE;
}
/*
* Sets player current Observer mode.
* @note Player must be a valid observer (m_afPhysicsFlags & PFLAG_OBSERVER).
*
* @param player Player index.
* @param mode Observer mode, see OBS_* constants in cssdk_const.inc
*
* @noreturn
*/
cell AMX_NATIVE_CALL rg_set_observer_mode(AMX* amx, cell* params)
{
enum args_e { arg_count, arg_index, arg_mode };
CHECK_ISPLAYER(arg_index)
CBasePlayer *pPlayer = UTIL_PlayerByIndex(params[arg_index]);
CHECK_CONNECTED(pPlayer, arg_index);
pPlayer->CSPlayer()->Observer_SetMode((int)params[arg_mode]);
return TRUE;
}
/*
* Emits a death notice (logs, DeathMsg event, win conditions check)
*
* @param pVictim Player index.
* @param pKiller Killer entity.
* @param pevInflictor Inflictor entity. 0 = world
*
* @noreturn
*/
cell AMX_NATIVE_CALL rg_death_notice(AMX* amx, cell* params)
{
enum args_e { arg_count, arg_victim, arg_killer, arg_inflictor };
CHECK_GAMERULES();
CHECK_ISPLAYER(arg_victim)
CBasePlayer *pPlayer = UTIL_PlayerByIndex(params[arg_victim]);
CHECK_CONNECTED(pPlayer, arg_victim);
CHECK_ISENTITY(arg_killer)
CAmxArgs args(amx, params);
CSGameRules()->DeathNotice(pPlayer, args[arg_killer], args[arg_inflictor]);
return TRUE;
}
AMX_NATIVE_INFO Misc_Natives_RG[] =
{
{ "rg_set_animation", rg_set_animation },
@ -2708,6 +3319,22 @@ AMX_NATIVE_INFO Misc_Natives_RG[] =
{ "rg_spawn_head_gib", rg_spawn_head_gib },
{ "rg_spawn_random_gibs", rg_spawn_random_gibs },
{ "rg_spawn_grenade", rg_spawn_grenade },
{ "rg_create_weaponbox", rg_create_weaponbox },
{ "rg_remove_entity", rg_remove_entity },
{ "rg_decal_trace", rg_decal_trace },
{ "rg_emit_texture_sound", rg_emit_texture_sound },
{ "rg_add_ammo_registry", rg_add_ammo_registry },
{ "rg_weapon_deploy", rg_weapon_deploy },
{ "rg_weapon_reload", rg_weapon_reload },
{ "rg_weapon_shotgun_reload", rg_weapon_shotgun_reload },
{ "rg_weapon_send_animation", rg_weapon_send_animation },
{ "rg_weapon_kickback", rg_weapon_kickback },
{ "rg_switch_best_weapon", rg_switch_best_weapon },
{ "rg_disappear", rg_disappear },
{ "rg_set_observer_mode", rg_set_observer_mode },
{ "rg_death_notice", rg_death_notice },
{ nullptr, nullptr }
};