Code:
/*
Reset Reload On Shove
Copyright (C) 2014 Buster "Mr. Zero" Nielsen
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/>.
*/
/* Includes */
#include <sourcemod>
#include <sdktools>
#include <l4d_stocks>
/* Plugin Information */
public Plugin:myinfo =
{
name = "Reset Reload On Shove",
author = "Buster \"Mr. Zero\" Nielsen",
description = "Reset reloading animation upon Survivors shoving",
version = "1.0.0",
url = "[email protected]"
}
/* Globals */
#define MAXEDICTS 2048
#define MAXENTITIES 4096
#define NETPROP_PLAYER_ACTIVEWEAPON "m_hActiveWeapon"
#define NETPROP_PLAYER_VIEWMODEL "m_hViewModel"
#define NETPROP_PLAYER_NEXTATTACK "m_flNextAttack"
#define NETPROP_WEAPON_INRELOAD "m_bInReload"
#define NETPROP_WEAPON_NEXTPRIMARYATTACK "m_flNextPrimaryAttack"
#define NETPROP_WEAPON_TIMEWEAPONIDLE "m_flTimeWeaponIdle"
#define NETPROP_WEAPON_SHOTGUN_RELOADSTATE "m_reloadState"
#define NETPROP_WEAPON_SHOTGUN_RELOADANIMSTATE "m_reloadAnimState"
#define NETPROP_WEAPON_SHOTGUN_RELOADNUMSHELLS "m_reloadNumShells"
#define NETPROP_WEAPON_SHOTGUN_SHELLSINSERTED "m_shellsInserted"
#define NETPROP_VIEWMODEL_LAYERSEQUENCE "m_nLayerSequence"
#define NETPROP_VIEWMODEL_LAYERSTARTTIME "m_flLayerStartTime"
#define NETPROP_VIEWMODEL_LAYER "m_nLayer"
#define SHOVE_SOUND_NAME_SEARCH "Swish"
#define SHOVE_DURATION 0.2 // Guess-timate, all guns have about 0.4 seconds of shove animation
new bool:g_InReload[MAXPLAYERS + 1]
/* Plugin Functions */
public OnPluginStart()
{
HookEvent("weapon_reload", WeaponReload_Event)
AddNormalSoundHook(ShoveSoundHook)
}
public OnClientDisconnect(client)
{
g_InReload[client] = false
}
public Action:ShoveSoundHook(clients[64], &numClients, String:sample[PLATFORM_MAX_PATH], &entity, &channel, &Float:volume, &level, &pitch, &flags)
{
if (entity <= 0 || entity > MaxClients || !g_InReload[entity] || IsFakeClient(entity))
{
return Plugin_Continue
}
if (StrContains(sample, SHOVE_SOUND_NAME_SEARCH) == -1)
{
return Plugin_Continue
}
new activeWeapon = GetEntPropEnt(entity, Prop_Send, NETPROP_PLAYER_ACTIVEWEAPON)
if (activeWeapon <= 0 || activeWeapon > MAXENTITIES)
{
g_InReload[entity] = false
return Plugin_Continue
}
new L4D2WeaponId:weaponId = L4D2_GetWeaponId(activeWeapon)
if (!IsReloadableWeapon(weaponId))
{
g_InReload[entity] = false
return Plugin_Continue
}
new bool:isShotgun = IsWeaponAShotgun(weaponId)
if (GetEntProp(activeWeapon, Prop_Send, NETPROP_WEAPON_INRELOAD) == 0)
{
g_InReload[entity] = false
return Plugin_Continue
}
g_InReload[entity] = false
SetEntProp(activeWeapon, Prop_Send, NETPROP_WEAPON_INRELOAD, 0)
ChangeEdictState(activeWeapon, FindDataMapOffs(activeWeapon, NETPROP_WEAPON_INRELOAD))
SetPlayerNextPrimaryAttack(entity, GetGameTime() + SHOVE_DURATION)
if (isShotgun)
{
SetEntProp(activeWeapon, Prop_Send, NETPROP_WEAPON_SHOTGUN_RELOADSTATE, 0)
SetEntProp(activeWeapon, Prop_Send, NETPROP_WEAPON_SHOTGUN_RELOADANIMSTATE, 0)
SetEntProp(activeWeapon, Prop_Send, NETPROP_WEAPON_SHOTGUN_RELOADNUMSHELLS, 0)
SetEntProp(activeWeapon, Prop_Send, NETPROP_WEAPON_SHOTGUN_SHELLSINSERTED, 0)
}
new viewModel = GetEntPropEnt(entity, Prop_Send, NETPROP_PLAYER_VIEWMODEL)
if (viewModel > 0 && viewModel <= MAXENTITIES && IsValidEntity(viewModel))
{
SetEntProp(viewModel, Prop_Send, NETPROP_VIEWMODEL_LAYER, 0) // Fixes reloading animation playing double after shoving!
}
return Plugin_Continue
}
public Action:OnPlayerRunCmd(client, &buttons, &impulse, Float:vel[3], Float:angles[3], &weapon, &subtype, &cmdnum, &tickcount, &seed, mouse[2])
{
if (!g_InReload[client])
{
return Plugin_Continue
}
new activeWeapon = GetEntPropEnt(client, Prop_Send, NETPROP_PLAYER_ACTIVEWEAPON)
if (activeWeapon <= 0 || activeWeapon > MAXENTITIES)
{
g_InReload[client] = false
return Plugin_Continue
}
new L4D2WeaponId:weaponId = L4D2_GetWeaponId(activeWeapon)
if (!IsReloadableWeapon(weaponId))
{
g_InReload[client] = false
return Plugin_Continue
}
if (GetEntProp(activeWeapon, Prop_Send, NETPROP_WEAPON_INRELOAD) == 0)
{
g_InReload[client] = false
return Plugin_Continue
}
if (weapon > 0)
{
g_InReload[client] = false
return Plugin_Continue
}
return Plugin_Continue
}
public WeaponReload_Event(Handle:event, const String:name[], bool:dontBroadcast)
{
new client = GetClientOfUserId(GetEventInt(event, "userid"))
if (client <= 0 || client > MaxClients || !IsClientInGame(client))
{
return
}
new weapon = GetEntPropEnt(client, Prop_Send, NETPROP_PLAYER_ACTIVEWEAPON)
if (weapon <= 0 || weapon > MAXENTITIES || !IsValidEntity(weapon))
{
return
}
new L4D2WeaponId:weaponId = L4D2_GetWeaponId(weapon)
if (!IsReloadableWeapon(weaponId))
{
return
}
g_InReload[client] = true
}
stock SetPlayerNextPrimaryAttack(client, Float:time)
{
new weapon = GetEntPropEnt(client, Prop_Send, NETPROP_PLAYER_ACTIVEWEAPON)
if (weapon <= 0 || weapon > MAXENTITIES || !IsValidEntity(weapon))
{
return
}
SetEntPropFloat(weapon, Prop_Send, NETPROP_WEAPON_NEXTPRIMARYATTACK, time)
SetEntPropFloat(weapon, Prop_Send, NETPROP_WEAPON_TIMEWEAPONIDLE, time)
SetEntPropFloat(client, Prop_Send, NETPROP_PLAYER_NEXTATTACK, time)
}
bool:IsReloadableWeapon(L4D2WeaponId:weaponId)
{
if (weaponId == L4D2WeaponId_Pistol ||
weaponId == L4D2WeaponId_Smg ||
weaponId == L4D2WeaponId_Pumpshotgun ||
weaponId == L4D2WeaponId_Autoshotgun ||
weaponId == L4D2WeaponId_Rifle ||
weaponId == L4D2WeaponId_HuntingRifle ||
weaponId == L4D2WeaponId_SmgSilenced ||
weaponId == L4D2WeaponId_ShotgunChrome ||
weaponId == L4D2WeaponId_RifleDesert ||
weaponId == L4D2WeaponId_SniperMilitary ||
weaponId == L4D2WeaponId_ShotgunSpas ||
weaponId == L4D2WeaponId_GrenadeLauncher ||
weaponId == L4D2WeaponId_RifleAK47 ||
weaponId == L4D2WeaponId_PistolMagnum ||
weaponId == L4D2WeaponId_SmgMP5 ||
weaponId == L4D2WeaponId_RifleSG552 ||
weaponId == L4D2WeaponId_SniperAWP ||
weaponId == L4D2WeaponId_SniperScout)
{
return true
}
return false
}
bool:IsWeaponAShotgun(L4D2WeaponId:weaponId)
{
if (weaponId == L4D2WeaponId_Pumpshotgun ||
weaponId == L4D2WeaponId_Autoshotgun ||
weaponId == L4D2WeaponId_ShotgunChrome ||
weaponId == L4D2WeaponId_ShotgunSpas)
{
return true
}
return false
}