sm-zombiereloaded-3/src/zr/weapons/weapons.inc

909 lines
25 KiB
PHP
Raw Normal View History

/*
* ============================================================================
*
* Zombie:Reloaded
*
* File: weapons.inc
* Type: Core
* Description: API for all weapon-related functions.
*
* Copyright (C) 2009 Greyscale, Richard Helgeby
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* ============================================================================
*/
/**
* Maximum length of a weapon name string
*/
#define WEAPONS_MAX_LENGTH 32
/**
* Number of REAL weapon slots (For CS:S)
*/
#define WEAPONS_SLOTS_MAX 5
/**
* @section CS:S start weapons.
*/
#define WEAPONS_SPAWN_T_WEAPON "weapon_glock"
#define WEAPONS_SPAWN_CT_WEAPON "weapon_usp"
/**
* @endsection
*/
/**
* Weapon config data indexes.
*/
enum WeaponsData
{
WEAPONS_DATA_NAME = 0,
WEAPONS_DATA_ENTITY,
WEAPONS_DATA_TYPE,
WEAPONS_DATA_SLOT,
WEAPONS_DATA_RESTRICTDEFAULT,
WEAPONS_DATA_TOGGLEABLE,
WEAPONS_DATA_AMMOTYPE,
WEAPONS_DATA_AMMOPRICE,
WEAPONS_DATA_KNOCKBACK,
WEAPONS_DATA_ZMARKETPRICE,
WEAPONS_DATA_ZMARKETPURCHASEMAX,
WEAPONS_DATA_RESTRICTED,
}
/**
* @endsection
*/
/**
* Variable to store active weapon offset value.
*/
new g_iToolsActiveWeapon;
/**
* Weapon slots.
*/
enum WeaponsSlot
{
Slot_Invalid = -1, /** Invalid weapon (slot). */
Slot_Primary = 0, /** Primary weapon slot. */
Slot_Secondary = 1, /** Secondary weapon slot. */
Slot_Melee = 2, /** Melee (knife) weapon slot. */
Slot_Projectile = 3, /** Projectile (grenades, flashbangs, etc) weapon slot. */
Slot_Explosive = 4, /** Explosive (c4) weapon slot. */
Slot_NVGs = 5, /** NVGs (fake) equipment slot. */
}
/**
* Array handle to store weapon config data.
*/
new Handle:arrayWeapons = INVALID_HANDLE;
#include "zr/weapons/restrict"
#include "zr/weapons/weaponammo"
#include "zr/weapons/weaponalpha"
#include "zr/weapons/zmarket"
#include "zr/weapons/menu_weapons"
/**
* Weapons module init function.
*/
WeaponsInit()
{
// Forward event to sub-modules.
RestrictInit();
}
/**
* All plugins have finished loading.
*/
WeaponsOnAllPluginsLoaded()
{
// Forward event to sub-modules.
WeaponAmmoOnAllPluginsLoaded();
}
/**
* Find active weapon-specific offsets here.
*/
WeaponsOnOffsetsFound()
{
// If offset "m_hActiveWeapon" can't be found, then stop the plugin.
g_iToolsActiveWeapon = FindSendPropInfo("CBasePlayer", "m_hActiveWeapon");
if (g_iToolsActiveWeapon == -1)
{
LogEvent(false, LogType_Fatal, LOG_CORE_EVENTS, LogModule_Weapons, "Offsets", "Offset \"CBasePlayer::m_hActiveWeapon\" was not found.");
}
// Forward event to sub-modules
WeaponAmmoOnOffsetsFound();
ZMarketOnOffsetsFound();
}
/**
* Create commands related to weapons here.
*/
WeaponsOnCommandsCreate()
{
// Forward event to sub-modules.
RestrictOnCommandsCreate();
ZMarketOnCommandsCreate();
}
/**
* Create weapon-related cookies here.
*/
WeaponsOnCookiesCreate()
{
// Forward event to sub-modules.
ZMarketOnCookiesCreate();
}
/**
* Loads weapon data from file.
*/
WeaponsLoad()
{
// Register config file.
ConfigRegisterConfig(File_Weapons, Structure_Keyvalue, CONFIG_FILE_ALIAS_WEAPONS);
// If module is disabled, then stop.
new bool:weapons = GetConVarBool(g_hCvarsList[CVAR_WEAPONS]);
if (!weapons)
{
return;
}
// Get weapons config path.
decl String:pathweapons[PLATFORM_MAX_PATH];
new bool:exists = ConfigGetCvarFilePath(CVAR_CONFIG_PATH_WEAPONS, pathweapons);
// If file doesn't exist, then log and stop.
if (!exists)
{
// Log failure.
LogEvent(false, LogType_Error, LOG_CORE_EVENTS, LogModule_Weapons, "Config Validation", "Missing weapons config file: %s", pathweapons);
return;
}
// Set the path to the config file.
ConfigSetConfigPath(File_Weapons, pathweapons);
// Load config from file and create array structure.
new bool:success = ConfigLoadConfig(File_Weapons, arrayWeapons);
// Unexpected error, stop plugin.
if (!success)
{
LogEvent(false, LogType_Fatal, LOG_CORE_EVENTS, LogModule_Weapons, "Config Validation", "Unexpected error encountered loading: %s", pathweapons);
}
// Validate weapons config.
new size = GetArraySize(arrayWeapons);
if (!size)
{
LogEvent(false, LogType_Error, LOG_CORE_EVENTS, LogModule_Weapons, "Config Validation", "No usable data found in weapons config file: %s", pathweapons);
}
// Now copy data to array structure.
WeaponsCacheData();
// Set config data.
ConfigSetConfigLoaded(File_Weapons, true);
ConfigSetConfigReloadFunc(File_Weapons, GetFunctionByName(GetMyHandle(), "WeaponsOnConfigReload"));
ConfigSetConfigHandle(File_Weapons, arrayWeapons);
// Forward event to sub-modules
RestrictLoad();
}
/**
* Caches weapon data from file into arrays.
* Make sure the file is loaded before (ConfigLoadConfig) to prep array structure.
*/
WeaponsCacheData()
{
// Get config's file path.
decl String:pathweapons[PLATFORM_MAX_PATH];
ConfigGetConfigPath(File_Weapons, pathweapons, sizeof(pathweapons));
new Handle:kvWeapons;
new bool:success = ConfigOpenConfigFile(File_Weapons, kvWeapons);
if (!success)
{
LogEvent(false, LogType_Fatal, LOG_CORE_EVENTS, LogModule_Weapons, "Config Validation", "Unexpected error caching data from weapons config file: %s", pathweapons);
}
decl String:weaponname[WEAPONS_MAX_LENGTH];
// x = array index
new size = GetArraySize(arrayWeapons);
for (new x = 0; x < size; x++)
{
WeaponsGetName(x, weaponname, sizeof(weaponname));
KvRewind(kvWeapons);
if (!KvJumpToKey(kvWeapons, weaponname))
{
LogEvent(false, LogType_Error, LOG_CORE_EVENTS, LogModule_Weapons, "Config Validation", "Couldn't cache weapon data for: %s (check weapons config)", weaponname);
continue;
}
// Get config data.
decl String:weaponentity[CONFIG_MAX_LENGTH];
decl String:weapontype[CONFIG_MAX_LENGTH];
decl String:ammotype[CONFIG_MAX_LENGTH];
// General
KvGetString(kvWeapons, "weaponentity", weaponentity, sizeof(weaponentity));
KvGetString(kvWeapons, "weapontype", weapontype, sizeof(weapontype));
new WeaponsSlot:weaponslot = WeaponsSlot:KvGetNum(kvWeapons, "weaponslot", -1);
// Restrict (core)
new bool:restrictdefault = ConfigKvGetStringBool(kvWeapons, "restrictdefault", "no");
new bool:toggleable = ConfigKvGetStringBool(kvWeapons, "toggleable", "yes");
// Weapon Ammo (core)
KvGetString(kvWeapons, "ammotype", ammotype, sizeof(ammotype));
new ammoprice = KvGetNum(kvWeapons, "ammoprice", -1);
// Knockback (module)
new Float:knockback = KvGetFloat(kvWeapons, "knockback", 1.0);
// ZMarket (module)
new zmarketprice = KvGetNum(kvWeapons, "zmarketprice", -1);
new zmarketpurchasemax = KvGetNum(kvWeapons, "zmarketpurchasemax", 0);
new Handle:arrayWeapon = GetArrayCell(arrayWeapons, x);
// Push data into array.
PushArrayString(arrayWeapon, weaponentity); // Index: 1
PushArrayString(arrayWeapon, weapontype); // Index: 2
PushArrayCell(arrayWeapon, weaponslot); // Index: 3
PushArrayCell(arrayWeapon, restrictdefault); // Index: 4
PushArrayCell(arrayWeapon, toggleable); // Index: 5
PushArrayString(arrayWeapon, ammotype); // Index: 6
PushArrayCell(arrayWeapon, ammoprice); // Index: 7
PushArrayCell(arrayWeapon, knockback); // Index: 8
PushArrayCell(arrayWeapon, zmarketprice); // Index: 9
PushArrayCell(arrayWeapon, zmarketpurchasemax); // Index: 10
// Initialize other stored weapon info here.
PushArrayCell(arrayWeapon, restrictdefault); // Index: 11
}
// We're done with this file now, so we can close it.
CloseHandle(kvWeapons);
}
/**
* Called when config is being reloaded.
*/
public WeaponsOnConfigReload()
{
// Reload weapons config.
WeaponsLoad();
}
/**
* Client is joining the server.
*
* @param client The client index.
*/
WeaponsClientInit(client)
{
// Forward event to sub-modules.
RestrictClientInit(client);
WeaponAlphaClientInit(client);
ZMarketClientInit(client);
}
/**
* Client is leaving the server.
*
* @param client The client index.
*/
WeaponsOnClientDisconnect(client)
{
// Forward event to sub-modules.
RestrictOnClientDisconnect(client);
WeaponAlphaOnClientDisconnect(client);
ZMarketOnClientDisconnect(client);
}
/**
* Client is spawning into the game.
*
* @param client The client index.
*/
WeaponsOnClientSpawn(client)
{
// Forward event to sub-modules.
RestrictOnClientSpawn(client);
}
/**
* Client is spawning into the game. *Post
*
* @param client The client index.
*/
WeaponsOnClientSpawnPost(client)
{
// Refresh all weapons on clients to cleanup any rendering errors.
WeaponsRefreshAllClientWeapons(client);
// Forward event to sub-modules.
ZMarketOnClientSpawnPost(client);
}
/**
* The round is ending.
*/
WeaponsOnRoundEnd()
{
// Forward event to sub-modules.
RestrictOnRoundEnd();
}
/**
* Called when a client picks up an item.
*
* @param client The client index.
* @param weapon The weapon index.
*/
WeaponsOnItemPickup(client, weapon)
{
// Forward event to sub-modules.
// Fire post OnItemPickup event.
// Fill datapack with event information.
new Handle:eventinfo = CreateDataPack();
WritePackCell(eventinfo, client);
WritePackCell(eventinfo, weapon);
// Create post delay timer.
2009-06-22 22:07:19 +02:00
CreateTimer(0.0, WeaponsOnItemPickupPost, eventinfo, TIMER_DATA_HNDL_CLOSE);
}
/**
* Called when a client picks up an item. *Post
*
* @param client The client index.
* @param weapon The weapon index.
*/
public Action:WeaponsOnItemPickupPost(Handle:timer, Handle:eventinfo)
{
// Get event info.
ResetPack(eventinfo);
new client = ReadPackCell(eventinfo);
new weapon = ReadPackCell(eventinfo);
// If client isn't in the game anymore, then stop.
if (!IsClientInGame(client))
{
return;
}
// If the weapon entity isn't valid anymore, then stop.
if (!IsValidEdict(weapon))
{
return;
}
// Forward event to sub-modules.
WeaponAlphaOnItemPickupPost(client, weapon);
}
/**
* Weapon data reading API.
*/
/**
* Clear cache for a given weapon.
*
* @param index The weapon index.
*/
stock WeaponsClearCache(index)
{
// Get array handle of weapon at given index.
new Handle:hWeapon = GetArrayCell(arrayWeapons, index);
// Clear array.
ClearArray(hWeapon);
}
/**
* Find the index at which the weapon's name is at.
*
* @param weapon The weapon name.
* @return The array index containing the given weapon name.
*/
stock WeaponsNameToIndex(const String:weapon[])
{
decl String:weaponname[WEAPONS_MAX_LENGTH];
// x = Array index.
new size = GetArraySize(arrayWeapons);
for (new x = 0; x < size; x++)
{
WeaponsGetName(x, weaponname, sizeof(weaponname));
// If names match, then return index.
if (StrEqual(weapon, weaponname, false))
{
return x;
}
}
// Name doesn't exist.
return -1;
}
/**
* Takes a weapon's entity name and returns the display name in weapons config file.
*
* @param entityname The entity to find the display of.
* @param display Buffer to store display name in.
* @param displaymaxlen The max length of the display name.
* @param noprefix If this is true, the entity name will be compared without the weapon_/item_ prefix.
* @return The index of the weapon found.
*/
stock WeaponsEntityToDisplay(const String:entityname[], String:display[], displaymaxlen, noprefix = false)
{
decl String:weaponentity[WEAPONS_MAX_LENGTH];
// Initialize string to null.
strcopy(display, sizeof(displaymaxlen), "");
// x = Array index.
new size = GetArraySize(arrayWeapons);
for (new x = 0; x < size; x++)
{
// If entity names don't match, then stop.
WeaponsGetEntity(x, weaponentity, sizeof(weaponentity));
// If noprefix is true, then strip the weapon_/item_ prefix.
if (noprefix)
{
ReplaceString(weaponentity, sizeof(weaponentity), "weapon_", "");
ReplaceString(weaponentity, sizeof(weaponentity), "item_", "");
}
if (!StrEqual(entityname, weaponentity, false))
{
continue;
}
// The entity names match, so return display.
WeaponsGetName(x, display, displaymaxlen);
// Return the weapon index.
return x;
}
// Nothing was found.
return -1;
}
/**
* Checks if a weapon is valid. (E.G. listed in weapons.txt)
* @param weapon The weapon name.
* @return Returns true if valid, false it not.
*/
stock bool:WeaponsIsWeaponValid(const String:weapon[])
{
return (WeaponsNameToIndex(weapon) != -1);
}
/**
* Gets the name of a weapon at a given index.
* @param index The weapon index.
* @param weapon The string to return name in.
* @param maxlen The max length of the string.
*/
stock WeaponsGetName(index, String:weapon[], maxlen)
{
// Get array handle of weapon at given index.
new Handle:arrayWeapon = GetArrayCell(arrayWeapons, index);
// Get weapon name.
GetArrayString(arrayWeapon, _:WEAPONS_DATA_NAME, weapon, maxlen);
}
/**
* Gets the entity of a weapon at a given index.
* @param index The weapon index.
* @param type The string to return entity in.
* @param maxlen The max length of the string.
*/
stock WeaponsGetEntity(index, String:type[], maxlen)
{
// Get array handle of weapon at given index.
new Handle:arrayWeapon = GetArrayCell(arrayWeapons, index);
// Get weapon type.
GetArrayString(arrayWeapon, _:WEAPONS_DATA_ENTITY, type, maxlen);
}
/**
* Gets the type of a weapon at a given index.
* @param index The weapon index.
* @param type The string to return type in.
* @param maxlen The max length of the string.
*/
stock WeaponsGetType(index, String:type[], maxlen)
{
// Get array handle of weapon at given index.
new Handle:arrayWeapon = GetArrayCell(arrayWeapons, index);
// Get weapon type.
GetArrayString(arrayWeapon, _:WEAPONS_DATA_TYPE, type, maxlen);
}
/**
* Gets the slot index of a weapon at a given index.
* @param index The weapon index.
* @return The slot index of the weapon.
*/
stock WeaponsSlot:WeaponsGetSlot(index)
{
// Get array handle of weapon at given index.
new Handle:arrayWeapon = GetArrayCell(arrayWeapons, index);
// Return default restriction status.
return WeaponsSlot:GetArrayCell(arrayWeapon, _:WEAPONS_DATA_SLOT);
}
/**
* Gets if a weapon is restricted by default.
* @param index The weapon index.
* @return True if the weapon is restricted by default, false if not.
*/
stock bool:WeaponsGetRestrictDefault(index)
{
// Get array handle of weapon at given index.
new Handle:arrayWeapon = GetArrayCell(arrayWeapons, index);
// Return default restriction status.
return bool:GetArrayCell(arrayWeapon, _:WEAPONS_DATA_RESTRICTDEFAULT);
}
/**
* Gets if a weapon's restriction status is toggleable.
* @param index The weapon index.
* @return True if the weapon restriction can be toggled, false if not.
*/
stock bool:WeaponsGetToggleable(index)
{
// Get array handle of weapon at given index.
new Handle:arrayWeapon = GetArrayCell(arrayWeapons, index);
// Return if weapon is toggleable.
return bool:GetArrayCell(arrayWeapon, _:WEAPONS_DATA_TOGGLEABLE);
}
/**
* Gets the ammo type of a weapon at a given index.
* @param index The weapon index.
* @param ammotype The string to return ammotype in.
* @param maxlen The max length of the string.
*/
stock WeaponsGetAmmoType(index, String:ammotype[], maxlen)
{
// Get array handle of weapon at given index.
new Handle:arrayWeapon = GetArrayCell(arrayWeapons, index);
// Get ammo type of the weapon.
GetArrayString(arrayWeapon, _:WEAPONS_DATA_AMMOTYPE, ammotype, maxlen);
}
/**
* Gets the price of ammo for the weapon.
* @param index The weapon index.
* @return The ammo price.
*/
stock WeaponsGetAmmoPrice(index)
{
// Get array handle of weapon at given index.
new Handle:arrayWeapon = GetArrayCell(arrayWeapons, index);
// Return ammo price of the weapon.
return GetArrayCell(arrayWeapon, _:WEAPONS_DATA_AMMOPRICE);
}
/**
* Gets the knockback multiplier for the weapon.
* @param index The weapon index.
* @return The weapon knockback multiplier.
*/
stock Float:WeaponsGetKnockback(index)
{
// Get array handle of weapon at given index.
new Handle:arrayWeapon = GetArrayCell(arrayWeapons, index);
// Return knockback multiplier of the weapon.
return Float:GetArrayCell(arrayWeapon, _:WEAPONS_DATA_KNOCKBACK);
}
/**
* Gets the ZMarket price for the weapon.
* @param index The weapon index.
* @return The ZMarket price.
*/
stock WeaponsGetZMarketPrice(index)
{
// Get array handle of weapon at given index.
new Handle:arrayWeapon = GetArrayCell(arrayWeapons, index);
// Return the ZMarket price of the weapon.
return GetArrayCell(arrayWeapon, _:WEAPONS_DATA_ZMARKETPRICE);
}
/**
* Gets the max purchases from ZMarket per round per client of a weapon.
* @param index The weapon index.
* @return The max purchases of the weapon.
*/
stock WeaponsGetZMarketPurchaseMax(index)
{
// Get array handle of weapon at given index.
new Handle:arrayWeapon = GetArrayCell(arrayWeapons, index);
// Return the ZMarket price of the weapon.
return GetArrayCell(arrayWeapon, _:WEAPONS_DATA_ZMARKETPURCHASEMAX);
}
/**
* General weapon API.
*/
/**
* Checks if a client has a specific weapon.
*
* @param client The client index.
* @param weapon The weapon classname.
*/
stock bool:WeaponsClientHasWeapon(client, const String:weapon[])
{
// Get all of client's current weapons.
new weapons[WeaponsSlot];
WeaponsGetClientWeapons(client, weapons);
decl String:classname[64];
// x = slot index
for (new x = 0; x < WEAPONS_SLOTS_MAX; x++)
{
// If slot is empty, then stop.
if (weapons[x] == -1)
{
continue;
}
// If the weapon's classname matches, then return true.
GetEdictClassname(weapons[x], classname, sizeof(classname));
if (StrEqual(weapon, classname, false))
{
return true;
}
}
return false;
}
/**
* Return an array that contains all client's weapon indexes.
*
* @param client The client index.
* @param weapons The weapon index array.
* -1 if no weapon in slot.
*/
stock WeaponsGetClientWeapons(client, weapons[WeaponsSlot])
{
// x = Weapon slot.
for (new x = 0; x < WEAPONS_SLOTS_MAX; x++)
{
weapons[x] = GetPlayerWeaponSlot(client, x);
}
}
/**
* Returns weapon index of the client's deployed weapon.
*
* @param client The client index.
* @return The weapon index of the deployed weapon.
* -1 if no weapon is deployed.
*/
stock WeaponsGetDeployedWeaponIndex(client)
{
// Return the client's active weapon.
return GetEntDataEnt2(client, offsActiveWeapon);
}
/**
* Returns slot of client's deployed weapon.
*
* @param client The client index.
* @return The slot number of deployed weapon.
*/
stock WeaponsSlot:WeaponsGetDeployedWeaponSlot(client)
{
// Get all client's weapon indexes.
new weapons[WeaponsSlot];
WeaponsGetClientWeapons(client, weapons);
// Get client's deployed weapon.
new deployedweapon = WeaponsGetDeployedWeaponIndex(client);
// If client has no deployed weapon, then stop.
if (deployedweapon == -1)
{
return Type_Invalid;
}
// x = weapon slot.
for (new x = 0; x < WEAPONS_SLOTS_MAX; x++)
{
if (weapons[x] == deployedweapon)
{
return WeaponsSlot:x;
}
}
return Type_Invalid;
}
/**
* Forces player to drop weapon index.
*
* @param client The client index.
* @param weapon The weapon index to force client to drop.
*/
stock WeaponsForceClientDrop(client, weapon)
{
// Force client to drop weapon.
2009-04-29 01:58:41 +02:00
SDKCall(g_hToolsCSWeaponDrop, client, weapon, true, false);
}
/**
* Used to explicitly remove projectile weapons from a client.
*
* @param client The client index.
* @param weaponsdrop True to force drop on all weapons, false to strip.
*/
stock WeaponsRemoveClientGrenades(client, bool:weaponsdrop)
{
// This while-structure is a stupid sloppy annoying workaround to stop the "unintended assignment" warning. I hate those.
// While GetPlayerWeaponSlot returns a valid projectile, remove it and then test again.
new grenade = GetPlayerWeaponSlot(client, _:Slot_Projectile);
while (grenade != -1)
{
// Check if we drop or strip the grenade.
if (weaponsdrop)
{
WeaponsForceClientDrop(client, grenade);
}
else
{
RemovePlayerItem(client, grenade);
}
// Find next grenade.
grenade = GetPlayerWeaponSlot(client, _:Slot_Projectile);
}
}
/**
* Refresh a weapon by taking it and giving it back.
*
* @param client The client index.
* @param slot The weapon slot to refresh. (see enum WeaponsSlot)
*/
stock WeaponsRefreshClientWeapon(client, WeaponsSlot:slot)
{
new weaponindex = GetPlayerWeaponSlot(client, _:slot);
// If weapon is invalid, then stop.
if (weaponindex == -1)
{
return;
}
// Get the classname of the weapon to re-give.
decl String:entityname[WEAPONS_MAX_LENGTH];
GetEdictClassname(weaponindex, entityname, sizeof(entityname));
// Refresh weapon.
RemovePlayerItem(client, weaponindex);
GivePlayerItem(client, entityname);
}
/**
* Remove all weapons, except knife, on a client, with options.
*
* @param client The client index.
* @param weaponsdrop True to force drop on all weapons, false to strip.
*/
stock WeaponsRemoveAllClientWeapons(client, bool:weaponsdrop)
{
// Get a list of all client's weapon indexes.
new weapons[WeaponsSlot];
WeaponsGetClientWeapons(client, weapons);
// Loop through array slots and force drop.
// x = weapon slot.
for (new x = 0; x < WEAPONS_SLOTS_MAX; x++)
{
// If weapon is invalid, then stop.
if (weapons[x] == -1)
{
continue;
}
// If this is the knife slot, then strip it and stop.
if (WeaponsSlot:x == Slot_Melee)
{
// Strip knife.
RemovePlayerItem(client, weapons[x]);
continue;
}
if (weaponsdrop)
{
// Force client to drop weapon.
WeaponsForceClientDrop(client, weapons[x]);
}
else
{
// Strip weapon.
RemovePlayerItem(client, weapons[x]);
}
}
// Remove left-over projectiles.
WeaponsRemoveClientGrenades(client, weaponsdrop);
// Give zombie a new knife. (If you leave the old one there will be glitches with the knife positioning)
GivePlayerItem(client, "weapon_knife");
}
/**
* Refresh a weapon by taking it and giving it back.
*
* @param client The client index.
*/
stock WeaponsRefreshAllClientWeapons(client)
{
// Get a list of all client's weapon indexes.
new weapons[WeaponsSlot];
WeaponsGetClientWeapons(client, weapons);
// Loop through array slots and force drop.
// x = weapon slot.
for (new x = 0; x < WEAPONS_SLOTS_MAX; x++)
{
// If weapon is invalid, then stop.
if (weapons[x] == -1)
{
continue;
}
WeaponsRefreshClientWeapon(client, WeaponsSlot:x);
}
}