diff --git a/reapi/extra/amxmodx/scripting/include/cssdk_const.inc b/reapi/extra/amxmodx/scripting/include/cssdk_const.inc index a3bfc5e9..0f91158b 100644 --- a/reapi/extra/amxmodx/scripting/include/cssdk_const.inc +++ b/reapi/extra/amxmodx/scripting/include/cssdk_const.inc @@ -1539,3 +1539,15 @@ enum Decal DECAL_MOMMABIRTH, // Big momma birth splatter DECAL_MOMMASPLAT, }; + +/** +* Player relationship return codes +*/ +enum +{ + GR_NOTTEAMMATE = 0, + GR_TEAMMATE, + GR_ENEMY, + GR_ALLY, + GR_NEUTRAL, +}; \ No newline at end of file diff --git a/reapi/extra/amxmodx/scripting/include/reapi_engine.inc b/reapi/extra/amxmodx/scripting/include/reapi_engine.inc index ce3aabb8..ba71180a 100644 --- a/reapi/extra/amxmodx/scripting/include/reapi_engine.inc +++ b/reapi/extra/amxmodx/scripting/include/reapi_engine.inc @@ -133,8 +133,8 @@ native GetAttachment(const entity, const attachment, Float:vecOrigin[3], Float:v * @return 1 on success, 0 otherwise * @error If the index is not within the range of 1 to maxEntities or * the entity is not valid, an error will be thrown. -* -*/ +* +*/ native SetBodygroup(const entity, const group, const value); /* @@ -146,8 +146,8 @@ native SetBodygroup(const entity, const group, const value); * @return Body group value * @error If the index is not within the range of 1 to maxEntities or * the entity is not valid, an error will be thrown. -* -*/ +* +*/ native GetBodygroup(const entity, const group); /* @@ -161,10 +161,26 @@ native GetBodygroup(const entity, const group); * @return True on success, false otherwise * @error If the index is not within the range of 1 to maxEntities or * the entity is not valid, an error will be thrown. -* -*/ +* +*/ native bool:GetSequenceInfo(const entity, &piFlags, &Float:pflFrameRate, &Float:pflGroundSpeed); +/* +* Test visibility of an entity from a given origin using either PVS or PAS +* +* @param entity Entity index +* @param origin Vector representing the origin from which visibility is checked +* @param type Type of visibility check: VisibilityInPVS (Potentially Visible Set) or VisibilityInPAS (Potentially Audible Set) +* +* @return 0 - Not visible +* 1 - Visible, passed by a leafnum +* 2 - Visible, passed by a headnode +* +* @remarks This function checks the visibility of the specified entity from the given origin, using either +* the Potentially Visible Set (PVS) or the Potentially Audible Set (PAS) depending on the provided type +*/ +native CheckVisibilityInOrigin(const ent, Float:origin[3], CheckVisibilityType:type = VisibilityInPVS); + /* * Sets the name of the map. * diff --git a/reapi/extra/amxmodx/scripting/include/reapi_engine_const.inc b/reapi/extra/amxmodx/scripting/include/reapi_engine_const.inc index d1b114e9..2302d05b 100644 --- a/reapi/extra/amxmodx/scripting/include/reapi_engine_const.inc +++ b/reapi/extra/amxmodx/scripting/include/reapi_engine_const.inc @@ -13,6 +13,15 @@ enum MapNameType MNT_SET // return the name of the current map }; +/** +* For native CheckVisibilityInOrigin +*/ +enum CheckVisibilityType +{ + VisibilityInPVS = 0, // Check in Potentially Visible Set (PVS) + VisibilityInPAS // Check in Potentially Audible Set (PAS) +}; + /* * For RH_SV_AddResource hook */ @@ -162,12 +171,6 @@ enum EngineFunc */ RH_SV_ClientPrintf, - /* - * Description: Called when a command is being sent to server. - * Params: (const cmd[], source, id) - */ - RH_ExecuteServerStringCmd, - /* * Description: Called before adding an entity to the physents of a player. * Return type: bool @@ -175,6 +178,12 @@ enum EngineFunc */ RH_SV_AllowPhysent, + /* + * Description: Called when a command is being sent to server. + * Params: (const cmd[], source, id) + */ + RH_ExecuteServerStringCmd, + }; /** diff --git a/reapi/extra/amxmodx/scripting/include/reapi_gamedll.inc b/reapi/extra/amxmodx/scripting/include/reapi_gamedll.inc index bf2386a3..52dcd9c8 100644 --- a/reapi/extra/amxmodx/scripting/include/reapi_gamedll.inc +++ b/reapi/extra/amxmodx/scripting/include/reapi_gamedll.inc @@ -443,12 +443,12 @@ native rg_find_ent_by_class(start_index, const classname[], const bool:useHashTa /* * Finds an entity in the world using Counter-Strike's custom FindEntityByString wrapper, matching by owner. * -* @param start_index Entity index to start searching from. -1 to start from the first entity +* @param start_index Entity index to start searching from. AMX_NULLENT (-1) to start from the first entity * @param classname Classname to search for * -* @return 1 if found, 0 otherwise +* @return true if found, false otherwise */ -native rg_find_ent_by_owner(&start_index, const classname[], owner); +native bool:rg_find_ent_by_owner(&start_index, const classname[], owner); /* * Finds the weapon by name in the player's inventory. @@ -1077,7 +1077,7 @@ native rg_emit_texture_sound(const ptr, Float:vecSrc[3], Float:vecEnd[3], Bullet * @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_.txt" file. * -* @param szAmmoname Ammo name to create. +* @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. @@ -1100,7 +1100,7 @@ native rg_remove_ammo_registry(const szAmmoname[]); * @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. +* @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. * @@ -1184,7 +1184,7 @@ native rg_switch_best_weapon(const player, const currentWeapon = 0); native rg_disappear(const player); /* -* Sets player current Observer mode. +* Sets player current Observer mode. * @note Player must be a valid observer (m_afPhysicsFlags & PFLAG_OBSERVER). * * @param player Player index. @@ -1204,3 +1204,13 @@ native rg_set_observer_mode(const player, const mode); * @noreturn */ native rg_death_notice(const pVictim, const pKiller, const pevInflictor); + +/* +* Checks a player relationship with another reference +* +* @param player Player index +* @param target Target index +* +* @return Match player relationship, see GR_* constants in cssdk_const.inc +*/ +native rg_player_relationship(const player, const target); \ No newline at end of file diff --git a/reapi/extra/amxmodx/scripting/include/reapi_gamedll_const.inc b/reapi/extra/amxmodx/scripting/include/reapi_gamedll_const.inc index e9459b5c..cbe0969b 100644 --- a/reapi/extra/amxmodx/scripting/include/reapi_gamedll_const.inc +++ b/reapi/extra/amxmodx/scripting/include/reapi_gamedll_const.inc @@ -134,7 +134,15 @@ enum WpnInfo * Get params: rg_get_weapon_info(const weapon_id, WI_NAME, const output[], maxlenght); * Set params: - */ - WI_NAME + WI_NAME, + + /* + * Description: - + * Return type: enum InventorySlotType + * Get params: rg_get_weapon_info(const weapon_id, WI_SLOT); + * Set params: rg_set_weapon_info(const weapon_id, WI_SLOT, const value); + */ + WI_SLOT, }; /** @@ -914,6 +922,18 @@ enum GamedllFunc_CBasePlayer * Params: (const this) */ RG_CBasePlayer_EntSelectSpawnPoint, + + /* + * Description: - + * Params: (const this) + */ + RG_CBasePlayer_PlayerDeathThink, + + /* + * Description: - + * Params: (const this) + */ + RG_CBasePlayer_Observer_Think, }; /** diff --git a/reapi/include/cssdk/dlls/regamedll_api.h b/reapi/include/cssdk/dlls/regamedll_api.h index 7d67ea17..f12c057d 100644 --- a/reapi/include/cssdk/dlls/regamedll_api.h +++ b/reapi/include/cssdk/dlls/regamedll_api.h @@ -622,6 +622,10 @@ typedef IHookChainRegistry IReGameHook_CBasePlayer_PlayerDeathThink; typedef IHookChainRegistryClass IReGameHookRegistry_CBasePlayer_PlayerDeathThink; +// CBasePlayer::Observer_Think hook +typedef IHookChainClass IReGameHook_CBasePlayer_Observer_Think; +typedef IHookChainRegistryClass IReGameHookRegistry_CBasePlayer_Observer_Think; + class IReGameHookchains { public: virtual ~IReGameHookchains() {} @@ -782,6 +786,8 @@ class IReGameHookchains { virtual IReGameHookRegistry_CSGameRules_SendDeathMessage *CSGameRules_SendDeathMessage() = 0; virtual IReGameHookRegistry_CBasePlayer_PlayerDeathThink *CBasePlayer_PlayerDeathThink() = 0; + virtual IReGameHookRegistry_CBasePlayer_Observer_Think *CBasePlayer_Observer_Think() = 0; + }; struct ReGameFuncs_t { diff --git a/reapi/src/hook_callback.cpp b/reapi/src/hook_callback.cpp index 518a74e0..669ea8ed 100644 --- a/reapi/src/hook_callback.cpp +++ b/reapi/src/hook_callback.cpp @@ -1460,7 +1460,7 @@ void PM_LadderMove_AMXX(IReGameHook_PM_LadderMove *chain, physent_t *pLadder, in void PM_LadderMove(IReGameHook_PM_LadderMove *chain, physent_t *pLadder) { - PM_LadderMove_AMXX(chain, pLadder, pLadder->player + 1); + PM_LadderMove_AMXX(chain, pLadder, g_pMove->player_index + 1); } void PM_WaterJump_AMXX(IReGameHook_PM_WaterJump *chain, int playerIndex) @@ -1607,7 +1607,7 @@ void BuyItem(IReGameHook_BuyItem *chain, CBasePlayer *pPlayer, int iSlot) chain->callNext(getPrivate(_pPlayer), _iSlot); }; - callVoidForward(RG_AddMultiDamage, original, indexOfEdict(pPlayer->pev), iSlot); + callVoidForward(RG_BuyItem, original, indexOfEdict(pPlayer->pev), iSlot); } void CSGameRules_Think(IReGameHook_CSGameRules_Think *chain) @@ -1710,6 +1710,25 @@ void CBasePlayerWeapon_SendWeaponAnim(IReGameHook_CBasePlayerWeapon_SendWeaponAn callVoidForward(RG_CBasePlayerWeapon_SendWeaponAnim, original, indexOfEdict(pthis->pev), iAnim, skiplocal); } +void CBasePlayer_PlayerDeathThink(IReGameHook_CBasePlayer_PlayerDeathThink *chain, CBasePlayer *pthis) +{ + auto original = [chain](int _pthis) + { + chain->callNext(getPrivate(_pthis)); + }; + + callVoidForward(RG_CBasePlayer_PlayerDeathThink, original, indexOfEdict(pthis->pev)); +} + +void CBasePlayer_Observer_Think(IReGameHook_CBasePlayer_Observer_Think *chain, CBasePlayer *pthis) +{ + auto original = [chain](int _pthis) + { + chain->callNext(getPrivate(_pthis)); + }; + + callVoidForward(RG_CBasePlayer_Observer_Think, original, indexOfEdict(pthis->pev)); +} /* * VTC functions diff --git a/reapi/src/hook_callback.h b/reapi/src/hook_callback.h index af39e6ad..ede4ad76 100644 --- a/reapi/src/hook_callback.h +++ b/reapi/src/hook_callback.h @@ -558,6 +558,8 @@ edict_t *CBasePlayer_EntSelectSpawnPoint(IReGameHook_CBasePlayer_EntSelectSpawnP void CBasePlayerWeapon_ItemPostFrame(IReGameHook_CBasePlayerWeapon_ItemPostFrame *chain, CBasePlayerWeapon *pthis); void CBasePlayerWeapon_KickBack(IReGameHook_CBasePlayerWeapon_KickBack *chain, CBasePlayerWeapon *pthis, float up_base, float lateral_base, float up_modifier, float lateral_modifier, float up_max, float lateral_max, int direction_change); void CBasePlayerWeapon_SendWeaponAnim(IReGameHook_CBasePlayerWeapon_SendWeaponAnim *chain, CBasePlayerWeapon *pthis, int iAnim, int skiplocal); +void CBasePlayer_PlayerDeathThink(IReGameHook_CBasePlayer_PlayerDeathThink *chain, CBasePlayer *pthis); +void CBasePlayer_Observer_Think(IReGameHook_CBasePlayer_Observer_Think *chain, CBasePlayer *pthis); /* * VTC functions diff --git a/reapi/src/hook_list.cpp b/reapi/src/hook_list.cpp index 870c95c1..8f5bf54a 100644 --- a/reapi/src/hook_list.cpp +++ b/reapi/src/hook_list.cpp @@ -212,6 +212,9 @@ hook_t hooklist_player[] = { DLL(CBasePlayer_CheckTimeBasedDamage), DLL(CBasePlayer_EntSelectSpawnPoint), + + DLL(CBasePlayer_PlayerDeathThink), + DLL(CBasePlayer_Observer_Think), }; hook_t hooklist_gamerules[] = { diff --git a/reapi/src/hook_list.h b/reapi/src/hook_list.h index 18483eb2..6e6d9da7 100644 --- a/reapi/src/hook_list.h +++ b/reapi/src/hook_list.h @@ -236,6 +236,9 @@ enum GamedllFunc_CBasePlayer RG_CBasePlayer_CheckTimeBasedDamage, RG_CBasePlayer_EntSelectSpawnPoint, + RG_CBasePlayer_PlayerDeathThink, + RG_CBasePlayer_Observer_Think, + // [...] }; diff --git a/reapi/src/natives/natives_common.cpp b/reapi/src/natives/natives_common.cpp index 416521a7..b538c14a 100644 --- a/reapi/src/natives/natives_common.cpp +++ b/reapi/src/natives/natives_common.cpp @@ -322,8 +322,8 @@ cell AMX_NATIVE_CALL amx_GetAttachment(AMX *amx, cell *params) * @return 1 on success, 0 otherwise * @error If the index is not within the range of 1 to maxEntities or * the entity is not valid, an error will be thrown. -* -*/ +* +*/ cell AMX_NATIVE_CALL amx_GetBodygroup(AMX *amx, cell *params) { enum args_e { arg_count, arg_index, arg_group }; @@ -353,8 +353,8 @@ cell AMX_NATIVE_CALL amx_GetBodygroup(AMX *amx, cell *params) * @return Body group value * @error If the index is not within the range of 1 to maxEntities or * the entity is not valid, an error will be thrown. -* -*/ +* +*/ cell AMX_NATIVE_CALL amx_SetBodygroup(AMX *amx, cell *params) { enum args_e { arg_count, arg_index, arg_group, arg_value }; @@ -387,8 +387,8 @@ cell AMX_NATIVE_CALL amx_SetBodygroup(AMX *amx, cell *params) * @return True on success, false otherwise * @error If the index is not within the range of 1 to maxEntities or * the entity is not valid, an error will be thrown. -* -*/ +* +*/ cell AMX_NATIVE_CALL amx_GetSequenceInfo(AMX *amx, cell *params) { enum args_e { arg_count, arg_index, arg_flags, arg_framerate, arg_groundspeed }; @@ -634,6 +634,58 @@ cell AMX_NATIVE_CALL amx_SetMoveDone(AMX *amx, cell *params) return (cell)EntityCallbackDispatcher().SetMoveDone(amx, pEntity, funcname, pParams, params[arg_len]); } +enum class CheckVisibilityType { + PVS = 0, // Check in Potentially Visible Set (PVS) + PAS // Check in Potentially Audible Set (PAS) +}; + +/* +* Test visibility of an entity from a given origin using either PVS or PAS +* +* @param entity Entity index +* @param origin Vector representing the origin from which visibility is checked +* @param type Type of visibility check: VisibilityInPVS (Potentially Visible Set) or VisibilityInPAS (Potentially Audible Set) +* +* @return 0 - Not visible +* 1 - Visible, passed by a leafnum +* 2 - Visible, passed by a headnode +* +* @remarks This function checks the visibility of the specified entity from the given origin, using either +* the Potentially Visible Set (PVS) or the Potentially Audible Set (PAS) depending on the provided type +* +* native CheckVisibilityInOrigin(const ent, Float:origin[3], CheckVisibilityType:type = VisibilityInPVS); +*/ +cell AMX_NATIVE_CALL amx_CheckVisibilityInOrigin(AMX *amx, cell *params) +{ + enum args_e { arg_count, arg_index, arg_origin, arg_type }; + + CHECK_ISENTITY(arg_index); + + CBaseEntity *pEntity = getPrivate(params[arg_index]); + if (unlikely(pEntity == nullptr)) { + AMXX_LogError(amx, AMX_ERR_NATIVE, "%s: invalid or uninitialized entity", __FUNCTION__); + return FALSE; + } + + CheckVisibilityType type = static_cast(params[arg_type]); + if (type < CheckVisibilityType::PVS || type > CheckVisibilityType::PAS) { + AMXX_LogError(amx, AMX_ERR_NATIVE, "%s: invalid visibility check type %d. Use either VisibilityInPVS or VisibilityInPAS.", __FUNCTION__, params[arg_type]); + return FALSE; + } + + Vector &origin = *(Vector *)getAmxAddr(amx, params[arg_origin]); + + unsigned char *pSet = NULL; + switch (type) + { + case CheckVisibilityType::PVS: pSet = ENGINE_SET_PVS(origin); break; + case CheckVisibilityType::PAS: pSet = ENGINE_SET_PAS(origin); break; + default: break; + } + + return ENGINE_CHECK_VISIBILITY(pEntity->edict(), pSet); +} + AMX_NATIVE_INFO Natives_Common[] = { { "FClassnameIs", amx_FClassnameIs }, @@ -655,6 +707,8 @@ AMX_NATIVE_INFO Natives_Common[] = { "SetBlocked", amx_SetBlocked }, { "SetMoveDone", amx_SetMoveDone }, + { "CheckVisibilityInOrigin", amx_CheckVisibilityInOrigin }, + { nullptr, nullptr } }; diff --git a/reapi/src/natives/natives_helper.h b/reapi/src/natives/natives_helper.h index 6ec6b5ea..f6c664e4 100644 --- a/reapi/src/natives/natives_helper.h +++ b/reapi/src/natives/natives_helper.h @@ -6,6 +6,7 @@ #define CHECK_ISENTITY(x) if (unlikely(params[x] < 0 || params[x] > gpGlobals->maxEntities)) { AMXX_LogError(amx, AMX_ERR_NATIVE, "%s: invalid entity index %i [%s]", __FUNCTION__, params[x], #x); return FALSE; } #define CHECK_GAMERULES() if (unlikely(!g_pGameRules)) { AMXX_LogError(amx, AMX_ERR_NATIVE, "%s: gamerules not initialized", __FUNCTION__); return FALSE; } #define CHECK_CONNECTED(x, y) if (unlikely(x == nullptr || x->has_disconnected)) { AMXX_LogError(amx, AMX_ERR_NATIVE, "%s: player %i is not connected", __FUNCTION__, params[y]); return FALSE; } +#define CHECK_INSTANCE_OF(x, y) if (unlikely(dynamic_cast((x::BaseClass *)y) == nullptr)) { AMXX_LogError(amx, AMX_ERR_NATIVE, "%s: invalid entity %d ('%s'), is not an instance of the base class '%s'", __FUNCTION__, indexOfEdict(y->pev), STRING(y->pev->classname), #x); return FALSE; } class CAmxArg { diff --git a/reapi/src/natives/natives_misc.cpp b/reapi/src/natives/natives_misc.cpp index 82ee7433..5bbe2848 100644 --- a/reapi/src/natives/natives_misc.cpp +++ b/reapi/src/natives/natives_misc.cpp @@ -613,12 +613,12 @@ cell AMX_NATIVE_CALL rg_find_ent_by_class(AMX *amx, cell *params) /* * Finds an entity in the world using Counter-Strike's custom FindEntityByString wrapper, matching by owner. * -* @param start_index Entity index to start searching from. -1 to start from the first entity +* @param start_index Entity index to start searching from. AMX_NULLENT (-1) to start from the first entity * @param classname Classname to search for * -* @return 1 if found, 0 otherwise +* @return true if found, false otherwise * -* native rg_find_ent_by_owner(&start_index, const classname[], owner); +* native bool:rg_find_ent_by_owner(&start_index, const classname[], owner); */ cell AMX_NATIVE_CALL rg_find_ent_by_owner(AMX *amx, cell *params) { @@ -629,12 +629,14 @@ cell AMX_NATIVE_CALL rg_find_ent_by_owner(AMX *amx, cell *params) char classname[256]; cell& startIndex = *getAmxAddr(amx, params[arg_start_index]); + startIndex = clamp(startIndex, AMX_NULLENT, gpGlobals->maxEntities - 1); + const char* value = getAmxString(amx, params[arg_classname], classname); edict_t* pOwner = edictByIndexAmx(params[arg_onwer]); - edict_t* pEntity = g_pEdicts + startIndex; - for (int i = startIndex; i < gpGlobals->maxEntities; i++, pEntity++) + for (int i = startIndex + 1; i < gpGlobals->maxEntities; i++) { + edict_t *pEntity = edictByIndex(i); if (pEntity->v.owner != pOwner) continue; @@ -838,7 +840,15 @@ cell AMX_NATIVE_CALL rg_get_weapon_info(AMX *amx, cell *params) setAmxString(dest, info->entityName, length); return 1; } + case WI_SLOT: + { + auto pInfo = g_ReGameApi->GetWeaponSlot(weaponId); + if (pInfo) { + return pInfo->slot; + } + return NONE_SLOT; + } default: AMXX_LogError(amx, AMX_ERR_NATIVE, "%s: unknown type statement %i, params count %i", __FUNCTION__, info_type, PARAMS_COUNT); return -1; @@ -894,6 +904,12 @@ cell AMX_NATIVE_CALL rg_set_weapon_info(AMX *amx, cell *params) case WI_NAME: AMXX_LogError(amx, AMX_ERR_NATIVE, "%s: this change will have no effect, type statement %i", __FUNCTION__, info_type); return 0; + case WI_SLOT: + { + auto pInfo = g_ReGameApi->GetWeaponSlot(weaponId); + pInfo->slot = static_cast(*value); + break; + } default: AMXX_LogError(amx, AMX_ERR_NATIVE, "%s: unknown type statement %i, params count %i", __FUNCTION__, info_type, PARAMS_COUNT); return 0; @@ -1659,8 +1675,15 @@ cell AMX_NATIVE_CALL rg_instant_reload_weapons(AMX *amx, cell *params) if (params[arg_weapon] != 0) { pWeapon = getPrivate(params[arg_weapon]); - if (!pWeapon || !pWeapon->IsWeapon()) { - AMXX_LogError(amx, AMX_ERR_NATIVE, "%s: Invalid entity weapon", __FUNCTION__); + if (unlikely(pWeapon == nullptr)) { + AMXX_LogError(amx, AMX_ERR_NATIVE, "%s: invalid or uninitialized entity", __FUNCTION__); + return FALSE; + } + + CHECK_INSTANCE_OF(CBasePlayerWeapon, pWeapon); + + if (!pWeapon->IsWeapon()) { + AMXX_LogError(amx, AMX_ERR_NATIVE, "%s: #%d entity is not a weapon.", __FUNCTION__, indexOfEdict(pWeapon->pev)); return FALSE; } } @@ -1851,9 +1874,16 @@ cell AMX_NATIVE_CALL rg_switch_weapon(AMX *amx, cell *params) CBasePlayer *pPlayer = UTIL_PlayerByIndex(params[arg_index]); CHECK_CONNECTED(pPlayer, arg_index); - auto pWeapon = getPrivate(params[arg_weapon]); - if (pWeapon == nullptr || !pWeapon->IsWeapon()) { - AMXX_LogError(amx, AMX_ERR_NATIVE, "%s: Invalid entity weapon", __FUNCTION__); + CBasePlayerWeapon *pWeapon = getPrivate(params[arg_weapon]); + if (unlikely(pWeapon == nullptr)) { + AMXX_LogError(amx, AMX_ERR_NATIVE, "%s: invalid or uninitialized entity", __FUNCTION__); + return FALSE; + } + + CHECK_INSTANCE_OF(CBasePlayerWeapon, pWeapon); + + if (!pWeapon->IsWeapon()) { + AMXX_LogError(amx, AMX_ERR_NATIVE, "%s: #%d entity is not a weapon.", __FUNCTION__, indexOfEdict(pWeapon->pev)); return FALSE; } @@ -2126,6 +2156,8 @@ cell AMX_NATIVE_CALL rg_set_iteminfo(AMX *amx, cell *params) return FALSE; } + CHECK_INSTANCE_OF(CBasePlayerWeapon, pWeapon); + if (!pWeapon->IsWeapon()) { AMXX_LogError(amx, AMX_ERR_NATIVE, "%s: #%d entity is not a weapon.", __FUNCTION__, indexOfEdict(pWeapon->pev)); return FALSE; @@ -2189,6 +2221,8 @@ cell AMX_NATIVE_CALL rg_get_iteminfo(AMX *amx, cell *params) return FALSE; } + CHECK_INSTANCE_OF(CBasePlayerWeapon, pWeapon); + if (!pWeapon->IsWeapon()) { AMXX_LogError(amx, AMX_ERR_NATIVE, "%s: #%d entity is not a weapon.", __FUNCTION__, indexOfEdict(pWeapon->pev)); return FALSE; @@ -2637,11 +2671,11 @@ cell AMX_NATIVE_CALL rg_spawn_grenade(AMX* amx, cell* params) 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], + pPlayer->pev, + args[arg_origin], + args[arg_velocity], + args[arg_time], + args[arg_team], args[arg_event]); // Sanity check anyway @@ -2677,7 +2711,7 @@ cell AMX_NATIVE_CALL rg_create_weaponbox(AMX* amx, cell* params) AMXX_LogError(amx, AMX_ERR_NATIVE, "%s: invalid or uninitialized entity", __FUNCTION__); return FALSE; } - + CBasePlayer *pPlayer = nullptr; if (params[arg_player] != 0) @@ -2771,7 +2805,7 @@ cell AMX_NATIVE_CALL rg_emit_texture_sound(AMX* amx, cell* params) * @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_.txt" file. * -* @param szAmmoname Ammo name to create. +* @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. @@ -2822,7 +2856,7 @@ cell AMX_NATIVE_CALL rg_remove_ammo_registry(AMX* amx, cell* params) * @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. +* @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. * @@ -2841,6 +2875,8 @@ cell AMX_NATIVE_CALL rg_weapon_deploy(AMX* amx, cell* params) return FALSE; } + CHECK_INSTANCE_OF(CBasePlayerWeapon, pWeapon); + if (!pWeapon->IsWeapon()) { AMXX_LogError(amx, AMX_ERR_NATIVE, "%s: #%d entity is not a weapon.", __FUNCTION__, indexOfEdict(pWeapon->pev)); @@ -2894,7 +2930,7 @@ cell AMX_NATIVE_CALL rg_weapon_reload(AMX* amx, cell* params) } else { - CHECK_ISENTITY(arg_weapon); + CHECK_ISENTITY(arg_weapon); pWeapon = getPrivate(params[arg_weapon]); } @@ -2905,6 +2941,8 @@ cell AMX_NATIVE_CALL rg_weapon_reload(AMX* amx, cell* params) return FALSE; } + CHECK_INSTANCE_OF(CBasePlayerWeapon, pWeapon); + if (!pWeapon->IsWeapon()) { AMXX_LogError(amx, AMX_ERR_NATIVE, "%s: #%d entity is not a weapon.", __FUNCTION__, indexOfEdict(pWeapon->pev)); @@ -2964,7 +3002,7 @@ cell AMX_NATIVE_CALL rg_weapon_shotgun_reload(AMX* amx, cell* params) } else { - CHECK_ISENTITY(arg_weapon); + CHECK_ISENTITY(arg_weapon); pWeapon = getPrivate(params[arg_weapon]); } @@ -2975,6 +3013,8 @@ cell AMX_NATIVE_CALL rg_weapon_shotgun_reload(AMX* amx, cell* params) return FALSE; } + CHECK_INSTANCE_OF(CBasePlayerWeapon, pWeapon); + if (!pWeapon->IsWeapon()) { AMXX_LogError(amx, AMX_ERR_NATIVE, "%s: #%d entity is not a weapon.", __FUNCTION__, indexOfEdict(pWeapon->pev)); @@ -3028,7 +3068,7 @@ cell AMX_NATIVE_CALL rg_weapon_send_animation(AMX* amx, cell* params) } else { - CHECK_ISENTITY(arg_weapon); + CHECK_ISENTITY(arg_weapon); pWeapon = getPrivate(params[arg_weapon]); } @@ -3039,6 +3079,8 @@ cell AMX_NATIVE_CALL rg_weapon_send_animation(AMX* amx, cell* params) return FALSE; } + CHECK_INSTANCE_OF(CBasePlayerWeapon, pWeapon); + if (!pWeapon->IsWeapon()) { AMXX_LogError(amx, AMX_ERR_NATIVE, "%s: #%d entity is not a weapon.", __FUNCTION__, indexOfEdict(pWeapon->pev)); @@ -3094,7 +3136,7 @@ cell AMX_NATIVE_CALL rg_weapon_kickback(AMX* amx, cell* params) } else { - CHECK_ISENTITY(arg_weapon); + CHECK_ISENTITY(arg_weapon); pWeapon = getPrivate(params[arg_weapon]); } @@ -3104,6 +3146,8 @@ cell AMX_NATIVE_CALL rg_weapon_kickback(AMX* amx, cell* params) return FALSE; } + CHECK_INSTANCE_OF(CBasePlayerWeapon, pWeapon); + if (!pWeapon->IsWeapon()) { AMXX_LogError(amx, AMX_ERR_NATIVE, "%s: #%d entity is not a weapon.", __FUNCTION__, indexOfEdict(pWeapon->pev)); @@ -3158,11 +3202,6 @@ cell AMX_NATIVE_CALL rg_switch_best_weapon(AMX* amx, cell* params) 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 { @@ -3174,6 +3213,13 @@ cell AMX_NATIVE_CALL rg_switch_best_weapon(AMX* amx, cell* params) } } + CHECK_INSTANCE_OF(CBasePlayerWeapon, pWeapon); + + if (!pWeapon->IsWeapon()) { + AMXX_LogError(amx, AMX_ERR_NATIVE, "%s: #%d entity is not a weapon.", __FUNCTION__, indexOfEdict(pWeapon->pev)); + return FALSE; + } + return CSGameRules()->GetNextBestWeapon(pPlayer, pWeapon); } @@ -3198,7 +3244,7 @@ cell AMX_NATIVE_CALL rg_disappear(AMX* amx, cell* params) } /* -* Sets player current Observer mode. +* Sets player current Observer mode. * @note Player must be a valid observer (m_afPhysicsFlags & PFLAG_OBSERVER). * * @param player Player index. @@ -3246,6 +3292,30 @@ cell AMX_NATIVE_CALL rg_death_notice(AMX* amx, cell* params) return TRUE; } +/* +* Checks a player relationship with another reference +* +* @param player Player index +* @param target Target index +* +* @return Match player relationship, see GR_* constants in cssdk_const.inc +*/ +cell AMX_NATIVE_CALL rg_player_relationship(AMX *amx, cell *params) +{ + enum args_e { arg_count, arg_player, arg_target }; + + CHECK_GAMERULES(); + CHECK_ISPLAYER(arg_player); + CHECK_ISENTITY(arg_target); + + CBasePlayer *pPlayer = UTIL_PlayerByIndex(params[arg_player]); + CHECK_CONNECTED(pPlayer, arg_player); + + CBaseEntity *pTarget = getPrivate(params[arg_target]); + + return CSGameRules()->PlayerRelationship(pPlayer, pTarget); +} + AMX_NATIVE_INFO Misc_Natives_RG[] = { { "rg_set_animation", rg_set_animation }, @@ -3358,6 +3428,7 @@ AMX_NATIVE_INFO Misc_Natives_RG[] = { "rg_disappear", rg_disappear }, { "rg_set_observer_mode", rg_set_observer_mode }, { "rg_death_notice", rg_death_notice }, + { "rg_player_relationship", rg_player_relationship }, { nullptr, nullptr } }; diff --git a/reapi/src/natives/natives_misc.h b/reapi/src/natives/natives_misc.h index 70ca2131..1ad58361 100644 --- a/reapi/src/natives/natives_misc.h +++ b/reapi/src/natives/natives_misc.h @@ -18,6 +18,7 @@ enum WpnInfo WI_AMMO_TYPE, WI_AMMO_NAME, WI_NAME, + WI_SLOT, }; void RegisterNatives_Misc();