├── api_advanced_pushing.sma ├── api_custom_entities.sma ├── api_custom_weapons.sma ├── api_particles.sma ├── api_player_camera.sma ├── api_player_cosmetics.sma ├── api_player_dizziness.sma ├── api_player_effects.sma ├── api_player_inventory.sma ├── api_player_model.sma ├── api_player_viewrange.sma ├── api_rounds.sma ├── api_waypoint_markers.sma ├── include ├── api_advanced_pushing.inc ├── api_custom_entities.inc ├── api_custom_weapons.inc ├── api_particles.inc ├── api_particles_const.inc ├── api_player_camera.inc ├── api_player_cosmetics.inc ├── api_player_dizziness.inc ├── api_player_effects.inc ├── api_player_effects_const.inc ├── api_player_inventory.inc ├── api_player_model.inc ├── api_player_viewrange.inc ├── api_rounds.inc ├── api_waypoint_markers.inc └── cellstruct.inc └── util ├── cellstruct.inc ├── command_util.inc ├── datapack_stocks.inc └── function_pointer.inc /api_advanced_pushing.sma: -------------------------------------------------------------------------------- 1 | #pragma semicolon 1 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | #include 9 | 10 | #define PLAYER_PREVENT_CLIMB (1<<5) 11 | 12 | #define IS_PLAYER(%1) (%1 >= 1 && %1 <= MaxClients) 13 | 14 | new Float:g_flPlayerReleaseClimbBlock[MAX_PLAYERS + 1]; 15 | 16 | public plugin_init() { 17 | register_plugin("[API] Advanced Pushing", "1.0.0", "Hedgehog Fog"); 18 | 19 | RegisterHamPlayer(Ham_Spawn, "HamHook_Player_Spawn_Post", .Post = 1); 20 | RegisterHamPlayer(Ham_Player_PostThink, "HamHook_Player_PostThink_Post", .Post = 1); 21 | } 22 | 23 | public plugin_natives() { 24 | register_library("api_advanced_pushing"); 25 | register_native("APS_Push", "Native_Push"); 26 | register_native("APS_PushFromOrigin", "Native_PushFromOrigin"); 27 | register_native("APS_PushFromBBox", "Native_PushFromBBox"); 28 | } 29 | 30 | public Native_Push(iPluginId, iArgc) { 31 | static pEntity = get_param(1); 32 | static Float:vecForce[3]; get_array_f(2, vecForce, sizeof(vecForce)); 33 | static APS_Flags:iFlags = APS_Flags:get_param(3); 34 | @Base_Push(pEntity, vecForce, iFlags); 35 | } 36 | 37 | public Native_PushFromOrigin(iPluginId, iArgc) { 38 | static pEntity; pEntity = get_param(1); 39 | static Float:flForce; flForce = get_param_f(2); 40 | static Float:vecPushOrigin[3]; get_array_f(3, vecPushOrigin, sizeof(vecPushOrigin)); 41 | static APS_Flags:iFlags; iFlags = APS_Flags:get_param(4); 42 | 43 | @Base_PushFromOrigin(pEntity, flForce, vecPushOrigin, iFlags); 44 | } 45 | 46 | public Native_PushFromBBox(iPluginId, iArgc) { 47 | static pEntity; pEntity = get_param(1); 48 | static Float:flForce; flForce = get_param_f(2); 49 | static Float:vecAbsMin[3]; get_array_f(3, vecAbsMin, sizeof(vecAbsMin)); 50 | static Float:vecAbsMax[3]; get_array_f(4, vecAbsMax, sizeof(vecAbsMax)); 51 | static Float:flMinDepthRatio; flMinDepthRatio = get_param_f(5); 52 | static Float:flMaxDepthRatio; flMaxDepthRatio = get_param_f(6); 53 | static Float:flDepthInfluenceMin; flDepthInfluenceMin = get_param_f(7); 54 | static Float:flDepthInfluenceMax; flDepthInfluenceMax = get_param_f(8); 55 | static APS_Flags:iFlags; iFlags = APS_Flags:get_param(9); 56 | 57 | @Base_PushFromBBox(pEntity, flForce, vecAbsMin, vecAbsMax, flMinDepthRatio, flMaxDepthRatio, flDepthInfluenceMin, flDepthInfluenceMax, iFlags); 58 | } 59 | 60 | public HamHook_Player_Spawn_Post(pPlayer) { 61 | @Player_ReleaseClimbPrevention(pPlayer); 62 | } 63 | 64 | public HamHook_Player_PostThink_Post(pPlayer) { 65 | if (g_flPlayerReleaseClimbBlock[pPlayer] && g_flPlayerReleaseClimbBlock[pPlayer] <= get_gametime()) { 66 | @Player_ReleaseClimbPrevention(pPlayer); 67 | } 68 | } 69 | 70 | @Player_SetClimbPrevention(pPlayer, bool:bValue) { 71 | new iPlayerFlags = pev(pPlayer, pev_iuser3); 72 | 73 | if (bValue) { 74 | iPlayerFlags |= PLAYER_PREVENT_CLIMB; 75 | } else { 76 | iPlayerFlags &= ~PLAYER_PREVENT_CLIMB; 77 | } 78 | 79 | set_pev(pPlayer, pev_iuser3, iPlayerFlags); 80 | } 81 | 82 | @Player_ReleaseClimbPrevention(this) { 83 | if (g_flPlayerReleaseClimbBlock[this]) { 84 | @Player_SetClimbPrevention(this, false); 85 | g_flPlayerReleaseClimbBlock[this] = 0.0; 86 | } 87 | } 88 | 89 | @Base_Push(this, const Float:vecForce[3], APS_Flags:iFlags) { 90 | static Float:vecVelocity[3]; pev(this, pev_velocity, vecVelocity); 91 | 92 | if (iFlags & APS_Flag_AddForce) { 93 | xs_vec_add(vecVelocity, vecForce, vecVelocity); 94 | } else { 95 | for (new i = 0; i < 3; ++i) { 96 | if (iFlags & APS_Flag_OverlapMode) { 97 | vecVelocity[i] = vecForce[i] ? vecForce[i] : vecVelocity[i]; 98 | } else { 99 | vecVelocity[i] = vecForce[i]; 100 | } 101 | } 102 | } 103 | 104 | set_pev(this, pev_velocity, vecVelocity); 105 | 106 | if (IS_PLAYER(this) && ~pev(this, pev_iuser3) & PLAYER_PREVENT_CLIMB) { 107 | @Player_SetClimbPrevention(this, true); 108 | g_flPlayerReleaseClimbBlock[this] = get_gametime() + 0.1; 109 | } 110 | } 111 | 112 | @Base_PushFromOrigin(this, Float:flForce, Float:vecPushOrigin[3], APS_Flags:iFlags) { 113 | static Float:vecOrigin[3]; pev(this, pev_origin, vecOrigin); 114 | 115 | static Float:vecForce[3]; 116 | xs_vec_sub(vecOrigin, vecPushOrigin, vecForce); 117 | xs_vec_normalize(vecForce, vecForce); 118 | xs_vec_mul_scalar(vecForce, flForce, vecForce); 119 | 120 | @Base_Push(this, vecForce, iFlags); 121 | } 122 | 123 | @Base_PushFromBBox( 124 | this, 125 | Float:flForce, 126 | const Float:vecAbsMin[3], 127 | const Float:vecAbsMax[3], 128 | Float:flMinDepthRatio, 129 | Float:flMaxDepthRatio, 130 | Float:flDepthInfluenceMin, 131 | Float:flDepthInfluenceMax, 132 | APS_Flags:iFlags 133 | ) { 134 | static Float:vecOrigin[3]; pev(this, pev_origin, vecOrigin); 135 | static Float:vecToucherAbsMin[3]; pev(this, pev_absmin, vecToucherAbsMin); 136 | static Float:vecToucherAbsMax[3]; pev(this, pev_absmax, vecToucherAbsMax); 137 | 138 | // Find and check intersection point 139 | for (new iAxis = 0; iAxis < 3; ++iAxis) { 140 | if (vecOrigin[iAxis] < vecAbsMin[iAxis]) { 141 | vecOrigin[iAxis] = vecToucherAbsMax[iAxis]; 142 | } else if (vecOrigin[iAxis] > vecAbsMax[iAxis]) { 143 | vecOrigin[iAxis] = vecToucherAbsMin[iAxis]; 144 | } 145 | 146 | if (vecAbsMin[iAxis] >= vecOrigin[iAxis]) return; 147 | if (vecAbsMax[iAxis] <= vecOrigin[iAxis]) return; 148 | } 149 | 150 | new iClosestAxis = -1; 151 | new pTrace = create_tr2(); 152 | static Float:vecOffset[3]; xs_vec_copy(Float:{0.0, 0.0, 0.0}, vecOffset); 153 | 154 | for (new iAxis = 0; iAxis < 3; ++iAxis) { 155 | // Calculates the toucher's offset relative to the current axis 156 | static Float:flSideOffsets[2]; 157 | flSideOffsets[0] = vecAbsMin[iAxis] - vecOrigin[iAxis]; 158 | flSideOffsets[1] = vecAbsMax[iAxis] - vecOrigin[iAxis]; 159 | 160 | if (iAxis == 2 && iClosestAxis != -1) { 161 | break; 162 | } 163 | 164 | for (new side = 0; side < 2; ++side) { 165 | // Check exit from current side 166 | static Float:vecTarget[3]; 167 | xs_vec_copy(vecOrigin, vecTarget); 168 | vecTarget[iAxis] += flSideOffsets[side]; 169 | engfunc(EngFunc_TraceMonsterHull, this, vecOrigin, vecTarget, IGNORE_MONSTERS | IGNORE_GLASS, this, pTrace); 170 | 171 | static Float:flFraction; 172 | get_tr2(pTrace, TR_flFraction, flFraction); 173 | 174 | // No exit, cannot push this way 175 | if (flFraction != 1.0) { 176 | flSideOffsets[side] = 0.0; 177 | } 178 | 179 | if (iAxis != 2) { 180 | // Save minimum offset, but ignore zero offsets 181 | if (!vecOffset[iAxis] || (flSideOffsets[side] && floatabs(flSideOffsets[side]) < floatabs(vecOffset[iAxis]))) { 182 | vecOffset[iAxis] = flSideOffsets[side]; 183 | } 184 | } else { 185 | // Priority on bottom side 186 | if (flSideOffsets[0]) { 187 | vecOffset[iAxis] = flSideOffsets[0]; 188 | } 189 | } 190 | 191 | // Find closest axis to push 192 | if (vecOffset[iAxis]) { 193 | if (iClosestAxis == -1 || floatabs(vecOffset[iAxis]) < floatabs(vecOffset[iClosestAxis])) { 194 | iClosestAxis = iAxis; 195 | } 196 | } 197 | } 198 | } 199 | 200 | free_tr2(pTrace); 201 | 202 | // Push by closest axis 203 | if (iClosestAxis == -1) return; 204 | 205 | static iPushDir; iPushDir = vecOffset[iClosestAxis] > 0.0 ? 1 : -1; 206 | static Float:vecSize[3]; xs_vec_sub(vecAbsMax, vecAbsMin, vecSize); 207 | static Float:flDepthRatio; flDepthRatio = floatabs(vecOffset[iClosestAxis]) / (vecSize[iClosestAxis] / 2); 208 | 209 | flDepthRatio = floatclamp(flDepthRatio, flMinDepthRatio, flMaxDepthRatio); 210 | 211 | static Float:vecForce[3]; xs_vec_copy(Float:{0.0, 0.0, 0.0}, vecForce); 212 | 213 | static bool:bInInfluence; bInInfluence = ( 214 | flDepthRatio >= flDepthInfluenceMin && 215 | flDepthRatio <= flDepthInfluenceMax 216 | ); 217 | 218 | if (bInInfluence) { 219 | vecForce[iClosestAxis] = flForce * flDepthRatio * iPushDir; 220 | } else { 221 | vecForce[iClosestAxis] = flForce * iPushDir; 222 | 223 | if (iFlags & APS_Flag_AddForceInfluenceMode) { 224 | iFlags &= ~APS_Flag_AddForce; 225 | } 226 | } 227 | 228 | @Base_Push(this, vecForce, iFlags); 229 | } 230 | -------------------------------------------------------------------------------- /api_custom_entities.sma: -------------------------------------------------------------------------------- 1 | #pragma semicolon 1 2 | 3 | #include 4 | #include 5 | 6 | #include 7 | #include 8 | #include 9 | 10 | #include 11 | #include 12 | 13 | #include 14 | 15 | #define PLUGIN "[API] Custom Entities" 16 | #define VERSION "1.2.3" 17 | #define AUTHOR "Hedgehog Fog" 18 | 19 | #define CE_BASE_CLASSNAME "info_target" 20 | #define LOG_PREFIX "[CE]" 21 | 22 | #define TASKID_SUM_DISAPPEAR 1000 23 | #define TASKID_SUM_RESPAWN 2000 24 | #define TASKID_SUM_REMOVE 3000 25 | 26 | /*--------------------------------[ Constants ]--------------------------------*/ 27 | 28 | enum CEPreset 29 | { 30 | CEPreset_None = 0, 31 | CEPreset_Item, 32 | CEPreset_NPC, 33 | CEPreset_Prop 34 | }; 35 | 36 | enum CEFunction 37 | { 38 | CEFunction_Spawn, 39 | CEFunction_Kill, 40 | CEFunction_Killed, 41 | CEFunction_Remove, 42 | CEFunction_Picked, 43 | CEFunction_Pickup, 44 | CEFunction_KVD 45 | }; 46 | 47 | enum CEHookData 48 | { 49 | CEHookData_PluginID, 50 | CEHookData_FuncID 51 | }; 52 | 53 | enum _:RegisterArgs 54 | { 55 | RegisterArg_Name = 1, 56 | RegisterArg_ModelIndex, 57 | RegisterArg_Mins, 58 | RegisterArg_Maxs, 59 | RegisterArg_LifeTime, 60 | RegisterArg_RespawnTime, 61 | RegisterArg_IgnoreRounds, 62 | RegisterArg_Preset 63 | }; 64 | 65 | enum _:CEData 66 | { 67 | CEData_Handler, 68 | CEData_TempIndex, 69 | CEData_WorldIndex, 70 | CEData_StartOrigin 71 | }; 72 | 73 | enum _:KVD { 74 | KVD_Key[64], 75 | KVD_Value[64] 76 | } 77 | 78 | /*--------------------------------[ Variables ]--------------------------------*/ 79 | 80 | new g_ptrBaseClassname; 81 | 82 | new Trie:g_entityHandlers = Invalid_Trie; 83 | new Array:g_entityName = Invalid_Array; 84 | new Array:g_entityPluginID = Invalid_Array; 85 | new Array:g_entityModelIndex = Invalid_Array; 86 | new Array:g_entityMins = Invalid_Array; 87 | new Array:g_entityMaxs = Invalid_Array; 88 | new Array:g_entityLifeTime = Invalid_Array; 89 | new Array:g_entityRespawnTime = Invalid_Array; 90 | new Array:g_entityPreset = Invalid_Array; 91 | new Array:g_entityIgnoreRounds = Invalid_Array; 92 | new Array:g_entityHooks = Invalid_Array; 93 | 94 | new g_entityCount = 0; 95 | 96 | new Array:g_worldEntities = Invalid_Array; 97 | new Array:g_tmpEntities = Invalid_Array; 98 | 99 | new g_lastCEIdx = 0; 100 | new g_lastCEEnt = 0; 101 | 102 | new Array:g_ceKvd = Invalid_Array; 103 | 104 | public plugin_init() 105 | { 106 | register_plugin(PLUGIN, VERSION, AUTHOR); 107 | 108 | SpawnLatestCe(); 109 | 110 | RegisterHam(Ham_Touch, CE_BASE_CLASSNAME, "OnTouch", .Post = 1); 111 | RegisterHam(Ham_Killed, CE_BASE_CLASSNAME, "OnKilled", .Post = 0); 112 | 113 | register_event("HLTV", "OnNewRound", "a", "1=0", "2=0"); 114 | 115 | register_concmd("ce_spawn", "OnClCmd_CESpawn", ADMIN_CVAR); 116 | } 117 | 118 | public plugin_end() 119 | { 120 | for (new i = 0; i < g_entityCount; ++i) { 121 | DestroyFunctions(i); 122 | } 123 | 124 | if (g_entityCount) { 125 | TrieDestroy(g_entityHandlers); 126 | ArrayDestroy(g_entityName); 127 | ArrayDestroy(g_entityPluginID); 128 | ArrayDestroy(g_entityModelIndex); 129 | ArrayDestroy(g_entityMins); 130 | ArrayDestroy(g_entityMaxs); 131 | ArrayDestroy(g_entityLifeTime); 132 | ArrayDestroy(g_entityRespawnTime); 133 | ArrayDestroy(g_entityIgnoreRounds); 134 | ArrayDestroy(g_entityPreset); 135 | ArrayDestroy(g_entityHooks); 136 | } 137 | 138 | if (g_tmpEntities) { 139 | ArrayDestroy(g_tmpEntities); 140 | } 141 | 142 | if (g_worldEntities) { 143 | ArrayDestroy(g_worldEntities); 144 | } 145 | 146 | if (g_ceKvd != Invalid_Array) { 147 | ArrayDestroy(g_ceKvd); 148 | } 149 | } 150 | 151 | public plugin_precache() 152 | { 153 | g_ptrBaseClassname = engfunc(EngFunc_AllocString, CE_BASE_CLASSNAME); 154 | 155 | register_forward(FM_KeyValue, "OnKeyValue", 1); 156 | RegisterHam(Ham_Spawn, CE_BASE_CLASSNAME, "OnSpawn", .Post = 1); 157 | } 158 | 159 | public plugin_natives() 160 | { 161 | register_library("api_custom_entities"); 162 | 163 | register_native("CE_Register", "Native_Register"); 164 | register_native("CE_Create", "Native_Create"); 165 | register_native("CE_Kill", "Native_Kill"); 166 | register_native("CE_Remove", "Native_Remove"); 167 | 168 | register_native("CE_GetSize", "Native_GetSize"); 169 | register_native("CE_GetModelIndex", "Native_GetModelIndex"); 170 | 171 | register_native("CE_RegisterHook", "Native_RegisterHook"); 172 | 173 | register_native("CE_CheckAssociation_", "Native_CheckAssociation"); 174 | 175 | register_native("CE_GetHandler", "Native_GetHandler"); 176 | register_native("CE_GetHandlerByEntity", "Native_GetHandlerByEntity"); 177 | } 178 | 179 | /*--------------------------------[ Natives ]--------------------------------*/ 180 | 181 | public Native_Register(pluginID, argc) 182 | { 183 | static szClassName[32]; 184 | get_string(RegisterArg_Name, szClassName, charsmax(szClassName)); 185 | 186 | new modelIndex = get_param(RegisterArg_ModelIndex); 187 | new Float:fLifeTime = get_param_f(RegisterArg_LifeTime); 188 | new Float:fRespawnTime = get_param_f(RegisterArg_RespawnTime); 189 | new bool:ignoreRounds = bool:get_param(RegisterArg_IgnoreRounds); 190 | new CEPreset:preset = CEPreset:get_param(RegisterArg_Preset); 191 | 192 | new Float:vMins[3]; 193 | get_array_f(RegisterArg_Mins, vMins, 3); 194 | 195 | new Float:vMaxs[3]; 196 | get_array_f(RegisterArg_Maxs, vMaxs, 3); 197 | 198 | return Register(szClassName, pluginID, modelIndex, vMins, vMaxs, fLifeTime, fRespawnTime, ignoreRounds, preset); 199 | } 200 | 201 | public Native_Create(pluginID, argc) 202 | { 203 | new szClassName[32]; 204 | get_string(1, szClassName, charsmax(szClassName)); 205 | 206 | new Float:vOrigin[3]; 207 | get_array_f(2, vOrigin, 3); 208 | 209 | new bool:temp = !!get_param(3); 210 | 211 | return Create(szClassName, vOrigin, temp); 212 | } 213 | 214 | public Native_Kill(pluginID, argc) 215 | { 216 | new ent = get_param(1); 217 | new killer = get_param(2); 218 | 219 | Kill(ent, killer); 220 | } 221 | 222 | public bool:Native_Remove(pluginID, argc) 223 | { 224 | new ent = get_param(1); 225 | return Remove(ent); 226 | } 227 | 228 | public Native_GetSize(pluginID, argc) 229 | { 230 | if (!g_entityCount) { 231 | return false; 232 | } 233 | 234 | new szClassName[32]; 235 | get_string(1, szClassName, charsmax(szClassName)); 236 | 237 | new ceIdx; 238 | if (!TrieGetCell(g_entityHandlers, szClassName, ceIdx)) { 239 | return false; 240 | } 241 | 242 | new Float:vMins[3]; 243 | ArrayGetArray(g_entityMins, ceIdx, vMins); 244 | 245 | new Float:vMaxs[3]; 246 | ArrayGetArray(g_entityMaxs, ceIdx, vMaxs); 247 | 248 | set_array_f(2, vMins, 3); 249 | set_array_f(3, vMaxs, 3); 250 | 251 | return true; 252 | } 253 | 254 | public Native_GetModelIndex(pluginID, argc) 255 | { 256 | if (!g_entityCount) { 257 | return false; 258 | } 259 | 260 | new szClassName[32]; 261 | get_string(1, szClassName, charsmax(szClassName)); 262 | 263 | new ceIdx; 264 | if (!TrieGetCell(g_entityHandlers, szClassName, ceIdx)) { 265 | return false; 266 | } 267 | 268 | return ArrayGetCell(g_entityModelIndex, ceIdx); 269 | } 270 | 271 | public Native_RegisterHook(pluginID, argc) 272 | { 273 | new CEFunction:function = CEFunction:get_param(1); 274 | 275 | new szClassname[32]; 276 | get_string(2, szClassname, charsmax(szClassname)); 277 | 278 | new szCallback[32]; 279 | get_string(3, szCallback, charsmax(szCallback)); 280 | 281 | RegisterHook(function, szClassname, szCallback, pluginID); 282 | } 283 | 284 | public Native_CheckAssociation(pluginID, argc) 285 | { 286 | new ent = get_param(1); 287 | new ceIdx = GetHandlerByEntity(ent); 288 | 289 | return (ceIdx > 0 && pluginID == ArrayGetCell(g_entityPluginID, ceIdx)); 290 | } 291 | 292 | public Native_GetHandler(pluginID, argc) 293 | { 294 | new szClassname[32]; 295 | get_string(1, szClassname, charsmax(szClassname)); 296 | 297 | return GetHandler(szClassname); 298 | } 299 | 300 | public Native_GetHandlerByEntity(pluginID, argc) 301 | { 302 | new ent = get_param(1); 303 | 304 | return GetHandlerByEntity(ent); 305 | } 306 | 307 | /*--------------------------------[ Hooks ]--------------------------------*/ 308 | 309 | public OnClCmd_CESpawn(id, level, cid) 310 | { 311 | if(!cmd_access(id, level, cid, 2)) { 312 | return PLUGIN_HANDLED; 313 | } 314 | 315 | static szClassname[128]; 316 | read_args(szClassname, charsmax(szClassname)); 317 | remove_quotes(szClassname); 318 | 319 | if(szClassname[0] == '^0') { 320 | return PLUGIN_HANDLED; 321 | } 322 | 323 | static Float:vOrigin[3]; 324 | pev(id, pev_origin, vOrigin); 325 | 326 | new ent = Create(szClassname, vOrigin); 327 | if (ent) { 328 | dllfunc(DLLFunc_Spawn, ent); 329 | } 330 | 331 | return PLUGIN_HANDLED; 332 | } 333 | 334 | public OnKeyValue(ent, kvd) 335 | { 336 | if (!g_entityCount) { 337 | return; 338 | } 339 | 340 | static szKey[32]; 341 | get_kvd(kvd, KV_KeyName, szKey, charsmax(szKey)); 342 | 343 | static szValue[32]; 344 | get_kvd(kvd, KV_Value, szValue, charsmax(szValue)); 345 | 346 | if (equal(szKey, "classname")) { 347 | SpawnLatestCe(); 348 | 349 | if (TrieGetCell(g_entityHandlers, szValue, g_lastCEIdx)) { 350 | g_lastCEEnt = Create (szValue, .temp = false); // clone entity 351 | } 352 | } 353 | 354 | if (g_lastCEEnt) { 355 | AddKvd(szKey, szValue); 356 | } 357 | } 358 | 359 | public OnSpawn(ent) 360 | { 361 | if (!Check(ent)) { 362 | return; 363 | } 364 | 365 | new Array:ceData = GetPData(ent); 366 | new ceIdx = ArrayGetCell(ceData, CEData_Handler); 367 | 368 | //Save start origin 369 | if (ArrayGetCell(ceData, CEData_StartOrigin) == Invalid_Array) { 370 | new Float:vOrigin[3]; 371 | pev(ent, pev_origin, vOrigin); 372 | 373 | new Array:startOrigin = ArrayCreate(3, 1); 374 | ArrayPushArray(startOrigin, vOrigin); 375 | 376 | ArraySetCell(ceData, CEData_StartOrigin, startOrigin); 377 | } 378 | 379 | new tmpIdx = ArrayGetCell(ceData, CEData_TempIndex); 380 | InitEntity(ent, ceIdx, (tmpIdx >= 0)); 381 | 382 | ExecuteFunction(CEFunction_Spawn, ceIdx, ent); 383 | } 384 | 385 | public OnTouch(ent, id) 386 | { 387 | // if (pev(ent, pev_flags) & ~FL_ONGROUND) { 388 | // return; 389 | // } 390 | 391 | if (!is_user_connected(id)) { 392 | return; 393 | } 394 | 395 | if (!is_user_alive(id)) { 396 | return; 397 | } 398 | 399 | if (!g_entityCount) { 400 | return; 401 | } 402 | 403 | static szClassname[32]; 404 | pev(ent, pev_classname, szClassname, charsmax(szClassname)); 405 | 406 | new ceIdx; 407 | if (!TrieGetCell(g_entityHandlers, szClassname, ceIdx)) { 408 | return; 409 | } 410 | 411 | new CEPreset:preset = ArrayGetCell(g_entityPreset, ceIdx); 412 | if (preset != CEPreset_Item) { 413 | return; 414 | } 415 | 416 | if (ExecuteFunction(CEFunction_Pickup, ceIdx, ent, id) > 0) { 417 | ExecuteFunction(CEFunction_Picked, ceIdx, ent, id); 418 | Kill(ent, id, .picked = true); 419 | } 420 | } 421 | 422 | public OnKilled(ent, killer) 423 | { 424 | if (!Check(ent)) { 425 | return HAM_IGNORED; 426 | } 427 | 428 | Kill(ent, killer); 429 | return HAM_SUPERCEDE; 430 | } 431 | 432 | public OnNewRound() 433 | { 434 | Cleanup(); 435 | set_task(0.1, "TaskRespawnEntities"); 436 | } 437 | 438 | /*--------------------------------[ Methods ]--------------------------------*/ 439 | 440 | Register( 441 | const szClassname[], 442 | pluginID, 443 | modelIndex, 444 | const Float:vMins[3], 445 | const Float:vMaxs[3], 446 | Float:fLifeTime, 447 | Float:fRespawnTime, 448 | bool:ignoreRounds, 449 | CEPreset:preset 450 | ) 451 | { 452 | if (!g_entityCount) { 453 | g_entityHandlers = TrieCreate(); 454 | g_entityName = ArrayCreate(32); 455 | g_entityPluginID = ArrayCreate(); 456 | g_entityModelIndex = ArrayCreate(); 457 | g_entityMaxs = ArrayCreate(3); 458 | g_entityMins = ArrayCreate(3); 459 | g_entityLifeTime = ArrayCreate(); 460 | g_entityRespawnTime = ArrayCreate(); 461 | g_entityIgnoreRounds = ArrayCreate(); 462 | g_entityPreset = ArrayCreate(); 463 | g_entityHooks = ArrayCreate(); 464 | } 465 | 466 | new index = g_entityCount; 467 | 468 | TrieSetCell(g_entityHandlers, szClassname, index); 469 | 470 | ArrayPushString(g_entityName, szClassname); 471 | ArrayPushCell(g_entityPluginID, pluginID); 472 | ArrayPushCell(g_entityModelIndex, modelIndex); 473 | ArrayPushArray(g_entityMins, vMins); 474 | ArrayPushArray(g_entityMaxs, vMaxs); 475 | ArrayPushCell(g_entityLifeTime, fLifeTime); 476 | ArrayPushCell(g_entityRespawnTime, fRespawnTime); 477 | ArrayPushCell(g_entityIgnoreRounds, ignoreRounds); 478 | ArrayPushCell(g_entityPreset, preset); 479 | ArrayPushCell(g_entityHooks, 0); 480 | 481 | g_entityCount++; 482 | 483 | log_amx("%s Entity %s successfully registred.", LOG_PREFIX, szClassname); 484 | 485 | return index; 486 | } 487 | 488 | Create(const szClassname[], const Float:vOrigin[3] = {0.0, 0.0, 0.0}, bool:temp = true) 489 | { 490 | new ceIdx; 491 | if (!g_entityCount || !TrieGetCell(g_entityHandlers, szClassname, ceIdx)) { 492 | log_error(0, "%s Entity %s is not registered as custom entity.", LOG_PREFIX, szClassname); 493 | return -1; 494 | } 495 | 496 | new ent = engfunc(EngFunc_CreateNamedEntity, g_ptrBaseClassname); 497 | set_pev(ent, pev_classname, szClassname, strlen(szClassname)); 498 | 499 | engfunc(EngFunc_SetOrigin, ent, vOrigin); 500 | 501 | new tmpIdx = -1; 502 | new worldIdx = -1; 503 | if (temp) { 504 | if (!g_tmpEntities) { 505 | g_tmpEntities = ArrayCreate(); 506 | } 507 | 508 | tmpIdx = ArraySize(g_tmpEntities); 509 | ArrayPushCell(g_tmpEntities, ent); 510 | } else { 511 | if (!g_worldEntities) { 512 | g_worldEntities = ArrayCreate(); 513 | } 514 | 515 | worldIdx = ArraySize(g_worldEntities); 516 | ArrayPushCell(g_worldEntities, ent); 517 | } 518 | 519 | new Array:ceData = CreatePData(ent); 520 | 521 | ArraySetCell(ceData, CEData_Handler, ceIdx); 522 | ArraySetCell(ceData, CEData_TempIndex, tmpIdx); 523 | ArraySetCell(ceData, CEData_WorldIndex, worldIdx); 524 | ArraySetCell(ceData, CEData_StartOrigin, Invalid_Array); 525 | 526 | set_pev(ent, pev_deadflag, DEAD_NO); 527 | 528 | return ent; 529 | } 530 | 531 | Respawn(ent) 532 | { 533 | remove_task(ent+TASKID_SUM_RESPAWN); 534 | 535 | new Array:ceData = GetPData(ent); 536 | 537 | new Array:startOrigin = ArrayGetCell(ceData, CEData_StartOrigin); 538 | if (startOrigin != Invalid_Array) { 539 | static Float:vOrigin[3]; 540 | ArrayGetArray(startOrigin, 0, vOrigin); 541 | engfunc(EngFunc_SetOrigin, ent, vOrigin); 542 | } 543 | 544 | set_pev(ent, pev_deadflag, DEAD_NO); 545 | set_pev(ent, pev_effects, pev(ent, pev_effects) & ~EF_NODRAW); 546 | 547 | set_pev(ent, pev_flags, pev(ent, pev_flags) & ~FL_ONGROUND); 548 | dllfunc(DLLFunc_Spawn, ent); 549 | } 550 | 551 | Kill(ent, killer = 0, bool:picked = false) 552 | { 553 | new Array:ceData = GetPData(ent); 554 | 555 | new ceIdx = ArrayGetCell(ceData, CEData_Handler); 556 | 557 | if (ExecuteFunction(CEFunction_Kill, ceIdx, ent, killer, picked) != PLUGIN_CONTINUE) { 558 | return; 559 | } 560 | 561 | set_pev(ent, pev_takedamage, DAMAGE_NO); 562 | set_pev(ent, pev_effects, pev(ent, pev_effects) | EF_NODRAW); 563 | set_pev(ent, pev_solid, SOLID_NOT); 564 | set_pev(ent, pev_movetype, MOVETYPE_NONE); 565 | set_pev(ent, pev_flags, pev(ent, pev_flags) & ~FL_ONGROUND); 566 | 567 | //Get temp index 568 | new tmpIdx = ArrayGetCell(ceData, CEData_TempIndex); 569 | 570 | //Check if entity is temp 571 | if (tmpIdx < 0) { 572 | new Float:fRespawnTime = ArrayGetCell(g_entityRespawnTime, ceIdx); 573 | if (fRespawnTime > 0.0) { 574 | set_pev(ent, pev_deadflag, DEAD_RESPAWNABLE); 575 | set_task(fRespawnTime, "TaskRespawn", ent+TASKID_SUM_RESPAWN); 576 | } else { 577 | set_pev(ent, pev_deadflag, DEAD_DEAD); 578 | } 579 | } else { 580 | set_pev(ent, pev_deadflag, DEAD_DISCARDBODY); 581 | } 582 | 583 | remove_task(ent+TASKID_SUM_DISAPPEAR); 584 | 585 | ExecuteFunction(CEFunction_Killed, ceIdx, ent, killer, picked); 586 | 587 | if (tmpIdx >= 0) { 588 | set_task(0.0, "TaskRemove", ent+TASKID_SUM_REMOVE); 589 | } 590 | } 591 | 592 | bool:Remove(ent) 593 | { 594 | if (!Check(ent)) { 595 | log_error(0, "%s Entity %i is not a custom entity.", LOG_PREFIX, ent); 596 | return false; 597 | } 598 | 599 | new Array:ceData = GetPData(ent); 600 | 601 | //Get temp index 602 | new tmpIdx = ArrayGetCell(ceData, CEData_TempIndex); 603 | 604 | //Check if entity is temp 605 | if (tmpIdx >= 0) { 606 | //Remove entity from storage of temp entities 607 | ArraySetCell(g_tmpEntities, tmpIdx, 0); 608 | } else { 609 | //Get world index 610 | new worldIdx = ArrayGetCell(ceData, CEData_WorldIndex); 611 | if (worldIdx >= 0) { 612 | ArraySetCell(g_worldEntities, worldIdx, 0); 613 | } 614 | } 615 | 616 | ClearTasks(ent); 617 | 618 | //Get handler 619 | new ceIdx = ArrayGetCell(ceData, CEData_Handler); 620 | 621 | //Execute remove function 622 | ExecuteFunction(CEFunction_Remove, ceIdx, ent); 623 | 624 | DestroyPData(ent); 625 | 626 | //Remove entity 627 | set_pev(ent, pev_flags, pev(ent, pev_flags) | FL_KILLME); 628 | dllfunc(DLLFunc_Think, ent); 629 | 630 | return true; 631 | } 632 | 633 | Check(ent) 634 | { 635 | return (pev(ent, pev_gaitsequence) == 'c'+'e'); 636 | } 637 | 638 | ClearTasks(ent) 639 | { 640 | remove_task(ent+TASKID_SUM_DISAPPEAR); 641 | remove_task(ent+TASKID_SUM_RESPAWN); 642 | remove_task(ent+TASKID_SUM_REMOVE); 643 | } 644 | 645 | GetHandlerByEntity(ent) 646 | { 647 | if (!Check(ent)) { 648 | return -1; 649 | } 650 | 651 | new Array:ceData = GetPData(ent); 652 | 653 | return ArrayGetCell(ceData, CEData_Handler); 654 | } 655 | 656 | GetHandler(const szClassname[]) 657 | { 658 | new ceIdx; 659 | if (!g_entityCount || !TrieGetCell(g_entityHandlers, szClassname, ceIdx)) { 660 | return -1; 661 | } 662 | 663 | return ceIdx; 664 | } 665 | 666 | Cleanup() 667 | { 668 | if (!g_tmpEntities) { 669 | return; 670 | } 671 | 672 | new size = ArraySize(g_tmpEntities); 673 | 674 | for (new i = size - 1; i >= 0; --i) 675 | { 676 | new ent = ArrayGetCell(g_tmpEntities, i); 677 | 678 | if (!ent || !pev_valid(ent)) { 679 | continue; 680 | } 681 | 682 | new ceIdx = GetHandlerByEntity(ent); 683 | if (ceIdx == -1) { 684 | log_error(0, "%s Entity %i is not a custom entity.", LOG_PREFIX, ent); 685 | continue; 686 | } 687 | 688 | new ignoreRounds = ArrayGetCell(g_entityIgnoreRounds, ceIdx); 689 | if (!ignoreRounds) { 690 | Remove(ent); 691 | ArrayDeleteItem(g_tmpEntities, i); 692 | } 693 | } 694 | 695 | // update temp entities refs 696 | new newSize = ArraySize(g_tmpEntities); 697 | for (new i = 0; i < newSize; ++i) { 698 | new ent = ArrayGetCell(g_tmpEntities, i); 699 | 700 | if (!ent || !pev_valid(ent)) { 701 | continue; 702 | } 703 | 704 | new Array:ceData = GetPData(ent); 705 | ArraySetCell(ceData, CEData_TempIndex, i); 706 | } 707 | } 708 | 709 | RespawnEntities() 710 | { 711 | if (!g_worldEntities) { 712 | return; 713 | } 714 | 715 | new size = ArraySize(g_worldEntities); 716 | for (new i = 0; i < size; ++i) { 717 | new ent = ArrayGetCell(g_worldEntities, i); 718 | if (ent) { 719 | Respawn(ent); 720 | 721 | new szModel[64]; 722 | pev(ent, pev_model, szModel, charsmax(szModel)); 723 | if (szModel[0] == '*') { 724 | engfunc(EngFunc_SetModel, ent, szModel); 725 | } 726 | } 727 | } 728 | } 729 | 730 | bool:InitEntity(ent, ceIdx, bool:temp) 731 | { 732 | static Float:vMins[3]; 733 | ArrayGetArray(g_entityMins, ceIdx, vMins); 734 | 735 | static Float:vMaxs[3]; 736 | ArrayGetArray(g_entityMaxs, ceIdx, vMaxs); 737 | 738 | static Float:vOrigin[3]; 739 | pev(ent, pev_origin, vOrigin); 740 | 741 | engfunc(EngFunc_SetSize, ent, vMins, vMaxs); 742 | engfunc(EngFunc_SetOrigin, ent, vOrigin); 743 | 744 | { 745 | new preset = ArrayGetCell(g_entityPreset, ceIdx); 746 | ApplyPreset(ent, preset); 747 | } 748 | 749 | new modelIndex = ArrayGetCell(g_entityModelIndex, ceIdx); 750 | if (modelIndex > 0) { 751 | set_pev(ent, pev_modelindex, modelIndex); 752 | } 753 | 754 | if (temp) { 755 | new Float:fLifeTime = ArrayGetCell(g_entityLifeTime, ceIdx); 756 | if (fLifeTime > 0.0) { 757 | set_task(fLifeTime, "TaskDisappear", ent+TASKID_SUM_DISAPPEAR); 758 | } 759 | } 760 | 761 | return true; 762 | } 763 | 764 | ApplyPreset(ent, preset) 765 | { 766 | switch (preset) 767 | { 768 | case CEPreset_Item: 769 | { 770 | set_pev(ent, pev_solid, SOLID_TRIGGER); 771 | set_pev(ent, pev_movetype, MOVETYPE_TOSS); 772 | set_pev(ent, pev_takedamage, DAMAGE_NO); 773 | } 774 | case CEPreset_NPC: 775 | { 776 | set_pev(ent, pev_solid, SOLID_BBOX); 777 | set_pev(ent, pev_movetype, MOVETYPE_PUSHSTEP); 778 | set_pev(ent, pev_takedamage, DAMAGE_AIM); 779 | 780 | set_pev(ent, pev_controller_0, 125); 781 | set_pev(ent, pev_controller_1, 125); 782 | set_pev(ent, pev_controller_2, 125); 783 | set_pev(ent, pev_controller_3, 125); 784 | 785 | set_pev(ent, pev_gamestate, 1); 786 | set_pev(ent, pev_gravity, 1.0); 787 | set_pev(ent, pev_flags, pev(ent, pev_flags) | FL_MONSTER); 788 | set_pev(ent, pev_fixangle, 1); 789 | set_pev(ent, pev_friction, 0.25); 790 | } 791 | case CEPreset_Prop: 792 | { 793 | set_pev(ent, pev_solid, SOLID_BBOX); 794 | set_pev(ent, pev_movetype, MOVETYPE_FLY); 795 | set_pev(ent, pev_takedamage, DAMAGE_NO); 796 | } 797 | } 798 | } 799 | 800 | AddKvd(const szKey[], const szValue[]) 801 | { 802 | if (g_ceKvd == Invalid_Array) { 803 | g_ceKvd = ArrayCreate(KVD); 804 | } 805 | 806 | new kvd[KVD]; 807 | copy(kvd[KVD_Key], charsmax(kvd[KVD_Key]), szKey); 808 | copy(kvd[KVD_Value], charsmax(kvd[KVD_Value]), szValue); 809 | ArrayPushArray(g_ceKvd, kvd); 810 | } 811 | 812 | SpawnLatestCe() 813 | { 814 | if (!g_lastCEEnt) { 815 | return; 816 | } 817 | 818 | if (g_ceKvd != Invalid_Array) { 819 | new size = ArraySize(g_ceKvd); 820 | for (new i = 0; i < size; ++i) { 821 | new kvd[KVD]; 822 | ArrayGetArray(g_ceKvd, i, kvd); 823 | DispatchKeyValue(g_lastCEEnt, kvd[KVD_Key], kvd[KVD_Value]); // dispatch kvd to cloned entity 824 | ExecuteFunction(CEFunction_KVD, g_lastCEIdx, g_lastCEEnt, kvd[KVD_Key], kvd[KVD_Value]); 825 | } 826 | } 827 | 828 | dllfunc(DLLFunc_Spawn, g_lastCEEnt); // spawn last handled entity 829 | 830 | if (g_ceKvd != Invalid_Array) { 831 | new size = ArraySize(g_ceKvd); 832 | for (new i = 0; i < size; ++i) { 833 | new kvd[KVD]; 834 | ArrayGetArray(g_ceKvd, i, kvd); 835 | 836 | if (equal(kvd[KVD_Key], "model") && kvd[KVD_Value][0] == '*') { 837 | engfunc(EngFunc_SetModel, g_lastCEEnt, kvd[KVD_Value]); 838 | } 839 | } 840 | } 841 | 842 | g_lastCEEnt = 0; 843 | 844 | if (g_ceKvd != Invalid_Array) { 845 | ArrayDestroy(g_ceKvd); 846 | g_ceKvd = Invalid_Array; 847 | } 848 | } 849 | 850 | RegisterHook(CEFunction:function, const szClassname[], const szCallback[], pluginID = -1) 851 | { 852 | new ceIdx; 853 | if (!g_entityCount || !TrieGetCell(g_entityHandlers, szClassname, ceIdx)) { 854 | log_error(0, "%s Entity %s is not registered.", LOG_PREFIX, szClassname); 855 | return -1; 856 | } 857 | 858 | new funcID = get_func_id(szCallback, pluginID); 859 | if (funcID < 0) { 860 | new szFilename[32]; 861 | get_plugin(pluginID, szFilename, charsmax(szFilename)); 862 | log_error(0, "Function %s not found in plugin %s.", szCallback, szFilename); 863 | return -1; 864 | } 865 | 866 | new Array:functions = ArrayGetCell(g_entityHooks, ceIdx); 867 | if (!functions) { 868 | functions = InitializeFunctions(ceIdx); 869 | } 870 | 871 | new Array:functionHooks = ArrayGetCell(functions, _:function); 872 | 873 | new Array:hookData = CreateHookData(pluginID, funcID); 874 | return ArrayPushCell(functionHooks, hookData); 875 | } 876 | 877 | Array:InitializeFunctions(ceIdx) 878 | { 879 | new Array:functions = ArrayCreate(1, _:CEFunction); 880 | 881 | for (new i = 0; i < _:CEFunction; ++i) { 882 | new Array:functionHooks = ArrayCreate(); 883 | ArrayPushCell(functions, functionHooks); 884 | } 885 | 886 | ArraySetCell(g_entityHooks, ceIdx, functions); 887 | 888 | return functions; 889 | } 890 | 891 | DestroyFunctions(ceIdx) 892 | { 893 | new Array:functions = ArrayGetCell(g_entityHooks, ceIdx); 894 | 895 | if (!functions) { 896 | return; 897 | } 898 | 899 | for (new i = 0; i < _:CEFunction; ++i) { 900 | new Array:functionHooks = ArrayGetCell(functions, i); 901 | ArrayDestroy(functionHooks); 902 | } 903 | 904 | ArrayDestroy(functions); 905 | ArraySetCell(g_entityHooks, ceIdx, 0); 906 | } 907 | 908 | Array:CreateHookData(pluginID, funcID) 909 | { 910 | new Array:hookData = ArrayCreate(1, _:CEHookData); 911 | ArrayPushCell(hookData, pluginID); 912 | ArrayPushCell(hookData, funcID); 913 | 914 | return hookData; 915 | } 916 | 917 | ExecuteFunction(CEFunction:function, ceIdx, any:...) 918 | { 919 | new result = 0; 920 | new ent = getarg(2); 921 | 922 | new Array:functions = ArrayGetCell(g_entityHooks, ceIdx); 923 | if (functions == Invalid_Array) { 924 | return 0; 925 | } 926 | 927 | new Array:functionHooks = ArrayGetCell(functions, _:function); 928 | 929 | new count = ArraySize(functionHooks); 930 | for (new i = 0; i < count; ++i) 931 | { 932 | new Array:hookData = ArrayGetCell(functionHooks, i); 933 | new pluginID = ArrayGetCell(hookData, _:CEHookData_PluginID); 934 | new funcID = ArrayGetCell(hookData, _:CEHookData_FuncID); 935 | 936 | if (funcID < 0) { 937 | continue; 938 | } 939 | 940 | if (callfunc_begin_i(funcID, pluginID) == 1) 941 | { 942 | callfunc_push_int(ent); 943 | 944 | switch (function) 945 | { 946 | case CEFunction_Kill, CEFunction_Killed: { 947 | new killer = getarg(3); 948 | new bool:picked = bool:getarg(4); 949 | callfunc_push_int(killer); 950 | callfunc_push_int(picked); 951 | } 952 | case CEFunction_Pickup, CEFunction_Picked: { 953 | new id = getarg(3); 954 | callfunc_push_int(id); 955 | } 956 | case CEFunction_KVD: { 957 | static szKey[32]; 958 | for (new i = 0; i < charsmax(szKey); ++i) { 959 | szKey[i] = getarg(3, i); 960 | 961 | if (szKey[i] == '^0') { 962 | break; 963 | } 964 | } 965 | 966 | static szValue[32]; 967 | for (new i = 0; i < charsmax(szValue); ++i) { 968 | szValue[i] = getarg(4, i); 969 | 970 | if (szValue[i] == '^0') { 971 | break; 972 | } 973 | } 974 | 975 | callfunc_push_str(szKey); 976 | callfunc_push_str(szValue); 977 | } 978 | } 979 | 980 | result += callfunc_end(); 981 | } 982 | } 983 | 984 | return result; 985 | } 986 | 987 | Array:CreatePData(ent) 988 | { 989 | new Array:ceData = ArrayCreate(1, CEData); 990 | for (new i = 0; i < CEData; ++i) { 991 | ArrayPushCell(ceData, 0); 992 | } 993 | 994 | set_pev(ent, pev_gaitsequence, 'c'+'e'); 995 | set_pev(ent, pev_iStepLeft, ceData); 996 | 997 | return ceData; 998 | } 999 | 1000 | DestroyPData(ent) 1001 | { 1002 | //Destroy data array 1003 | new Array:ceData = GetPData(ent); 1004 | { 1005 | new Array:startOrigin = ArrayGetCell(ceData, CEData_StartOrigin); 1006 | if (startOrigin != Invalid_Array) { 1007 | ArrayDestroy(startOrigin); 1008 | } 1009 | } ArrayDestroy(ceData); 1010 | 1011 | set_pev(ent, pev_gaitsequence, 0); 1012 | set_pev(ent, pev_iStepLeft, 0); 1013 | } 1014 | 1015 | Array:GetPData(ent) 1016 | { 1017 | new Array:ceData = any:pev(ent, pev_iStepLeft); 1018 | if (ceData == Invalid_Array) { 1019 | log_error(0, "%s Invalid Custom Entity data provided for %i.", LOG_PREFIX, ent); 1020 | } 1021 | 1022 | return ceData; 1023 | } 1024 | 1025 | /*--------------------------------[ Tasks ]--------------------------------*/ 1026 | 1027 | public TaskDisappear(taskID) 1028 | { 1029 | new ent = taskID - TASKID_SUM_DISAPPEAR; 1030 | Kill(ent, 0); 1031 | } 1032 | 1033 | public TaskRespawn(taskID) 1034 | { 1035 | new ent = taskID - TASKID_SUM_RESPAWN; 1036 | Respawn(ent); 1037 | } 1038 | 1039 | public TaskRemove(taskID) 1040 | { 1041 | new ent = taskID - TASKID_SUM_REMOVE; 1042 | Remove(ent); 1043 | } 1044 | 1045 | public TaskRespawnEntities() 1046 | { 1047 | RespawnEntities(); 1048 | } 1049 | -------------------------------------------------------------------------------- /api_particles.sma: -------------------------------------------------------------------------------- 1 | #pragma semicolon 1 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #include 10 | 11 | #include 12 | 13 | #define PLUGIN "[API] Particles" 14 | #define VERSION "1.0.0" 15 | #define AUTHOR "Hedgehog Fog" 16 | 17 | #define BIT(%0) (1<<(%0)) 18 | 19 | #define PARTICLE_CLASSNAME "_particle" 20 | 21 | #define UPDATE_RATE 0.01 22 | #define VISIBILITY_UPDATE_RATE 0.25 23 | 24 | enum Callback { 25 | Callback_PluginId, 26 | Callback_FunctionId 27 | }; 28 | 29 | enum PositionVars { 30 | Float:PositionVars_Origin[3], 31 | Float:PositionVars_Angles[3], 32 | Float:PositionVars_Velocity[3] 33 | }; 34 | 35 | enum ParticleEffect { 36 | ParticleEffect_Id[32], 37 | ParticleEffect_EmitAmount, 38 | Float:ParticleEffect_EmitRate, 39 | Float:ParticleEffect_ParticleLifeTime, 40 | ParticleEffect_VisibilityDistance, 41 | ParticleEffect_MaxParticles, 42 | ParticleEffectFlag:ParticleEffect_Flags, 43 | Array:ParticleEffect_Hooks[ParticleEffectHook] 44 | }; 45 | 46 | enum ParticleSystem { 47 | Struct:ParticleSystem_Effect, 48 | bool:ParticleSystem_Active, 49 | Float:ParticleSystem_EffectSpeed, 50 | ParticleSystem_ParentEntity, 51 | Float:ParticleSystem_CreatedTime, 52 | ParticleSystem_VisibilityBits, 53 | Float:ParticleSystem_KillTime, 54 | Array:ParticleSystem_Particles, 55 | Float:ParticleSystem_NextEmit, 56 | Float:ParticleSystem_NextVisibilityUpdate, 57 | Float:ParticleSystem_LastThink, 58 | Trie:ParticleSystem_Members, 59 | ParticleSystem_PositionVars[PositionVars] 60 | }; 61 | 62 | enum Particle { 63 | Particle_Index, 64 | Particle_BatchIndex, 65 | Particle_Entity, 66 | Float:Particle_CreatedTime, 67 | Float:Particle_KillTime, 68 | Float:Particle_LastThink, 69 | Struct:Particle_System, 70 | bool:Particle_Attached, 71 | Particle_PositionVars[PositionVars], 72 | Particle_AbsPositionVars[PositionVars] 73 | }; 74 | 75 | new g_pCvarEnabled; 76 | new bool:g_bEnabled; 77 | 78 | new g_iszParticleClassName; 79 | new g_pTrace; 80 | 81 | new Float:g_flNextSystemsUpdate; 82 | 83 | new Array:g_irgSystems; 84 | new Trie:g_tParticleEffects; 85 | 86 | public plugin_precache() { 87 | g_flNextSystemsUpdate = 0.0; 88 | g_irgSystems = ArrayCreate(); 89 | g_tParticleEffects = TrieCreate(); 90 | g_iszParticleClassName = engfunc(EngFunc_AllocString, "info_target"); 91 | g_pTrace = create_tr2(); 92 | } 93 | 94 | public plugin_init() { 95 | register_plugin(PLUGIN, VERSION, AUTHOR); 96 | 97 | register_forward(FM_AddToFullPack, "FMHook_AddToFullPack", 0); 98 | 99 | g_pCvarEnabled = register_cvar("particles", "1"); 100 | bind_pcvar_num(g_pCvarEnabled, g_bEnabled); 101 | hook_cvar_change(g_pCvarEnabled, "CvarHook_Enabled"); 102 | 103 | register_concmd("particle_create", "Command_Create", ADMIN_CVAR); 104 | } 105 | 106 | public plugin_natives() { 107 | register_library("api_particles"); 108 | 109 | register_native("ParticleEffect_Register", "Native_RegisterParticleEffect"); 110 | register_native("ParticleEffect_RegisterHook", "Native_RegisterParticleEffectHook"); 111 | 112 | register_native("ParticleSystem_Create", "Native_CreateParticleSystem"); 113 | register_native("ParticleSystem_Destroy", "Native_DestroyParticleSystem"); 114 | register_native("ParticleSystem_Activate", "Native_ActivateParticleSystem"); 115 | register_native("ParticleSystem_Deactivate", "Native_DeactivateParticleSystem"); 116 | register_native("ParticleSystem_GetEffectSpeed", "Native_GetParticleSystemEffectSpeed"); 117 | register_native("ParticleSystem_SetEffectSpeed", "Native_SetParticleSystemEffectSpeed"); 118 | register_native("ParticleSystem_GetCreatedTime", "Native_GetParticleSystemCreatedTime"); 119 | register_native("ParticleSystem_GetKillTime", "Native_GetParticleSystemKillTime"); 120 | register_native("ParticleSystem_GetLastThinkTime", "Native_GetParticleSystemLastThink"); 121 | register_native("ParticleSystem_GetVisibilityBits", "Native_GetParticleSystemVisibilityBits"); 122 | register_native("ParticleSystem_GetOrigin", "Native_GetParticleSystemOrigin"); 123 | register_native("ParticleSystem_SetOrigin", "Native_SetParticleSystemOrigin"); 124 | register_native("ParticleSystem_GetParentEntity", "Native_GetParticleSystemParentEntity"); 125 | register_native("ParticleSystem_SetParentEntity", "Native_SetParticleSystemParentEntity"); 126 | register_native("ParticleSystem_GetEffect", "Native_GetParticleSystemEffect"); 127 | register_native("ParticleSystem_SetEffect", "Native_SetParticleSystemEffect"); 128 | register_native("ParticleSystem_HasMember", "Native_HasMember"); 129 | register_native("ParticleSystem_DeleteMember", "Native_DeleteMember"); 130 | register_native("ParticleSystem_GetMember", "Native_GetMember"); 131 | register_native("ParticleSystem_SetMember", "Native_SetMember"); 132 | register_native("ParticleSystem_GetMemberVec", "Native_GetMemberVec"); 133 | register_native("ParticleSystem_SetMemberVec", "Native_SetMemberVec"); 134 | register_native("ParticleSystem_GetMemberString", "Native_GetMemberString"); 135 | register_native("ParticleSystem_SetMemberString", "Native_SetMemberString"); 136 | 137 | register_native("Particle_GetIndex", "Native_GetParticleIndex"); 138 | register_native("Particle_GetBatchIndex", "Native_GetParticleBatchIndex"); 139 | register_native("Particle_GetEntity", "Native_GetParticleEntity"); 140 | register_native("Particle_GetSystem", "Native_GetParticleSystem"); 141 | register_native("Particle_GetCreatedTime", "Native_GetParticleCreatedTime"); 142 | register_native("Particle_GetKillTime", "Native_GetParticleKillTime"); 143 | register_native("Particle_GetLastThink", "Native_GetParticleLastThink"); 144 | register_native("Particle_GetOrigin", "Native_GetParticleOrigin"); 145 | register_native("Particle_SetOrigin", "Native_SetParticleOrigin"); 146 | register_native("Particle_GetAngles", "Native_GetParticleAngles"); 147 | register_native("Particle_SetAngles", "Native_SetParticleAngles"); 148 | register_native("Particle_GetVelocity", "Native_GetParticleVelocity"); 149 | register_native("Particle_SetVelocity", "Native_SetParticleVelocity"); 150 | } 151 | 152 | public plugin_end() { 153 | static irgSystemsNum; irgSystemsNum = ArraySize(g_irgSystems); 154 | for (new iSystem = 0; iSystem < irgSystemsNum; ++iSystem) { 155 | static Struct:sSystem; sSystem = ArrayGetCell(g_irgSystems, iSystem); 156 | if (sSystem == Invalid_Struct) continue; 157 | 158 | @ParticleSystem_Destroy(sSystem); 159 | } 160 | 161 | ArrayDestroy(g_irgSystems); 162 | TrieDestroy(g_tParticleEffects); 163 | free_tr2(g_pTrace); 164 | } 165 | 166 | /*--------------------------------[ Natives ]--------------------------------*/ 167 | 168 | public Native_RegisterParticleEffect(iPluginId, iArgc) { 169 | new szName[32]; get_string(1, szName, charsmax(szName)); 170 | new Float:flEmitRate = get_param_f(2); 171 | new Float:flParticleLifeTime = get_param_f(3); 172 | new iMaxParticles = get_param(4); 173 | new iEmitAmount = get_param(5); 174 | new Float:flVisibilityDistance = get_param_f(6); 175 | new ParticleEffectFlag:iFlags = ParticleEffectFlag:get_param(7); 176 | 177 | if (TrieKeyExists(g_tParticleEffects, szName)) { 178 | log_error(AMX_ERR_NATIVE, "Particle effect ^"%s^" is already registered.", szName); 179 | return; 180 | } 181 | 182 | new Struct:sEffect = @ParticleEffect_Create(szName, flEmitRate, flParticleLifeTime, flVisibilityDistance, iMaxParticles, iEmitAmount, iFlags); 183 | 184 | TrieSetCell(g_tParticleEffects, szName, sEffect); 185 | } 186 | public Native_RegisterParticleEffectHook(iPluginId, iArgc) { 187 | new szName[32]; get_string(1, szName, charsmax(szName)); 188 | new ParticleEffectHook:iHookId = ParticleEffectHook:get_param(2); 189 | new szCallback[64]; get_string(3, szCallback, charsmax(szCallback)); 190 | 191 | static Struct:sEffect; 192 | if (!TrieGetCell(g_tParticleEffects, szName, sEffect)) { 193 | log_error(AMX_ERR_NATIVE, "[Particles] Effect ^"%s^" is not registered!", szName); 194 | return; 195 | } 196 | 197 | new Array:irgHooks = StructGetCell(sEffect, ParticleEffect_Hooks, iHookId); 198 | 199 | new rgCallback[Callback]; 200 | rgCallback[Callback_PluginId] = iPluginId; 201 | rgCallback[Callback_FunctionId] = get_func_id(szCallback, iPluginId); 202 | 203 | if (rgCallback[Callback_FunctionId] == -1) { 204 | log_error(AMX_ERR_NATIVE, "[Particles] Function ^"%s^" is not found!", szCallback); 205 | return; 206 | } 207 | 208 | ArrayPushArray(irgHooks, rgCallback[any:0], sizeof(rgCallback)); 209 | } 210 | 211 | public Struct:Native_CreateParticleSystem(iPluginId, iArgc) { 212 | new szName[32]; get_string(1, szName, charsmax(szName)); 213 | new Float:vecOrigin[3]; get_array_f(2, vecOrigin, sizeof(vecOrigin)); 214 | new Float:vecAngles[3]; get_array_f(3, vecAngles, sizeof(vecAngles)); 215 | new pParent; pParent = get_param(4); 216 | 217 | new Struct:sEffect; 218 | if (!TrieGetCell(g_tParticleEffects, szName, sEffect)) { 219 | log_error(AMX_ERR_NATIVE, "[Particles] Effect ^"%s^" is not registered!", szName); 220 | return Invalid_Struct; 221 | } 222 | 223 | new Struct:sSystem; sSystem = @ParticleSystem_Create(sEffect, vecOrigin, vecAngles, pParent); 224 | 225 | return sSystem; 226 | } 227 | 228 | public Native_DestroyParticleSystem(iPluginId, iArgc) { 229 | static Struct:sSystem; sSystem = Struct:get_param_byref(1); 230 | 231 | StructSetCell(sSystem, ParticleSystem_KillTime, get_gametime()); 232 | 233 | set_param_byref(1, _:Invalid_Struct); 234 | } 235 | 236 | public Float:Native_ActivateParticleSystem(iPluginId, iArgc) { 237 | static Struct:sSystem; sSystem = Struct:get_param_byref(1); 238 | 239 | StructSetCell(sSystem, ParticleSystem_Active, true); 240 | } 241 | 242 | public Float:Native_DeactivateParticleSystem(iPluginId, iArgc) { 243 | static Struct:sSystem; sSystem = Struct:get_param_byref(1); 244 | 245 | StructSetCell(sSystem, ParticleSystem_Active, false); 246 | } 247 | 248 | public Float:Native_GetParticleSystemEffectSpeed(iPluginId, iArgc) { 249 | static Struct:sSystem; sSystem = Struct:get_param_byref(1); 250 | 251 | return StructGetCell(sSystem, ParticleSystem_EffectSpeed); 252 | } 253 | 254 | public Native_SetParticleSystemEffectSpeed(iPluginId, iArgc) { 255 | static Struct:sSystem; sSystem = Struct:get_param_byref(1); 256 | static Float:flSpeed; flSpeed = get_param_f(2); 257 | 258 | StructSetCell(sSystem, ParticleSystem_EffectSpeed, flSpeed); 259 | } 260 | 261 | public Float:Native_GetParticleSystemCreatedTime(iPluginId, iArgc) { 262 | static Struct:sSystem; sSystem = Struct:get_param_byref(1); 263 | 264 | return Float:StructGetCell(sSystem, ParticleSystem_CreatedTime); 265 | } 266 | 267 | public Float:Native_GetParticleSystemKillTime(iPluginId, iArgc) { 268 | static Struct:sSystem; sSystem = Struct:get_param_byref(1); 269 | 270 | return Float:StructGetCell(sSystem, ParticleSystem_KillTime); 271 | } 272 | 273 | public Native_GetParticleSystemLastThink(iPluginId, iArgc) { 274 | static Struct:sSystem; sSystem = Struct:get_param_byref(1); 275 | 276 | return StructGetCell(sSystem, ParticleSystem_LastThink); 277 | } 278 | 279 | public Native_GetParticleSystemVisibilityBits(iPluginId, iArgc) { 280 | static Struct:sSystem; sSystem = Struct:get_param_byref(1); 281 | 282 | return StructGetCell(sSystem, ParticleSystem_VisibilityBits); 283 | } 284 | 285 | public Native_GetParticleSystemOrigin(iPluginId, iArgc) { 286 | static Struct:sSystem; sSystem = Struct:get_param_byref(1); 287 | 288 | static Float:vecOrigin[3]; StructGetArray(sSystem, ParticleSystem_PositionVars, vecOrigin, 3, PositionVars_Origin); 289 | 290 | set_array_f(2, vecOrigin, sizeof(vecOrigin)); 291 | } 292 | 293 | public Native_SetParticleSystemOrigin(iPluginId, iArgc) { 294 | static Struct:sSystem; sSystem = Struct:get_param_byref(1); 295 | static Float:vecOrigin[3]; get_array_f(2, vecOrigin, sizeof(vecOrigin)); 296 | 297 | StructSetArray(sSystem, ParticleSystem_PositionVars, vecOrigin, 3, PositionVars_Origin); 298 | } 299 | 300 | public Native_GetParticleSystemParentEntity(iPluginId, iArgc) { 301 | static Struct:sSystem; sSystem = Struct:get_param_byref(1); 302 | 303 | return StructGetCell(sSystem, ParticleSystem_ParentEntity); 304 | } 305 | 306 | public Native_SetParticleSystemParentEntity(iPluginId, iArgc) { 307 | static Struct:sSystem; sSystem = Struct:get_param_byref(1); 308 | static pParent; pParent = get_param(2); 309 | 310 | StructSetCell(sSystem, ParticleSystem_ParentEntity, pParent); 311 | } 312 | 313 | public Native_GetParticleSystemEffect(iPluginId, iArgc) { 314 | static Struct:sSystem; sSystem = Struct:get_param_byref(1); 315 | 316 | static Struct:sEffect; sEffect = StructGetCell(sSystem, ParticleSystem_Effect); 317 | static szName[32]; StructGetString(sEffect, ParticleEffect_Id, szName, charsmax(szName)); 318 | 319 | set_string(2, szName, get_param(3)); 320 | } 321 | 322 | public Native_SetParticleSystemEffect(iPluginId, iArgc) { 323 | static Struct:sSystem; sSystem = Struct:get_param_byref(1); 324 | static szName[32]; get_string(2, szName, charsmax(szName)); 325 | 326 | static Struct:sEffect; 327 | if (!TrieGetCell(g_tParticleEffects, szName, sEffect)) { 328 | log_error(AMX_ERR_NATIVE, "[Particles] Effect ^"%s^" is not registered!", szName); 329 | return; 330 | } 331 | 332 | StructSetCell(sSystem, ParticleSystem_Effect, sEffect); 333 | } 334 | 335 | public bool:Native_HasMember(iPluginId, iArgc) { 336 | static Struct:sSystem; sSystem = Struct:get_param_byref(1); 337 | static szMember[PARTICLE_MAX_MEMBER_LENGTH]; get_string(2, szMember, charsmax(szMember)); 338 | 339 | static Trie:itMembers; itMembers = StructGetCell(sSystem, ParticleSystem_Members); 340 | 341 | return TrieKeyExists(itMembers, szMember); 342 | } 343 | 344 | public Native_DeleteMember(iPluginId, iArgc) { 345 | static Struct:sSystem; sSystem = Struct:get_param_byref(1); 346 | static szMember[PARTICLE_MAX_MEMBER_LENGTH]; get_string(2, szMember, charsmax(szMember)); 347 | 348 | static Trie:itMembers; itMembers = StructGetCell(sSystem, ParticleSystem_Members); 349 | 350 | TrieDeleteKey(itMembers, szMember); 351 | } 352 | 353 | public any:Native_GetMember(iPluginId, iArgc) { 354 | static Struct:sSystem; sSystem = Struct:get_param_byref(1); 355 | static szMember[PARTICLE_MAX_MEMBER_LENGTH]; get_string(2, szMember, charsmax(szMember)); 356 | 357 | static Trie:itMembers; itMembers = StructGetCell(sSystem, ParticleSystem_Members); 358 | 359 | static iValue; 360 | if (!TrieGetCell(itMembers, szMember, iValue)) return 0; 361 | 362 | return iValue; 363 | } 364 | 365 | public Native_SetMember(iPluginId, iArgc) { 366 | static Struct:sSystem; sSystem = Struct:get_param_byref(1); 367 | static szMember[PARTICLE_MAX_MEMBER_LENGTH]; get_string(2, szMember, charsmax(szMember)); 368 | static iValue; iValue = get_param(3); 369 | 370 | static Trie:itMembers; itMembers = StructGetCell(sSystem, ParticleSystem_Members); 371 | 372 | TrieSetCell(itMembers, szMember, iValue); 373 | } 374 | 375 | public bool:Native_GetMemberVec(iPluginId, iArgc) { 376 | static Struct:sSystem; sSystem = Struct:get_param_byref(1); 377 | static szMember[PARTICLE_MAX_MEMBER_LENGTH]; get_string(2, szMember, charsmax(szMember)); 378 | 379 | static Trie:itMembers; itMembers = StructGetCell(sSystem, ParticleSystem_Members); 380 | 381 | static Float:vecValue[3]; 382 | if (!TrieGetArray(itMembers, szMember, vecValue, 3)) return false; 383 | 384 | set_array_f(3, vecValue, sizeof(vecValue)); 385 | 386 | return true; 387 | } 388 | 389 | public Native_SetMemberVec(iPluginId, iArgc) { 390 | static Struct:sSystem; sSystem = Struct:get_param_byref(1); 391 | static szMember[PARTICLE_MAX_MEMBER_LENGTH]; get_string(2, szMember, charsmax(szMember)); 392 | static Float:vecValue[3]; get_array_f(3, vecValue, sizeof(vecValue)); 393 | 394 | static Trie:itMembers; itMembers = StructGetCell(sSystem, ParticleSystem_Members); 395 | TrieSetArray(itMembers, szMember, vecValue, 3); 396 | } 397 | 398 | public bool:Native_GetMemberString(iPluginId, iArgc) { 399 | static Struct:sSystem; sSystem = Struct:get_param_byref(1); 400 | static szMember[PARTICLE_MAX_MEMBER_LENGTH]; get_string(2, szMember, charsmax(szMember)); 401 | 402 | static Trie:itMembers; itMembers = StructGetCell(sSystem, ParticleSystem_Members); 403 | 404 | static szValue[128]; 405 | if (!TrieGetString(itMembers, szMember, szValue, charsmax(szValue))) return false; 406 | 407 | set_string(3, szValue, get_param(4)); 408 | 409 | return true; 410 | } 411 | 412 | public Native_SetMemberString(iPluginId, iArgc) { 413 | static Struct:sSystem; sSystem = Struct:get_param_byref(1); 414 | static szMember[PARTICLE_MAX_MEMBER_LENGTH]; get_string(2, szMember, charsmax(szMember)); 415 | static szValue[128]; get_string(3, szValue, charsmax(szValue)); 416 | 417 | static Trie:itMembers; itMembers = StructGetCell(sSystem, ParticleSystem_Members); 418 | TrieSetString(itMembers, szMember, szValue); 419 | } 420 | 421 | public Native_GetParticleOrigin(iPluginId, iArgc) { 422 | static Struct:sParticle; sParticle = Struct:get_param_byref(1); 423 | 424 | static Float:vecOrigin[3]; StructGetArray(sParticle, Particle_PositionVars, vecOrigin, 3, PositionVars_Origin); 425 | 426 | set_array_f(2, vecOrigin, sizeof(vecOrigin)); 427 | } 428 | 429 | public Native_SetParticleOrigin(iPluginId, iArgc) { 430 | static Struct:sParticle; sParticle = Struct:get_param_byref(1); 431 | static Float:vecOrigin[3]; get_array_f(2, vecOrigin, sizeof(vecOrigin)); 432 | 433 | StructSetArray(sParticle, Particle_PositionVars, vecOrigin, 3, PositionVars_Origin); 434 | } 435 | 436 | public Native_GetParticleAngles(iPluginId, iArgc) { 437 | static Struct:sParticle; sParticle = Struct:get_param_byref(1); 438 | 439 | static Float:vecAngles[3]; StructGetArray(sParticle, Particle_PositionVars, vecAngles, 3, PositionVars_Angles); 440 | 441 | set_array_f(2, vecAngles, sizeof(vecAngles)); 442 | } 443 | 444 | public Native_SetParticleAngles(iPluginId, iArgc) { 445 | static Struct:sParticle; sParticle = Struct:get_param_byref(1); 446 | static Float:vecAngles[3]; get_array_f(2, vecAngles, sizeof(vecAngles)); 447 | 448 | StructSetArray(sParticle, Particle_PositionVars, vecAngles, 3, PositionVars_Angles); 449 | } 450 | 451 | public Native_GetParticleVelocity(iPluginId, iArgc) { 452 | static Struct:sParticle; sParticle = Struct:get_param_byref(1); 453 | 454 | static Float:vecVelocity[3]; StructGetArray(sParticle, Particle_PositionVars, vecVelocity, 3, PositionVars_Velocity); 455 | 456 | set_array_f(2, vecVelocity, sizeof(vecVelocity)); 457 | } 458 | 459 | public Native_SetParticleVelocity(iPluginId, iArgc) { 460 | static Struct:sParticle; sParticle = Struct:get_param_byref(1); 461 | 462 | static Float:vecVelocity[3]; get_array_f(2, vecVelocity, sizeof(vecVelocity)); 463 | 464 | StructSetArray(sParticle, Particle_PositionVars, vecVelocity, 3, PositionVars_Velocity); 465 | } 466 | 467 | public Struct:Native_GetParticleIndex(iPluginId, iArgc) { 468 | static Struct:sParticle; sParticle = Struct:get_param_byref(1); 469 | 470 | return StructGetCell(sParticle, Particle_Index); 471 | } 472 | 473 | public Struct:Native_GetParticleBatchIndex(iPluginId, iArgc) { 474 | static Struct:sParticle; sParticle = Struct:get_param_byref(1); 475 | 476 | return StructGetCell(sParticle, Particle_BatchIndex); 477 | } 478 | 479 | public Struct:Native_GetParticleEntity(iPluginId, iArgc) { 480 | static Struct:sParticle; sParticle = Struct:get_param_byref(1); 481 | 482 | return StructGetCell(sParticle, Particle_Entity); 483 | } 484 | 485 | public Struct:Native_GetParticleSystem(iPluginId, iArgc) { 486 | static Struct:sParticle; sParticle = Struct:get_param_byref(1); 487 | 488 | return StructGetCell(sParticle, Particle_System); 489 | } 490 | 491 | public Float:Native_GetParticleCreatedTime(iPluginId, iArgc) { 492 | static Struct:sParticle; sParticle = Struct:get_param_byref(1); 493 | 494 | return Float:StructGetCell(sParticle, Particle_CreatedTime); 495 | } 496 | 497 | public Float:Native_GetParticleKillTime(iPluginId, iArgc) { 498 | static Struct:sParticle; sParticle = Struct:get_param_byref(1); 499 | 500 | return Float:StructGetCell(sParticle, Particle_KillTime); 501 | } 502 | 503 | public Float:Native_GetParticleLastThink(iPluginId, iArgc) { 504 | static Struct:sParticle; sParticle = Struct:get_param_byref(1); 505 | 506 | return Float:StructGetCell(sParticle, Particle_LastThink); 507 | } 508 | 509 | /*--------------------------------[ Forwards ]--------------------------------*/ 510 | 511 | public server_frame() { 512 | if (g_bEnabled) { 513 | static Float:flGameTime; flGameTime = get_gametime(); 514 | 515 | if (g_flNextSystemsUpdate <= flGameTime) { 516 | UpdateSystems(); 517 | g_flNextSystemsUpdate = flGameTime + UPDATE_RATE; 518 | } 519 | } 520 | } 521 | 522 | /*--------------------------------[ Hooks ]--------------------------------*/ 523 | 524 | public Command_Create(pPlayer, iLevel, iCId) { 525 | if (!cmd_access(pPlayer, iLevel, iCId, 2)) { 526 | return PLUGIN_HANDLED; 527 | } 528 | 529 | static szName[32]; read_argv(1, szName, charsmax(szName)); 530 | 531 | if (equal(szName, NULL_STRING)) return PLUGIN_HANDLED; 532 | 533 | static Float:vecOrigin[3]; pev(pPlayer, pev_origin, vecOrigin); 534 | static Float:vecAngles[3]; pev(pPlayer, pev_angles, vecAngles); 535 | 536 | static Struct:sEffect; 537 | if (!TrieGetCell(g_tParticleEffects, szName, sEffect)) return PLUGIN_HANDLED; 538 | 539 | static Struct:sSystem; sSystem = @ParticleSystem_Create(sEffect, vecOrigin, vecAngles, 0); 540 | StructSetCell(sSystem, ParticleSystem_Active, true); 541 | 542 | return PLUGIN_HANDLED; 543 | } 544 | 545 | public FMHook_AddToFullPack(es, e, pEntity, pHost, hostflags, player, pSet) { 546 | if (!pev_valid(pEntity)) return FMRES_IGNORED; 547 | 548 | static szClassName[32]; pev(pEntity, pev_classname, szClassName, charsmax(szClassName)); 549 | 550 | if (equal(szClassName, PARTICLE_CLASSNAME)) { 551 | static Struct:sParticle; sParticle = Struct:pev(pEntity, pev_iuser1); 552 | static Struct:sSystem; sSystem = StructGetCell(sParticle, Particle_System); 553 | static iVisibilityBits; iVisibilityBits = StructGetCell(sSystem, ParticleSystem_VisibilityBits); 554 | 555 | if (~iVisibilityBits & BIT(pHost & 31)) return FMRES_SUPERCEDE; 556 | 557 | return FMRES_IGNORED; 558 | } 559 | 560 | return FMRES_IGNORED; 561 | } 562 | 563 | public CvarHook_Enabled() { 564 | if (!get_pcvar_num(g_pCvarEnabled)) { 565 | FreeParticles(); 566 | } 567 | } 568 | 569 | /*--------------------------------[ ParticleEffect Methods ]--------------------------------*/ 570 | 571 | Struct:@ParticleEffect_Create(const szName[], Float:flEmitRate, Float:flParticleLifeTime, Float:flVisibilityDistance, iMaxParticles, iEmitAmount, ParticleEffectFlag:iFlags) { 572 | static Struct:this; this = StructCreate(ParticleEffect); 573 | 574 | StructSetString(this, ParticleEffect_Id, szName); 575 | StructSetCell(this, ParticleEffect_EmitRate, flEmitRate); 576 | StructSetCell(this, ParticleEffect_EmitAmount, iEmitAmount); 577 | StructSetCell(this, ParticleEffect_VisibilityDistance, flVisibilityDistance); 578 | StructSetCell(this, ParticleEffect_ParticleLifeTime, flParticleLifeTime); 579 | StructSetCell(this, ParticleEffect_MaxParticles, iMaxParticles); 580 | StructSetCell(this, ParticleEffect_Flags, iFlags); 581 | 582 | for (new ParticleEffectHook:iHookId = ParticleEffectHook:0; iHookId < ParticleEffectHook; ++iHookId) { 583 | StructSetCell(this, ParticleEffect_Hooks, ArrayCreate(_:Callback, 1), iHookId); 584 | } 585 | 586 | return this; 587 | } 588 | 589 | @ParticleEffect_Destroy(&Struct:this) { 590 | for (new ParticleEffectHook:iHookId = ParticleEffectHook:0; iHookId < ParticleEffectHook; ++iHookId) { 591 | new Array:irgHooks = StructGetCell(this, ParticleEffect_Hooks, iHookId); 592 | ArrayDestroy(irgHooks); 593 | } 594 | 595 | StructDestroy(this); 596 | } 597 | 598 | static @ParticleEffect_ExecuteHook(const &Struct:this, ParticleEffectHook:iHook, const &Struct:sInstance, any:...) { 599 | new iResult = 0; 600 | 601 | new Array:irgHooks = StructGetCell(this, ParticleEffect_Hooks, iHook); 602 | 603 | new iHooksNum = ArraySize(irgHooks); 604 | for (new iHookId = 0; iHookId < iHooksNum; ++iHookId) { 605 | new iPluginId = ArrayGetCell(irgHooks, iHookId, _:Callback_PluginId); 606 | new iFunctionId = ArrayGetCell(irgHooks, iHookId, _:Callback_FunctionId); 607 | 608 | if (callfunc_begin_i(iFunctionId, iPluginId) == 1) { 609 | callfunc_push_int(_:sInstance); 610 | 611 | switch (iHook) { 612 | case ParticleEffectHook_Particle_EntityInit: { 613 | callfunc_push_int(getarg(3)); 614 | } 615 | } 616 | 617 | iResult = max(iResult, callfunc_end()); 618 | } 619 | } 620 | 621 | 622 | return iResult; 623 | } 624 | 625 | /*--------------------------------[ ParticleSystem Methods ]--------------------------------*/ 626 | 627 | Struct:@ParticleSystem_Create(const &Struct:sEffect, const Float:vecOrigin[3], const Float:vecAngles[3], pParent) { 628 | static Struct:this; this = StructCreate(ParticleSystem); 629 | 630 | static iMaxParticles; iMaxParticles = StructGetCell(sEffect, ParticleEffect_MaxParticles); 631 | 632 | static Array:irgParticles; irgParticles = ArrayCreate(iMaxParticles); 633 | for (new i = 0; i < iMaxParticles; ++i) ArrayPushCell(irgParticles, Invalid_Struct); 634 | 635 | StructSetCell(this, ParticleSystem_Effect, sEffect); 636 | StructSetArray(this, ParticleSystem_PositionVars, vecOrigin, 3, PositionVars_Origin); 637 | StructSetArray(this, ParticleSystem_PositionVars, vecAngles, 3, PositionVars_Angles); 638 | StructSetArray(this, ParticleSystem_PositionVars, Float:{0.0, 0.0, 0.0}, 3, PositionVars_Velocity); 639 | StructSetCell(this, ParticleSystem_ParentEntity, pParent); 640 | StructSetCell(this, ParticleSystem_Particles, irgParticles); 641 | StructSetCell(this, ParticleSystem_CreatedTime, get_gametime()); 642 | StructSetCell(this, ParticleSystem_KillTime, 0.0); 643 | StructSetCell(this, ParticleSystem_EffectSpeed, 1.0); 644 | StructSetCell(this, ParticleSystem_Active, false); 645 | StructSetCell(this, ParticleSystem_NextEmit, 0.0); 646 | StructSetCell(this, ParticleSystem_NextVisibilityUpdate, 0.0); 647 | StructSetCell(this, ParticleSystem_Members, TrieCreate()); 648 | 649 | ArrayPushCell(g_irgSystems, this); 650 | 651 | @ParticleEffect_ExecuteHook(sEffect, ParticleEffectHook_System_Init, this); 652 | 653 | return this; 654 | } 655 | 656 | @ParticleSystem_Destroy(&Struct:this) { 657 | static Array:irgParticles; irgParticles = StructGetCell(this, ParticleSystem_Particles); 658 | static iParticlesNum; iParticlesNum = ArraySize(irgParticles); 659 | static Struct:sEffect; sEffect = StructGetCell(this, ParticleSystem_Effect); 660 | static Trie:itMembers; itMembers = StructGetCell(this, ParticleSystem_Members); 661 | 662 | @ParticleEffect_ExecuteHook(sEffect, ParticleEffectHook_System_Destroy, this); 663 | 664 | for (new iParticle = 0; iParticle < iParticlesNum; ++iParticle) { 665 | static Struct:sParticle; sParticle = ArrayGetCell(irgParticles, iParticle); 666 | if (sParticle == Invalid_Struct) continue; 667 | 668 | @Particle_Destroy(sParticle); 669 | } 670 | 671 | ArrayDestroy(irgParticles); 672 | TrieDestroy(itMembers); 673 | StructDestroy(this); 674 | } 675 | 676 | @ParticleSystem_FreeParticles(const &Struct:this) { 677 | static Array:irgParticles; irgParticles = StructGetCell(this, ParticleSystem_Particles); 678 | static iParticlesNum; iParticlesNum = ArraySize(irgParticles); 679 | 680 | for (new iParticle = 0; iParticle < iParticlesNum; ++iParticle) { 681 | static Struct:sParticle; sParticle = ArrayGetCell(irgParticles, iParticle); 682 | if (sParticle == Invalid_Struct) continue; 683 | @Particle_Destroy(sParticle); 684 | ArraySetCell(irgParticles, iParticle, Invalid_Struct); 685 | } 686 | } 687 | 688 | @ParticleSystem_Update(const &Struct:this) { 689 | static Float:flGameTime; flGameTime = get_gametime(); 690 | 691 | static Struct:sEffect; sEffect = StructGetCell(this, ParticleSystem_Effect); 692 | static Array:irgParticles; irgParticles = StructGetCell(this, ParticleSystem_Particles); 693 | static iVisibilityBits; iVisibilityBits = StructGetCell(this, ParticleSystem_VisibilityBits); 694 | static bool:bActive; bActive = StructGetCell(this, ParticleSystem_Active); 695 | static iParticlesNum; iParticlesNum = ArraySize(irgParticles); 696 | static Float:flLastThink; flLastThink = StructGetCell(this, ParticleSystem_LastThink); 697 | static Float:flSpeed; flSpeed = StructGetCell(this, ParticleSystem_EffectSpeed); 698 | 699 | static Float:flDelta; flDelta = flGameTime - flLastThink; 700 | 701 | static Float:vecOrigin[3]; StructGetArray(this, ParticleSystem_PositionVars, vecOrigin, 3, PositionVars_Origin); 702 | static Float:vecVelocity[3]; StructGetArray(this, ParticleSystem_PositionVars, vecVelocity, 3, PositionVars_Velocity); 703 | static Float:vecAngles[3]; StructGetArray(this, ParticleSystem_PositionVars, vecAngles, 3, PositionVars_Angles); 704 | 705 | xs_vec_add_scaled(vecOrigin, vecVelocity, flDelta * flSpeed, vecOrigin); 706 | StructSetArray(this, ParticleSystem_PositionVars, vecOrigin, 3, PositionVars_Origin); 707 | 708 | @ParticleEffect_ExecuteHook(sEffect, ParticleEffectHook_System_Think, this); 709 | 710 | // Emit particles 711 | if (bActive) { 712 | static Float:flNextEmit; flNextEmit = StructGetCell(this, ParticleSystem_NextEmit); 713 | if (iVisibilityBits && flNextEmit <= flGameTime) { 714 | static Float:flEmitRate; flEmitRate = StructGetCell(sEffect, ParticleEffect_EmitRate); 715 | static iEmitAmount; iEmitAmount = StructGetCell(sEffect, ParticleEffect_EmitAmount); 716 | 717 | if (flEmitRate || !iParticlesNum) { 718 | for (new iBatchIndex = 0; iBatchIndex < iEmitAmount; ++iBatchIndex) { 719 | @ParticleSystem_Emit(this, iBatchIndex); 720 | } 721 | } 722 | 723 | StructSetCell(this, ParticleSystem_NextEmit, flGameTime + (flEmitRate / flSpeed)); 724 | } 725 | } 726 | 727 | for (new iParticle = 0; iParticle < iParticlesNum; ++iParticle) { 728 | static Struct:sParticle; sParticle = ArrayGetCell(irgParticles, iParticle); 729 | if (sParticle == Invalid_Struct) continue; 730 | 731 | // Destroy expired particle and skip (also destroy all particles in case no one see the system or the system is deactivated) 732 | static Float:flKillTime; flKillTime = StructGetCell(sParticle, Particle_KillTime); 733 | if (!iVisibilityBits || !bActive || (flKillTime > 0.0 && flKillTime <= flGameTime)) { 734 | ArraySetCell(irgParticles, iParticle, Invalid_Struct); 735 | @Particle_Destroy(sParticle); 736 | continue; 737 | } 738 | 739 | static bool:bAttached; bAttached = StructGetCell(sParticle, Particle_Attached); 740 | static Float:vecParticleOrigin[3]; StructGetArray(sParticle, Particle_PositionVars, vecParticleOrigin, 3, PositionVars_Origin); 741 | static Float:vecParticleVelocity[3]; StructGetArray(sParticle, Particle_PositionVars, vecParticleVelocity, 3, PositionVars_Velocity); 742 | static Float:vecParticleAngles[3]; StructGetArray(sParticle, Particle_PositionVars, vecParticleAngles, 3, PositionVars_Angles); 743 | 744 | xs_vec_add_scaled(vecParticleOrigin, vecParticleVelocity, flDelta * flSpeed, vecParticleOrigin); 745 | StructSetArray(sParticle, Particle_PositionVars, vecParticleOrigin, 3, PositionVars_Origin); 746 | 747 | @ParticleEffect_ExecuteHook(sEffect, ParticleEffectHook_Particle_Think, sParticle); 748 | 749 | if (bAttached) { 750 | @ParticleSystem_UpdateParticleAbsPosition(this, sParticle); 751 | } 752 | 753 | @ParticleSystem_SyncParticleVars(this, sParticle); 754 | 755 | StructSetCell(sParticle, Particle_LastThink, flGameTime); 756 | } 757 | 758 | StructSetCell(this, ParticleSystem_LastThink, flGameTime); 759 | } 760 | 761 | @ParticleSystem_Emit(const &Struct:this, iBatchIndex) { 762 | static iVisibilityBits; iVisibilityBits = StructGetCell(this, ParticleSystem_VisibilityBits); 763 | if (!iVisibilityBits) return; 764 | 765 | static Float:flGameTime; flGameTime = get_gametime(); 766 | static Struct:sEffect; sEffect = StructGetCell(this, ParticleSystem_Effect); 767 | static Float:flSpeed; flSpeed = StructGetCell(this, ParticleSystem_EffectSpeed); 768 | static ParticleEffectFlag:iEffectFlags; iEffectFlags = StructGetCell(sEffect, ParticleEffect_Flags); 769 | 770 | static Struct:sParticle; sParticle = @Particle_Create(this, !!(iEffectFlags & ParticleEffectFlag_AttachParticles)); 771 | 772 | static Float:vecAbsOrigin[3]; @ParticleSystem_GetAbsPositionVar(this, PositionVars_Origin, vecAbsOrigin); 773 | static Float:vecAbsAngles[3]; @ParticleSystem_GetAbsPositionVar(this, PositionVars_Angles, vecAbsAngles); 774 | static Float:vecAbsVelocity[3]; @ParticleSystem_GetAbsPositionVar(this, PositionVars_Velocity, vecAbsVelocity); 775 | 776 | StructSetArray(sParticle, Particle_AbsPositionVars, vecAbsOrigin, 3, PositionVars_Origin); 777 | StructSetArray(sParticle, Particle_AbsPositionVars, vecAbsAngles, 3, PositionVars_Angles); 778 | StructSetArray(sParticle, Particle_AbsPositionVars, vecAbsVelocity, 3, PositionVars_Velocity); 779 | 780 | StructSetCell(sParticle, Particle_BatchIndex, iBatchIndex); 781 | 782 | static Float:flLifeTime; flLifeTime = StructGetCell(sEffect, ParticleEffect_ParticleLifeTime); 783 | if (flLifeTime > 0.0) { 784 | StructSetCell(sParticle, Particle_KillTime, flGameTime + (flLifeTime / flSpeed)); 785 | } 786 | 787 | @ParticleSystem_AddParticle(this, sParticle); 788 | 789 | @ParticleEffect_ExecuteHook(sEffect, ParticleEffectHook_Particle_Init, sParticle); 790 | 791 | @Particle_InitEntity(sParticle); 792 | 793 | static Float:flEmitRate; flEmitRate = StructGetCell(sEffect, ParticleEffect_EmitRate); 794 | StructSetCell(this, ParticleSystem_NextEmit, flGameTime + (flEmitRate * flSpeed)); 795 | 796 | @ParticleSystem_SyncParticleVars(this, sParticle); 797 | } 798 | 799 | @ParticleSystem_AddParticle(const &Struct:this, const &Struct:sNewParticle) { 800 | static Array:irgParticles; irgParticles = StructGetCell(this, ParticleSystem_Particles); 801 | static iParticlesNum; iParticlesNum = ArraySize(irgParticles); 802 | 803 | static iIndex; iIndex = -1; 804 | static Struct:sOldParticle; sOldParticle = Invalid_Struct; 805 | 806 | for (new iParticle = 0; iParticle < iParticlesNum; ++iParticle) { 807 | static Struct:sParticle; sParticle = ArrayGetCell(irgParticles, iParticle); 808 | if (sParticle == Invalid_Struct) { 809 | sOldParticle = Invalid_Struct; 810 | iIndex = iParticle; 811 | break; 812 | } 813 | 814 | static Float:flKillTime; flKillTime = StructGetCell(sParticle, Particle_KillTime); 815 | if (iIndex == -1 || flKillTime < StructGetCell(sOldParticle, Particle_KillTime)) { 816 | iIndex = iParticle; 817 | sOldParticle = sParticle; 818 | } 819 | } 820 | 821 | if (sOldParticle != Invalid_Struct) { 822 | @Particle_Destroy(sOldParticle); 823 | } 824 | 825 | ArraySetCell(irgParticles, iIndex, sNewParticle); 826 | StructSetCell(sNewParticle, Particle_Index, iIndex); 827 | } 828 | 829 | @ParticleSystem_GetAbsPositionVar(const &Struct:this, PositionVars:iVariable, Float:vecOut[]) { 830 | static pParent; pParent = StructGetCell(this, ParticleSystem_ParentEntity); 831 | 832 | if (pParent > 0) { 833 | pev(pParent, PositionVarsToPevMemberVec(iVariable), vecOut); 834 | 835 | for (new i = 0; i < 3; ++i) { 836 | vecOut[i] += Float:StructGetCell(this, ParticleSystem_PositionVars, _:iVariable + i); 837 | } 838 | } else { 839 | StructGetArray(this, ParticleSystem_PositionVars, vecOut, 3, iVariable); 840 | } 841 | } 842 | 843 | @ParticleSystem_SetAbsVectorVar(const &Struct:this, PositionVars:iVariable, const Float:vecValue[3]) { 844 | static Float:vecAbsValue[3]; 845 | 846 | static pParent; pParent = StructGetCell(this, ParticleSystem_ParentEntity); 847 | if (pParent > 0) { 848 | pev(pParent, PositionVarsToPevMemberVec(iVariable), vecAbsValue); 849 | xs_vec_sub(vecValue, vecAbsValue, vecAbsValue); 850 | } else { 851 | xs_vec_copy(vecValue, vecAbsValue); 852 | } 853 | 854 | StructSetArray(this, ParticleSystem_PositionVars, vecAbsValue, 3, iVariable); 855 | } 856 | 857 | @ParticleSystem_UpdateVisibilityBits(const &Struct:this) { 858 | static Struct:sEffect; sEffect = StructGetCell(this, ParticleSystem_Effect); 859 | 860 | static Float:flVisibleDistance; flVisibleDistance = StructGetCell(sEffect, ParticleEffect_VisibilityDistance); 861 | static Float:vecAbsOrigin[3]; @ParticleSystem_GetAbsPositionVar(this, PositionVars_Origin, vecAbsOrigin); 862 | 863 | new iVisibilityBits = 0; 864 | for (new pPlayer = 1; pPlayer <= MaxClients; ++pPlayer) { 865 | if (!is_user_connected(pPlayer)) continue; 866 | 867 | static Float:vecPlayerOrigin[3]; ExecuteHamB(Ham_EyePosition, pPlayer, vecPlayerOrigin); 868 | static Float:flDistance; flDistance = get_distance_f(vecAbsOrigin, vecPlayerOrigin); 869 | static Float:flFOV; pev(pPlayer, pev_fov, flFOV); 870 | 871 | if (flDistance > 32.0 && !UTIL_IsInViewCone(pPlayer, vecAbsOrigin, flFOV / 2)) continue; 872 | if (flDistance > flVisibleDistance) continue; 873 | 874 | engfunc(EngFunc_TraceLine, vecPlayerOrigin, vecAbsOrigin, IGNORE_MONSTERS, pPlayer, g_pTrace); 875 | 876 | static Float:flFraction; get_tr2(g_pTrace, TR_flFraction, flFraction); 877 | if (flFraction == 1.0) { 878 | iVisibilityBits |= BIT(pPlayer & 31); 879 | } 880 | } 881 | 882 | StructSetCell(this, ParticleSystem_VisibilityBits, iVisibilityBits); 883 | } 884 | 885 | @ParticleSystem_UpdateParticleAbsPosition(const &Struct:this, const &Struct:sParticle) { 886 | static Float:vecAbsOrigin[3]; @ParticleSystem_GetAbsPositionVar(this, PositionVars_Origin, vecAbsOrigin); 887 | static Float:vecAbsAngles[3]; @ParticleSystem_GetAbsPositionVar(this, PositionVars_Angles, vecAbsAngles); 888 | static Float:vecAbsVelocity[3]; @ParticleSystem_GetAbsPositionVar(this, PositionVars_Velocity, vecAbsVelocity); 889 | 890 | StructSetArray(sParticle, Particle_AbsPositionVars, vecAbsOrigin, 3, PositionVars_Origin); 891 | StructSetArray(sParticle, Particle_AbsPositionVars, vecAbsAngles, 3, PositionVars_Angles); 892 | StructSetArray(sParticle, Particle_AbsPositionVars, vecAbsVelocity, 3, PositionVars_Velocity); 893 | } 894 | 895 | @ParticleSystem_SyncParticleVars(const &Struct:this, const &Struct:sParticle) { 896 | static Float:flSpeed; flSpeed = StructGetCell(this, ParticleSystem_EffectSpeed); 897 | 898 | static pEntity; pEntity = StructGetCell(sParticle, Particle_Entity); 899 | static bool:bAttached; bAttached = StructGetCell(sParticle, Particle_Attached); 900 | 901 | static Float:vecAbsOrigin[3]; StructGetArray(sParticle, Particle_AbsPositionVars, vecAbsOrigin, 3, PositionVars_Origin); 902 | static Float:vecAbsAngles[3]; StructGetArray(sParticle, Particle_AbsPositionVars, vecAbsAngles, 3, PositionVars_Angles); 903 | static Float:vecAbsVelocity[3]; StructGetArray(sParticle, Particle_AbsPositionVars, vecAbsVelocity, 3, PositionVars_Velocity); 904 | 905 | static Float:vecOrigin[3]; StructGetArray(sParticle, Particle_PositionVars, vecOrigin, 3, PositionVars_Origin); 906 | static Float:vecAngles[3]; StructGetArray(sParticle, Particle_PositionVars, vecAngles, 3, PositionVars_Angles); 907 | static Float:vecVelocity[3]; StructGetArray(sParticle, Particle_PositionVars, vecVelocity, 3, PositionVars_Velocity); 908 | 909 | if (bAttached) { 910 | static Float:rgAngleMatrix[3][4]; UTIL_AngleMatrix(vecAbsAngles, rgAngleMatrix); 911 | 912 | UTIL_RotateVectorByMatrix(vecOrigin, rgAngleMatrix, vecOrigin); 913 | UTIL_RotateVectorByMatrix(vecVelocity, rgAngleMatrix, vecVelocity); 914 | } 915 | 916 | xs_vec_add(vecAbsOrigin, vecOrigin, vecAbsOrigin); 917 | xs_vec_add(vecAbsAngles, vecAngles, vecAbsAngles); 918 | xs_vec_add(vecAbsVelocity, vecVelocity, vecAbsVelocity); 919 | 920 | if (flSpeed != 1.0) { 921 | xs_vec_mul_scalar(vecVelocity, flSpeed, vecVelocity); 922 | } 923 | 924 | set_pev(pEntity, pev_angles, vecAbsAngles); 925 | set_pev(pEntity, pev_origin, vecAbsOrigin); 926 | set_pev(pEntity, pev_velocity, vecAbsVelocity); 927 | } 928 | 929 | /*--------------------------------[ Particle Methods ]--------------------------------*/ 930 | 931 | Struct:@Particle_Create(const &Struct:sSystem, bool:bAttached) { 932 | static Struct:this; this = StructCreate(Particle); 933 | 934 | StructSetCell(this, Particle_System, sSystem); 935 | StructSetCell(this, Particle_Index, -1); 936 | StructSetCell(this, Particle_BatchIndex, 0); 937 | StructSetCell(this, Particle_Entity, -1); 938 | StructSetCell(this, Particle_CreatedTime, get_gametime()); 939 | StructSetCell(this, Particle_LastThink, get_gametime()); 940 | StructSetCell(this, Particle_KillTime, 0.0); 941 | StructSetCell(this, Particle_Attached, bAttached); 942 | 943 | StructSetArray(this, Particle_PositionVars, Float:{0.0, 0.0, 0.0}, 3, PositionVars_Origin); 944 | StructSetArray(this, Particle_PositionVars, Float:{0.0, 0.0, 0.0}, 3, PositionVars_Angles); 945 | StructSetArray(this, Particle_PositionVars, Float:{0.0, 0.0, 0.0}, 3, PositionVars_Velocity); 946 | 947 | return this; 948 | } 949 | 950 | @Particle_InitEntity(const &Struct:this) { 951 | static Struct:sSystem; sSystem = StructGetCell(this, Particle_System); 952 | static Struct:sEffect; sEffect = StructGetCell(sSystem, ParticleSystem_Effect); 953 | 954 | static pParticle; pParticle = CreateParticleEnity(Float:{0.0, 0.0, 0.0}, Float:{0.0, 0.0, 0.0}); 955 | set_pev(pParticle, pev_iuser1, this); 956 | 957 | StructSetCell(this, Particle_Entity, pParticle); 958 | 959 | @ParticleEffect_ExecuteHook(sEffect, ParticleEffectHook_Particle_EntityInit, this, pParticle); 960 | } 961 | 962 | @Particle_Destroy(&Struct:this) { 963 | static Struct:sSystem; sSystem = StructGetCell(this, Particle_System); 964 | static Struct:sEffect; sEffect = StructGetCell(sSystem, ParticleSystem_Effect); 965 | @ParticleEffect_ExecuteHook(sEffect, ParticleEffectHook_Particle_Destroy, this); 966 | 967 | static pParticle; pParticle = StructGetCell(this, Particle_Entity); 968 | engfunc(EngFunc_RemoveEntity, pParticle); 969 | 970 | StructDestroy(this); 971 | } 972 | 973 | /*--------------------------------[ Functions ]--------------------------------*/ 974 | 975 | CreateParticleEnity(const Float:vecOrigin[3], const Float:vecAngles[3]) { 976 | static pEntity; pEntity = engfunc(EngFunc_CreateNamedEntity, g_iszParticleClassName); 977 | dllfunc(DLLFunc_Spawn, pEntity); 978 | 979 | set_pev(pEntity, pev_classname, PARTICLE_CLASSNAME); 980 | set_pev(pEntity, pev_solid, SOLID_NOT); 981 | set_pev(pEntity, pev_movetype, MOVETYPE_NOCLIP); 982 | set_pev(pEntity, pev_angles, vecAngles); 983 | 984 | engfunc(EngFunc_SetOrigin, pEntity, vecOrigin); 985 | 986 | return pEntity; 987 | } 988 | 989 | UpdateSystems() { 990 | static Float:flGameTime; flGameTime = get_gametime(); 991 | static irgSystemsNum; irgSystemsNum = ArraySize(g_irgSystems); 992 | 993 | for (new iSystem = 0; iSystem < irgSystemsNum; ++iSystem) { 994 | static Struct:sSystem; sSystem = ArrayGetCell(g_irgSystems, iSystem); 995 | if (sSystem == Invalid_Struct) continue; 996 | 997 | // Destroy expired system and skip 998 | static Float:flKillTime; flKillTime = StructGetCell(sSystem, ParticleSystem_KillTime); 999 | if (flKillTime && flKillTime <= flGameTime) { 1000 | ArraySetCell(g_irgSystems, iSystem, Invalid_Struct); 1001 | @ParticleSystem_Destroy(sSystem); 1002 | continue; 1003 | } 1004 | 1005 | @ParticleSystem_Update(sSystem); 1006 | 1007 | static Float:flNextVisibilityUpdate; flNextVisibilityUpdate = StructGetCell(sSystem, ParticleSystem_NextVisibilityUpdate); 1008 | if (flNextVisibilityUpdate <= flGameTime) { 1009 | @ParticleSystem_UpdateVisibilityBits(sSystem); 1010 | StructSetCell(sSystem, ParticleSystem_NextVisibilityUpdate, flGameTime + VISIBILITY_UPDATE_RATE); 1011 | } 1012 | } 1013 | 1014 | UTIL_ArrayFindAndDelete(g_irgSystems, Invalid_Struct); 1015 | } 1016 | 1017 | FreeParticles() { 1018 | static irgSystemsNum; irgSystemsNum = ArraySize(g_irgSystems); 1019 | 1020 | for (new iSystem = 0; iSystem < irgSystemsNum; ++iSystem) { 1021 | static Struct:sSystem; sSystem = ArrayGetCell(g_irgSystems, iSystem); 1022 | if (sSystem == Invalid_Struct) continue; 1023 | @ParticleSystem_FreeParticles(sSystem); 1024 | } 1025 | } 1026 | 1027 | PositionVarsToPevMemberVec(PositionVars:iVariable) { 1028 | switch (iVariable) { 1029 | case PositionVars_Origin: return pev_origin; 1030 | case PositionVars_Angles: return pev_angles; 1031 | case PositionVars_Velocity: return pev_velocity; 1032 | } 1033 | 1034 | return -1; 1035 | } 1036 | 1037 | /*--------------------------------[ Stocks ]--------------------------------*/ 1038 | 1039 | stock UTIL_ArrayFindAndDelete(const &Array:irgArray, any:iValue) { 1040 | static iSize; iSize = ArraySize(irgArray); 1041 | 1042 | for (new i = 0; i < iSize; ++i) { 1043 | if (ArrayGetCell(irgArray, i) == iValue) { 1044 | ArrayDeleteItem(irgArray, i); 1045 | i--; 1046 | iSize--; 1047 | } 1048 | } 1049 | } 1050 | 1051 | stock UTIL_RotateVectorByMatrix(const Float:vecValue[3], Float:rgAngleMatrix[3][4], Float:vecOut[3]) { 1052 | static Float:vecTemp[3]; 1053 | 1054 | for (new i = 0; i < 3; ++i) { 1055 | vecTemp[i] = (vecValue[0] * rgAngleMatrix[0][i]) + (vecValue[1] * rgAngleMatrix[1][i]) + (vecValue[2] * rgAngleMatrix[2][i]); 1056 | } 1057 | 1058 | xs_vec_copy(vecTemp, vecOut); 1059 | } 1060 | 1061 | stock UTIL_AngleMatrix(const Float:vecAngles[3], Float:rgMatrix[3][4]) { 1062 | static Float:cp; cp = floatcos(vecAngles[0], degrees); 1063 | static Float:sp; sp = floatsin(vecAngles[0], degrees); 1064 | static Float:cy; cy = floatcos(vecAngles[1], degrees); 1065 | static Float:sy; sy = floatsin(vecAngles[1], degrees); 1066 | static Float:cr; cr = floatcos(-vecAngles[2], degrees); 1067 | static Float:sr; sr = floatsin(-vecAngles[2], degrees); 1068 | static Float:crcy; crcy = cr * cy; 1069 | static Float:crsy; crsy = cr * sy; 1070 | static Float:srcy; srcy = sr * cy; 1071 | static Float:srsy; srsy = sr * sy; 1072 | 1073 | // matrix = (YAW * PITCH) * ROLL 1074 | 1075 | rgMatrix[0][0] = cp * cy; 1076 | rgMatrix[1][0] = cp * sy; 1077 | rgMatrix[2][0] = -sp; 1078 | 1079 | rgMatrix[0][1] = (sp * srcy) + crsy; 1080 | rgMatrix[1][1] = (sp * srsy) - crcy; 1081 | rgMatrix[2][1] = sr * cp; 1082 | 1083 | rgMatrix[0][2] = (sp * crcy) - srsy; 1084 | rgMatrix[1][2] = (sp * crsy) + srcy; 1085 | rgMatrix[2][2] = cr * cp; 1086 | 1087 | rgMatrix[0][3] = 0.0; 1088 | rgMatrix[1][3] = 0.0; 1089 | rgMatrix[2][3] = 0.0; 1090 | } 1091 | 1092 | stock V_swap(&Float:v1, &Float:v2) { 1093 | static Float:tmp; 1094 | tmp = v1; 1095 | v1 = v2; 1096 | v2 = tmp; 1097 | } 1098 | 1099 | stock bool:UTIL_IsInViewCone(pEntity, const Float:vecTarget[3], Float:fMaxAngle) { 1100 | static Float:vecOrigin[3]; 1101 | ExecuteHamB(Ham_EyePosition, pEntity, vecOrigin); 1102 | 1103 | static Float:vecDir[3]; 1104 | xs_vec_sub(vecTarget, vecOrigin, vecDir); 1105 | xs_vec_normalize(vecDir, vecDir); 1106 | 1107 | static Float:vecForward[3]; 1108 | pev(pEntity, pev_v_angle, vecForward); 1109 | angle_vector(vecForward, ANGLEVECTOR_FORWARD, vecForward); 1110 | 1111 | new Float:flAngle = xs_rad2deg(xs_acos((vecDir[0] * vecForward[0]) + (vecDir[1] * vecForward[1]), radian)); 1112 | 1113 | return flAngle < fMaxAngle; 1114 | } 1115 | -------------------------------------------------------------------------------- /api_player_camera.sma: -------------------------------------------------------------------------------- 1 | #pragma semicolon 1 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | new g_rgpPlayerCamera[MAX_PLAYERS + 1]; 9 | new Float:g_rgflPlayerCameraDistance[MAX_PLAYERS + 1]; 10 | new Float:g_rgflPlayerCameraAngles[MAX_PLAYERS + 1][3]; 11 | new Float:g_rgflPlayerCameraOffset[MAX_PLAYERS + 1][3]; 12 | new bool:g_rgbPlayerCameraAxisLock[MAX_PLAYERS + 1][3]; 13 | new Float:g_rgflPlayerCameraThinkDelay[MAX_PLAYERS + 1]; 14 | new Float:g_rgflPlayerCameraNextThink[MAX_PLAYERS + 1]; 15 | new g_pPlayerTargetEntity[MAX_PLAYERS + 1]; 16 | 17 | new g_fwActivate; 18 | new g_fwDeactivate; 19 | new g_fwActivated; 20 | new g_fwDeactivated; 21 | 22 | new g_iszTriggerCameraClassname; 23 | 24 | new g_iCameraModelIndex; 25 | 26 | public plugin_precache() { 27 | g_iszTriggerCameraClassname = engfunc(EngFunc_AllocString, "trigger_camera"); 28 | 29 | g_iCameraModelIndex = precache_model("models/rpgrocket.mdl"); 30 | } 31 | 32 | public plugin_init() { 33 | register_plugin("[API] Player Camera", "1.0.0", "Hedgehog Fog"); 34 | 35 | RegisterHamPlayer(Ham_Spawn, "HamHook_Player_Spawn_Post", .Post = 1); 36 | RegisterHamPlayer(Ham_Player_PreThink, "HamHook_Player_PreThink_Post", .Post = 1); 37 | 38 | g_fwActivate = CreateMultiForward("PlayerCamera_Fw_Activate", ET_STOP, FP_CELL); 39 | g_fwDeactivate = CreateMultiForward("PlayerCamera_Fw_Deactivate", ET_STOP, FP_CELL); 40 | g_fwActivated = CreateMultiForward("PlayerCamera_Fw_Activated", ET_IGNORE, FP_CELL); 41 | g_fwDeactivated = CreateMultiForward("PlayerCamera_Fw_Deactivated", ET_IGNORE, FP_CELL); 42 | } 43 | 44 | public plugin_natives() { 45 | register_library("api_player_camera"); 46 | register_native("PlayerCamera_Activate", "Native_Activate"); 47 | register_native("PlayerCamera_Deactivate", "Native_Deactivate"); 48 | register_native("PlayerCamera_IsActive", "Native_IsActive"); 49 | register_native("PlayerCamera_SetOffset", "Native_SetOffset"); 50 | register_native("PlayerCamera_SetAngles", "Native_SetAngles"); 51 | register_native("PlayerCamera_SetDistance", "Native_SetDistance"); 52 | register_native("PlayerCamera_SetAxisLock", "Native_SetAxisLock"); 53 | register_native("PlayerCamera_SetThinkDelay", "Native_SetThinkDelay"); 54 | register_native("PlayerCamera_SetTargetEntity", "Native_SetTargetEntity"); 55 | } 56 | 57 | public bool:Native_Activate(iPluginId, iArgc) { 58 | new pPlayer = get_param(1); 59 | 60 | ActivatePlayerCamera(pPlayer); 61 | } 62 | 63 | public Native_Deactivate(iPluginId, iArgc) { 64 | new pPlayer = get_param(1); 65 | 66 | DeactivatePlayerCamera(pPlayer); 67 | } 68 | 69 | public Native_IsActive(iPluginId, iArgc) { 70 | new pPlayer = get_param(1); 71 | 72 | return g_rgpPlayerCamera[pPlayer] != -1; 73 | } 74 | 75 | public Native_SetOffset(iPluginId, iArgc) { 76 | new pPlayer = get_param(1); 77 | 78 | static Float:vecOffset[3]; 79 | get_array_f(2, vecOffset, 3); 80 | 81 | SetCameraOffset(pPlayer, vecOffset); 82 | } 83 | 84 | public Native_SetAngles(iPluginId, iArgc) { 85 | new pPlayer = get_param(1); 86 | 87 | static Float:vecAngles[3]; 88 | get_array_f(2, vecAngles, 3); 89 | 90 | SetCameraAngles(pPlayer, vecAngles); 91 | } 92 | 93 | public Native_SetDistance(iPluginId, iArgc) { 94 | new pPlayer = get_param(1); 95 | new Float:flDistance = get_param_f(2); 96 | 97 | SetCameraDistance(pPlayer, flDistance); 98 | } 99 | 100 | public Native_SetAxisLock(iPluginId, iArgc) { 101 | new pPlayer = get_param(1); 102 | new bool:bLockPitch = bool:get_param(2); 103 | new bool:bLockYaw = bool:get_param(3); 104 | new bool:bLockRoll = bool:get_param(4); 105 | 106 | SetAxisLock(pPlayer, bLockPitch, bLockYaw, bLockRoll); 107 | } 108 | 109 | public Native_SetThinkDelay(iPluginId, iArgc) { 110 | new pPlayer = get_param(1); 111 | new Float:flThinkDelay = get_param_f(2); 112 | 113 | SetCameraThinkDelay(pPlayer, flThinkDelay); 114 | } 115 | 116 | public Native_SetTargetEntity(iPluginId, iArgc) { 117 | new pPlayer = get_param(1); 118 | new pTarget = get_param(2); 119 | 120 | SetCameraTarget(pPlayer, pTarget); 121 | } 122 | 123 | public HamHook_Player_Spawn_Post(pPlayer) { 124 | ReattachCamera(pPlayer); 125 | } 126 | 127 | public HamHook_Player_PreThink_Post(pPlayer) { 128 | PlayerCameraThink(pPlayer); 129 | } 130 | 131 | public client_connect(pPlayer) { 132 | g_rgpPlayerCamera[pPlayer] = -1; 133 | SetCameraTarget(pPlayer, pPlayer); 134 | SetCameraDistance(pPlayer, 200.0); 135 | SetAxisLock(pPlayer, false, false, false); 136 | SetCameraAngles(pPlayer, Float:{0.0, 0.0, 0.0}); 137 | SetCameraOffset(pPlayer, Float:{0.0, 0.0, 0.0}); 138 | SetCameraThinkDelay(pPlayer, 0.01); 139 | } 140 | 141 | public client_disconnected(pPlayer) { 142 | DeactivatePlayerCamera(pPlayer); 143 | } 144 | 145 | ActivatePlayerCamera(pPlayer) { 146 | if (g_rgpPlayerCamera[pPlayer] != -1) { 147 | return; 148 | } 149 | 150 | new iResult = 0; ExecuteForward(g_fwActivate, iResult, pPlayer); 151 | if (iResult != PLUGIN_CONTINUE) return; 152 | 153 | g_rgpPlayerCamera[pPlayer] = CreatePlayerCamera(pPlayer); 154 | g_rgflPlayerCameraNextThink[pPlayer] = 0.0; 155 | 156 | engfunc(EngFunc_SetView, pPlayer, g_rgpPlayerCamera[pPlayer]); 157 | 158 | static Float:vecOrigin[3]; 159 | pev(g_pPlayerTargetEntity[pPlayer], pev_origin, vecOrigin); 160 | engfunc(EngFunc_SetOrigin, g_rgpPlayerCamera[pPlayer], vecOrigin); 161 | 162 | ExecuteForward(g_fwActivated, _, pPlayer); 163 | } 164 | 165 | DeactivatePlayerCamera(pPlayer) { 166 | if (g_rgpPlayerCamera[pPlayer] == -1) { 167 | return; 168 | } 169 | 170 | new iResult = 0; ExecuteForward(g_fwDeactivate, iResult, pPlayer); 171 | if (iResult != PLUGIN_CONTINUE) return; 172 | 173 | engfunc(EngFunc_RemoveEntity, g_rgpPlayerCamera[pPlayer]); 174 | g_rgpPlayerCamera[pPlayer] = -1; 175 | g_pPlayerTargetEntity[pPlayer] = pPlayer; 176 | 177 | if (is_user_connected(pPlayer)) { 178 | engfunc(EngFunc_SetView, pPlayer, pPlayer); 179 | } 180 | 181 | ExecuteForward(g_fwDeactivated, _, pPlayer); 182 | } 183 | 184 | SetCameraOffset(pPlayer, const Float:vecOffset[3]) { 185 | xs_vec_copy(vecOffset, g_rgflPlayerCameraOffset[pPlayer]); 186 | } 187 | 188 | SetCameraAngles(pPlayer, const Float:vecAngles[3]) { 189 | xs_vec_copy(vecAngles, g_rgflPlayerCameraAngles[pPlayer]); 190 | } 191 | 192 | SetCameraDistance(pPlayer, Float:flDistance) { 193 | g_rgflPlayerCameraDistance[pPlayer] = flDistance; 194 | } 195 | 196 | SetAxisLock(pPlayer, bool:bLockPitch, bool:bLockYaw, bool:bLockRoll) { 197 | g_rgbPlayerCameraAxisLock[pPlayer][0] = bLockPitch; 198 | g_rgbPlayerCameraAxisLock[pPlayer][1] = bLockYaw; 199 | g_rgbPlayerCameraAxisLock[pPlayer][2] = bLockRoll; 200 | } 201 | 202 | SetCameraThinkDelay(pPlayer, Float:flThinkDelay) { 203 | g_rgflPlayerCameraThinkDelay[pPlayer] = flThinkDelay; 204 | } 205 | 206 | SetCameraTarget(pPlayer, pTarget) { 207 | g_pPlayerTargetEntity[pPlayer] = pTarget; 208 | } 209 | 210 | CreatePlayerCamera(pPlayer) { 211 | new pCamera = engfunc(EngFunc_CreateNamedEntity, g_iszTriggerCameraClassname); 212 | 213 | set_pev(pCamera, pev_classname, "trigger_camera"); 214 | set_pev(pCamera, pev_modelindex, g_iCameraModelIndex); 215 | set_pev(pCamera, pev_owner, pPlayer); 216 | set_pev(pCamera, pev_solid, SOLID_NOT); 217 | set_pev(pCamera, pev_movetype, MOVETYPE_FLY); 218 | set_pev(pCamera, pev_rendermode, kRenderTransTexture); 219 | 220 | return pCamera; 221 | } 222 | 223 | PlayerCameraThink(pPlayer) { 224 | if (g_rgflPlayerCameraNextThink[pPlayer] > get_gametime()) { 225 | return; 226 | } 227 | 228 | g_rgflPlayerCameraNextThink[pPlayer] = get_gametime() + g_rgflPlayerCameraThinkDelay[pPlayer]; 229 | 230 | if (g_rgpPlayerCamera[pPlayer] == -1) { 231 | return; 232 | } 233 | 234 | if (!is_user_alive(pPlayer)) { 235 | return; 236 | } 237 | 238 | static Float:vecOrigin[3]; 239 | pev(g_pPlayerTargetEntity[pPlayer], pev_origin, vecOrigin); 240 | xs_vec_add(vecOrigin, g_rgflPlayerCameraOffset[pPlayer], vecOrigin); 241 | 242 | static Float:vecAngles[3]; 243 | pev(g_pPlayerTargetEntity[pPlayer], pev_v_angle, vecAngles); 244 | for (new iAxis = 0; iAxis < 3; ++iAxis) { 245 | if (g_rgbPlayerCameraAxisLock[pPlayer][iAxis]) { 246 | vecAngles[iAxis] = 0.0; 247 | } 248 | } 249 | 250 | xs_vec_add(vecAngles, g_rgflPlayerCameraAngles[pPlayer], vecAngles); 251 | 252 | static Float:vecBack[3]; 253 | angle_vector(vecAngles, ANGLEVECTOR_FORWARD, vecBack); 254 | xs_vec_neg(vecBack, vecBack); 255 | 256 | static Float:vecVelocity[3]; 257 | pev(g_pPlayerTargetEntity[pPlayer], pev_velocity, vecVelocity); 258 | 259 | static Float:vecCameraOrigin[3]; 260 | for (new i = 0; i < 3; ++i) { 261 | vecCameraOrigin[i] = vecOrigin[i] + (vecBack[i] * g_rgflPlayerCameraDistance[pPlayer]); 262 | } 263 | 264 | new pTr = create_tr2(); 265 | engfunc(EngFunc_TraceLine, vecOrigin, vecCameraOrigin, IGNORE_MONSTERS, pPlayer, pTr); 266 | 267 | static Float:flFraction; 268 | get_tr2(pTr, TR_flFraction, flFraction); 269 | 270 | free_tr2(pTr); 271 | 272 | if(flFraction != 1.0) { 273 | for (new i = 0; i < 3; ++i) { 274 | vecCameraOrigin[i] = vecOrigin[i] + (vecBack[i] * (g_rgflPlayerCameraDistance[pPlayer] * flFraction)); 275 | } 276 | } 277 | 278 | set_pev(g_rgpPlayerCamera[pPlayer], pev_origin, vecCameraOrigin); 279 | set_pev(g_rgpPlayerCamera[pPlayer], pev_angles, vecAngles); 280 | set_pev(g_rgpPlayerCamera[pPlayer], pev_velocity, vecVelocity); 281 | } 282 | 283 | ReattachCamera(pPlayer) { 284 | if (g_rgpPlayerCamera[pPlayer] == -1) { 285 | return; 286 | } 287 | 288 | engfunc(EngFunc_SetView, pPlayer, g_rgpPlayerCamera[pPlayer]); 289 | } 290 | -------------------------------------------------------------------------------- /api_player_cosmetics.sma: -------------------------------------------------------------------------------- 1 | #pragma semicolon 1 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | #include 9 | 10 | #define PLUGIN "[API] Player Cosmetics" 11 | #define VERSION "1.0.0" 12 | #define AUTHOR "Hedgehog Fog" 13 | 14 | #define COSMETIC_CLASSNAME "_cosmetic" 15 | 16 | new Trie:g_itPlayerCosmetics[MAX_PLAYERS + 1]; 17 | new g_iszCosmeticClassName; 18 | 19 | new Float:g_rgflPlayerNextRenderingUpdate[MAX_PLAYERS + 1]; 20 | 21 | public plugin_precache() { 22 | g_iszCosmeticClassName = engfunc(EngFunc_AllocString, "info_target"); 23 | } 24 | 25 | public plugin_init() { 26 | register_plugin(PLUGIN, VERSION, AUTHOR); 27 | 28 | RegisterHam(Ham_Think, "info_target", "HamHook_Target_Think", .Post = 0); 29 | 30 | register_concmd("player_cosmetic_equip", "Command_Equip", ADMIN_CVAR); 31 | register_concmd("player_cosmetic_unequip", "Command_Unequip", ADMIN_CVAR); 32 | } 33 | 34 | public plugin_natives() { 35 | register_library("api_player_cosmetic"); 36 | register_native("PlayerCosmetic_Equip", "Native_Equip"); 37 | register_native("PlayerCosmetic_Unequip", "Native_Unquip"); 38 | register_native("PlayerCosmetic_IsEquiped", "Native_IsEquiped"); 39 | register_native("PlayerCosmetic_GetEntity", "Native_GetEntity"); 40 | } 41 | 42 | public client_connect(pPlayer) { 43 | g_itPlayerCosmetics[pPlayer] = TrieCreate(); 44 | g_rgflPlayerNextRenderingUpdate[pPlayer] = get_gametime(); 45 | } 46 | 47 | public client_disconnected(pPlayer) { 48 | for (new TrieIter:iIterator = TrieIterCreate(g_itPlayerCosmetics[pPlayer]); !TrieIterEnded(iIterator); TrieIterNext(iIterator)) { 49 | static pCosmetic; 50 | TrieIterGetCell(iIterator, pCosmetic); 51 | @PlayerCosmetic_Destroy(pCosmetic); 52 | } 53 | 54 | TrieDestroy(g_itPlayerCosmetics[pPlayer]); 55 | } 56 | 57 | public Native_Equip(iPluginId, iArgc) { 58 | new pPlayer = get_param(1); 59 | new iModelIndex = get_param(2); 60 | 61 | return @Player_EquipCosmetic(pPlayer, iModelIndex); 62 | } 63 | 64 | public Native_Unquip(iPluginId, iArgc) { 65 | new pPlayer = get_param(1); 66 | new iModelIndex = get_param(2); 67 | 68 | return @Player_UnequipCosmetic(pPlayer, iModelIndex); 69 | } 70 | 71 | public Native_IsEquiped(iPluginId, iArgc) { 72 | new pPlayer = get_param(1); 73 | new iModelIndex = get_param(2); 74 | 75 | return @Player_IsCosmeticEquiped(pPlayer, iModelIndex); 76 | } 77 | 78 | public Native_GetEntity(iPluginId, iArgc) { 79 | new pPlayer = get_param(1); 80 | new iModelIndex = get_param(2); 81 | 82 | return @Player_GetCosmeticEntity(pPlayer, iModelIndex); 83 | } 84 | 85 | public Command_Equip(pPlayer, iLevel, iCId) { 86 | if (!cmd_access(pPlayer, iLevel, iCId, 2)) { 87 | return PLUGIN_HANDLED; 88 | } 89 | 90 | static szTarget[32]; 91 | read_argv(1, szTarget, charsmax(szTarget)); 92 | 93 | static szModel[256]; 94 | read_argv(2, szModel, charsmax(szModel)); 95 | 96 | new iTarget = CMD_RESOLVE_TARGET(szTarget); 97 | new iModelIndex = engfunc(EngFunc_ModelIndex, szModel); 98 | 99 | for (new pTarget = 1; pTarget <= MaxClients; ++pTarget) { 100 | if (CMD_SHOULD_TARGET_PLAYER(pTarget, iTarget, pPlayer)) { 101 | @Player_EquipCosmetic(pTarget, iModelIndex); 102 | } 103 | } 104 | 105 | return PLUGIN_HANDLED; 106 | } 107 | 108 | public Command_Unequip(pPlayer, iLevel, iCId) { 109 | if (!cmd_access(pPlayer, iLevel, iCId, 2)) { 110 | return PLUGIN_HANDLED; 111 | } 112 | 113 | static szTarget[32]; read_argv(1, szTarget, charsmax(szTarget)); 114 | static szModel[256]; read_argv(2, szModel, charsmax(szModel)); 115 | 116 | new iTarget = CMD_RESOLVE_TARGET(szTarget); 117 | new iModelIndex = engfunc(EngFunc_ModelIndex, szModel); 118 | 119 | for (new pTarget = 1; pTarget <= MaxClients; ++pTarget) { 120 | if (CMD_SHOULD_TARGET_PLAYER(pTarget, iTarget, pPlayer)) { 121 | @Player_UnequipCosmetic(pTarget, iModelIndex); 122 | } 123 | } 124 | 125 | return PLUGIN_HANDLED; 126 | } 127 | 128 | public HamHook_Target_Think(pEntity) { 129 | static szClassName[32]; 130 | pev(pEntity, pev_classname, szClassName, charsmax(szClassName)); 131 | 132 | if (equal(szClassName, COSMETIC_CLASSNAME)) { 133 | @PlayerCosmetic_Think(pEntity); 134 | } 135 | } 136 | 137 | @Player_EquipCosmetic(this, iModelIndex) { 138 | if (g_itPlayerCosmetics[this] == Invalid_Trie) { 139 | return -1; 140 | } 141 | 142 | static szModelIndex[8]; 143 | num_to_str(iModelIndex, szModelIndex, charsmax(szModelIndex)); 144 | 145 | new pCosmetic = -1; 146 | if (TrieKeyExists(g_itPlayerCosmetics[this], szModelIndex)) { 147 | TrieGetCell(g_itPlayerCosmetics[this], szModelIndex, pCosmetic); 148 | } else { 149 | pCosmetic = @PlayerCosmetic_Create(this, iModelIndex); 150 | TrieSetCell(g_itPlayerCosmetics[this], szModelIndex, pCosmetic); 151 | } 152 | 153 | return pCosmetic; 154 | } 155 | 156 | bool:@Player_UnequipCosmetic(this, iModelIndex) { 157 | if (g_itPlayerCosmetics[this] == Invalid_Trie) { 158 | return false; 159 | } 160 | 161 | static szModelIndex[8]; 162 | num_to_str(iModelIndex, szModelIndex, charsmax(szModelIndex)); 163 | 164 | static pCosmetic; 165 | if (!TrieGetCell(g_itPlayerCosmetics[this], szModelIndex, pCosmetic)) { 166 | return false; 167 | } 168 | 169 | @PlayerCosmetic_Destroy(pCosmetic); 170 | TrieDeleteKey(g_itPlayerCosmetics[this], szModelIndex); 171 | 172 | return true; 173 | } 174 | 175 | bool:@Player_IsCosmeticEquiped(this, iModelIndex) { 176 | if (g_itPlayerCosmetics[this] == Invalid_Trie) { 177 | return false; 178 | } 179 | 180 | static szModelIndex[8]; 181 | num_to_str(iModelIndex, szModelIndex, charsmax(szModelIndex)); 182 | 183 | return TrieKeyExists(g_itPlayerCosmetics[this], szModelIndex); 184 | } 185 | 186 | @Player_GetCosmeticEntity(this, iModelIndex) { 187 | if (g_itPlayerCosmetics[this] == Invalid_Trie) { 188 | return -1; 189 | } 190 | 191 | static szModelIndex[8]; 192 | num_to_str(iModelIndex, szModelIndex, charsmax(szModelIndex)); 193 | 194 | static pCosmetic; 195 | if (!TrieGetCell(g_itPlayerCosmetics[this], szModelIndex, pCosmetic)) { 196 | return -1; 197 | } 198 | 199 | return pCosmetic; 200 | } 201 | 202 | @PlayerCosmetic_Create(pPlayer, iModelIndex) { 203 | new this = engfunc(EngFunc_CreateNamedEntity, g_iszCosmeticClassName); 204 | 205 | set_pev(this, pev_classname, COSMETIC_CLASSNAME); 206 | set_pev(this, pev_movetype, MOVETYPE_FOLLOW); 207 | set_pev(this, pev_aiment, pPlayer); 208 | set_pev(this, pev_owner, pPlayer); 209 | set_pev(this, pev_modelindex, iModelIndex); 210 | 211 | set_pev(this, pev_nextthink, get_gametime()); 212 | 213 | return this; 214 | } 215 | 216 | @PlayerCosmetic_Think(this) { 217 | new pOwner = pev(this, pev_owner); 218 | 219 | static iRenderMode; iRenderMode = pev(pOwner, pev_rendermode); 220 | static iRenderFx; iRenderFx = pev(pOwner, pev_renderfx); 221 | static Float:flRenderAmt; pev(pOwner, pev_renderamt, flRenderAmt); 222 | static Float:rgflRenderColor[3]; pev(pOwner, pev_rendercolor, rgflRenderColor); 223 | 224 | set_pev(this, pev_rendermode, iRenderMode); 225 | set_pev(this, pev_renderamt, flRenderAmt); 226 | set_pev(this, pev_renderfx, iRenderFx); 227 | set_pev(this, pev_rendercolor, rgflRenderColor); 228 | 229 | set_pev(this, pev_nextthink, get_gametime() + 0.1); 230 | } 231 | 232 | @PlayerCosmetic_Destroy(this) { 233 | set_pev(this, pev_movetype, MOVETYPE_NONE); 234 | set_pev(this, pev_aiment, 0); 235 | set_pev(this, pev_flags, pev(this, pev_flags) | FL_KILLME); 236 | dllfunc(DLLFunc_Think, this); 237 | } 238 | -------------------------------------------------------------------------------- /api_player_dizziness.sma: -------------------------------------------------------------------------------- 1 | #pragma semicolon 1 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | #define DIZZINESS_THINK_RATE 0.01 9 | #define DIZZINESS_RANDOM_PUSH_RATE 1.0 10 | #define DIZZINESS_JUMP_SPEED 200.0 11 | #define DIZZINESS_ANGLE_HANDLE_SPEED 100.0 12 | #define DIZZINESS_ANGLE_HANDLE_SPEED_MIN 50.0 13 | #define DIZZINESS_ANGLE_HANDLE_SPEED_MAX 150.0 14 | #define DIZZINESS_PUSH_SPEED 30.0 15 | #define DIZZINESS_PUSH_SPEED_MIN 0.0 16 | #define DIZZINESS_PUSH_SPEED_MAX 40.0 17 | #define DIZZINESS_PUNCH_ANGLE 45.0 18 | #define DIZZINESS_PUNCH_ANGLE_MIN 20.0 19 | #define DIZZINESS_PUNCH_ANGLE_MAX 75.0 20 | #define DIZZINESS_BLINK_DURATION 0.1 21 | #define DIZZINESS_BLINK_DURATION_MIN 0.1 22 | #define DIZZINESS_BLINK_DURATION_MAX 1.0 23 | #define DIZZINESS_BLINK_TRANSITION_DURATION 0.75 24 | #define DIZZINESS_BLINK_TRANSITION_DURATION_MIN 0.25 25 | #define DIZZINESS_BLINK_TRANSITION_DURATION_MAX 1.0 26 | #define DIZZINESS_RANDOM_BLINK_RATE 3.0 27 | #define DIZZINESS_RANDOM_BLINK_RATE_MIN 1.0 28 | #define DIZZINESS_RANDOM_BLINK_RATE_MAX 10.0 29 | #define DIZZINESS_MIN_STRENGTH_TO_BLINK 0.5 30 | 31 | new gmsgScreenFade; 32 | 33 | new Float:g_rgflPlayerDizzinessNextThink[MAX_PLAYERS + 1]; 34 | new Float:g_rgflPlayerDizzinessStrength[MAX_PLAYERS + 1]; 35 | new Float:g_rgflPlayerNextPush[MAX_PLAYERS + 1]; 36 | new Float:g_rgvecPlayerPushVelocityTarget[MAX_PLAYERS + 1][3]; 37 | new Float:g_rgvecPlayerPushVelocityAcc[MAX_PLAYERS + 1][3]; 38 | new Float:g_rgflPlayerLastPushThink[MAX_PLAYERS + 1]; 39 | new Float:g_rgflPlayerNextPushThink[MAX_PLAYERS + 1]; 40 | new Float:g_rgflPlayerNextBlink[MAX_PLAYERS + 1]; 41 | 42 | public plugin_init() { 43 | register_plugin("[API] Player Dizziness", "1.0.0", "Hedgehog Fog"); 44 | 45 | RegisterHamPlayer(Ham_Player_Jump, "HamHook_Player_Jump_Post", .Post = 1); 46 | RegisterHamPlayer(Ham_Player_PreThink, "HamHook_Player_PreThink_Post", .Post = 1); 47 | 48 | gmsgScreenFade = get_user_msgid("ScreenFade"); 49 | } 50 | 51 | public plugin_natives() { 52 | register_library("api_player_dizziness"); 53 | register_native("PlayerDizziness_Set", "Native_SetPlayerDizziness"); 54 | register_native("PlayerDizziness_Get", "Native_GetPlayerDizziness"); 55 | } 56 | 57 | public Native_SetPlayerDizziness(iPluginId, iArgc) { 58 | new pPlayer = get_param(1); 59 | new Float:flValue = get_param_f(2); 60 | 61 | g_rgflPlayerDizzinessStrength[pPlayer] = floatclamp(flValue, 0.0, 10.0); 62 | } 63 | 64 | public Float:Native_GetPlayerDizziness(iPluginId, iArgc) { 65 | new pPlayer = get_param(1); 66 | 67 | return g_rgflPlayerDizzinessStrength[pPlayer]; 68 | } 69 | 70 | public client_connect(pPlayer) { 71 | g_rgflPlayerDizzinessNextThink[pPlayer] = 0.0; 72 | g_rgflPlayerDizzinessStrength[pPlayer] = 0.0; 73 | g_rgflPlayerNextPush[pPlayer] = 0.0; 74 | g_rgflPlayerLastPushThink[pPlayer] = 0.0; 75 | g_rgflPlayerNextPushThink[pPlayer] = 0.0; 76 | g_rgflPlayerNextBlink[pPlayer] = 0.0; 77 | 78 | xs_vec_copy(Float:{0.0, 0.0, 0.0}, g_rgvecPlayerPushVelocityTarget[pPlayer]); 79 | xs_vec_copy(Float:{0.0, 0.0, 0.0}, g_rgvecPlayerPushVelocityAcc[pPlayer]); 80 | } 81 | 82 | public HamHook_Player_PreThink_Post(pPlayer) { 83 | new Float:flGameTime = get_gametime(); 84 | 85 | if (flGameTime >= g_rgflPlayerDizzinessNextThink[pPlayer]) { 86 | @Player_Think(pPlayer); 87 | g_rgflPlayerDizzinessNextThink[pPlayer] = flGameTime + DIZZINESS_THINK_RATE; 88 | } 89 | } 90 | 91 | public HamHook_Player_Jump_Post(pPlayer) { 92 | if (pev(pPlayer, pev_flags) & FL_ONGROUND && ~pev(pPlayer, pev_oldbuttons) & IN_JUMP) { 93 | @Player_Jump(pPlayer); 94 | } 95 | } 96 | 97 | @Player_Think(this) { 98 | new Float:flDizzinessStrength = g_rgflPlayerDizzinessStrength[this]; 99 | if (flDizzinessStrength <= 0.0) { 100 | return; 101 | } 102 | 103 | if (pev(this, pev_flags) & FL_FROZEN) { 104 | return; 105 | } 106 | 107 | new Float:flGameTime = get_gametime(); 108 | 109 | if (is_user_alive(this)) { 110 | static Float:vecVelocity[3]; 111 | pev(this, pev_velocity, vecVelocity); 112 | 113 | 114 | new Float:flMaxPushForce = floatclamp(DIZZINESS_PUSH_SPEED * flDizzinessStrength, DIZZINESS_PUSH_SPEED_MIN, DIZZINESS_PUSH_SPEED_MAX); 115 | if (g_rgflPlayerNextPush[this] <= flGameTime) { 116 | @Player_Push(this, flMaxPushForce); 117 | g_rgflPlayerNextPush[this] = flGameTime + DIZZINESS_RANDOM_PUSH_RATE; 118 | } 119 | 120 | if (flDizzinessStrength >= DIZZINESS_MIN_STRENGTH_TO_BLINK) { 121 | if (g_rgflPlayerNextBlink[this] <= flGameTime) { 122 | new Float:flBlinkTransitionDuration = floatclamp(DIZZINESS_BLINK_TRANSITION_DURATION * flDizzinessStrength, DIZZINESS_BLINK_TRANSITION_DURATION_MIN, DIZZINESS_BLINK_TRANSITION_DURATION_MAX); 123 | new Float:flBlinkDuration = floatclamp(DIZZINESS_BLINK_DURATION * flDizzinessStrength, DIZZINESS_BLINK_DURATION_MIN, DIZZINESS_BLINK_DURATION_MAX); 124 | new Float:flBlinkRate = floatclamp(DIZZINESS_RANDOM_BLINK_RATE / flDizzinessStrength, DIZZINESS_RANDOM_BLINK_RATE_MIN, DIZZINESS_RANDOM_BLINK_RATE_MAX); 125 | 126 | @Player_Blink(this, flBlinkDuration, flBlinkTransitionDuration); 127 | g_rgflPlayerNextBlink[this] = flGameTime + flBlinkRate + flBlinkDuration; 128 | } 129 | } 130 | 131 | @Player_PushThink(this); 132 | 133 | new Float:flMaxPunchAngle = floatclamp(DIZZINESS_PUNCH_ANGLE * flDizzinessStrength, DIZZINESS_PUNCH_ANGLE_MIN, DIZZINESS_PUNCH_ANGLE_MAX); 134 | new Float:flAngleHandleSpeed = floatclamp(DIZZINESS_ANGLE_HANDLE_SPEED / flDizzinessStrength, DIZZINESS_ANGLE_HANDLE_SPEED_MIN, DIZZINESS_ANGLE_HANDLE_SPEED_MAX); 135 | @Player_CameraThink(this, flMaxPunchAngle, flAngleHandleSpeed); 136 | } 137 | } 138 | 139 | @Player_PushThink(this) { 140 | new Float:flGameTime = get_gametime(); 141 | 142 | if (pev(this, pev_flags) & FL_ONGROUND) { 143 | new Float:flDelta = flGameTime - g_rgflPlayerLastPushThink[this]; 144 | 145 | for (new i = 0; i < 3; ++i) { 146 | g_rgvecPlayerPushVelocityAcc[this][i] += (g_rgvecPlayerPushVelocityTarget[this][i] - g_rgvecPlayerPushVelocityAcc[this][i]) * flDelta; 147 | } 148 | 149 | static Float:vecVelocity[3]; 150 | pev(this, pev_velocity, vecVelocity); 151 | xs_vec_add(vecVelocity, g_rgvecPlayerPushVelocityAcc[this], vecVelocity); 152 | set_pev(this, pev_velocity, vecVelocity); 153 | } 154 | 155 | g_rgflPlayerLastPushThink[this] = get_gametime(); 156 | } 157 | 158 | @Player_CameraThink(this, Float:flMaxPunchAngle, Float:flAngleHandleSpeed) { 159 | static Float:vecAngles[3]; 160 | pev(this, pev_v_angle, vecAngles); 161 | vecAngles[0] = 0.0; 162 | vecAngles[2] = 0.0; 163 | 164 | static Float:vecForward[3]; 165 | angle_vector(vecAngles, ANGLEVECTOR_FORWARD, vecForward); 166 | 167 | static Float:vecRight[3]; 168 | angle_vector(vecAngles, ANGLEVECTOR_RIGHT, vecRight); 169 | 170 | static Float:vecVelocity[3]; 171 | pev(this, pev_velocity, vecVelocity); 172 | 173 | static Float:flMaxSpeed; 174 | pev(this, pev_maxspeed, flMaxSpeed); 175 | flMaxSpeed = floatmin(flMaxSpeed, flAngleHandleSpeed); 176 | 177 | static Float:vecPunchAngle[3]; 178 | pev(this, pev_punchangle, vecPunchAngle); 179 | vecPunchAngle[0] += floatclamp(xs_vec_dot(vecVelocity, vecForward), -flMaxSpeed, flMaxSpeed) / flMaxSpeed * flMaxPunchAngle * DIZZINESS_THINK_RATE; 180 | vecPunchAngle[2] += floatclamp(xs_vec_dot(vecVelocity, vecRight), -flMaxSpeed, flMaxSpeed) / flMaxSpeed * flMaxPunchAngle * DIZZINESS_THINK_RATE; 181 | 182 | if (xs_vec_len(vecPunchAngle) > 0.0) { 183 | set_pev(this, pev_punchangle, vecPunchAngle); 184 | } 185 | } 186 | 187 | @Player_Push(this, Float:flMaxForce) { 188 | new Float:flGameTime = get_gametime(); 189 | 190 | xs_vec_copy(Float:{0.0, 0.0, 0.0}, g_rgvecPlayerPushVelocityAcc[this]); 191 | 192 | g_rgvecPlayerPushVelocityTarget[this][0] = random_float(-flMaxForce, flMaxForce); 193 | g_rgvecPlayerPushVelocityTarget[this][1] = random_float(-flMaxForce, flMaxForce); 194 | g_rgvecPlayerPushVelocityTarget[this][2] = 0.0; 195 | 196 | g_rgflPlayerLastPushThink[this] = flGameTime; 197 | } 198 | 199 | @Player_Blink(this, Float:flDuration, Float:flTransitionDuration) { 200 | static const iFlags = 0; 201 | static const rgiColor[3] = {0, 0, 0}; 202 | static const iAlpha = 255; 203 | 204 | new iFadeTime = FixedUnsigned16(flTransitionDuration , 1<<12); 205 | new iHoldTime = FixedUnsigned16(flDuration , 1<<12); 206 | 207 | emessage_begin(MSG_ONE, gmsgScreenFade, _, this); 208 | ewrite_short(iFadeTime); 209 | ewrite_short(iHoldTime); 210 | ewrite_short(iFlags); 211 | ewrite_byte(rgiColor[0]); 212 | ewrite_byte(rgiColor[1]); 213 | ewrite_byte(rgiColor[2]); 214 | ewrite_byte(iAlpha); 215 | emessage_end(); 216 | } 217 | 218 | @Player_Jump(this) { 219 | if (g_rgflPlayerDizzinessStrength[this] < 1.0) { 220 | return; 221 | } 222 | 223 | static Float:vecVelocity[3]; 224 | vecVelocity[0] = random_float(-1.0, 1.0); 225 | vecVelocity[1] = random_float(-1.0, 1.0); 226 | vecVelocity[2] = 0.0; 227 | 228 | xs_vec_normalize(vecVelocity, vecVelocity); 229 | xs_vec_mul_scalar(vecVelocity, random_float(80.0, 100.0), vecVelocity); 230 | vecVelocity[2] = DIZZINESS_JUMP_SPEED; 231 | 232 | set_pev(this, pev_velocity, vecVelocity); 233 | } 234 | 235 | stock FixedUnsigned16(Float:flValue, iScale) { 236 | return clamp(floatround(flValue * iScale), 0, 0xFFFF); 237 | } 238 | -------------------------------------------------------------------------------- /api_player_effects.sma: -------------------------------------------------------------------------------- 1 | #pragma semicolon 1 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | #tryinclude 9 | #include 10 | 11 | #include 12 | 13 | #define PLUGIN "[API] Player Effects" 14 | #define VERSION "1.0.0" 15 | #define AUTHOR "Hedgehog Fog" 16 | 17 | #define BIT(%0) (1<<(%0)) 18 | 19 | enum PEffectData { 20 | Array:PEffectData_Id, 21 | Array:PEffectData_InvokeFunctionId, 22 | Array:PEffectData_RevokeFunctionId, 23 | Array:PEffectData_PluginId, 24 | Array:PEffectData_Icon, 25 | Array:PEffectData_IconColor, 26 | Array:PEffectData_Players, 27 | Array:PEffectData_PlayerEffectDuration, 28 | Array:PEffectData_PlayerEffectEnd 29 | }; 30 | 31 | new gmsgStatusIcon; 32 | 33 | new Trie:g_itEffectsIds = Invalid_Trie; 34 | new g_rgPEffectData[PEffectData] = { Invalid_Array, ... }; 35 | new g_iEffectssNum = 0; 36 | 37 | public plugin_precache() { 38 | g_itEffectsIds = TrieCreate(); 39 | 40 | g_rgPEffectData[PEffectData_Id] = ArrayCreate(32); 41 | g_rgPEffectData[PEffectData_InvokeFunctionId] = ArrayCreate(); 42 | g_rgPEffectData[PEffectData_RevokeFunctionId] = ArrayCreate(); 43 | g_rgPEffectData[PEffectData_PluginId] = ArrayCreate(); 44 | g_rgPEffectData[PEffectData_Icon] = ArrayCreate(32); 45 | g_rgPEffectData[PEffectData_IconColor] = ArrayCreate(3); 46 | g_rgPEffectData[PEffectData_Players] = ArrayCreate(); 47 | g_rgPEffectData[PEffectData_PlayerEffectEnd] = ArrayCreate(MAX_PLAYERS + 1); 48 | g_rgPEffectData[PEffectData_PlayerEffectDuration] = ArrayCreate(MAX_PLAYERS + 1); 49 | } 50 | 51 | public plugin_init() { 52 | register_plugin(PLUGIN, VERSION, AUTHOR); 53 | 54 | RegisterHamPlayer(Ham_Player_PostThink, "HamHook_Player_PostThink_Post", .Post = 1); 55 | RegisterHamPlayer(Ham_Killed, "HamHook_Player_Killed", .Post = 0); 56 | 57 | register_concmd("player_effect_set", "Command_Set", ADMIN_CVAR); 58 | 59 | gmsgStatusIcon = get_user_msgid("StatusIcon"); 60 | } 61 | 62 | public plugin_end() { 63 | TrieDestroy(g_itEffectsIds); 64 | 65 | for (new PEffectData:iEffectData = PEffectData:0; iEffectData < PEffectData; ++iEffectData) { 66 | ArrayDestroy(Array:g_rgPEffectData[iEffectData]); 67 | } 68 | } 69 | 70 | public plugin_natives() { 71 | register_library("api_player_effects"); 72 | register_native("PlayerEffect_Register", "Native_Register"); 73 | register_native("PlayerEffect_Set", "Native_SetPlayerEffect"); 74 | register_native("PlayerEffect_Get", "Native_GetPlayerEffect"); 75 | register_native("PlayerEffect_GetEndtime", "Native_GetPlayerEffectEndTime"); 76 | register_native("PlayerEffect_GetDuration", "Native_GetPlayerEffectDuration"); 77 | } 78 | 79 | public Native_Register(iPluginId, iArgc) { 80 | new szId[32]; get_string(1, szId, charsmax(szId)); 81 | new szInvokeFunction[32]; get_string(2, szInvokeFunction, charsmax(szInvokeFunction)); 82 | new szRevokeFunction[32]; get_string(3, szRevokeFunction, charsmax(szRevokeFunction)); 83 | new szIcon[32]; get_string(4, szIcon, charsmax(szIcon)); 84 | new rgiIconColor[3]; get_array(5, rgiIconColor, sizeof(rgiIconColor)); 85 | 86 | new iInvokeFunctionId = get_func_id(szInvokeFunction, iPluginId); 87 | new iRevokeFunctionId = get_func_id(szRevokeFunction, iPluginId); 88 | 89 | return Register(szId, iInvokeFunctionId, iRevokeFunctionId, iPluginId, szIcon, rgiIconColor); 90 | } 91 | 92 | public bool:Native_SetPlayerEffect(iPluginId, iArgc) { 93 | new pPlayer = get_param(1); 94 | new szEffectId[32]; get_string(2, szEffectId, charsmax(szEffectId)); 95 | 96 | new iEffectId = -1; 97 | if (!TrieGetCell(g_itEffectsIds, szEffectId, iEffectId)) return false; 98 | 99 | new bool:bValue = bool:get_param(3); 100 | new Float:flDuration = get_param_f(4); 101 | new bool:bExtend = bool:get_param(5); 102 | 103 | return @Player_SetEffect(pPlayer, iEffectId, bValue, flDuration, bExtend); 104 | } 105 | 106 | public bool:Native_GetPlayerEffect(iPluginId, iArgc) { 107 | new pPlayer = get_param(1); 108 | new szEffectId[32]; get_string(2, szEffectId, charsmax(szEffectId)); 109 | 110 | new iEffectId = -1; 111 | if (!TrieGetCell(g_itEffectsIds, szEffectId, iEffectId)) return false; 112 | 113 | return @Player_GetEffect(pPlayer, iEffectId); 114 | } 115 | 116 | public Float:Native_GetPlayerEffectEndTime(iPluginId, iArgc) { 117 | new pPlayer = get_param(1); 118 | new szEffectId[32]; get_string(2, szEffectId, charsmax(szEffectId)); 119 | 120 | new iEffectId = -1; 121 | if (!TrieGetCell(g_itEffectsIds, szEffectId, iEffectId)) return 0.0; 122 | 123 | return Float:ArrayGetCell(g_rgPEffectData[PEffectData_PlayerEffectEnd], iEffectId, pPlayer); 124 | } 125 | 126 | public Float:Native_GetPlayerEffectDuration(iPluginId, iArgc) { 127 | new pPlayer = get_param(1); 128 | new szEffectId[32]; get_string(2, szEffectId, charsmax(szEffectId)); 129 | 130 | new iEffectId = -1; 131 | if (!TrieGetCell(g_itEffectsIds, szEffectId, iEffectId)) return 0.0; 132 | 133 | return Float:ArrayGetCell(g_rgPEffectData[PEffectData_PlayerEffectDuration], iEffectId, pPlayer); 134 | } 135 | 136 | /*--------------------------------[ Forwards ]--------------------------------*/ 137 | 138 | public client_disconnected(pPlayer) { 139 | @Player_RevokeEffects(pPlayer); 140 | } 141 | 142 | public Round_Fw_NewRound() { 143 | for (new pPlayer = 1; pPlayer <= MaxClients; ++pPlayer) @Player_RevokeEffects(pPlayer); 144 | } 145 | 146 | /*--------------------------------[ Hooks ]--------------------------------*/ 147 | 148 | public Command_Set(pPlayer, iLevel, iCId) { 149 | if (!cmd_access(pPlayer, iLevel, iCId, 1)) return PLUGIN_HANDLED; 150 | 151 | static szTarget[32]; read_argv(1, szTarget, charsmax(szTarget)); 152 | static szEffectId[32]; read_argv(2, szEffectId, charsmax(szEffectId)); 153 | static szValue[32]; read_argv(3, szValue, charsmax(szValue)); 154 | static szDuration[32]; read_argv(4, szDuration, charsmax(szDuration)); 155 | 156 | new iEffectId = -1; 157 | if (!TrieGetCell(g_itEffectsIds, szEffectId, iEffectId)) return PLUGIN_HANDLED; 158 | 159 | new iTarget = CMD_RESOLVE_TARGET(szTarget); 160 | new bool:bValue = equal(szValue, NULL_STRING) ? true : bool:str_to_num(szValue); 161 | new Float:flDuration = equal(szDuration, NULL_STRING) ? -1.0 : str_to_float(szDuration); 162 | 163 | for (new pTarget = 1; pTarget <= MaxClients; ++pTarget) { 164 | if (!CMD_SHOULD_TARGET_PLAYER(pTarget, iTarget, pPlayer)) continue; 165 | @Player_SetEffect(pTarget, iEffectId, bValue, flDuration, false); 166 | } 167 | 168 | return PLUGIN_HANDLED; 169 | } 170 | 171 | public HamHook_Player_Killed(pPlayer) { 172 | @Player_RevokeEffects(pPlayer); 173 | } 174 | 175 | public HamHook_Player_PostThink_Post(pPlayer) { 176 | static Float:flGameTime; flGameTime = get_gametime(); 177 | 178 | for (new iEffectId = 0; iEffectId < g_iEffectssNum; ++iEffectId) { 179 | static iPlayers; iPlayers = ArrayGetCell(g_rgPEffectData[PEffectData_Players], iEffectId); 180 | if (~iPlayers & BIT(pPlayer & 31)) continue; 181 | 182 | static Float:flEndTime; flEndTime = ArrayGetCell(g_rgPEffectData[PEffectData_PlayerEffectEnd], iEffectId, pPlayer); 183 | if (!flEndTime || flEndTime > flGameTime) continue; 184 | 185 | @Player_SetEffect(pPlayer, iEffectId, false, -1.0, true); 186 | } 187 | } 188 | 189 | /*--------------------------------[ Methods ]--------------------------------*/ 190 | 191 | bool:@Player_GetEffect(pPlayer, iEffectId) { 192 | new iPlayers = ArrayGetCell(g_rgPEffectData[PEffectData_Players], iEffectId); 193 | 194 | return !!(iPlayers & BIT(pPlayer & 31)); 195 | } 196 | 197 | bool:@Player_SetEffect(pPlayer, iEffectId, bool:bValue, Float:flDuration, bool:bExtend) { 198 | if (bValue && !is_user_alive(pPlayer)) return false; 199 | 200 | new iPlayers = ArrayGetCell(g_rgPEffectData[PEffectData_Players], iEffectId); 201 | new bool:bCurrentValue = !!(iPlayers & BIT(pPlayer & 31)); 202 | 203 | if (bValue == bCurrentValue && (!bValue || !bExtend)) return false; 204 | 205 | if (bValue) { 206 | ArraySetCell(g_rgPEffectData[PEffectData_Players], iEffectId, iPlayers | BIT(pPlayer & 31)); 207 | } else { 208 | ArraySetCell(g_rgPEffectData[PEffectData_Players], iEffectId, iPlayers & ~BIT(pPlayer & 31)); 209 | } 210 | 211 | new bool:bResult = ( 212 | bValue 213 | ? CallInvokeFunction(pPlayer, iEffectId, flDuration) 214 | : CallRevokeFunction(pPlayer, iEffectId) 215 | ); 216 | 217 | if (!bResult) { 218 | ArraySetCell(g_rgPEffectData[PEffectData_Players], iEffectId, iPlayers); 219 | return false; 220 | } 221 | 222 | if (bValue) { 223 | if (bCurrentValue && bExtend && flDuration >= 0.0) { 224 | new Float:flEndTime = ArrayGetCell(g_rgPEffectData[PEffectData_PlayerEffectEnd], iEffectId, pPlayer); 225 | if (flEndTime) { 226 | new Float:flPrevDuration = ArrayGetCell(g_rgPEffectData[PEffectData_PlayerEffectDuration], iEffectId, pPlayer); 227 | ArraySetCell(g_rgPEffectData[PEffectData_PlayerEffectEnd], iEffectId, flEndTime + flDuration, pPlayer); 228 | ArraySetCell(g_rgPEffectData[PEffectData_PlayerEffectDuration], iEffectId, flPrevDuration + flDuration, pPlayer); 229 | } 230 | } else { 231 | new Float:flEndTime = flDuration < 0.0 ? 0.0 : get_gametime() + flDuration; 232 | ArraySetCell(g_rgPEffectData[PEffectData_PlayerEffectEnd], iEffectId, flEndTime, pPlayer); 233 | ArraySetCell(g_rgPEffectData[PEffectData_PlayerEffectDuration], iEffectId, flDuration, pPlayer); 234 | } 235 | } 236 | 237 | static szIcon[32]; ArrayGetString(g_rgPEffectData[PEffectData_Icon], iEffectId, szIcon, charsmax(szIcon)); 238 | 239 | if (!equal(szIcon, NULL_STRING)) { 240 | new irgIconColor[3]; 241 | ArrayGetArray(g_rgPEffectData[PEffectData_IconColor], iEffectId, irgIconColor, sizeof(irgIconColor)); 242 | 243 | message_begin(MSG_ONE, gmsgStatusIcon, _, pPlayer); 244 | write_byte(bValue); 245 | write_string(szIcon); 246 | 247 | if (bValue) { 248 | write_byte(irgIconColor[0]); 249 | write_byte(irgIconColor[1]); 250 | write_byte(irgIconColor[2]); 251 | } 252 | 253 | message_end(); 254 | } 255 | 256 | return true; 257 | } 258 | 259 | @Player_RevokeEffects(pPlayer) { 260 | for (new iEffectId = 0; iEffectId < g_iEffectssNum; ++iEffectId) { 261 | @Player_SetEffect(pPlayer, iEffectId, false, -1.0, true); 262 | } 263 | } 264 | 265 | /*--------------------------------[ Functions ]--------------------------------*/ 266 | 267 | Register(const szId[], iInvokeFunctionId, iRevokeFunctionId, iPluginId, const szIcon[], const rgiIconColor[3]) { 268 | new iEffectId = g_iEffectssNum; 269 | 270 | ArrayPushString(g_rgPEffectData[PEffectData_Id], szId); 271 | ArrayPushCell(g_rgPEffectData[PEffectData_InvokeFunctionId], iInvokeFunctionId); 272 | ArrayPushCell(g_rgPEffectData[PEffectData_RevokeFunctionId], iRevokeFunctionId); 273 | ArrayPushCell(g_rgPEffectData[PEffectData_PluginId], iPluginId); 274 | ArrayPushString(g_rgPEffectData[PEffectData_Icon], szIcon); 275 | ArrayPushArray(g_rgPEffectData[PEffectData_IconColor], rgiIconColor); 276 | ArrayPushCell(g_rgPEffectData[PEffectData_Players], 0); 277 | ArrayPushCell(g_rgPEffectData[PEffectData_PlayerEffectEnd], 0); 278 | ArrayPushCell(g_rgPEffectData[PEffectData_PlayerEffectDuration], 0); 279 | 280 | TrieSetCell(g_itEffectsIds, szId, iEffectId); 281 | 282 | g_iEffectssNum++; 283 | 284 | return iEffectId; 285 | } 286 | 287 | bool:CallInvokeFunction(pPlayer, iEffectId, Float:flDuration) { 288 | new iPluginId = ArrayGetCell(g_rgPEffectData[PEffectData_PluginId], iEffectId); 289 | new iFunctionId = ArrayGetCell(g_rgPEffectData[PEffectData_InvokeFunctionId], iEffectId); 290 | 291 | callfunc_begin_i(iFunctionId, iPluginId); 292 | callfunc_push_int(pPlayer); 293 | callfunc_push_float(flDuration); 294 | new iResult = callfunc_end(); 295 | 296 | if (iResult >= PLUGIN_HANDLED) return false; 297 | 298 | return true; 299 | } 300 | 301 | bool:CallRevokeFunction(pPlayer, iEffectId) { 302 | new iPluginId = ArrayGetCell(g_rgPEffectData[PEffectData_PluginId], iEffectId); 303 | new iFunctionId = ArrayGetCell(g_rgPEffectData[PEffectData_RevokeFunctionId], iEffectId); 304 | 305 | callfunc_begin_i(iFunctionId, iPluginId); 306 | callfunc_push_int(pPlayer); 307 | new iResult = callfunc_end(); 308 | 309 | if (iResult >= PLUGIN_HANDLED) return false; 310 | 311 | return true; 312 | } 313 | -------------------------------------------------------------------------------- /api_player_inventory.sma: -------------------------------------------------------------------------------- 1 | #pragma semicolon 1 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | #include 8 | 9 | #define VAULT_NAME "api_player_inventory" 10 | #define VAULT_VERSION 1 11 | 12 | #define PLUGIN "[API] Player Inventory" 13 | #define VERSION "1.0.0" 14 | #define AUTHOR "Hedgehog Fog" 15 | 16 | enum InventorySlot { InventorySlot_Item, InventorySlot_Type[32] }; 17 | 18 | new g_fwInitialized; 19 | new g_fwLoad; 20 | new g_fwLoaded; 21 | new g_fwSave; 22 | new g_fwSaved; 23 | new g_fwSlotCreated; 24 | new g_fwSlotRemoved; 25 | new g_fwSlotLoad; 26 | new g_fwSlotLoaded; 27 | new g_fwSlotSave; 28 | new g_fwSlotSaved; 29 | 30 | new g_hVault; 31 | 32 | new g_rgszPlayerAuthId[MAX_PLAYERS + 1][32]; 33 | new Array:g_irgPlayerInventories[MAX_PLAYERS + 1] = { Invalid_Array, ... }; 34 | 35 | public plugin_precache() { 36 | g_hVault = OpenVault(); 37 | } 38 | 39 | public plugin_init() { 40 | register_plugin(PLUGIN, VERSION, AUTHOR); 41 | 42 | g_fwInitialized = CreateMultiForward("PlayerInventory_Fw_Initialized", ET_STOP, FP_CELL); 43 | g_fwLoad = CreateMultiForward("PlayerInventory_Fw_Load", ET_STOP, FP_CELL); 44 | g_fwLoaded = CreateMultiForward("PlayerInventory_Fw_Loaded", ET_IGNORE, FP_CELL); 45 | g_fwSave = CreateMultiForward("PlayerInventory_Fw_Save", ET_STOP, FP_CELL); 46 | g_fwSaved = CreateMultiForward("PlayerInventory_Fw_Saved", ET_IGNORE, FP_CELL); 47 | g_fwSlotCreated = CreateMultiForward("PlayerInventory_Fw_SlotCreated", ET_IGNORE, FP_CELL, FP_CELL); 48 | g_fwSlotRemoved = CreateMultiForward("PlayerInventory_Fw_SlotRemoved", ET_IGNORE, FP_CELL, FP_CELL); 49 | g_fwSlotLoad = CreateMultiForward("PlayerInventory_Fw_SlotLoad", ET_STOP, FP_CELL, FP_CELL); 50 | g_fwSlotLoaded = CreateMultiForward("PlayerInventory_Fw_SlotLoaded", ET_IGNORE, FP_CELL, FP_CELL); 51 | g_fwSlotSave = CreateMultiForward("PlayerInventory_Fw_SlotSave", ET_STOP, FP_CELL, FP_CELL); 52 | g_fwSlotSaved = CreateMultiForward("PlayerInventory_Fw_SlotSaved", ET_IGNORE, FP_CELL, FP_CELL); 53 | } 54 | 55 | public plugin_end() { 56 | nvault_close(g_hVault); 57 | } 58 | 59 | public plugin_natives() { 60 | register_library("api_player_inventory"); 61 | 62 | register_native("PlayerInventory_GetItem", "Native_GetItem"); 63 | register_native("PlayerInventory_CheckItemType", "Native_CheckItemType"); 64 | register_native("PlayerInventory_GetItemType", "Native_GetItemType"); 65 | register_native("PlayerInventory_GiveItem", "Native_GiveItem"); 66 | register_native("PlayerInventory_SetItem", "Native_SetItem"); 67 | register_native("PlayerInventory_TakeItem", "Native_TakeItem"); 68 | register_native("PlayerInventory_Size", "Native_Size"); 69 | } 70 | 71 | /*--------------------------------[ Natives ]--------------------------------*/ 72 | 73 | public Struct:Native_GetItem(iPluginId, iArgc) { 74 | new pPlayer = get_param(1); 75 | new iSlot = get_param(2); 76 | 77 | new Struct:sSlot = ArrayGetCell(g_irgPlayerInventories[pPlayer], iSlot); 78 | if (sSlot == Invalid_Struct) { 79 | return Invalid_Struct; 80 | } 81 | 82 | return StructGetCell(sSlot, InventorySlot_Item); 83 | } 84 | 85 | public bool:Native_CheckItemType(iPluginId, iArgc) { 86 | new pPlayer = get_param(1); 87 | new iSlot = get_param(2); 88 | 89 | static szType[32]; 90 | get_string(3, szType, charsmax(szType)); 91 | 92 | new Struct:sSlot = ArrayGetCell(g_irgPlayerInventories[pPlayer], iSlot); 93 | if (sSlot == Invalid_Struct) { 94 | return false; 95 | } 96 | 97 | static szSlotType[32]; 98 | StructGetString(sSlot, InventorySlot_Type, szSlotType, charsmax(szSlotType)); 99 | 100 | return !!equal(szType, szSlotType); 101 | } 102 | 103 | public bool:Native_GetItemType(iPluginId, iArgc) { 104 | new pPlayer = get_param(1); 105 | new iSlot = get_param(2); 106 | 107 | new Struct:sSlot = ArrayGetCell(g_irgPlayerInventories[pPlayer], iSlot); 108 | if (sSlot == Invalid_Struct) { 109 | return false; 110 | } 111 | 112 | static szType[32]; 113 | StructGetString(sSlot, InventorySlot_Type, szType, charsmax(szType)); 114 | 115 | set_string(3, szType, get_param(4)); 116 | 117 | return true; 118 | } 119 | 120 | public Native_GiveItem(iPluginId, iArgc) { 121 | new pPlayer = get_param(1); 122 | 123 | static szType[32]; 124 | get_string(2, szType, charsmax(szType)); 125 | 126 | new Struct:sItem = Struct:get_param(3); 127 | 128 | return @Player_GiveItem(pPlayer, szType, sItem); 129 | } 130 | 131 | public Native_SetItem(iPluginId, iArgc) { 132 | new pPlayer = get_param(1); 133 | new iSlot = get_param(2); 134 | 135 | static szType[32]; 136 | get_string(3, szType, charsmax(szType)); 137 | 138 | new Struct:sItem = Struct:get_param(4); 139 | 140 | @Player_SetItem(pPlayer, iSlot, szType, sItem); 141 | } 142 | 143 | public Native_TakeItem(iPluginId, iArgc) { 144 | new pPlayer = get_param(1); 145 | new iSlot = get_param(2); 146 | 147 | return @Player_TakeItem(pPlayer, iSlot); 148 | } 149 | 150 | public Native_Size(iPluginId, iArgc) { 151 | new pPlayer = get_param(1); 152 | 153 | return ArraySize(g_irgPlayerInventories[pPlayer]); 154 | } 155 | 156 | /*--------------------------------[ Forwards ]--------------------------------*/ 157 | 158 | public client_connect(pPlayer) { 159 | if (g_irgPlayerInventories[pPlayer] != Invalid_Array) { 160 | ArrayDestroy(g_irgPlayerInventories[pPlayer]); 161 | } 162 | 163 | g_irgPlayerInventories[pPlayer] = ArrayCreate(); 164 | 165 | ExecuteForward(g_fwInitialized, _, pPlayer); 166 | } 167 | 168 | public client_authorized(pPlayer) { 169 | get_user_authid(pPlayer, g_rgszPlayerAuthId[pPlayer], charsmax(g_rgszPlayerAuthId[])); 170 | LoadPlayerInventory(pPlayer); 171 | } 172 | 173 | public client_disconnected(pPlayer) { 174 | SavePlayerInventory(pPlayer); 175 | } 176 | 177 | /*--------------------------------[ Player Methods ]--------------------------------*/ 178 | 179 | @Player_GiveItem(this, const szType[], Struct:sItem) { 180 | new Struct:sSlot = @InventorySlot_Create(this, szType, sItem); 181 | 182 | static szSavedType[32]; 183 | StructGetString(sSlot, InventorySlot_Type, szSavedType, charsmax(szSavedType)); 184 | 185 | new iSlot = ArrayPushCell(g_irgPlayerInventories[this], sSlot); 186 | ExecuteForward(g_fwSlotCreated, _, this, iSlot); 187 | 188 | return iSlot; 189 | } 190 | 191 | @Player_SetItem(this, iSlot, const szType[], Struct:sItem) { 192 | new Struct:sSlot = ArrayGetCell(g_irgPlayerInventories[this], iSlot); 193 | if (sSlot == Invalid_Struct) { 194 | sSlot = @InventorySlot_Create(this, szType, sItem); 195 | } else { 196 | StructSetString(sSlot, InventorySlot_Type, szType); 197 | StructSetCell(sSlot, InventorySlot_Item, sItem); 198 | } 199 | } 200 | 201 | @Player_TakeItem(this, iSlot) { 202 | new Struct:sSlot = ArrayGetCell(g_irgPlayerInventories[this], iSlot); 203 | if (sSlot == Invalid_Struct) { 204 | return false; 205 | } 206 | 207 | static iResult; 208 | ExecuteForward(g_fwSlotRemoved, iResult, this, iSlot); 209 | 210 | if (iResult != PLUGIN_CONTINUE) { 211 | return false; 212 | } 213 | 214 | @InventorySlot_Destroy(sSlot); 215 | ArraySetCell(g_irgPlayerInventories[this], iSlot, Invalid_Struct); 216 | 217 | return true; 218 | } 219 | 220 | /*--------------------------------[ Inventory Methods ]--------------------------------*/ 221 | 222 | Struct:@InventorySlot_Create(pPlayer, const szType[], Struct:sItem) { 223 | new Struct:this = StructCreate(InventorySlot); 224 | StructSetString(this, InventorySlot_Type, szType); 225 | StructSetCell(this, InventorySlot_Item, sItem); 226 | 227 | return this; 228 | } 229 | 230 | @InventorySlot_Destroy(&Struct:this) { 231 | StructDestroy(this); 232 | } 233 | 234 | /*--------------------------------[ Vault ]--------------------------------*/ 235 | 236 | OpenVault() { 237 | new szVaultDir[256]; 238 | get_datadir(szVaultDir, charsmax(szVaultDir)); 239 | format(szVaultDir, charsmax(szVaultDir), "%s/vault", szVaultDir); 240 | 241 | static szVaultFilePath[256]; 242 | format(szVaultFilePath, charsmax(szVaultFilePath), "%s/%s.vault", szVaultDir, VAULT_NAME); 243 | 244 | new bool:bNew = true; 245 | 246 | if (file_exists(szVaultFilePath)) { 247 | new hVault = nvault_open(VAULT_NAME); 248 | new iVersion = nvault_get(hVault, "_version"); 249 | nvault_close(hVault); 250 | 251 | if (iVersion < VAULT_VERSION) { 252 | log_amx("Invalid vault file. The vault file will be replaced!"); 253 | 254 | static szBacukupVaultFilePath[256]; 255 | format(szBacukupVaultFilePath, charsmax(szBacukupVaultFilePath), "%s/%s.vault.backup%d", szVaultDir, VAULT_NAME, get_systime()); 256 | 257 | rename_file(szVaultFilePath, szBacukupVaultFilePath, 1); 258 | } else { 259 | bNew = false; 260 | } 261 | } 262 | 263 | new hVault = nvault_open(VAULT_NAME); 264 | 265 | if (bNew) { 266 | static szVersion[4]; 267 | num_to_str(VAULT_VERSION, szVersion, charsmax(szVersion)); 268 | nvault_pset(hVault, "_version", szVersion); 269 | } 270 | 271 | return hVault; 272 | } 273 | 274 | LoadPlayerInventory(pPlayer) { 275 | if (g_rgszPlayerAuthId[pPlayer][0] == '^0') { 276 | return; 277 | } 278 | 279 | static iLoadResult; 280 | ExecuteForward(g_fwLoad, iLoadResult, pPlayer); 281 | if (iLoadResult != PLUGIN_CONTINUE) { 282 | return; 283 | } 284 | 285 | ArrayClear(g_irgPlayerInventories[pPlayer]); 286 | 287 | new szKey[32]; 288 | new szValue[1024]; 289 | 290 | format(szKey, charsmax(szKey), "%s_size", g_rgszPlayerAuthId[pPlayer]); 291 | new iInventorySize = nvault_get(g_hVault, szKey); 292 | 293 | //Save items 294 | for (new iSlot = 0; iSlot < iInventorySize; ++iSlot) { 295 | static iSlotLoadResult; 296 | ExecuteForward(g_fwSlotLoad, iSlotLoadResult, pPlayer, iSlot); 297 | if (iSlotLoadResult != PLUGIN_CONTINUE) { 298 | continue; 299 | } 300 | 301 | // item type 302 | format(szKey, charsmax(szKey), "%s_item_%i_type", g_rgszPlayerAuthId[pPlayer], iSlot); 303 | 304 | new szType[32]; 305 | nvault_get(g_hVault, szKey, szType, charsmax(szType)); 306 | 307 | // item struct 308 | format(szKey, charsmax(szKey), "%s_item_%i", g_rgszPlayerAuthId[pPlayer], iSlot); 309 | nvault_get(g_hVault, szKey, szValue, charsmax(szValue)); 310 | new Struct:sItem = StructFromString(sItem, szValue); 311 | 312 | @Player_GiveItem(pPlayer, szType, sItem); 313 | 314 | ExecuteForward(g_fwSlotLoaded, _, pPlayer, iSlot); 315 | } 316 | 317 | ExecuteForward(g_fwLoaded, _, pPlayer); 318 | } 319 | 320 | SavePlayerInventory(pPlayer) { 321 | if (g_rgszPlayerAuthId[pPlayer][0] == '^0') { 322 | return; 323 | } 324 | 325 | new Array:irgInventory = g_irgPlayerInventories[pPlayer]; 326 | 327 | new iInventorySize = ArraySize(irgInventory); 328 | if (!iInventorySize) { 329 | return; 330 | } 331 | 332 | new iSaveResult = 0; 333 | ExecuteForward(g_fwSave, iSaveResult, pPlayer); 334 | if (iSaveResult != PLUGIN_CONTINUE) { 335 | return; 336 | } 337 | 338 | new szKey[32]; 339 | new szValue[1024]; 340 | 341 | //Save items 342 | new iNewInventorySize = 0; 343 | for (new iSlot = 0; iSlot < iInventorySize; ++iSlot) { 344 | new Struct:sSlot = ArrayGetCell(irgInventory, iSlot); 345 | 346 | if (sSlot == Invalid_Struct) { 347 | continue; 348 | } 349 | 350 | static iSlotSaveResult; 351 | ExecuteForward(g_fwSlotSave, iSlotSaveResult, pPlayer, iSlot); 352 | if (iSlotSaveResult != PLUGIN_CONTINUE) { 353 | continue; 354 | } 355 | 356 | new Struct:sItem = StructGetCell(sSlot, InventorySlot_Item); 357 | 358 | // item type 359 | format(szKey, charsmax(szKey), "%s_item_%i_type", g_rgszPlayerAuthId[pPlayer], iNewInventorySize); 360 | StructGetString(sSlot, InventorySlot_Type, szValue, charsmax(szValue)); 361 | nvault_set(g_hVault, szKey, szValue); 362 | 363 | // item struct 364 | format(szKey, charsmax(szKey), "%s_item_%i", g_rgszPlayerAuthId[pPlayer], iNewInventorySize); 365 | StructStringify(sItem, szValue, charsmax(szValue)); 366 | nvault_set(g_hVault, szKey, szValue); 367 | 368 | iNewInventorySize++; 369 | 370 | ExecuteForward(g_fwSlotSaved, _, pPlayer, iSlot); 371 | } 372 | 373 | for (new iSlot = iNewInventorySize; iSlot < iInventorySize; ++iSlot) { 374 | format(szKey, charsmax(szKey), "%s_item_%i", g_rgszPlayerAuthId[pPlayer], iSlot); 375 | nvault_remove(g_hVault, szKey); 376 | 377 | format(szKey, charsmax(szKey), "%s_item_%i_type", g_rgszPlayerAuthId[pPlayer], iSlot); 378 | nvault_remove(g_hVault, szKey); 379 | } 380 | 381 | // save inventory size 382 | format(szKey, charsmax(szKey), "%s_size", g_rgszPlayerAuthId[pPlayer]); 383 | format(szValue, charsmax(szValue), "%i", iNewInventorySize); 384 | 385 | nvault_set(g_hVault, szKey, szValue); 386 | 387 | ExecuteForward(g_fwSaved, _, pPlayer); 388 | } 389 | -------------------------------------------------------------------------------- /api_player_model.sma: -------------------------------------------------------------------------------- 1 | #pragma semicolon 1 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #tryinclude 8 | 9 | #define PLUGIN "[API] Player Model" 10 | #define VERSION "1.0.1" 11 | #define AUTHOR "Hedgehog Fog" 12 | 13 | #define NATIVE_ERROR_NOT_CONNECTED(%1) log_error(AMX_ERR_NATIVE, "User %d is not connected", %1) 14 | 15 | #define MAX_SEQUENCES 101 16 | 17 | new g_iszSubModelClassname; 18 | 19 | new bool:g_bIsCStrike; 20 | 21 | new g_rgszDefaultPlayerModel[MAX_PLAYERS + 1][32]; 22 | new g_rgszCurrentPlayerModel[MAX_PLAYERS + 1][256]; 23 | new g_rgszCustomPlayerModel[MAX_PLAYERS + 1][256]; 24 | new g_rgiPlayerAnimationIndex[MAX_PLAYERS + 1]; 25 | new g_rgpPlayerSubModel[MAX_PLAYERS + 1]; 26 | new bool:g_rgbPlayerUseCustomModel[MAX_PLAYERS + 1]; 27 | 28 | new Trie:g_itPlayerSequenceModelIndexes = Invalid_Trie; 29 | new Trie:g_itPlayerSequences = Invalid_Trie; 30 | 31 | public plugin_precache() { 32 | g_bIsCStrike = !!cstrike_running(); 33 | g_iszSubModelClassname = engfunc(EngFunc_AllocString, "info_target"); 34 | g_itPlayerSequenceModelIndexes = TrieCreate(); 35 | g_itPlayerSequences = TrieCreate(); 36 | } 37 | 38 | public plugin_init() { 39 | register_plugin(PLUGIN, VERSION, AUTHOR); 40 | 41 | register_forward(FM_SetClientKeyValue, "FMHook_SetClientKeyValue"); 42 | 43 | RegisterHamPlayer(Ham_Spawn, "HamHook_Player_Spawn_Post", .Post = 1); 44 | RegisterHamPlayer(Ham_Player_PostThink, "HamHook_Player_PostThink_Post", .Post = 1); 45 | 46 | #if defined _reapi_included 47 | RegisterHookChain(RG_CBasePlayer_SetAnimation, "HC_Player_SetAnimation"); 48 | #endif 49 | 50 | register_message(get_user_msgid("ClCorpse"), "Message_ClCorpse"); 51 | } 52 | 53 | public plugin_natives() { 54 | register_library("api_player_model"); 55 | register_native("PlayerModel_Get", "Native_GetPlayerModel"); 56 | register_native("PlayerModel_GetCurrent", "Native_GetCurrentPlayerModel"); 57 | register_native("PlayerModel_GetEntity", "Native_GetPlayerEntity"); 58 | register_native("PlayerModel_HasCustom", "Native_HasCustomPlayerModel"); 59 | register_native("PlayerModel_Set", "Native_SetPlayerModel"); 60 | register_native("PlayerModel_Reset", "Native_ResetPlayerModel"); 61 | register_native("PlayerModel_Update", "Native_UpdatePlayerModel"); 62 | register_native("PlayerModel_UpdateAnimation", "Native_UpdatePlayerAnimation"); 63 | register_native("PlayerModel_SetSequence", "Native_SetPlayerSequence"); 64 | register_native("PlayerModel_PrecacheAnimation", "Native_PrecacheAnimation"); 65 | } 66 | 67 | public plugin_end() { 68 | TrieDestroy(g_itPlayerSequenceModelIndexes); 69 | TrieDestroy(g_itPlayerSequences); 70 | } 71 | 72 | // ANCHOR: Natives 73 | 74 | public Native_GetPlayerModel(iPluginId, iArgc) { 75 | new pPlayer = get_param(1); 76 | 77 | if (!is_user_connected(pPlayer)) { 78 | NATIVE_ERROR_NOT_CONNECTED(pPlayer); 79 | } 80 | 81 | set_string(2, g_rgszCustomPlayerModel[pPlayer], get_param(3)); 82 | } 83 | 84 | public Native_GetCurrentPlayerModel(iPluginId, iArgc) { 85 | new pPlayer = get_param(1); 86 | 87 | if (!is_user_connected(pPlayer)) { 88 | NATIVE_ERROR_NOT_CONNECTED(pPlayer); 89 | } 90 | 91 | set_string(2, g_rgszCurrentPlayerModel[pPlayer], get_param(3)); 92 | } 93 | 94 | public Native_GetPlayerEntity(iPluginId, iArgc) { 95 | new pPlayer = get_param(1); 96 | 97 | if (!is_user_connected(pPlayer)) { 98 | NATIVE_ERROR_NOT_CONNECTED(pPlayer); 99 | } 100 | 101 | if (g_rgpPlayerSubModel[pPlayer] && @PlayerSubModel_IsActive(g_rgpPlayerSubModel[pPlayer])) { 102 | return g_rgpPlayerSubModel[pPlayer]; 103 | } 104 | 105 | return pPlayer; 106 | } 107 | 108 | public bool:Native_HasCustomPlayerModel(iPluginId, iArgc) { 109 | new pPlayer = get_param(1); 110 | 111 | if (!is_user_connected(pPlayer)) { 112 | NATIVE_ERROR_NOT_CONNECTED(pPlayer); 113 | } 114 | 115 | return g_rgbPlayerUseCustomModel[pPlayer]; 116 | } 117 | 118 | public Native_SetPlayerModel(iPluginId, iArgc) { 119 | new pPlayer = get_param(1); 120 | 121 | if (!is_user_connected(pPlayer)) { 122 | NATIVE_ERROR_NOT_CONNECTED(pPlayer); 123 | } 124 | 125 | get_string(2, g_rgszCustomPlayerModel[pPlayer], charsmax(g_rgszCustomPlayerModel[])); 126 | } 127 | 128 | public Native_ResetPlayerModel(iPluginId, iArgc) { 129 | new pPlayer = get_param(1); 130 | 131 | if (!is_user_connected(pPlayer)) { 132 | NATIVE_ERROR_NOT_CONNECTED(pPlayer); 133 | } 134 | 135 | @Player_ResetModel(pPlayer); 136 | } 137 | 138 | public Native_UpdatePlayerModel(iPluginId, iArgc) { 139 | new pPlayer = get_param(1); 140 | 141 | if (!is_user_connected(pPlayer)) { 142 | NATIVE_ERROR_NOT_CONNECTED(pPlayer); 143 | } 144 | 145 | @Player_UpdateCurrentModel(pPlayer); 146 | } 147 | 148 | public Native_UpdatePlayerAnimation(iPluginId, iArgc) { 149 | new pPlayer = get_param(1); 150 | 151 | if (!is_user_connected(pPlayer)) { 152 | NATIVE_ERROR_NOT_CONNECTED(pPlayer); 153 | } 154 | 155 | @Player_UpdateAnimationModel(pPlayer); 156 | } 157 | 158 | public Native_SetPlayerSequence(iPluginId, iArgc) { 159 | new pPlayer = get_param(1); 160 | 161 | if (!is_user_connected(pPlayer)) { 162 | NATIVE_ERROR_NOT_CONNECTED(pPlayer); 163 | } 164 | 165 | static szSequence[MAX_RESOURCE_PATH_LENGTH]; 166 | get_string(2, szSequence, charsmax(szSequence)); 167 | 168 | return @Player_SetSequence(pPlayer, szSequence); 169 | } 170 | 171 | public Native_PrecacheAnimation(iPluginId, iArgc) { 172 | static szAnimation[MAX_RESOURCE_PATH_LENGTH]; 173 | get_string(1, szAnimation, charsmax(szAnimation)); 174 | return PrecachePlayerAnimation(szAnimation); 175 | } 176 | 177 | // ANCHOR: Hooks and Forwards 178 | 179 | public client_connect(pPlayer) { 180 | copy(g_rgszCustomPlayerModel[pPlayer], charsmax(g_rgszCustomPlayerModel[]), NULL_STRING); 181 | copy(g_rgszDefaultPlayerModel[pPlayer], charsmax(g_rgszDefaultPlayerModel[]), NULL_STRING); 182 | copy(g_rgszCurrentPlayerModel[pPlayer], charsmax(g_rgszCurrentPlayerModel[]), NULL_STRING); 183 | g_rgiPlayerAnimationIndex[pPlayer] = 0; 184 | g_rgbPlayerUseCustomModel[pPlayer] = false; 185 | } 186 | 187 | public client_disconnected(pPlayer) { 188 | if (g_rgpPlayerSubModel[pPlayer]) { 189 | @PlayerSubModel_Destroy(g_rgpPlayerSubModel[pPlayer]); 190 | g_rgpPlayerSubModel[pPlayer] = 0; 191 | } 192 | } 193 | 194 | public FMHook_SetClientKeyValue(pPlayer, const szInfoBuffer[], const szKey[], const szValue[]) { 195 | if (equal(szKey, "model")) { 196 | copy(g_rgszDefaultPlayerModel[pPlayer], charsmax(g_rgszDefaultPlayerModel[]), szValue); 197 | 198 | if (@Player_ShouldUseCurrentModel(pPlayer)) { 199 | return FMRES_SUPERCEDE; 200 | } 201 | 202 | return FMRES_HANDLED; 203 | } 204 | 205 | return FMRES_IGNORED; 206 | } 207 | 208 | public HamHook_Player_Spawn_Post(pPlayer) { 209 | @Player_UpdateCurrentModel(pPlayer); 210 | 211 | return HAM_HANDLED; 212 | } 213 | 214 | public HamHook_Player_PostThink_Post(pPlayer) { 215 | if (g_rgpPlayerSubModel[pPlayer]) { 216 | @PlayerSubModel_Think(g_rgpPlayerSubModel[pPlayer]); 217 | } 218 | 219 | if (@Player_ShouldUseCurrentModel(pPlayer)) { 220 | static szModel[MAX_RESOURCE_PATH_LENGTH]; 221 | get_user_info(pPlayer, "model", szModel, charsmax(szModel)); 222 | 223 | if (!equal(szModel, NULL_STRING)) { 224 | set_user_info(pPlayer, "model", ""); 225 | } 226 | } 227 | 228 | if (!g_bIsCStrike) { 229 | static szModel[MAX_RESOURCE_PATH_LENGTH]; 230 | get_user_info(pPlayer, "model", szModel, charsmax(szModel)); 231 | if (!equal(szModel, NULL_STRING)) { 232 | copy(g_rgszDefaultPlayerModel[pPlayer], charsmax(g_rgszDefaultPlayerModel[]), szModel); 233 | } 234 | 235 | @Player_UpdateModel(pPlayer, false); 236 | } 237 | 238 | return HAM_HANDLED; 239 | } 240 | 241 | #if defined _reapi_included 242 | public HC_Player_SetAnimation(pPlayer) { 243 | @Player_UpdateAnimationModel(pPlayer); 244 | } 245 | #endif 246 | 247 | public Message_ClCorpse(iMsgId, iMsgDest, pPlayer) { 248 | new pTargetPlayer = get_msg_arg_int(12); 249 | if (@Player_ShouldUseCurrentModel(pTargetPlayer)) { 250 | set_msg_arg_string(1, g_rgszCurrentPlayerModel[pTargetPlayer]); 251 | } 252 | } 253 | 254 | // ANCHOR: Methods 255 | 256 | @Player_UpdateAnimationModel(this) { 257 | new iAnimationIndex = 0; 258 | 259 | if (is_user_alive(this)) { 260 | static szAnimExt[32]; get_ent_data_string(this, "CBasePlayer", "m_szAnimExtention", szAnimExt, charsmax(szAnimExt)); 261 | iAnimationIndex = GetAnimationIndexByAnimExt(szAnimExt); 262 | } 263 | 264 | if (iAnimationIndex != g_rgiPlayerAnimationIndex[this]) { 265 | g_rgiPlayerAnimationIndex[this] = iAnimationIndex; 266 | @Player_UpdateModel(this, !iAnimationIndex); 267 | } 268 | } 269 | 270 | @Player_UpdateCurrentModel(this) { 271 | new bool:bUsedCustom = g_rgbPlayerUseCustomModel[this]; 272 | new bool:bSetDefaultModel = false; 273 | new bool:bReset = !!equal(g_rgszCurrentPlayerModel[this], NULL_STRING); 274 | 275 | g_rgbPlayerUseCustomModel[this] = !equal(g_rgszCustomPlayerModel[this], NULL_STRING); 276 | 277 | if (g_rgbPlayerUseCustomModel[this]) { 278 | copy(g_rgszCurrentPlayerModel[this], charsmax(g_rgszCurrentPlayerModel[]), g_rgszCustomPlayerModel[this]); 279 | } else if (!equal(g_rgszDefaultPlayerModel[this], NULL_STRING)) { 280 | format(g_rgszCurrentPlayerModel[this], charsmax(g_rgszCurrentPlayerModel[]), "models/player/%s/%s.mdl", g_rgszDefaultPlayerModel[this], g_rgszDefaultPlayerModel[this]); 281 | bSetDefaultModel = true; 282 | } 283 | 284 | if (!g_bIsCStrike && bSetDefaultModel) { 285 | set_user_info(this, "model", g_rgszDefaultPlayerModel[this]); 286 | } else { 287 | @Player_UpdateModel(this, bReset || bUsedCustom && !g_rgbPlayerUseCustomModel[this]); 288 | } 289 | } 290 | 291 | @Player_UpdateModel(this, bool:bForceUpdate) { 292 | new iSubModelModelIndex = 0; 293 | 294 | if (bForceUpdate || @Player_ShouldUseCurrentModel(this)) { 295 | new iAnimationIndex = g_rgiPlayerAnimationIndex[this]; 296 | new iModelIndex = engfunc(EngFunc_ModelIndex, g_rgszCurrentPlayerModel[this]); 297 | @Player_SetModelIndex(this, iAnimationIndex ? iAnimationIndex : iModelIndex); 298 | iSubModelModelIndex = iAnimationIndex ? iModelIndex : 0; 299 | } 300 | 301 | if (iSubModelModelIndex && !g_rgpPlayerSubModel[this]) { 302 | g_rgpPlayerSubModel[this] = @PlayerSubModel_Create(this); 303 | } 304 | 305 | if (g_rgpPlayerSubModel[this]) { 306 | set_pev(g_rgpPlayerSubModel[this], pev_modelindex, iSubModelModelIndex); 307 | } 308 | } 309 | 310 | bool:@Player_ShouldUseCurrentModel(this) { 311 | return g_rgbPlayerUseCustomModel[this] || g_rgiPlayerAnimationIndex[this]; 312 | } 313 | 314 | @Player_ResetModel(this) { 315 | if (equal(g_rgszDefaultPlayerModel[this], NULL_STRING)) { 316 | return; 317 | } 318 | 319 | copy(g_rgszCustomPlayerModel[this], charsmax(g_rgszCustomPlayerModel[]), NULL_STRING); 320 | copy(g_rgszCurrentPlayerModel[this], charsmax(g_rgszCurrentPlayerModel[]), NULL_STRING); 321 | g_rgiPlayerAnimationIndex[this] = 0; 322 | 323 | @Player_UpdateCurrentModel(this); 324 | } 325 | 326 | @Player_SetModelIndex(this, iModelIndex) { 327 | set_user_info(this, "model", ""); 328 | set_pev(this, pev_modelindex, iModelIndex); 329 | 330 | if (g_bIsCStrike) { 331 | set_ent_data(this, "CBasePlayer", "m_modelIndexPlayer", iModelIndex); 332 | } 333 | } 334 | 335 | @Player_SetSequence(this, const szSequence[]) { 336 | new iAnimationIndex = GetAnimationIndexBySequence(szSequence); 337 | if (!iAnimationIndex) { 338 | return -1; 339 | } 340 | 341 | g_rgiPlayerAnimationIndex[this] = iAnimationIndex; 342 | @Player_UpdateModel(this, false); 343 | 344 | new iSequence = GetSequenceIndex(szSequence); 345 | set_pev(this, pev_sequence, iSequence); 346 | return iSequence; 347 | } 348 | 349 | @PlayerSubModel_Create(pPlayer) { 350 | new this = engfunc(EngFunc_CreateNamedEntity, g_iszSubModelClassname); 351 | set_pev(this, pev_movetype, MOVETYPE_FOLLOW); 352 | set_pev(this, pev_aiment, pPlayer); 353 | set_pev(this, pev_owner, pPlayer); 354 | 355 | return this; 356 | } 357 | 358 | @PlayerSubModel_Destroy(this) { 359 | set_pev(this, pev_modelindex, 0); 360 | set_pev(this, pev_flags, pev(this, pev_flags) | FL_KILLME); 361 | dllfunc(DLLFunc_Think, this); 362 | } 363 | 364 | @PlayerSubModel_Think(this) { 365 | if (!@PlayerSubModel_IsActive(this)) { 366 | set_pev(this, pev_effects, pev(this, pev_effects) | EF_NODRAW); 367 | return; 368 | } 369 | 370 | new pOwner = pev(this, pev_owner); 371 | 372 | set_pev(this, pev_skin, pev(pOwner, pev_skin)); 373 | set_pev(this, pev_body, pev(pOwner, pev_body)); 374 | set_pev(this, pev_colormap, pev(pOwner, pev_colormap)); 375 | set_pev(this, pev_rendermode, pev(pOwner, pev_rendermode)); 376 | set_pev(this, pev_renderfx, pev(pOwner, pev_renderfx)); 377 | set_pev(this, pev_effects, pev(this, pev_effects) & ~EF_NODRAW); 378 | 379 | static Float:flRenderAmt; pev(pOwner, pev_renderamt, flRenderAmt); 380 | set_pev(this, pev_renderamt, flRenderAmt); 381 | 382 | static rgflColor[3]; pev(pOwner, pev_rendercolor, rgflColor); 383 | set_pev(this, pev_rendercolor, rgflColor); 384 | } 385 | 386 | @PlayerSubModel_IsActive(this) { 387 | return (pev(this, pev_modelindex) > 0); 388 | } 389 | 390 | // ANCHOR: Functions 391 | 392 | GetAnimationIndexByAnimExt(const szAnimExt[]) { 393 | if (equal(szAnimExt, NULL_STRING)) return 0; 394 | 395 | static szSequence[32]; format(szSequence, charsmax(szSequence), "ref_aim_%s", szAnimExt); 396 | 397 | return GetAnimationIndexBySequence(szSequence); 398 | } 399 | 400 | GetAnimationIndexBySequence(const szSequence[]) { 401 | static iAnimationIndex; 402 | if (!TrieGetCell(g_itPlayerSequenceModelIndexes, szSequence, iAnimationIndex)) { 403 | return 0; 404 | } 405 | 406 | return iAnimationIndex; 407 | } 408 | 409 | GetSequenceIndex(const szSequence[]) { 410 | static iSequence; 411 | if (!TrieGetCell(g_itPlayerSequences, szSequence, iSequence)) { 412 | return -1; 413 | } 414 | 415 | return iSequence; 416 | } 417 | 418 | // Credis: HamletEagle 419 | PrecachePlayerAnimation(const szAnim[]) { 420 | new szFilePath[MAX_RESOURCE_PATH_LENGTH]; 421 | format(szFilePath, charsmax(szFilePath), "animations/%s", szAnim); 422 | 423 | new iModelIndex = precache_model(szFilePath); 424 | 425 | new iFile = fopen(szFilePath, "rb"); 426 | if (!iFile) { 427 | return 0; 428 | } 429 | 430 | // Got to "numseq" position of the studiohdr_t structure 431 | // https://github.com/dreamstalker/rehlds/blob/65c6ce593b5eabf13e92b03352e4b429d0d797b0/rehlds/public/rehlds/studio.h#L68 432 | fseek(iFile, 164, SEEK_SET); 433 | 434 | new iSeqNum; 435 | fread(iFile, iSeqNum, BLOCK_INT); 436 | 437 | if (!iSeqNum) { 438 | return 0; 439 | } 440 | 441 | new iSeqIndex; 442 | fread(iFile, iSeqIndex, BLOCK_INT); 443 | fseek(iFile, iSeqIndex, SEEK_SET); 444 | 445 | new szLabel[32]; 446 | for (new i = 0; i < iSeqNum; i++) { 447 | if (i >= MAX_SEQUENCES) { 448 | log_amx("Warning! Sequence limit reached for ^"%s^". Max sequences %d.", szFilePath, MAX_SEQUENCES); 449 | break; 450 | } 451 | 452 | fread_blocks(iFile, szLabel, sizeof(szLabel), BLOCK_CHAR); 453 | TrieSetCell(g_itPlayerSequenceModelIndexes, szLabel, iModelIndex); 454 | TrieSetCell(g_itPlayerSequences, szLabel, i); 455 | 456 | // jump to the end of the studiohdr_t structure 457 | // https://github.com/dreamstalker/rehlds/blob/65c6ce593b5eabf13e92b03352e4b429d0d797b0/rehlds/public/rehlds/studio.h#L95 458 | fseek(iFile, 176 - sizeof(szLabel), SEEK_CUR); 459 | } 460 | 461 | fclose(iFile); 462 | 463 | return iModelIndex; 464 | } 465 | -------------------------------------------------------------------------------- /api_player_viewrange.sma: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #define PLUGIN "[API] Player View Range" 4 | #define VERSION "0.9.0" 5 | #define AUTHOR "Hedgehog Fog" 6 | 7 | new Float:g_rgflPlayerViewRange[MAX_PLAYERS + 1]; 8 | new g_rgiPlayerNativeFogColor[MAX_PLAYERS + 1][3]; 9 | new Float:g_flPlayerNativeFogDensity[MAX_PLAYERS + 1]; 10 | 11 | new gmsgFog; 12 | 13 | public plugin_init() { 14 | register_plugin(PLUGIN, VERSION, AUTHOR); 15 | 16 | gmsgFog = get_user_msgid("Fog"); 17 | 18 | register_message(gmsgFog, "Message_Fog"); 19 | } 20 | 21 | public plugin_natives() { 22 | register_library("api_player_viewrange"); 23 | register_native("PlayerViewRange_Get", "Native_GetPlayerViewRange"); 24 | register_native("PlayerViewRange_Set", "Native_SetPlayerViewRange"); 25 | register_native("PlayerViewRange_Reset", "Native_ResetPlayerViewRange"); 26 | register_native("PlayerViewRange_Update", "Native_UpdatePlayerViewRange"); 27 | } 28 | 29 | public Float:Native_GetPlayerViewRange(iPluginId, iArgc) { 30 | new pPlayer = get_param(1); 31 | 32 | return g_rgflPlayerViewRange[pPlayer]; 33 | } 34 | 35 | public Native_SetPlayerViewRange(iPluginId, iArgc) { 36 | new pPlayer = get_param(1); 37 | new Float:flValue = get_param_f(2); 38 | 39 | @Player_SetViewRange(pPlayer, flValue); 40 | } 41 | 42 | public Native_ResetPlayerViewRange(iPluginId, iArgc) { 43 | new pPlayer = get_param(1); 44 | 45 | @Player_SetViewRange(pPlayer, -1.0); 46 | } 47 | 48 | public Native_UpdatePlayerViewRange(iPluginId, iArgc) { 49 | new pPlayer = get_param(1); 50 | 51 | @Player_UpdateViewRange(pPlayer); 52 | } 53 | 54 | public client_connect(pPlayer) { 55 | g_rgflPlayerViewRange[pPlayer] = 0.0; 56 | g_rgiPlayerNativeFogColor[pPlayer][0] = 0; 57 | g_rgiPlayerNativeFogColor[pPlayer][1] = 0; 58 | g_rgiPlayerNativeFogColor[pPlayer][2] = 0; 59 | g_flPlayerNativeFogDensity[pPlayer] = 0.0; 60 | } 61 | 62 | public Message_Fog(iMsgId, iMsgDest, pPlayer) { 63 | g_rgiPlayerNativeFogColor[pPlayer][0] = get_msg_arg_int(1); 64 | g_rgiPlayerNativeFogColor[pPlayer][1] = get_msg_arg_int(2); 65 | g_rgiPlayerNativeFogColor[pPlayer][2] = get_msg_arg_int(3); 66 | g_flPlayerNativeFogDensity[pPlayer] = Float:( 67 | get_msg_arg_int(4) | 68 | (get_msg_arg_int(5) << 8) | 69 | (get_msg_arg_int(6) << 16) | 70 | (get_msg_arg_int(7) << 24) 71 | ); 72 | } 73 | 74 | public @Player_SetViewRange(this, Float:flViewRange) { 75 | if (g_rgflPlayerViewRange[this] == flViewRange) { 76 | return; 77 | } 78 | 79 | g_rgflPlayerViewRange[this] = flViewRange; 80 | 81 | @Player_UpdateViewRange(this); 82 | } 83 | 84 | public @Player_UpdateViewRange(this) { 85 | if (g_rgflPlayerViewRange[this] >= 0.0) { 86 | new Float:flDensity = g_rgflPlayerViewRange[this] < 0 ? 0.0 : (1.0 / g_rgflPlayerViewRange[this]); 87 | 88 | message_begin(MSG_ONE, gmsgFog, {0, 0, 0}, this); 89 | write_byte(0); 90 | write_byte(0); 91 | write_byte(0); 92 | write_long(_:flDensity); 93 | message_end(); 94 | } else { // reset to engine fog 95 | message_begin(MSG_ONE, gmsgFog, {0, 0, 0}, this); 96 | write_byte(g_rgiPlayerNativeFogColor[this][0]); 97 | write_byte(g_rgiPlayerNativeFogColor[this][1]); 98 | write_byte(g_rgiPlayerNativeFogColor[this][2]); 99 | write_long(_:g_flPlayerNativeFogDensity[this]); 100 | message_end(); 101 | } 102 | } 103 | -------------------------------------------------------------------------------- /api_rounds.sma: -------------------------------------------------------------------------------- 1 | #pragma semicolon 1 2 | 3 | #include 4 | #include 5 | 6 | enum GameState { 7 | GameState_NewRound, 8 | GameState_RoundStarted, 9 | GameState_RoundEnd 10 | }; 11 | 12 | enum _:Hook { 13 | Hook_PluginId, 14 | Hook_FunctionId 15 | }; 16 | 17 | new GameState:g_iGameState; 18 | 19 | new g_iFwNewRound; 20 | new g_iFwRoundStart; 21 | new g_iFwRoundEnd; 22 | new g_iFwRoundExpired; 23 | new g_iFwRoundRestart; 24 | new g_iFwRoundTimerTick; 25 | new g_iFwCheckWinConditions; 26 | 27 | new Array:g_irgCheckWinConditionHooks; 28 | 29 | new g_pCvarRoundEndDelay; 30 | 31 | public plugin_init() { 32 | register_plugin("[API] Rounds", "2.1.0", "Hedgehog Fog"); 33 | 34 | register_event("HLTV", "Event_NewRound", "a", "1=0", "2=0"); 35 | RegisterHookChain(RG_CSGameRules_RestartRound, "HC_RestartRound", .post = 0); 36 | RegisterHookChain(RG_CSGameRules_OnRoundFreezeEnd, "HC_OnRoundFreezeEnd_Post", .post = 1); 37 | RegisterHookChain(RG_RoundEnd, "HC_RoundEnd", .post = 1); 38 | RegisterHookChain(RG_CSGameRules_CheckWinConditions, "HC_CheckWinConditions", .post = 0); 39 | 40 | g_iFwNewRound = CreateMultiForward("Round_Fw_NewRound", ET_IGNORE); 41 | g_iFwRoundStart = CreateMultiForward("Round_Fw_RoundStart", ET_IGNORE); 42 | g_iFwRoundEnd = CreateMultiForward("Round_Fw_RoundEnd", ET_IGNORE, FP_CELL); 43 | g_iFwRoundExpired = CreateMultiForward("Round_Fw_RoundExpired", ET_IGNORE); 44 | g_iFwRoundRestart = CreateMultiForward("Round_Fw_RoundRestart", ET_IGNORE); 45 | g_iFwRoundTimerTick = CreateMultiForward("Round_Fw_RoundTimerTick", ET_IGNORE); 46 | g_iFwCheckWinConditions = CreateMultiForward("Round_Fw_CheckWinCondition", ET_STOP); 47 | 48 | g_irgCheckWinConditionHooks = ArrayCreate(Hook); 49 | 50 | g_pCvarRoundEndDelay = get_cvar_pointer("mp_round_restart_delay"); 51 | } 52 | 53 | public plugin_natives() { 54 | register_library("api_rounds"); 55 | register_native("Round_DispatchWin", "Native_DispatchWin"); 56 | register_native("Round_GetTime", "Native_GetTime"); 57 | register_native("Round_SetTime", "Native_SetTime"); 58 | register_native("Round_GetTimeLeft", "Native_GetTimeLeft"); 59 | register_native("Round_IsRoundStarted", "Native_IsRoundStarted"); 60 | register_native("Round_IsRoundEnd", "Native_IsRoundEnd"); 61 | register_native("Round_HookCheckWinConditions", "Native_HookCheckWinConditions"); 62 | } 63 | 64 | public plugin_destroy() { 65 | ArrayDestroy(g_irgCheckWinConditionHooks); 66 | } 67 | 68 | public server_frame() { 69 | static Float:flTime; 70 | flTime = get_gametime(); 71 | 72 | static Float:flNextPeriodicThink; 73 | flNextPeriodicThink = get_member_game(m_tmNextPeriodicThink); 74 | 75 | if (flNextPeriodicThink < flTime) { 76 | static bool:bFreezePeriod; 77 | bFreezePeriod = get_member_game(m_bFreezePeriod); 78 | 79 | ExecuteForward(g_iFwRoundTimerTick); 80 | 81 | static iRoundTimeSecs; 82 | iRoundTimeSecs = get_member_game(m_iRoundTimeSecs); 83 | 84 | static Float:flStartTime; 85 | flStartTime = get_member_game(m_fRoundStartTimeReal); 86 | 87 | static Float:flEndTime; 88 | flEndTime = flStartTime + float(iRoundTimeSecs); 89 | 90 | if (!bFreezePeriod) { 91 | if (flTime >= flEndTime) { 92 | ExecuteForward(g_iFwRoundExpired); 93 | } 94 | } 95 | } 96 | } 97 | 98 | public HC_RestartRound() { 99 | if (!get_member_game(m_bCompleteReset)) { 100 | // g_iGameState = GameState_NewRound; 101 | // ExecuteForward(g_iFwNewRound); 102 | } else { 103 | ExecuteForward(g_iFwRoundRestart); 104 | } 105 | } 106 | 107 | public HC_OnRoundFreezeEnd_Post() { 108 | g_iGameState = GameState_RoundStarted; 109 | ExecuteForward(g_iFwRoundStart); 110 | } 111 | 112 | public Event_NewRound() { 113 | g_iGameState = GameState_NewRound; 114 | ExecuteForward(g_iFwNewRound); 115 | } 116 | 117 | public HC_RoundEnd(WinStatus:iStatus, ScenarioEventEndRound:iEvent, Float:flDelay) { 118 | new TeamName:iWinTeam = TEAM_UNASSIGNED; 119 | 120 | switch (iStatus) { 121 | case WINSTATUS_TERRORISTS: iWinTeam = TEAM_TERRORIST; 122 | case WINSTATUS_CTS: iWinTeam = TEAM_CT; 123 | case WINSTATUS_DRAW: iWinTeam = TEAM_SPECTATOR; 124 | } 125 | 126 | g_iGameState = GameState_RoundEnd; 127 | 128 | ExecuteForward(g_iFwRoundEnd, _, _:iWinTeam); 129 | } 130 | 131 | public HC_CheckWinConditions() { 132 | new iSize = ArraySize(g_irgCheckWinConditionHooks); 133 | 134 | for (new i = 0; i < iSize; ++i) { 135 | static hook[_:Hook]; 136 | ArrayGetArray(g_irgCheckWinConditionHooks, i, hook); 137 | 138 | if (callfunc_begin_i(hook[Hook_FunctionId], hook[Hook_PluginId]) == 1) { 139 | if (callfunc_end() > PLUGIN_CONTINUE) { 140 | return HC_SUPERCEDE; 141 | } 142 | } 143 | } 144 | 145 | static iReturn; 146 | ExecuteForward(g_iFwCheckWinConditions, iReturn); 147 | if (iReturn != PLUGIN_CONTINUE) { 148 | return HC_SUPERCEDE; 149 | } 150 | 151 | return HC_CONTINUE; 152 | } 153 | 154 | public Native_DispatchWin(iPluginId, iArgc) { 155 | new iTeam = get_param(1); 156 | new Float:flDelay = get_param_f(2); 157 | DispatchWin(iTeam, flDelay); 158 | } 159 | 160 | public Native_GetTime(iPluginId, iArgc) { 161 | return get_member_game(m_iRoundTimeSecs); 162 | } 163 | 164 | public Native_SetTime(iPluginId, iArgc) { 165 | new iTime = get_param(1); 166 | SetTime(iTime); 167 | } 168 | 169 | public Native_GetTimeLeft(iPluginId, iArgc) { 170 | return GetTimeLeft(); 171 | } 172 | 173 | public bool:Native_IsRoundStarted(iPluginId, iArgc) { 174 | return g_iGameState > GameState_NewRound; 175 | } 176 | 177 | public bool:Native_IsRoundEnd(iPluginId, iArgc) { 178 | return g_iGameState == GameState_RoundEnd; 179 | } 180 | 181 | public Native_HookCheckWinConditions(iPluginId, iArgc) { 182 | new szFunctionName[32]; 183 | get_string(1, szFunctionName, charsmax(szFunctionName)); 184 | 185 | new hook[Hook]; 186 | hook[Hook_PluginId] = iPluginId; 187 | hook[Hook_FunctionId] = get_func_id(szFunctionName, iPluginId); 188 | 189 | ArrayPushArray(g_irgCheckWinConditionHooks, hook); 190 | } 191 | 192 | DispatchWin(iTeam, Float:flDelay = -1.0) { 193 | if (g_iGameState == GameState_RoundEnd) { 194 | return; 195 | } 196 | 197 | if (iTeam < 1 || iTeam > 3) { 198 | return; 199 | } 200 | 201 | if (flDelay < 0.0) { 202 | flDelay = g_pCvarRoundEndDelay ? get_pcvar_float(g_pCvarRoundEndDelay) : 5.0; 203 | } 204 | 205 | new WinStatus:iWinstatus = WINSTATUS_DRAW; 206 | if (iTeam == 1) { 207 | iWinstatus = WINSTATUS_TERRORISTS; 208 | } else if (iTeam == 2) { 209 | iWinstatus = WINSTATUS_CTS; 210 | } 211 | 212 | new ScenarioEventEndRound:iEvent = ROUND_END_DRAW; 213 | if (iTeam == 1) { 214 | iEvent = ROUND_TERRORISTS_WIN; 215 | } else if (iTeam == 2) { 216 | iEvent = ROUND_CTS_WIN; 217 | } 218 | 219 | rg_round_end(flDelay, iWinstatus, iEvent, _, _, true); 220 | rg_update_teamscores(iTeam == 2 ? 1 : 0, iTeam == 1 ? 1 : 0); 221 | } 222 | 223 | SetTime(iTime) { 224 | new Float:flStartTime = get_member_game(m_fRoundStartTimeReal); 225 | 226 | set_member_game(m_iRoundTime, iTime); 227 | set_member_game(m_iRoundTimeSecs, iTime); 228 | set_member_game(m_fRoundStartTime, flStartTime); 229 | 230 | UpdateTimer(0, GetTimeLeft()); 231 | } 232 | 233 | GetTimeLeft() { 234 | new Float:flStartTime = get_member_game(m_fRoundStartTimeReal); 235 | new iTime = get_member_game(m_iRoundTimeSecs); 236 | return floatround(flStartTime + float(iTime) - get_gametime()); 237 | } 238 | 239 | UpdateTimer(iClient, iTime) { 240 | static iMsgId = 0; 241 | if(!iMsgId) { 242 | iMsgId = get_user_msgid("RoundTime"); 243 | } 244 | 245 | message_begin(iClient ? MSG_ONE : MSG_ALL, iMsgId); 246 | write_short(iTime); 247 | message_end(); 248 | } 249 | -------------------------------------------------------------------------------- /api_waypoint_markers.sma: -------------------------------------------------------------------------------- 1 | #pragma semicolon 1 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #include 10 | 11 | #define IS_PLAYER(%1) (%1 >= 1 && %1 <= MaxClients) 12 | 13 | #define MARKER_CLASSNAME "_wpmarker" 14 | #define MARKER_UPDATE_RATE 0.01 15 | #define TRACE_IGNORE_FLAGS (IGNORE_GLASS | IGNORE_MONSTERS) 16 | #define SCREEN_SIZE_FACTOR 1024.0 17 | #define SPRITE_MIN_SCALE 0.004 18 | 19 | enum _:Frame { 20 | Frame_TopLeft, 21 | Frame_TopRight, 22 | Frame_Center, 23 | Frame_BottomLeft, 24 | Frame_BottomRight 25 | }; 26 | 27 | enum MarkerPlayerData { 28 | Float:MarkerPlayerData_Origin[3], 29 | Float:MarkerPlayerData_Angles[3], 30 | Float:MarkerPlayerData_Scale, 31 | Float:MarkerPlayerData_LastUpdate, 32 | Float:MarkerPlayerData_IsVisible, 33 | Float:MarkerPlayerData_ShouldHide, 34 | Float:MarkerPlayerData_NextUpdate 35 | }; 36 | 37 | new g_pCvarCompensation; 38 | 39 | new g_fwCreated; 40 | new g_fwDestroy; 41 | 42 | new g_pTrace; 43 | new g_iszInfoTargetClassname; 44 | new Array:g_irgpMarkers; 45 | new bool:g_bCompensation; 46 | 47 | new Float:g_rgflPlayerDelay[MAX_PLAYERS + 1]; 48 | new Float:g_rgflPlayerNextDelayUpdate[MAX_PLAYERS + 1]; 49 | 50 | public plugin_precache() { 51 | g_pTrace = create_tr2(); 52 | g_irgpMarkers = ArrayCreate(); 53 | g_iszInfoTargetClassname = engfunc(EngFunc_AllocString, "info_target"); 54 | 55 | g_fwCreated = CreateMultiForward("WaypointMarker_Fw_Created", ET_IGNORE, FP_CELL); 56 | g_fwDestroy = CreateMultiForward("WaypointMarker_Fw_Destroy", ET_IGNORE, FP_CELL); 57 | } 58 | 59 | public plugin_init() { 60 | register_plugin("[API] Waypoint Markers", "1.0.0", "Hedgehog Fog"); 61 | 62 | RegisterHamPlayer(Ham_Player_PostThink, "HamHook_Player_PostThink_Post", 1); 63 | 64 | register_forward(FM_AddToFullPack, "FMHook_AddToFullPack", 0); 65 | register_forward(FM_AddToFullPack, "FMHook_AddToFullPack_Post", 1); 66 | register_forward(FM_CheckVisibility, "FMHook_CheckVisibility", 0); 67 | register_forward(FM_OnFreeEntPrivateData, "FMHook_OnFreeEntPrivateData", 0); 68 | 69 | g_pCvarCompensation = create_cvar("waypoint_marker_compensation", "1"); 70 | 71 | bind_pcvar_num(g_pCvarCompensation, g_bCompensation); 72 | } 73 | 74 | public plugin_end() { 75 | free_tr2(g_pTrace); 76 | ArrayDestroy(g_irgpMarkers); 77 | } 78 | 79 | public plugin_natives() { 80 | register_library("api_waypoint_markers"); 81 | register_native("WaypointMarker_Create", "Native_CreateMarker"); 82 | register_native("WaypointMarker_SetVisible", "Native_SetVisible"); 83 | } 84 | 85 | public Native_CreateMarker(iPluginId, iArgc) { 86 | new szModel[MAX_RESOURCE_PATH_LENGTH]; get_string(1, szModel, charsmax(szModel)); 87 | new Float:vecOrigin[3]; get_array_f(2, vecOrigin, sizeof(vecOrigin)); 88 | new Float:flScale = get_param_f(3); 89 | new Float:vecSize[3]; get_array_f(4, vecSize, 2); 90 | 91 | vecSize[2] = floatmax(vecSize[0], vecSize[1]); 92 | 93 | new pMarker = @Marker_Create(); 94 | dllfunc(DLLFunc_Spawn, pMarker); 95 | engfunc(EngFunc_SetModel, pMarker, szModel); 96 | engfunc(EngFunc_SetOrigin, pMarker, vecOrigin); 97 | set_pev(pMarker, pev_scale, flScale); 98 | set_pev(pMarker, pev_size, vecSize); 99 | 100 | return pMarker; 101 | } 102 | 103 | public Native_SetVisible(iPluginId, iArgc) { 104 | new pMarker = get_param(1); 105 | new pPlayer = get_param(2); 106 | new bool:bValue = bool:get_param(3); 107 | 108 | @Marker_SetVisible(pMarker, pPlayer, bValue); 109 | } 110 | 111 | public HamHook_Player_PostThink_Post(pPlayer) { 112 | static Float:flGameTime; flGameTime = get_gametime(); 113 | 114 | if (g_rgflPlayerNextDelayUpdate[pPlayer] <= flGameTime) { 115 | if (g_bCompensation) { 116 | static iPing, iLoss; get_user_ping(pPlayer, iPing, iLoss); 117 | g_rgflPlayerDelay[pPlayer] = float(iPing) / 1000.0; 118 | } else { 119 | g_rgflPlayerDelay[pPlayer] = 0.0; 120 | } 121 | 122 | g_rgflPlayerNextDelayUpdate[pPlayer] = flGameTime + 0.1; 123 | } 124 | 125 | static iMarkersNum; iMarkersNum = ArraySize(g_irgpMarkers); 126 | for (new iMarker = 0; iMarker < iMarkersNum; ++iMarker) { 127 | static pMarker; pMarker = ArrayGetCell(g_irgpMarkers, iMarker); 128 | @Marker_Calculate(pMarker, pPlayer, g_rgflPlayerDelay[pPlayer]); 129 | } 130 | } 131 | 132 | public FMHook_AddToFullPack(es, e, pEntity, pHost, pHostFlags, iPlayer, pSet) { 133 | if (!IS_PLAYER(pHost)) return FMRES_IGNORED; 134 | if (!pev_valid(pEntity)) return FMRES_IGNORED; 135 | 136 | if (@Base_IsMarker(pEntity)) { 137 | if (!is_user_alive(pHost)) return FMRES_SUPERCEDE; 138 | if (is_user_bot(pHost)) return FMRES_SUPERCEDE; 139 | 140 | static Struct:sPlayerData; sPlayerData = @Marker_GetPlayerData(pEntity, pHost); 141 | 142 | if (!StructGetCell(sPlayerData, MarkerPlayerData_IsVisible)) return FMRES_SUPERCEDE; 143 | if (StructGetCell(sPlayerData, MarkerPlayerData_ShouldHide)) return FMRES_SUPERCEDE; 144 | } 145 | 146 | return FMRES_IGNORED; 147 | } 148 | 149 | public FMHook_AddToFullPack_Post(es, e, pEntity, pHost, pHostFlags, iPlayer, pSet) { 150 | if (!IS_PLAYER(pHost)) return FMRES_IGNORED; 151 | if (!pev_valid(pEntity)) return FMRES_IGNORED; 152 | 153 | if (@Base_IsMarker(pEntity)) { 154 | if (!is_user_alive(pHost)) return FMRES_SUPERCEDE; 155 | if (is_user_bot(pHost)) return FMRES_SUPERCEDE; 156 | 157 | static Struct:sPlayerData; sPlayerData = @Marker_GetPlayerData(pEntity, pHost); 158 | 159 | if (!StructGetCell(sPlayerData, MarkerPlayerData_IsVisible)) return FMRES_SUPERCEDE; 160 | if (StructGetCell(sPlayerData, MarkerPlayerData_ShouldHide)) return FMRES_SUPERCEDE; 161 | 162 | static Float:vecOrigin[3]; StructGetArray(sPlayerData, MarkerPlayerData_Origin, vecOrigin, sizeof(vecOrigin)); 163 | static Float:vecAngles[3]; StructGetArray(sPlayerData, MarkerPlayerData_Angles, vecAngles, sizeof(vecAngles)); 164 | static Float:flScale; flScale = StructGetCell(sPlayerData, MarkerPlayerData_Scale); 165 | 166 | set_es(es, ES_Origin, vecOrigin); 167 | set_es(es, ES_Angles, vecAngles); 168 | set_es(es, ES_Scale, flScale); 169 | set_es(es, ES_AimEnt, 0); 170 | set_es(es, ES_MoveType, MOVETYPE_NONE); 171 | } 172 | 173 | return FMRES_HANDLED; 174 | } 175 | 176 | public FMHook_CheckVisibility(pEntity) { 177 | if (!pev_valid(pEntity)) return FMRES_IGNORED; 178 | 179 | if (@Base_IsMarker(pEntity)) { 180 | forward_return(FMV_CELL, 1); 181 | return FMRES_SUPERCEDE; 182 | } 183 | 184 | return FMRES_IGNORED; 185 | } 186 | 187 | public FMHook_OnFreeEntPrivateData(pEntity) { 188 | if (@Base_IsMarker(pEntity)) { 189 | @Marker_Free(pEntity); 190 | } 191 | } 192 | 193 | @Base_IsMarker(this) { 194 | static szClassName[32]; 195 | pev(this, pev_classname, szClassName, charsmax(szClassName)); 196 | 197 | return equal(szClassName, MARKER_CLASSNAME); 198 | } 199 | 200 | @Marker_Create() { 201 | new this = engfunc(EngFunc_CreateNamedEntity, g_iszInfoTargetClassname); 202 | 203 | set_pev(this, pev_classname, MARKER_CLASSNAME); 204 | set_pev(this, pev_scale, 1.0); 205 | set_pev(this, pev_rendermode, kRenderTransAdd); 206 | set_pev(this, pev_renderamt, 255.0); 207 | set_pev(this, pev_movetype, MOVETYPE_NONE); 208 | set_pev(this, pev_solid, SOLID_NOT); 209 | set_pev(this, pev_spawnflags, SF_SPRITE_STARTON); 210 | 211 | new Array:irgsPlayersData = ArrayCreate(1, MaxClients + 1); 212 | for (new pPlayer = 0; pPlayer <= MaxClients; ++pPlayer) { 213 | ArrayPushCell(irgsPlayersData, Invalid_Struct); 214 | } 215 | 216 | set_pev(this, pev_iuser1, irgsPlayersData); 217 | 218 | ArrayPushCell(g_irgpMarkers, this); 219 | 220 | ExecuteForward(g_fwCreated, _, this); 221 | 222 | return this; 223 | } 224 | 225 | @Marker_Free(this) { 226 | ExecuteForward(g_fwDestroy, _, this); 227 | 228 | static Array:irgsPlayersData; irgsPlayersData = Array:pev(this, pev_iuser1); 229 | 230 | for (new pPlayer = 1; pPlayer <= MaxClients; ++pPlayer) { 231 | static Struct:sPlayerData; sPlayerData = ArrayGetCell(irgsPlayersData, pPlayer); 232 | if (sPlayerData == Invalid_Struct) continue; 233 | StructDestroy(sPlayerData); 234 | } 235 | 236 | ArrayDestroy(irgsPlayersData); 237 | 238 | new iGlobalId = ArrayFindValue(g_irgpMarkers, this); 239 | if (iGlobalId != -1) { 240 | ArrayDeleteItem(g_irgpMarkers, iGlobalId); 241 | } 242 | } 243 | 244 | @Marker_SetVisible(this, pPlayer, bool:bValue) { 245 | if (!pPlayer) { 246 | for (new pPlayer = 0; pPlayer <= MaxClients; ++pPlayer) { 247 | @Marker_SetVisible(this, pPlayer, bValue); 248 | } 249 | 250 | return; 251 | } 252 | 253 | if (!IS_PLAYER(pPlayer)) return; 254 | 255 | static Struct:sPlayerData; sPlayerData = @Marker_GetPlayerData(this, pPlayer); 256 | StructSetCell(sPlayerData, MarkerPlayerData_IsVisible, bValue); 257 | } 258 | 259 | @Marker_Calculate(this, pPlayer, Float:flDelay) { 260 | static Float:flGameTime; flGameTime = get_gametime(); 261 | static Struct:sPlayerData; sPlayerData = @Marker_GetPlayerData(this, pPlayer); 262 | 263 | if (!StructGetCell(sPlayerData, MarkerPlayerData_IsVisible)) return; 264 | if (StructGetCell(sPlayerData, MarkerPlayerData_NextUpdate) > flGameTime) return; 265 | 266 | static Float:flLastUpdate; flLastUpdate = StructGetCell(sPlayerData, MarkerPlayerData_LastUpdate); 267 | static Float:flDelta; flDelta = flGameTime - flLastUpdate; 268 | 269 | static Float:vecViewOrigin[3]; ExecuteHam(Ham_EyePosition, pPlayer, vecViewOrigin); 270 | 271 | if (g_bCompensation) { 272 | static Float:vecVelocity[3]; 273 | pev(pPlayer, pev_velocity, vecVelocity); 274 | xs_vec_add_scaled(vecViewOrigin, vecVelocity, flDelay * flDelta, vecViewOrigin); 275 | } 276 | 277 | static Float:vecOrigin[3]; pev(this, pev_origin, vecOrigin); 278 | 279 | static iFov; iFov = get_ent_data(pPlayer, "CBasePlayer", "m_iFOV"); 280 | 281 | // We have to fix default HL FOV, because it equal to 0 and we can't use it in calculations 282 | if (!iFov) iFov = 90; 283 | 284 | // Default view cone test functions not working for Half-Life, so we have to use this stock 285 | if (!UTIL_IsInViewCone(pPlayer, vecOrigin, float(iFov) / 2)) { 286 | StructSetCell(sPlayerData, MarkerPlayerData_ShouldHide, true); 287 | return; 288 | } 289 | 290 | static Float:vecAngles[3]; 291 | xs_vec_sub(vecOrigin, vecViewOrigin, vecAngles); 292 | xs_vec_normalize(vecAngles, vecAngles); 293 | vector_to_angle(vecAngles, vecAngles); 294 | vecAngles[0] = -vecAngles[0]; 295 | 296 | static Float:flDistance; flDistance = xs_vec_distance(vecViewOrigin, vecOrigin); 297 | static Float:vecSize[3]; pev(this, pev_size, vecSize); 298 | static Float:vecForward[3]; angle_vector(vecAngles, ANGLEVECTOR_FORWARD, vecForward); 299 | static Float:vecUp[3]; angle_vector(vecAngles, ANGLEVECTOR_UP, vecUp); 300 | static Float:vecRight[3]; angle_vector(vecAngles, ANGLEVECTOR_RIGHT, vecRight); 301 | static Float:flFrameScale; flFrameScale = CalculateDistanceScaleFactor(flDistance, iFov); 302 | 303 | static Float:rgFrame[Frame][3]; 304 | CreateFrame(vecOrigin, vecSize[0] * flFrameScale, vecSize[1] * flFrameScale, vecUp, vecRight, rgFrame); 305 | TraceFrame(vecViewOrigin, rgFrame, pPlayer, rgFrame); 306 | 307 | static Float:flProjectionDistance; flProjectionDistance = xs_vec_distance(rgFrame[Frame_Center], vecViewOrigin); 308 | 309 | static Float:flScale; pev(this, pev_scale, flScale); 310 | flScale *= CalculateDistanceScaleFactor(flProjectionDistance, iFov); 311 | flScale = floatmax(flScale, SPRITE_MIN_SCALE); 312 | 313 | static Float:flDepth; flDepth = floatmin((vecSize[2] / 2) * flScale, flProjectionDistance); 314 | MoveFrame(rgFrame, vecForward, -flDepth, rgFrame); 315 | 316 | StructSetCell(sPlayerData, MarkerPlayerData_ShouldHide, false); 317 | StructSetCell(sPlayerData, MarkerPlayerData_Scale, flScale); 318 | StructSetArray(sPlayerData, MarkerPlayerData_Origin, rgFrame[Frame_Center], sizeof(rgFrame[])); 319 | StructSetArray(sPlayerData, MarkerPlayerData_Angles, vecAngles, sizeof(vecAngles)); 320 | StructSetCell(sPlayerData, MarkerPlayerData_LastUpdate, flGameTime); 321 | StructSetCell(sPlayerData, MarkerPlayerData_NextUpdate, flGameTime + MARKER_UPDATE_RATE); 322 | } 323 | 324 | Struct:@Marker_GetPlayerData(this, pPlayer) { 325 | static Array:irgsPlayersData; irgsPlayersData = Array:pev(this, pev_iuser1); 326 | static Struct:sPlayerData; sPlayerData = ArrayGetCell(irgsPlayersData, pPlayer); 327 | 328 | if (sPlayerData == Invalid_Struct) { 329 | sPlayerData = StructCreate(MarkerPlayerData); 330 | StructSetCell(sPlayerData, MarkerPlayerData_IsVisible, true); 331 | StructSetCell(sPlayerData, MarkerPlayerData_ShouldHide, false); 332 | StructSetCell(sPlayerData, MarkerPlayerData_LastUpdate, get_gametime()); 333 | StructSetCell(sPlayerData, MarkerPlayerData_NextUpdate, get_gametime()); 334 | ArraySetCell(irgsPlayersData, pPlayer, sPlayerData); 335 | } 336 | 337 | return sPlayerData; 338 | } 339 | 340 | CreateFrame(const Float:vecOrigin[3], Float:flWidth, Float:flHeight, const Float:vecUp[3], const Float:vecRight[3], Float:rgFrameOut[Frame][3]) { 341 | static Float:flHalfWidth; flHalfWidth = flWidth / 2; 342 | static Float:flHalfHeight; flHalfHeight = flHeight / 2; 343 | 344 | for (new iAxis = 0; iAxis < 3; ++iAxis) { 345 | rgFrameOut[Frame_TopLeft][iAxis] = vecOrigin[iAxis] + (-vecRight[iAxis] * flHalfWidth) + (vecUp[iAxis] * flHalfHeight); 346 | rgFrameOut[Frame_TopRight][iAxis] = vecOrigin[iAxis] + (vecRight[iAxis] * flHalfWidth) + (vecUp[iAxis] * flHalfHeight); 347 | rgFrameOut[Frame_BottomLeft][iAxis] = vecOrigin[iAxis] + (-vecRight[iAxis] * flHalfWidth) + (-vecUp[iAxis] * flHalfHeight); 348 | rgFrameOut[Frame_BottomRight][iAxis] = vecOrigin[iAxis] + (vecRight[iAxis] * flHalfWidth) + (-vecUp[iAxis] * flHalfHeight); 349 | rgFrameOut[Frame_Center][iAxis] = vecOrigin[iAxis]; 350 | } 351 | } 352 | 353 | Float:TraceFrame(const Float:vecViewOrigin[3], const Float:rgFrame[Frame][3], pIgnore, Float:rgFrameOut[Frame][3]) { 354 | static Float:flMinFraction; flMinFraction = 1.0; 355 | 356 | for (new iFramePoint = 0; iFramePoint < Frame; ++iFramePoint) { 357 | engfunc(EngFunc_TraceLine, vecViewOrigin, rgFrame[iFramePoint], TRACE_IGNORE_FLAGS, pIgnore, g_pTrace); 358 | 359 | static Float:flFraction; get_tr2(g_pTrace, TR_flFraction, flFraction); 360 | if (flFraction < flMinFraction) { 361 | flMinFraction = flFraction; 362 | } 363 | } 364 | 365 | if (flMinFraction < 1.0) { 366 | for (new iFramePoint = 0; iFramePoint < Frame; ++iFramePoint) { 367 | for (new iAxis = 0; iAxis < 3; ++iAxis) { 368 | rgFrameOut[iFramePoint][iAxis] = vecViewOrigin[iAxis] + ((rgFrame[iFramePoint][iAxis] - vecViewOrigin[iAxis]) * flMinFraction); 369 | } 370 | } 371 | } 372 | 373 | return flMinFraction; 374 | } 375 | 376 | MoveFrame(const Float:rgFrame[Frame][3], const Float:vecDirection[3], Float:flDistance, Float:rgFrameOut[Frame][3]) { 377 | for (new iFramePoint = 0; iFramePoint < Frame; ++iFramePoint) { 378 | for (new iAxis = 0; iAxis < 3; ++iAxis) { 379 | rgFrameOut[iFramePoint][iAxis] = rgFrame[iFramePoint][iAxis] + (vecDirection[iAxis] * flDistance); 380 | } 381 | } 382 | } 383 | 384 | Float:CalculateDistanceScaleFactor(Float:flDistance, iFov = 90) { 385 | static Float:flAngle; flAngle = floattan(xs_deg2rad(float(iFov) / 2)); 386 | static Float:flScaleFactor; flScaleFactor = ((2 * flAngle) / SCREEN_SIZE_FACTOR) * flDistance; 387 | 388 | return flScaleFactor; 389 | } 390 | 391 | stock bool:UTIL_IsInViewCone(pEntity, const Float:vecTarget[3], Float:fMaxAngle) { 392 | static Float:vecOrigin[3]; ExecuteHamB(Ham_EyePosition, pEntity, vecOrigin); 393 | 394 | static Float:vecDir[3]; 395 | xs_vec_sub(vecTarget, vecOrigin, vecDir); 396 | xs_vec_normalize(vecDir, vecDir); 397 | 398 | static Float:vecForward[3]; 399 | pev(pEntity, pev_v_angle, vecForward); 400 | angle_vector(vecForward, ANGLEVECTOR_FORWARD, vecForward); 401 | 402 | new Float:flAngle = xs_rad2deg(xs_acos((vecDir[0] * vecForward[0]) + (vecDir[1] * vecForward[1]), radian)); 403 | 404 | return flAngle <= fMaxAngle; 405 | } 406 | -------------------------------------------------------------------------------- /include/api_advanced_pushing.inc: -------------------------------------------------------------------------------- 1 | #if defined _api_advanced_pushing_included 2 | #endinput 3 | #endif 4 | #define _api_advanced_pushing_included 5 | 6 | #pragma reqlib api_advanced_pushing 7 | 8 | enum APS_Flags (<<=1) { 9 | APS_Flag_None, 10 | APS_Flag_AddForce = 1, 11 | APS_Flag_AddForceInfluenceMode, 12 | APS_Flag_OverlapMode 13 | }; 14 | 15 | /** 16 | * Pushes the entity using the given force vector. 17 | * 18 | * @param pEntity The entity to push. 19 | * @param vecForce The force vector to apply. 20 | * @param iFlags The flags for the push operation. 21 | * 22 | * @noreturn 23 | */ 24 | native APS_Push(pEntity, const Float:vecForce[3], APS_Flags:iFlags = APS_Flag_None); 25 | 26 | /** 27 | * Pushes the entity from a specified origin with a force magnitude. 28 | * 29 | * @param pEntity The entity to push. 30 | * @param flForce The force magnitude to apply. 31 | * @param vecOrigin The origin point of the push. 32 | * @param iFlags The flags for the push operation. 33 | * 34 | * @noreturn 35 | */ 36 | native APS_PushFromOrigin(pEntity, Float:flForce, Float:vecOrigin[3], APS_Flags:iFlags = APS_Flag_None); 37 | 38 | /** 39 | * Pushes the entity using a bounding box as the toucher. 40 | * 41 | * @param pEntity The entity to push. 42 | * @param flForce The force magnitude to apply. 43 | * @param vecAbsMin The absolute minimum point of the bounding box. 44 | * @param vecAbsMax The absolute maximum point of the bounding box. 45 | * @param flMinDepthRatio The minimum depth ratio for depth influence. 46 | * @param flMaxDepthRatio The maximum depth ratio for depth influence. 47 | * @param flDepthInfluenceMin The minimum depth influence. 48 | * @param flDepthInfluenceMax The maximum depth influence. 49 | * @param iFlags The flags for the push operation. 50 | * 51 | * @noreturn 52 | */ 53 | native APS_PushFromBBox( 54 | pEntity, 55 | Float:flForce, 56 | const Float:vecAbsMin[3], 57 | const Float:vecAbsMax[3], 58 | Float:flMinDepthRatio = 0.0, 59 | Float:flMaxDepthRatio = 1.0, 60 | Float:flDepthInfluenceMin = 0.0, 61 | Float:flDepthInfluenceMax = 1.0, 62 | APS_Flags:iFlags = APS_Flag_None 63 | ); 64 | -------------------------------------------------------------------------------- /include/api_custom_entities.inc: -------------------------------------------------------------------------------- 1 | #if defined _api_custom_entities_included 2 | #endinput 3 | #endif 4 | #define _api_custom_entities_included 5 | 6 | #pragma reqlib api_custom_entities 7 | 8 | #define CE_LOG_PREFIX "[CE]" 9 | #define CE_BASE_CLASSNAME "info_target" 10 | 11 | enum CEPreset 12 | { 13 | CEPreset_None = 0, 14 | CEPreset_Item, // For items 15 | CEPreset_NPC, // For NPC 16 | CEPreset_Prop // For static props 17 | }; 18 | 19 | enum CEFunction 20 | { 21 | CEFunction_Spawn, // Call when entity spawned 22 | CEFunction_Kill, // Call when some plugin try to kill entity. return PLUGIN_HANDLED to discard kill. 23 | CEFunction_Killed, // Call when entity killed 24 | CEFunction_Remove, // Call when entity removed 25 | CEFunction_Picked, // Call when player pick item 26 | CEFunction_Pickup, // Call when player touch item. Should return PLUGIN_HANDLED if picked. 27 | CEFunction_KVD // Call when new key value obtained 28 | }; 29 | /* 30 | * Register entity. 31 | * 32 | * @param szName Name of entity. 33 | * @param modelIndex Precached model index. 34 | * @param size Size of entity. 35 | * @param offset Offset of entity origin. 36 | * @param lifeTime Life time of entity. 37 | * @param preset Preset for entity. 38 | * @return Handler of registered entity. 39 | */ 40 | native CE_Register 41 | ( 42 | const szName[], 43 | modelIndex = 0, 44 | const Float:vMins[3] = {-8.0, -8.0, -8.0}, 45 | const Float:vMaxs[3] = {8.0, 8.0, 8.0}, 46 | Float:fLifeTime = 0.0, 47 | Float:fRespawnTime = 10.0, 48 | bool:ignoreRounds = false, 49 | CEPreset:preset = CEPreset_None 50 | ); 51 | 52 | /* 53 | * Spawn entity. 54 | * 55 | * @param szName Name of entity. 56 | * @param vOrigin Spawn origin. 57 | * @return Entity index. 58 | */ 59 | native CE_Create(const szName[], const Float:vOrigin[3], bool:temp = true); 60 | 61 | /* 62 | * Kill entity. 63 | * 64 | * @param ent Index of entity. 65 | * @param killer Index of killer. 66 | */ 67 | native bool:CE_Kill(ent, killer = 0); 68 | 69 | 70 | /* 71 | * Gets size of entity. 72 | * 73 | * @param szClassname Classname of entity. 74 | * @param vSize Output vector. 75 | */ 76 | native CE_GetSize(const szName[], Float:vMins[3], Float:vMaxs[3]); 77 | 78 | /* 79 | * Gets modelindex of entity. 80 | * 81 | * @param szClassname Classname of entity. 82 | * @return Modelindex of entity 83 | */ 84 | native CE_GetModelIndex(const szName[]); 85 | 86 | /* 87 | * Remove entity correctly. 88 | * 89 | * @param ent Index of entity. 90 | * @return Result true/false 91 | */ 92 | native bool:CE_Remove(ent); 93 | 94 | /* 95 | * Register new hook for entity. 96 | * 97 | * @param function Function handler 98 | * @param szClassname Classname of entity 99 | * @param szCallback Callback 100 | */ 101 | native CE_RegisterHook(CEFunction:function, const szClassname[], const szCallback[]); 102 | 103 | /* 104 | * Check if entity is associated with current plugin. 105 | * 106 | * @param ent Index of entity. 107 | * @return Result true/false 108 | */ 109 | native CE_CheckAssociation_(ent); 110 | 111 | stock bool:CE_CheckAssociation(ent) { 112 | static bool:notified = false; 113 | if (!notified) { 114 | log_amx("%s function ^"CE_CheckAssociation^" is deprecated. Check ^"CE_GetHandlerByEntity^" function.", CE_LOG_PREFIX); 115 | notified = true; 116 | } 117 | 118 | return CE_CheckAssociation_(ent); 119 | } 120 | 121 | native CE_GetHandler(const szClassname[]); 122 | native CE_GetHandlerByEntity(ent); -------------------------------------------------------------------------------- /include/api_custom_weapons.inc: -------------------------------------------------------------------------------- 1 | // This is a beta version, some functions may be unstable. Use at your own risk. 2 | 3 | #if defined _api_custom_weapons_included 4 | #endinput 5 | #endif 6 | #define _api_custom_weapons_included 7 | 8 | #pragma reqlib api_custom_weapons 9 | 10 | #define WEAPON_NOCLIP -1 11 | #define CW_INVALID_HANDLER CW:-1 12 | 13 | #define DEFAULT_FOV 90 14 | 15 | #define VECTOR_CONE_1DEGREES {0.00873, 0.00873, 0.00873} 16 | #define VECTOR_CONE_2DEGREES {0.01745, 0.01745, 0.01745} 17 | #define VECTOR_CONE_3DEGREES {0.02618, 0.02618, 0.02618} 18 | #define VECTOR_CONE_4DEGREES {0.03490, 0.03490, 0.03490} 19 | #define VECTOR_CONE_5DEGREES {0.04362, 0.04362, 0.04362} 20 | #define VECTOR_CONE_6DEGREES {0.05234, 0.05234, 0.05234} 21 | #define VECTOR_CONE_7DEGREES {0.06105, 0.06105, 0.06105} 22 | #define VECTOR_CONE_8DEGREES {0.06976, 0.06976, 0.06976} 23 | #define VECTOR_CONE_9DEGREES {0.07846, 0.07846, 0.07846} 24 | #define VECTOR_CONE_10DEGREES {0.08716, 0.08716, 0.08716} 25 | #define VECTOR_CONE_15DEGREES {0.13053, 0.13053, 0.13053} 26 | #define VECTOR_CONE_20DEGREES {0.17365, 0.17365, 0.17365} 27 | #define VECTOR_CONE_DM_SHOTGUN {0.08716, 0.04362, 0.00} 28 | #define VECTOR_CONE_DM_DOUBLESHOTGUN {0.17365, 0.04362, 0.00} 29 | 30 | enum CW_Data { 31 | CW_Data_PluginId, 32 | CW_Data_Name, 33 | CW_Data_Icon, 34 | CW_Data_Id, 35 | CW_Data_ClipSize, 36 | CW_Data_PrimaryAmmoType, 37 | CW_Data_PrimaryAmmoMaxAmount, 38 | CW_Data_SecondaryAmmoType, 39 | CW_Data_SecondaryAmmoMaxAmount, 40 | CW_Data_SlotId, 41 | CW_Data_Position, 42 | CW_Data_WeaponFlags, 43 | CW_Data_Bindings, 44 | CW_Data_Flags 45 | } 46 | 47 | enum CW_Binding { 48 | CWB_Idle, 49 | CWB_Holster, 50 | CWB_Deploy, 51 | CWB_PrimaryAttack, 52 | CWB_SecondaryAttack, 53 | CWB_Reload, 54 | CWB_DefaultReloadEnd, 55 | CWB_CanDrop, 56 | CWB_GetMaxSpeed, 57 | CWB_Spawn, 58 | CWB_WeaponBoxModelUpdate, 59 | CWB_Pump, 60 | CWB_GrenadeThrow 61 | } 62 | 63 | enum CW_Flags (<<=1) { 64 | CWF_None, 65 | CWF_NoBulletSmoke = 1, 66 | CWF_NoBulletDecal, 67 | CWF_CustomReload, 68 | CWF_NotRefillable 69 | } 70 | 71 | native CW:CW_Register(const szName[], iWeaponId, iClipSize = WEAPON_NOCLIP, iPrimaryAmmoType = -1, iPrimaryAmmoMaxAmount = -1, iSecondaryAmmoType = -1, iSecondaryAmmoMaxAmount = -1, iSlotId = 0, iPosition = 0, iWeaponFlags = 0, const szIcon[] = "", CW_Flags:iFlags = CWF_None); 72 | native CW_Bind(CW:iHandler, CW_Binding:iBinding, const szFunctionName[]); 73 | native CW:CW_GetHandlerByEntity(pEntity); 74 | native CW:CW_GetHandler(const szName[]); 75 | native any:CW_GetWeaponData(CW:iHandler, CW_Data:iParam); 76 | native CW_GetWeaponStringData(CW:iHandler, CW_Data:iParam, szOut[], iLen); 77 | 78 | native CW_Deploy(pItem); 79 | native CW_Holster(pItem); 80 | native CW_ItemPostFrame(pItem); 81 | native CW_Idle(pItem); 82 | native CW_Reload(pItem); 83 | native CW_PrimaryAttack(pItem); 84 | native CW_SecondaryAttack(pItem); 85 | 86 | native CW_PlayAnimation(pItem, iSequence, Float:flDuration = 0.0); 87 | native CW_FireBulletsPlayer(pPlayer, iShots, const Float:vecSrc[3], const Float:vecDirShooting[3], const Float:vecSpread[3], Float:flDistance, Float:flDamage, Float:flRangeModifier = 1.0, pevAttacker = 0, Float:vOut[3]); 88 | native CW_GrenadeDetonate(pGrenade, Float:flRadius = 0.0, Float:flMagnitude = 0.0); 89 | native CW_GrenadeSmoke(pGrenade); 90 | native CW_EjectWeaponBrass(pItem, iModelIndex, iSoundType); 91 | 92 | native bool:CW_DefaultDeploy(pWeapon, const szViewModel[], const szWeaponModel[], iAnim, const szAnimExt[] = ""); 93 | native bool:CW_DefaultShot(pItem, Float:flDamage, Float:flRangeModifier, Float:flRate, Float:flSpread[3] = VECTOR_CONE_6DEGREES, iShots = 1, Float:flDistance = 8192.0); 94 | native CW_DefaultReload(pItem, iAnim, Float:fDuration); 95 | native bool:CW_DefaultShotgunIdle(pItem, iAnim, iReloadEndAnim, Float:fDuration = 0.25, Float:fReloadEndDuration = 1.0, const szPumpSound[] = ""); 96 | native bool:CW_DefaultShotgunShot(pItem, Float:flDamage, Float:flRangeModifier, Float:flRate, Float:flPumpDelay, Float:flSpread[3] = VECTOR_CONE_DM_SHOTGUN, iShots = 16, Float:flDistance = 2048.0); 97 | native CW_DefaultShotgunReload(pItem, iStartAnim, iEndAnim, Float:fDelay, Float:fDuration); 98 | native CW_DefaultSwing(pItem, Float:flDamage, Float:flRate, Float:flDistance); 99 | 100 | native CW_GetPlayer(pItem); 101 | native CW_RemovePlayerItem(pItem); 102 | 103 | native CW_GiveWeapon(pPlayer, const szWeapon[]); 104 | native CW_SpawnWeapon(CW:iHandler); 105 | native CW_SpawnWeaponBox(CW:iHandler); 106 | -------------------------------------------------------------------------------- /include/api_particles.inc: -------------------------------------------------------------------------------- 1 | #if defined _api_particles_included 2 | #endinput 3 | #endif 4 | #define _api_particles_included 5 | 6 | #include 7 | 8 | /** 9 | * Registers a particle effect. 10 | * 11 | * @param szName The name of the effect. 12 | * @param flEmitRate The rate at which particles are emitted. 13 | * @param flParticleLifeTime The lifetime of each particle. 14 | * @param iMaxParticles The maximum number of particles. 15 | * @param iEmitAmount The amount of emitted particles. 16 | * @param flVisibilityDistance Max visible distance. 17 | * @param iFlags Effect flags. 18 | * 19 | * @noreturn 20 | */ 21 | native ParticleEffect_Register(const szName[], Float:flEmitRate = 0.1, Float:flParticleLifeTime = 1.0, iMaxParticles = 10, iEmitAmount = 1, Float:flVisibilityDistance = 1024.0, ParticleEffectFlag:iFlags = ParticleEffectFlag_None); 22 | 23 | /** 24 | * Registers a particle effect hook. 25 | * 26 | * @param iHook Hook to handle. 27 | * @param szName Name of the particle effect. 28 | * @param szCallback Callback function to be called during particle effects. 29 | * 30 | * @noreturn 31 | */ 32 | native ParticleEffect_RegisterHook(const szName[], ParticleEffectHook:iHook, const szCallback[]); 33 | 34 | /** 35 | * Creates a particle system. 36 | * 37 | * @param szEffect The name of the effect. 38 | * @param vecOrigin The origin of the system. 39 | * @param vecAngles The angles of the system. 40 | * @param pParent The parent System. 41 | * 42 | * @return The particle system structure pointer. 43 | */ 44 | native ParticleSystem:ParticleSystem_Create(const szEffect[], const Float:vecOrigin[3] = {0.0, 0.0, 0.0}, const Float:vecAngles[3] = {0.0, 0.0, 0.0}, pParent = 0); 45 | 46 | /** 47 | * Destroys the particle system. 48 | * 49 | * @param sSystem The particle system structure pointer. 50 | * 51 | * @noreturn 52 | */ 53 | native ParticleSystem_Destroy(&ParticleSystem:sSystem); 54 | 55 | /** 56 | * Activates the particle system. 57 | * 58 | * @param sSystem The particle system structure pointer. 59 | * 60 | * @noreturn 61 | */ 62 | native ParticleSystem_Activate(const &ParticleSystem:sSystem); 63 | 64 | /** 65 | * Deactivates the particle system. 66 | * 67 | * @param sSystem The particle system structure pointer. 68 | * 69 | * @noreturn 70 | */ 71 | native ParticleSystem_Deactivate(const &ParticleSystem:sSystem); 72 | 73 | /** 74 | * Gets particle effect speed. 75 | * 76 | * @param sSystem The particle system structure pointer. 77 | * 78 | * @return The particle system effect speed. 79 | */ 80 | native Float:ParticleSystem_GetEffectSpeed(const &ParticleSystem:sSystem); 81 | 82 | /** 83 | * Sets particle effect speed. 84 | * 85 | * @param sSystem The particle system structure pointer. 86 | * @param flSpeed The particle system effect speed. 87 | * 88 | * @noreturn 89 | */ 90 | native ParticleSystem_SetEffectSpeed(const &ParticleSystem:sSystem, Float:flSpeed); 91 | 92 | /** 93 | * Retrieves the time at which a particle system was created. 94 | * 95 | * @param sSystem The particle system structure pointer. 96 | * 97 | * @return The creation time of the particle system. 98 | */ 99 | native Float:ParticleSystem_GetCreatedTime(const &ParticleSystem:sSystem); 100 | 101 | /** 102 | * Retrieves the time at which a particle system will killed. 103 | * 104 | * @param sSystem The particle system structure pointer. 105 | * 106 | * @return The kill time of the particle system. 107 | */ 108 | native Float:ParticleSystem_GetKillTime(const &ParticleSystem:sSystem); 109 | 110 | /** 111 | * Retrieves the last time a particle system was thinked. 112 | * 113 | * @param sSystem The particle system structure pointer. 114 | * 115 | * @return The last think time of the particle system. 116 | */ 117 | native Float:ParticleSystem_GetLastThink(const &ParticleSystem:sSystem); 118 | 119 | /** 120 | * Retrieves the visibility bits of a particle. 121 | * 122 | * @param sSystem The particle system structure pointer. 123 | * 124 | * @return The visibility bits of the particle system. 125 | */ 126 | native Float:ParticleSystem_GetVisibilityBits(const &ParticleSystem:sSystem); 127 | 128 | /** 129 | * Retrieves the origin of the particle system. 130 | * 131 | * @param sSystem The particle system structure pointer. 132 | * @param vecOut The vector to set. 133 | * 134 | * @noreturn 135 | */ 136 | native ParticleSystem_GetOrigin(const &ParticleSystem:sSystem, const vecOut[]); 137 | 138 | /** 139 | * Sets the origin of the particle system. 140 | * 141 | * @param sSystem The particle system structure pointer. 142 | * @param vecOrigin The origin vector. 143 | * 144 | * @noreturn 145 | */ 146 | native ParticleSystem_SetOrigin(const &ParticleSystem:sSystem, const Float:vecOrigin[3]); 147 | 148 | /** 149 | * Retrieves the parent System of the particle system. 150 | * @param sSystem The particle system structure pointer. 151 | * @param pParent The parent System. 152 | * 153 | * @noreturn 154 | */ 155 | native ParticleSystem_GetParentSystem(const &ParticleSystem:sSystem, pParent); 156 | 157 | /** 158 | * Sets the parent System of the particle system. 159 | * 160 | * @param sSystem The particle system structure pointer. 161 | * 162 | * @return The parent System. 163 | */ 164 | native ParticleSystem_SetParentSystem(const &ParticleSystem:sSystem); 165 | 166 | /** 167 | * Retrieves the effect name of the particle system. 168 | * 169 | * @param sSystem The particle system structure pointer. 170 | * @param szOut The buffer to copy the value. 171 | * @param iMaxLen Maximum size of buffer. 172 | * 173 | * @noreturn 174 | */ 175 | native ParticleSystem_GetEffect(const &ParticleSystem:sSystem, szOut[], iMaxLen); 176 | 177 | /** 178 | * Sets the effect of the particle system. 179 | * 180 | * @param sSystem The particle system structure pointer. 181 | * @param szName The name of the particle effect. 182 | * 183 | * @noreturn 184 | */ 185 | native ParticleSystem_SetEffect(const &ParticleSystem:sSystem, const szName[]); 186 | 187 | /** 188 | * Checks if System has member 189 | * 190 | * @param sSystem System index 191 | * @param szMember Member name 192 | */ 193 | native ParticleSystem_HasMember(const &ParticleSystem:sSystem, const szMember[]); 194 | 195 | /** 196 | * Deletes member of an System 197 | * 198 | * @param sSystem System index 199 | * @param szMember Member name 200 | */ 201 | native ParticleSystem_DeleteMember(const &ParticleSystem:sSystem, const szMember[]); 202 | 203 | /** 204 | * Gets member of an System 205 | * 206 | * @param sSystem System index 207 | * @param szMember Member name 208 | * 209 | * @return Member value 210 | */ 211 | native any:ParticleSystem_GetMember(const &ParticleSystem:sSystem, const szMember[]); 212 | 213 | /** 214 | * Sets member of an System 215 | * 216 | * @param sSystem System index 217 | * @param szMember Member name 218 | * @param value Value to set 219 | */ 220 | native ParticleSystem_SetMember(const &ParticleSystem:sSystem, const szMember[], any:value); 221 | 222 | /** 223 | * Gets vector member of an System 224 | * 225 | * @param sSystem System index 226 | * @param szMember Member name 227 | * @param vecOut Output vector 228 | */ 229 | native bool:ParticleSystem_GetMemberVec(const &ParticleSystem:sSystem, const szMember[], Float:vecOut[3]); 230 | 231 | /** 232 | * Sets vector member of an System 233 | * 234 | * @param sSystem System index 235 | * @param szMember Member name 236 | * @param vecValue Vector to set 237 | */ 238 | native ParticleSystem_SetMemberVec(const &ParticleSystem:sSystem, const szMember[], const Float:vecValue[3]); 239 | 240 | /** 241 | * Gets string member of an System 242 | * 243 | * @param sSystem System index 244 | * @param szMember Member name 245 | * @param szOut Buffer to copy the value 246 | * @param iLen Maximum size of buffer 247 | */ 248 | native bool:ParticleSystem_GetMemberString(const &ParticleSystem:sSystem, const szMember[], szOut[], iLen); 249 | 250 | /** 251 | * Sets string member of an System 252 | * 253 | * @param sSystem System index 254 | * @param szMember Member name 255 | * @param szValue String value to set 256 | */ 257 | native ParticleSystem_SetMemberString(const &ParticleSystem:sSystem, const szMember[], const szValue[]); 258 | 259 | /** 260 | * Gets particle index by particle pointer. 261 | * 262 | * @param sParticle The particle pointer. 263 | * 264 | * @return The index of the particle. 265 | */ 266 | native Particle_GetIndex(const &Particle:sParticle); 267 | 268 | /** 269 | * Gets particle batch index by particle pointer. 270 | * 271 | * @param sParticle The particle pointer. 272 | * 273 | * @return The batch index of the particle. 274 | */ 275 | native Particle_GetBatchIndex(const &Particle:sParticle); 276 | 277 | /** 278 | * Gets particle entity by particle pointer. 279 | * 280 | * @param sParticle The particle pointer. 281 | * 282 | * @return The entity of the particle. 283 | */ 284 | native Particle_GetEntity(const &Particle:sParticle); 285 | 286 | /** 287 | * Gets particle system pointer by particle pointer. 288 | * 289 | * @param sParticle The particle pointer. 290 | * 291 | * @return The particle system pointer. 292 | */ 293 | native ParticleSystem:Particle_GetSystem(const &Particle:sParticle); 294 | 295 | /** 296 | * Retrieves the time at which a particle was created. 297 | * 298 | * @param sParticle The particle pointer. 299 | * 300 | * @return The creation time of the particle. 301 | */ 302 | native Float:Particle_GetCreatedTime(const &Particle:sParticle); 303 | 304 | /** 305 | * Retrieves the time at which a particle will killed. 306 | * 307 | * @param sParticle The particle pointer. 308 | * 309 | * @return The kill time of the particle. 310 | */ 311 | native Float:Particle_GetKillTime(const &Particle:sParticle); 312 | 313 | /** 314 | * Retrieves the time at which a particle was thinked last. 315 | * 316 | * @param sParticle The particle pointer. 317 | * 318 | * @return The last think time of the particle. 319 | */ 320 | native Float:Particle_GetLastThink(const &Particle:sParticle); 321 | 322 | /** 323 | * Retrieves the origin of the particle. 324 | * 325 | * @param sSystem The particle structure pointer. 326 | * @param vecOut The vector to set. 327 | * 328 | * @noreturn 329 | */ 330 | native Particle_GetOrigin(const &Particle:sParticle, Float:vecOut[3]); 331 | 332 | /** 333 | * Sets the origin of the particle. 334 | * 335 | * @param sSystem The particle structure pointer. 336 | * @param vecOrigin The origin vector. 337 | * 338 | * @noreturn 339 | */ 340 | native Particle_SetOrigin(const &Particle:sParticle, const Float:vecOrigin[3]); 341 | 342 | /** 343 | * Retrieves the angles of the particle. 344 | * 345 | * @param sSystem The particle structure pointer. 346 | * @param vecOut The vector to set. 347 | * 348 | * @noreturn 349 | */ 350 | native Particle_GetAngles(const &Particle:sParticle, Float:vecOut[3]); 351 | 352 | /** 353 | * Sets the angles of the particle. 354 | * 355 | * @param sSystem The particle structure pointer. 356 | * @param vecAngles The angles vector. 357 | * 358 | * @noreturn 359 | */ 360 | native Particle_SetAngles(const &Particle:sParticle, const Float:vecAngles[3]); 361 | 362 | /** 363 | * Retrieves the velocity of the particle. 364 | * 365 | * @param sSystem The particle structure pointer. 366 | * @param vecOut The vector to set. 367 | * 368 | * @noreturn 369 | */ 370 | native Particle_GetVelocity(const &Particle:sParticle, Float:vecOut[3]); 371 | 372 | /** 373 | * Sets the velocity of the particle. 374 | * 375 | * @param sSystem The particle structure pointer. 376 | * @param vecVelocity The origin velocity. 377 | * 378 | * @noreturn 379 | */ 380 | native Particle_SetVelocity(const &Particle:sParticle, const Float:vecVelocity[3]); 381 | -------------------------------------------------------------------------------- /include/api_particles_const.inc: -------------------------------------------------------------------------------- 1 | #if defined _api_particles_const_included 2 | #endinput 3 | #endif 4 | #define _api_particles_const_included 5 | 6 | #define PARTICLE_MAX_MEMBER_LENGTH 64 7 | 8 | enum ParticleEffectHook { 9 | ParticleEffectHook_System_Init, 10 | ParticleEffectHook_System_Destroy, 11 | ParticleEffectHook_System_Think, 12 | ParticleEffectHook_System_Activated, 13 | ParticleEffectHook_System_Deactivated, 14 | ParticleEffectHook_Particle_Init, 15 | ParticleEffectHook_Particle_Destroy, 16 | ParticleEffectHook_Particle_Think, 17 | ParticleEffectHook_Particle_EntityInit 18 | }; 19 | 20 | enum ParticleEffectFlag (<<=1) { 21 | ParticleEffectFlag_None = 0, 22 | ParticleEffectFlag_AttachParticles = 1 23 | }; 24 | -------------------------------------------------------------------------------- /include/api_player_camera.inc: -------------------------------------------------------------------------------- 1 | #if defined _api_player_camera_included 2 | #endinput 3 | #endif 4 | #define _api_player_camera_included 5 | 6 | #pragma reqlib api_player_camera 7 | 8 | /** 9 | * Activates the player's camera. 10 | * 11 | * @param pPlayer The player entity. 12 | * 13 | * @noreturn 14 | */ 15 | native PlayerCamera_Activate(pPlayer); 16 | 17 | /** 18 | * Deactivates the player's camera. 19 | * 20 | * @param pPlayer The player entity. 21 | * 22 | * @noreturn 23 | */ 24 | native PlayerCamera_Deactivate(pPlayer); 25 | 26 | /** 27 | * Checks if the player's camera is active. 28 | * 29 | * @param pPlayer The player entity. 30 | * 31 | * @return True if the camera is active, false otherwise. 32 | */ 33 | native bool:PlayerCamera_IsActive(pPlayer); 34 | 35 | /** 36 | * Sets the offset of the player's camera. 37 | * 38 | * @param pPlayer The player entity. 39 | * @param vecOffset The offset vector. 40 | * 41 | * @noreturn 42 | */ 43 | native PlayerCamera_SetOffset(pPlayer, const Float:vecOffset[3]); 44 | 45 | /** 46 | * Sets the angles of the player's camera. 47 | * 48 | * @param pPlayer The player entity. 49 | * @param vecAngles The angles vector. 50 | * 51 | * @noreturn 52 | */ 53 | native PlayerCamera_SetAngles(pPlayer, const Float:vecAngles[3]); 54 | 55 | /** 56 | * Sets the distance of the player's camera. 57 | * 58 | * @param pPlayer The player entity. 59 | * @param flDistance The distance value. 60 | * 61 | * @noreturn 62 | */ 63 | native PlayerCamera_SetDistance(pPlayer, Float:flDistance); 64 | 65 | /** 66 | * Sets the axis lock of the player's camera. 67 | * 68 | * @param pPlayer The player entity. 69 | * @param bLockPitch Lock Pitch axis. 70 | * @param bLockYaw Lock Yaw axis. 71 | * @param bLockRoll Lock Roll axis. 72 | * 73 | * @noreturn 74 | */ 75 | native PlayerCamera_SetAxisLock(pPlayer, bool:bLockPitch, bool:bLockYaw, bool:bLockRoll); 76 | 77 | /** 78 | * Sets the target entity of the player's camera. 79 | * 80 | * @param pPlayer The player entity. 81 | * @param pTarget The target entity. 82 | * 83 | * @noreturn 84 | */ 85 | native PlayerCamera_SetTargetEntity(pPlayer, pTarget); 86 | 87 | /** 88 | * Sets the thinking delay of the player's camera. 89 | * 90 | * @param pPlayer The player entity. 91 | * @param flThinkDelay The thinking delay value. 92 | * 93 | * @noreturn 94 | */ 95 | native PlayerCamera_SetThinkDelay(pPlayer, Float:flThinkDelay); 96 | 97 | /** 98 | * Function called when the player's camera is activated. 99 | * 100 | * @param pPlayer The player entity. 101 | * 102 | * @noreturn 103 | */ 104 | forward PlayerCamera_Fw_Activate(pPlayer); 105 | 106 | /** 107 | * Function called when the player's camera is deactivated. 108 | * 109 | * @param pPlayer The player entity. 110 | * 111 | * @noreturn 112 | */ 113 | forward PlayerCamera_Fw_Deactivate(pPlayer); 114 | 115 | /** 116 | * Function called when the player's camera is activated. 117 | * 118 | * @param pPlayer The player entity. 119 | * 120 | * @noreturn 121 | */ 122 | forward PlayerCamera_Fw_Activated(pPlayer); 123 | 124 | /** 125 | * Function called when the player's camera is deactivated. 126 | * 127 | * @param pPlayer The player entity. 128 | * 129 | * @noreturn 130 | */ 131 | forward PlayerCamera_Fw_Deactivated(pPlayer); 132 | -------------------------------------------------------------------------------- /include/api_player_cosmetics.inc: -------------------------------------------------------------------------------- 1 | #if defined _api_player_cosmetic_included 2 | #endinput 3 | #endif 4 | #define _api_player_cosmetic_included 5 | 6 | #pragma reqlib api_player_cosmetic 7 | 8 | /** 9 | * Equip a player with a cosmetic item. 10 | * 11 | * @param pPlayer The player to equip the item to. 12 | * @param iModelIndex The index of the cosmetic item model. 13 | * 14 | * @noreturn 15 | */ 16 | native PlayerCosmetic_Equip(pPlayer, iModelIndex); 17 | 18 | /** 19 | * Unequip a cosmetic item from a player. 20 | * 21 | * @param pPlayer The player to unequip the item from. 22 | * @param iModelIndex The index of the cosmetic item model. 23 | * 24 | * @return True if the item was successfully unequipped, false otherwise. 25 | */ 26 | native bool:PlayerCosmetic_Unequip(pPlayer, iModelIndex); 27 | 28 | /** 29 | * Check if a player has equipped a specific cosmetic item. 30 | * 31 | * @param pPlayer The player to check. 32 | * @param iModelIndex The index of the cosmetic item model. 33 | * 34 | * @return True if the player has the item equipped, false otherwise. 35 | */ 36 | native bool:PlayerCosmetic_IsEquiped(pPlayer, iModelIndex); 37 | 38 | /** 39 | * Get the entity of the equipped cosmetic item for a player. 40 | * 41 | * @param pPlayer The player whose equipped item entity to get. 42 | * @param iModelIndex The index of the cosmetic item model. 43 | * 44 | * @return The entity of the equipped cosmetic item, or 0 if not equipped. 45 | */ 46 | native PlayerCosmetic_GetEntity(pPlayer, iModelIndex); 47 | -------------------------------------------------------------------------------- /include/api_player_dizziness.inc: -------------------------------------------------------------------------------- 1 | #if defined _api_player_dizziness_included 2 | #endinput 3 | #endif 4 | #define _api_player_dizziness_included 5 | 6 | #pragma reqlib api_player_dizziness 7 | 8 | /** 9 | * Sets the dizziness strength for a player. 10 | * 11 | * @param pPlayer The player ID. 12 | * @param flStrength The strength of the dizziness. 13 | * 14 | * @noreturn 15 | */ 16 | native PlayerDizziness_Set(pPlayer, Float:flStrength); 17 | 18 | /** 19 | * Gets the current dizziness strength for a player. 20 | * 21 | * @param pPlayer The player ID. 22 | * 23 | * @return The current dizziness strength as a float. 24 | */ 25 | native Float:PlayerDizziness_Get(pPlayer); 26 | -------------------------------------------------------------------------------- /include/api_player_effects.inc: -------------------------------------------------------------------------------- 1 | #if defined _api_player_effects_included 2 | #endinput 3 | #endif 4 | #define _api_player_effects_included 5 | 6 | #pragma reqlib api_player_effects 7 | 8 | #include 9 | 10 | native PlayerEffect_Register(const szId[], const szInvokeFunction[], const szRevokeFunction[], const szIcon[] = "", const irgIconColor[3] = {255, 255, 255}); 11 | native PlayerEffect_Set(pPlayer, const szId[], bool:bValue, Float:flDuration = -1.0, bool:bExtend = true); 12 | native bool:PlayerEffect_Get(pPlayer, const szId[]); 13 | native Float:PlayerEffect_GetEndtime(pPlayer, const szId[]); 14 | native Float:PlayerEffect_GetDuration(pPlayer, const szId[]); 15 | -------------------------------------------------------------------------------- /include/api_player_effects_const.inc: -------------------------------------------------------------------------------- 1 | #if defined _api_player_effects_const_included 2 | #endinput 3 | #endif 4 | #define _api_player_effects_const_included 5 | -------------------------------------------------------------------------------- /include/api_player_inventory.inc: -------------------------------------------------------------------------------- 1 | #if defined _api_player_inventory_included 2 | #endinput 3 | #endif 4 | #define _api_player_inventory_included 5 | 6 | #pragma reqlib api_player_inventory 7 | 8 | /** 9 | * Retrieves an item from a player's inventory. 10 | * 11 | * @param pPlayer The player for which to get the item. 12 | * @param iSlot The slot index of the item to retrieve. 13 | * 14 | * @return Returns a structure containing the structure of the item. 15 | */ 16 | native Struct:PlayerInventory_GetItem(pPlayer, iSlot); 17 | 18 | /** 19 | * Retrieves the type of an item in a player's inventory. 20 | * 21 | * @param pPlayer The player for which to check the item type. 22 | * @param iSlot The slot index of the item. 23 | * @param szType The type of the item is copied into this string. 24 | * @param iLen The maximum length of the string. 25 | * 26 | * @noreturn 27 | */ 28 | native PlayerInventory_GetItemType(pPlayer, iSlot, szType[], iLen); 29 | 30 | /** 31 | * Checks if an item in a player's inventory matches the specified type. 32 | * 33 | * @param pPlayer The player for which to check the item type. 34 | * @param iSlot The slot index of the item. 35 | * @param szType The type of the item to check. 36 | * 37 | * @return Returns 1 if the item matches the type, 0 otherwise. 38 | */ 39 | native PlayerInventory_CheckItemType(pPlayer, iSlot, const szType[]); 40 | 41 | /** 42 | * Gives an item to a player's inventory. 43 | * 44 | * @param pPlayer The player to give the item to. 45 | * @param szType The type of the item to give. 46 | * @param sItem The structure of the item to give. 47 | * 48 | * @noreturn 49 | */ 50 | native PlayerInventory_GiveItem(pPlayer, const szType[], Struct:sItem); 51 | 52 | /** 53 | * Sets the details of an item in a player's inventory. 54 | * 55 | * @param pPlayer The player for which to set the item. 56 | * @param iSlot The slot index of the item to set. 57 | * @param szType The type of the item to set. 58 | * @param sItem The structure of the item to set. 59 | * 60 | * @noreturn 61 | */ 62 | native PlayerInventory_SetItem(pPlayer, iSlot, const szType[], Struct:sItem); 63 | 64 | /** 65 | * Takes an item from a player's inventory. 66 | * 67 | * @param pPlayer The player from which to take the item. 68 | * @param iSlot The slot index of the item to take. 69 | * 70 | * @noreturn 71 | */ 72 | native PlayerInventory_TakeItem(pPlayer, iSlot); 73 | 74 | /** 75 | * Retrieves the number of slots in a player's inventory. 76 | * 77 | * @param pPlayer The player for which to get the inventory size. 78 | * 79 | * @return The number of slots in the player's inventory. 80 | */ 81 | native PlayerInventory_Size(pPlayer); 82 | 83 | forward PlayerInventory_Fw_Initialized(pPlayer); 84 | forward PlayerInventory_Fw_Load(pPlayer); 85 | forward PlayerInventory_Fw_Loaded(pPlayer); 86 | forward PlayerInventory_Fw_Save(pPlayer); 87 | forward PlayerInventory_Fw_Saved(pPlayer); 88 | forward PlayerInventory_Fw_SlotCreated(pPlayer, iSlot); 89 | forward PlayerInventory_Fw_SlotRemoved(pPlayer, iSlot); 90 | forward PlayerInventory_Fw_SlotLoad(pPlayer, iSlot); 91 | forward PlayerInventory_Fw_SlotLoaded(pPlayer, iSlot); 92 | forward PlayerInventory_Fw_SlotSave(pPlayer, iSlot); 93 | forward PlayerInventory_Fw_SlotSaved(pPlayer, iSlot); 94 | -------------------------------------------------------------------------------- /include/api_player_model.inc: -------------------------------------------------------------------------------- 1 | #if defined _api_player_model_included 2 | #endinput 3 | #endif 4 | #define _api_player_model_included 5 | 6 | #pragma reqlib api_player_model 7 | 8 | native PlayerModel_Get(pPlayer, szOut[], iLen); 9 | native PlayerModel_GetCurrent(pPlayer, szOut[], iLen); 10 | native PlayerModel_GetEntity(pPlayer); 11 | native bool:PlayerModel_HasCustom(pPlayer); 12 | native PlayerModel_Set(pPlayer, const szModel[]); 13 | native PlayerModel_Update(pPlayer); 14 | native PlayerModel_UpdateAnimation(pPlayer); 15 | native PlayerModel_Reset(pPlayer); 16 | native PlayerModel_SetSequence(pPlayer, const szSequence[]); 17 | native PlayerModel_PrecacheAnimation(const szAnimation[]); 18 | -------------------------------------------------------------------------------- /include/api_player_viewrange.inc: -------------------------------------------------------------------------------- 1 | // This is a beta version, some functions may be unstable. Use at your own risk. 2 | 3 | #if defined _api_player_viewrange_included 4 | #endinput 5 | #endif 6 | #define _api_player_viewrange_included 7 | 8 | #pragma reqlib api_player_viewrange 9 | 10 | native Float:PlayerViewRange_Get(pPlayer); 11 | native PlayerViewRange_Set(pPlayer, Float:flValue); 12 | native PlayerViewRange_Update(pPlayer); 13 | native PlayerViewRange_Reset(pPlayer); 14 | -------------------------------------------------------------------------------- /include/api_rounds.inc: -------------------------------------------------------------------------------- 1 | #if defined _api_rounds_included 2 | #endinput 3 | #endif 4 | #define _api_rounds_included 5 | 6 | #pragma reqlib api_rounds 7 | 8 | native Round_DispatchWin(iTeam, Float:fDelay); 9 | native Round_SetTime(iTime); 10 | native Round_GetTime(); 11 | native Round_GetTimeLeft(); 12 | native bool:Round_IsRoundStarted(); 13 | native bool:Round_IsRoundEnd(); 14 | 15 | forward Round_Fw_NewRound(); 16 | forward Round_Fw_RoundStart(); 17 | forward Round_Fw_RoundEnd(iWinnerTeam); 18 | forward Round_Fw_RoundExpired(); 19 | forward Round_Fw_RoundRestart(); 20 | forward Round_Fw_RoundTimerTick(); 21 | forward Round_Fw_CheckWinCondition(); 22 | 23 | /** 24 | * @deprecated This function is deprecated, use Round_Fw_CheckWinCondition forward instead. 25 | */ 26 | native Round_HookCheckWinConditions(const szFunction[]); 27 | -------------------------------------------------------------------------------- /include/api_waypoint_markers.inc: -------------------------------------------------------------------------------- 1 | /* 2 | Credits: 3 | joaquimandrade 4 | */ 5 | 6 | #if defined _api_waypoint_markers_included 7 | #endinput 8 | #endif 9 | #define _api_waypoint_markers_included 10 | 11 | #pragma reqlib api_waypoint_markers 12 | 13 | native WaypointMarker_Create(const szModel[], const Float:vecOrigin[3] = {0.0, 0.0, 0.0}, Float:flScale = 1.0, const Float:rgflSize[2] = {64.0, 64.0}); 14 | native WaypointMarker_SetVisible(pMarker, pPlayer, bool:bValue); 15 | 16 | forward WaypointMarker_Fw_Created(pMarker); 17 | forward WaypointMarker_Fw_Destroy(pMarker); 18 | -------------------------------------------------------------------------------- /include/cellstruct.inc: -------------------------------------------------------------------------------- 1 | #if defined _cellstruct_included 2 | #endinput 3 | #endif 4 | 5 | #define _cellstruct_included 6 | 7 | #include 8 | #include 9 | 10 | enum Struct { 11 | Invalid_Struct = 0 12 | }; 13 | 14 | stock Struct:StructCreate(any:interface) { 15 | new Struct:struct = Struct:ArrayCreate(_, interface); 16 | ArrayResize(Array:struct, interface); 17 | return struct; 18 | } 19 | 20 | stock Struct:StructFromArray(any:interface, const any:data[any:0]) { 21 | new Struct:struct = StructCreate(interface); 22 | StructSetArray(struct, 0, data, interface); 23 | return struct; 24 | } 25 | 26 | stock Struct:StructClone(const &Struct:which) { 27 | return Struct:ArrayClone(Array:which); 28 | } 29 | 30 | stock StructSize(const &Struct:which) { 31 | return ArraySize(Array:which); 32 | } 33 | 34 | stock StructCopy(const &Struct:which, &Struct:other) { 35 | new size = min(StructSize(which), StructSize(other)); 36 | 37 | for (new i = 0; i < size; ++i) { 38 | StructSetCell(other, i, StructGetCell(which, i)); 39 | } 40 | } 41 | 42 | stock StructDestroy(&Struct:which) { 43 | ArrayDestroy(Array:which); 44 | which = Invalid_Struct; 45 | } 46 | 47 | stock any:StructGetCell(const &Struct:which, any:item, any:block = 0, bool:asChar = false) { 48 | return ArrayGetCell(Array:which, item + block, _, asChar); 49 | } 50 | 51 | stock StructSetCell(const &Struct:which, any:item, any:value, any:block = 0, bool:asChar = false) { 52 | ArraySetCell(Array:which, item + block, value, _, asChar); 53 | } 54 | 55 | stock StructGetArray(const &Struct:which, any:item, any:output[any:0], any:size, any:block = 0) { 56 | for (new i = 0; i < size; ++i) { 57 | output[i] = StructGetCell(which, item, block + i); 58 | } 59 | } 60 | 61 | stock StructSetArray(const &Struct:which, any:item, const any:input[any:0], any:size, any:block = 0) { 62 | for (new i = 0; i < size; ++i) { 63 | StructSetCell(which, item, input[i], block + i); 64 | } 65 | } 66 | 67 | stock StructGetString(const &Struct:which, any:item, output[], any:len, any:block = 0) { 68 | for (new i = 0; i < len; ++i) { 69 | output[i] = StructGetCell(which, item, block + i); 70 | 71 | if (output[i] == '^0') { 72 | break; 73 | } 74 | } 75 | } 76 | 77 | stock DoNotUse:StructGetStringHandle(const &Struct:which, any:item, any:block = 0) { 78 | return ArrayGetStringHandle(Array:which, item + block); 79 | } 80 | 81 | stock StructSetString(const &Struct:which, any:item, const input[], any:len = -1, any:block = 0) { 82 | for (new i = 0; i < len || len == -1; ++i) { 83 | StructSetCell(which, item, input[i], block + i); 84 | 85 | if (input[i] == '^0') { 86 | break; 87 | } 88 | } 89 | } 90 | 91 | stock StructStringify(const &Struct:which, output[], len) { 92 | new size = StructSize(which); 93 | new JSON:jsonData = json_init_array(); 94 | 95 | for (new i = 0; i < size; ++i) { 96 | json_array_append_number(jsonData, StructGetCell(which, i)); 97 | } 98 | 99 | json_serial_to_string(jsonData, output, len); 100 | 101 | json_free(jsonData); 102 | } 103 | 104 | stock Struct:StructFromString(const &Struct:which, const input[]) { 105 | new JSON:jsonData = json_parse(input); 106 | new size = json_array_get_count(jsonData); 107 | 108 | new Struct:sStruct = StructCreate(size); 109 | 110 | for (new i = 0; i < size; ++i) { 111 | StructSetCell(sStruct, i, json_array_get_number(jsonData, i)); 112 | } 113 | 114 | json_free(jsonData); 115 | 116 | return sStruct; 117 | } 118 | -------------------------------------------------------------------------------- /util/cellstruct.inc: -------------------------------------------------------------------------------- 1 | #if defined _cellstruct_included 2 | #endinput 3 | #endif 4 | 5 | #define _cellstruct_included 6 | 7 | #include 8 | #include 9 | 10 | enum Struct { 11 | Invalid_Struct = 0 12 | }; 13 | 14 | stock Struct:StructCreate(any:interface) { 15 | new Struct:struct = Struct:ArrayCreate(_, interface); 16 | ArrayResize(Array:struct, interface); 17 | return struct; 18 | } 19 | 20 | stock Struct:StructFromArray(any:interface, const any:data[any:0]) { 21 | new Struct:struct = StructCreate(interface); 22 | StructSetArray(struct, 0, data, interface); 23 | return struct; 24 | } 25 | 26 | stock Struct:StructClone(const &Struct:which) { 27 | return Struct:ArrayClone(Array:which); 28 | } 29 | 30 | stock StructSize(const &Struct:which) { 31 | return ArraySize(Array:which); 32 | } 33 | 34 | stock StructCopy(const &Struct:which, &Struct:other) { 35 | new size = min(StructSize(which), StructSize(other)); 36 | 37 | for (new i = 0; i < size; ++i) { 38 | StructSetCell(other, i, StructGetCell(which, i)); 39 | } 40 | } 41 | 42 | stock StructDestroy(&Struct:which) { 43 | ArrayDestroy(Array:which); 44 | which = Invalid_Struct; 45 | } 46 | 47 | stock any:StructGetCell(const &Struct:which, any:item, any:block = 0, bool:asChar = false) { 48 | return ArrayGetCell(Array:which, item + block, _, asChar); 49 | } 50 | 51 | stock StructSetCell(const &Struct:which, any:item, any:value, any:block = 0, bool:asChar = false) { 52 | ArraySetCell(Array:which, item + block, value, _, asChar); 53 | } 54 | 55 | stock StructGetArray(const &Struct:which, any:item, any:output[any:0], any:size, any:block = 0) { 56 | for (new i = 0; i < size; ++i) { 57 | output[i] = StructGetCell(which, item, block + i); 58 | } 59 | } 60 | 61 | stock StructSetArray(const &Struct:which, any:item, const any:input[any:0], any:size, any:block = 0) { 62 | for (new i = 0; i < size; ++i) { 63 | StructSetCell(which, item, input[i], block + i); 64 | } 65 | } 66 | 67 | stock StructGetString(const &Struct:which, any:item, output[], any:len, any:block = 0) { 68 | for (new i = 0; i < len; ++i) { 69 | output[i] = StructGetCell(which, item, block + i); 70 | 71 | if (output[i] == '^0') { 72 | break; 73 | } 74 | } 75 | } 76 | 77 | stock DoNotUse:StructGetStringHandle(const &Struct:which, any:item, any:block = 0) { 78 | return ArrayGetStringHandle(Array:which, item + block); 79 | } 80 | 81 | stock StructSetString(const &Struct:which, any:item, const input[], any:len = -1, any:block = 0) { 82 | for (new i = 0; i < len || len == -1; ++i) { 83 | StructSetCell(which, item, input[i], block + i); 84 | 85 | if (input[i] == '^0') { 86 | break; 87 | } 88 | } 89 | } 90 | 91 | stock StructStringify(const &Struct:which, output[], len) { 92 | new size = StructSize(which); 93 | new JSON:jsonData = json_init_array(); 94 | 95 | for (new i = 0; i < size; ++i) { 96 | json_array_append_number(jsonData, StructGetCell(which, i)); 97 | } 98 | 99 | json_serial_to_string(jsonData, output, len); 100 | 101 | json_free(jsonData); 102 | } 103 | 104 | stock Struct:StructFromString(const &Struct:which, const input[]) { 105 | new JSON:jsonData = json_parse(input); 106 | new size = json_array_get_count(jsonData); 107 | 108 | new Struct:sStruct = StructCreate(size); 109 | 110 | for (new i = 0; i < size; ++i) { 111 | StructSetCell(sStruct, i, json_array_get_number(jsonData, i)); 112 | } 113 | 114 | json_free(jsonData); 115 | 116 | return sStruct; 117 | } 118 | -------------------------------------------------------------------------------- /util/command_util.inc: -------------------------------------------------------------------------------- 1 | #if defined _command_util_included 2 | #endinput 3 | #endif 4 | #define _command_util_included 5 | 6 | #include 7 | #include 8 | 9 | enum (<<=1) { 10 | CMD_TARGET_ALL, 11 | CMD_TARGET_NO_ONE = 1, 12 | CMD_TARGET_HAS_CALLER, 13 | CMD_TARGET_CALLER, 14 | CMD_TARGET_IGNORE_CALLER, 15 | CMD_TARGET_ALIVE, 16 | CMD_TARGET_DEAD, 17 | CMD_TARGET_HUMAN, 18 | CMD_TARGET_BOT, 19 | CMD_TARGET_ADMIN, 20 | CMD_TARGET_VIEWCONE, 21 | CMD_TARGET_VISIBLE, 22 | CMD_TARGET_TEAM_T, 23 | CMD_TARGET_TEAM_CT, 24 | CMD_TARGET_TEAM_SPEC 25 | }; 26 | 27 | stock CMD_RESOLVE_TARGET(const szTarget[]) { 28 | if (szTarget[0] == '@') { 29 | return -CMD_RESOLVE_ALIASES_BITS(szTarget[1]); 30 | } else if (szTarget[0] == '#') { 31 | static pTarget; pTarget = find_player("k", str_to_num(szTarget[1])); 32 | if (pTarget) return pTarget; 33 | } else { 34 | static pTarget; pTarget = find_player("b", szTarget); 35 | if (pTarget) return pTarget; 36 | } 37 | 38 | return CMD_TARGET_NO_ONE; 39 | } 40 | 41 | stock CMD_RESOLVE_ALIASES_BITS(const szAliases[]) { 42 | static iBits; iBits = 0; 43 | static iAliasStartPos; iAliasStartPos = 0; 44 | static iCursor; iCursor = 0; 45 | 46 | do { 47 | if (iCursor && (szAliases[iCursor] == '_' || szAliases[iCursor] == '^0')) { 48 | if (iCursor > iAliasStartPos && szAliases[iAliasStartPos] != '_') { 49 | iBits |= CMD_RESOLVE_ALIAS_BITS(szAliases[iAliasStartPos], iCursor - iAliasStartPos); 50 | static szSubAlias[32]; copy(szSubAlias, iCursor - iAliasStartPos, szAliases[iAliasStartPos]); 51 | } 52 | 53 | iAliasStartPos = iCursor + 1; 54 | } 55 | 56 | iCursor++; 57 | } while (szAliases[iCursor - 1] != '^0'); 58 | 59 | return iBits; 60 | } 61 | 62 | stock CMD_RESOLVE_ALIAS_BITS(const szAlias[], iMaxLen = 0) { 63 | if (equal(szAlias, "all", iMaxLen)) return CMD_TARGET_ALL; 64 | else if (equal(szAlias, "alive", iMaxLen)) return CMD_TARGET_ALIVE; 65 | else if (equal(szAlias, "dead", iMaxLen)) return CMD_TARGET_DEAD; 66 | else if (equal(szAlias, "human", iMaxLen)) return CMD_TARGET_HUMAN; 67 | else if (equal(szAlias, "bot", iMaxLen)) return CMD_TARGET_BOT; 68 | else if (equal(szAlias, "admin", iMaxLen)) return CMD_TARGET_ADMIN; 69 | else if (equal(szAlias, "t", iMaxLen)) return CMD_TARGET_TEAM_T; 70 | else if (equal(szAlias, "ct", iMaxLen)) return CMD_TARGET_TEAM_CT; 71 | else if (equal(szAlias, "spec", iMaxLen)) return CMD_TARGET_TEAM_SPEC; 72 | else if (equal(szAlias, "me", iMaxLen)) return CMD_TARGET_HAS_CALLER | CMD_TARGET_CALLER; 73 | else if (equal(szAlias, "notme", iMaxLen)) return CMD_TARGET_HAS_CALLER | CMD_TARGET_IGNORE_CALLER; 74 | else if (equal(szAlias, "view", iMaxLen)) return CMD_TARGET_HAS_CALLER | CMD_TARGET_VIEWCONE | CMD_TARGET_VISIBLE | CMD_TARGET_ALIVE; 75 | 76 | return CMD_TARGET_NO_ONE; 77 | } 78 | 79 | stock bool:CMD_SHOULD_TARGET_PLAYER(pPlayer, iTarget, pCaller = 0) { 80 | if (!is_user_connected(pPlayer)) return false; 81 | if (iTarget == pPlayer) return true; 82 | if (iTarget > 0) return false; 83 | 84 | static iTargetBits; iTargetBits = -iTarget; 85 | 86 | if (!iTargetBits) return true; 87 | if (iTargetBits & CMD_TARGET_ALL) return true; 88 | if (iTargetBits & CMD_TARGET_NO_ONE) return false; 89 | if (iTargetBits & CMD_TARGET_HAS_CALLER && !pCaller) return false; 90 | if (iTargetBits & CMD_TARGET_CALLER && pPlayer != pCaller) return false; 91 | if (iTargetBits & CMD_TARGET_IGNORE_CALLER && pPlayer == pCaller) return false; 92 | 93 | static bool:bAlive; bAlive = !!is_user_alive(pPlayer); 94 | if (iTargetBits & CMD_TARGET_ALIVE && !bAlive) return false; 95 | if (iTargetBits & CMD_TARGET_DEAD && bAlive) return false; 96 | 97 | static bool:bBot; bBot = !!is_user_bot(pPlayer); 98 | if (iTargetBits & CMD_TARGET_HUMAN && bBot) return false; 99 | if (iTargetBits & CMD_TARGET_BOT && !bBot) return false; 100 | 101 | static iFlags; iFlags = get_user_flags(pPlayer); 102 | if (iTargetBits & CMD_TARGET_ADMIN && ~iFlags & ADMIN_ADMIN) return false; 103 | 104 | if (cstrike_running()) { 105 | #if AMXX_VERSION_NUM > 182 106 | static iTeam; iTeam = get_ent_data(pPlayer, "CBasePlayer", "m_iTeam"); 107 | 108 | if (iTargetBits & CMD_TARGET_TEAM_T && iTeam != 1) return false; 109 | if (iTargetBits & CMD_TARGET_TEAM_CT && iTeam != 2) return false; 110 | if (iTargetBits & CMD_TARGET_TEAM_SPEC && iTeam != 0 && iTeam != 3) return false; 111 | #endif 112 | } 113 | 114 | if (iTargetBits & CMD_TARGET_VISIBLE && !is_visible(pCaller, pPlayer)) return false; 115 | 116 | if (iTargetBits & CMD_TARGET_VIEWCONE) { 117 | static Float:vecOrigin[3]; pev(pPlayer, pev_origin, vecOrigin); 118 | if (!is_in_viewcone(pCaller, vecOrigin)) return false; 119 | } 120 | 121 | return true; 122 | } 123 | -------------------------------------------------------------------------------- /util/datapack_stocks.inc: -------------------------------------------------------------------------------- 1 | #if defined _datapack_stocks_included 2 | #endinput 3 | #endif 4 | #define _datapack_stocks_included 5 | 6 | #if !defined _datapack_included 7 | #tryinclude 8 | #endif 9 | 10 | #if !defined _datapack_included 11 | #endinput 12 | #endif 13 | 14 | stock ReadPackArray(DataPack:pack, buffer[], maxlen = -1) { 15 | static len; len = ReadPackCell(pack); 16 | 17 | if (maxlen != -1) len = min(maxlen, len); 18 | 19 | for (new i = 0; i < len; ++i) { 20 | static value; value = ReadPackCell(pack); 21 | buffer[i] = value; 22 | } 23 | 24 | return len; 25 | } 26 | 27 | stock ReadPackFloatArray(DataPack:pack, Float:buffer[], maxlen = -1) { 28 | static len; len = ReadPackCell(pack); 29 | 30 | if (maxlen != -1) len = min(maxlen, len); 31 | 32 | for (new i = 0; i < len; ++i) { 33 | static Float:value; value = ReadPackFloat(pack); 34 | buffer[i] = value; 35 | } 36 | 37 | return len; 38 | } 39 | 40 | stock WritePackArray(DataPack:pack, const array[], maxlen) { 41 | WritePackCell(pack, maxlen); 42 | 43 | for (new i = 0; i < maxlen; ++i) { 44 | WritePackCell(pack, array[i]); 45 | } 46 | } 47 | 48 | stock WritePackFloatArray(DataPack:pack, const Float:array[], maxlen) { 49 | WritePackCell(pack, maxlen); 50 | 51 | for (new i = 0; i < maxlen; ++i) { 52 | WritePackFloat(pack, array[i]); 53 | } 54 | } 55 | 56 | stock GetDataPackOffsets(&cellOffset = 0, &floatOffset = 0, &stringOffset = 0, &charOffset = 0, &arrayOffset = 0) { 57 | new DataPack:pack = CreateDataPack(); 58 | 59 | SetPackPosition(pack, DataPackPos:0); 60 | WritePackCell(pack, DataPackPos:0); 61 | cellOffset = _:GetPackPosition(pack); 62 | 63 | SetPackPosition(pack, DataPackPos:0); 64 | WritePackCell(pack, DataPackPos:0); 65 | floatOffset = _:GetPackPosition(pack); 66 | 67 | SetPackPosition(pack, DataPackPos:0); 68 | WritePackString(pack, ""); 69 | stringOffset = _:GetPackPosition(pack); 70 | 71 | SetPackPosition(pack, DataPackPos:0); 72 | WritePackString(pack, "_"); 73 | charOffset = _:GetPackPosition(pack) - stringOffset; 74 | 75 | arrayOffset = cellOffset; 76 | 77 | DestroyDataPack(pack); 78 | } 79 | -------------------------------------------------------------------------------- /util/function_pointer.inc: -------------------------------------------------------------------------------- 1 | #if defined _function_pointer_included 2 | #endinput 3 | #endif 4 | #define _function_pointer_included 5 | 6 | enum Function { 7 | Invalid_FunctionPointer = 0 8 | }; 9 | 10 | stock Function:get_func_pointer(const szFunction[], iPluginId = -1) { 11 | static iFunctionId; iFunctionId = get_func_id(szFunction, iPluginId); 12 | 13 | if (iPluginId == -1) { 14 | iPluginId = get_plugin(-1); 15 | } 16 | 17 | if (iPluginId >= 0xFFFF) return Invalid_FunctionPointer; 18 | if (iFunctionId > 0xFFFF) return Invalid_FunctionPointer; 19 | 20 | return Function:(((iPluginId + 1) << 16) | (iFunctionId + 1)); 21 | } 22 | 23 | stock get_pfunc_function(const &Function:function) { 24 | return (_:function & 0xFFFF) - 1; 25 | } 26 | 27 | stock get_pfunc_plugin(const &Function:function) { 28 | return ((_:function >> 16) & 0xFFFF) - 1; 29 | } 30 | 31 | stock bool:is_pfunc_local(const &Function:function) { 32 | return get_pfunc_plugin(function) == -1; 33 | } 34 | 35 | stock callfunc_begin_p(const &Function:function) { 36 | return callfunc_begin_i(get_pfunc_function(function), get_pfunc_plugin(function)); 37 | } 38 | --------------------------------------------------------------------------------