#include <amxmodx>
#include <fakemeta>
#include <engine>
#include <hamsandwich>
#include <xs>
#include <zombieplague>
/*================================================================================
[Customization]
=================================================================================*/
// Item Cost
new const g_SawnOff_Cost = 30
// Models
new const sawnoff_model_v[] = "models/v_sawn_off_shotgun.mdl"
new const sawnoff_model_p[] = "models/p_sawn_off_shotgun.mdl"
new const sawnoff_model_w[] = "models/w_sawn_off_shotgun.mdl"
// ---------------------------------------------------------------
// ------------------ Customization ends here!! ------------------
// ---------------------------------------------------------------
// Offsets
#if cellbits == 32
const OFFSET_CLIPAMMO = 51
#else
const OFFSET_CLIPAMMO = 65
#endif
const OFFSET_LINUX = 5
const OFFSET_LINUX_WEAPONS = 4
const OFFSET_LASTPRIMARYITEM = 368
// Version
#define VERSION "0.4.5"
// Arrays
new g_sawnoff_shotgun[33], g_currentweapon[33]
// Variables
new g_SawnOff, g_MaxPlayers
// Cvar Pointers
new cvar_enable, cvar_oneround, cvar_knockback, cvar_knockbackpower, cvar_uclip, cvar_damage
/*================================================================================
[Init and Precache]
=================================================================================*/
public plugin_init()
{
// Plugin Info
register_plugin("[ZP] Extra Item: Sawn-Off Shotgun", VERSION, "meTaLiCroSS")
// Ham Forwards
RegisterHam(Ham_TakeDamage, "player", "fw_TakeDamage")
RegisterHam(Ham_TraceAttack, "player", "fw_TraceAttack")
RegisterHam(Ham_Killed, "player", "fw_PlayerKilled")
// Fakemeta Forwards
register_forward(FM_SetModel, "fw_SetModel")
// Event: Round Start
register_event("HLTV", "event_round_start", "a", "1=0", "2=0")
// Message: Cur Weapon
register_message(get_user_msgid("CurWeapon"), "message_cur_weapon")
// CVARS
register_cvar("zp_extra_sawnoff", VERSION, FCVAR_SERVER|FCVAR_SPONLY)
cvar_enable = register_cvar("zp_sawnoff_enable", "1")
cvar_uclip = register_cvar("zp_sawnoff_unlimited_clip", "1")
cvar_damage = register_cvar("zp_sawnoff_damage_mult", "4.0")
cvar_oneround = register_cvar("zp_sawnoff_oneround", "0")
cvar_knockback = register_cvar("zp_sawnoff_knockback", "1")
cvar_knockbackpower = register_cvar("zp_sawnoff_kbackpower", "10.0")
// Variables
g_MaxPlayers = get_maxplayers()
g_SawnOff = zp_register_extra_item("Sawn-Off Shotgun", g_SawnOff_Cost, ZP_TEAM_HUMAN)
}
public plugin_precache()
{
// Precaching models
precache_model(sawnoff_model_v)
precache_model(sawnoff_model_p)
precache_model(sawnoff_model_w)
}
/*================================================================================
[Main Functions]
=================================================================================*/
// Round Start Event
public event_round_start()
{
// Get all the players
for(new id = 1; id <= g_MaxPlayers; id++)
{
// Check
if(get_pcvar_num(cvar_oneround) || !get_pcvar_num(cvar_enable))
{
// Striping Sawn Off
if(g_sawnoff_shotgun[id])
{
g_sawnoff_shotgun[id] = false;
ham_strip_weapon(id, "weapon_m3")
}
}
}
}
// Message Current Weapon
public message_cur_weapon(msg_id, msg_dest, id)
{
// Doesn't have a Sawn Off
if (!g_sawnoff_shotgun[id])
return PLUGIN_CONTINUE
// Isn't alive / not active weapon
if (!is_user_alive(id) || get_msg_arg_int(1) != 1)
return PLUGIN_CONTINUE
// Get Weapon Clip
new clip = get_msg_arg_int(3)
// Update Weapon Array
g_currentweapon[id] = get_msg_arg_int(2) // get weapon ID
// Weapon isn't M3
if(g_currentweapon[id] != CSW_M3)
return PLUGIN_CONTINUE;
// Replace Models
entity_set_string(id, EV_SZ_viewmodel, sawnoff_model_v)
entity_set_string(id, EV_SZ_weaponmodel, sawnoff_model_p)
// Check cvar
if(get_pcvar_num(cvar_uclip))
{
// Set Ammo HUD in 8
set_msg_arg_int(3, get_msg_argtype(3), 8)
// Check clip if more than 2
if (clip < 2)
{
// Update weapon ammo
fm_set_weapon_ammo(find_ent_by_owner(-1, "weapon_m3", id), 8)
}
}
return PLUGIN_CONTINUE;
}
// Touch fix (when user drop the Sawn off, already has the Sawn off.
public touch_fix(id)
{
if(g_sawnoff_shotgun[id])
g_sawnoff_shotgun[id] = false;
}
/*================================================================================
[Main Forwards]
=================================================================================*/
public fw_PlayerKilled(victim, attacker, shouldgib)
{
// Victim has a Sawn off
if(g_sawnoff_shotgun[victim])
g_sawnoff_shotgun[victim] = false;
}
public fw_SetModel(entity, model[])
{
// Entity is not valid
if(!is_valid_ent(entity))
return FMRES_IGNORED;
// Entity model is not a M3
if(!equali(model, "models/w_m3.mdl"))
return FMRES_IGNORED;
// Get owner and entity classname
new owner = entity_get_edict(entity, EV_ENT_owner)
new classname[33]
entity_get_string(entity, EV_SZ_classname, classname, charsmax(classname))
// Entity classname is a weaponbox
if(equal(classname, "weaponbox"))
{
// The weapon owner has a Sawn Off
if(g_sawnoff_shotgun[owner])
{
// Striping Sawn off and set New Model
g_sawnoff_shotgun[owner] = false;
entity_set_model(entity, sawnoff_model_w)
set_task(0.1, "touch_fix", owner)
return FMRES_SUPERCEDE
}
}
return FMRES_IGNORED
}
public fw_TakeDamage(victim, inflictor, attacker, Float:damage, damage_type)
{
// Attacker isn't a Player (1 in 32)
if(!(1 <= attacker <= g_MaxPlayers))
return HAM_IGNORED;
// Attacker's weapon isn't a M3
if(g_currentweapon[attacker] != CSW_M3)
return HAM_IGNORED;
// User doesn't have a Sawn Off
if(!g_sawnoff_shotgun[attacker])
return HAM_IGNORED;
SetHamParamFloat(4, damage * get_pcvar_float(cvar_damage) )
return HAM_IGNORED;
}
public fw_TraceAttack(victim, attacker, Float:damage, Float:direction[3], tracehandle, damage_type)
{
// Player is allowed to make a Knockback
if(!allowed_knockback(victim, attacker))
return HAM_IGNORED;
// Check damage type
if(!(damage_type & DMG_BULLET))
return HAM_IGNORED;
// Make Knockback...
new Float:velocity[3]; pev(victim, pev_velocity, velocity)
xs_vec_mul_scalar(direction, get_pcvar_float(cvar_knockbackpower), direction)
xs_vec_add(velocity, direction, direction)
entity_set_vector(victim, EV_VEC_velocity, direction)
return HAM_IGNORED;
}
public pfn_touch(entity, toucher)
{
new model[33], toucherclass[33], entityclass[33]
// Get toucher Classname
if((toucher > 0) && is_valid_ent(toucher)) entity_get_string(toucher, EV_SZ_classname, toucherclass, charsmax(toucherclass))
// Get entity Classname
if((entity > 0) && is_valid_ent(entity)) entity_get_string(entity, EV_SZ_classname, entityclass, charsmax(entityclass))
// Now check if is a Weapon and is a Player
if(equali(toucherclass, "player") && equali(entityclass, "weaponbox"))
{
// Get Model
entity_get_string(entity, EV_SZ_model, model, charsmax(model))
// Check Model
if(equali(model, sawnoff_model_w))
if(allowed_touch(toucher)) // Player is allowed to pickup the weapon
g_sawnoff_shotgun[toucher] = true // Set Weapon
}
}
/*================================================================================
[Internal Functions]
=================================================================================*/
allowed_knockback(victim, attacker)
{
// Obviously, doesn't is allowed to be Knockbacked (WTF)
if(!g_sawnoff_shotgun[attacker] || !get_pcvar_num(cvar_knockback) || g_currentweapon[attacker] != CSW_M3 || !zp_get_user_zombie(victim))
return false;
return true;
}
allowed_touch(toucher)
{
// Can't touch the Weapon
if(zp_get_user_survivor(toucher) || zp_get_user_zombie(toucher) || fm_get_user_lastprimaryitem(toucher) || g_sawnoff_shotgun[toucher])
return false;
return true;
}
/*================================================================================
[Zombie Plague Forwards]
=================================================================================*/
public zp_extra_item_selected(id, itemid)
{
// Item is the Sawn-Off
if(itemid == g_SawnOff)
{
if(!get_pcvar_num(cvar_enable))
{
zp_set_user_ammo_packs(id, zp_get_user_ammo_packs(id) + g_SawnOff_Cost)
client_print(id, print_chat, "[ZP] The Sawn-Off Shotgun is Disabled")
return;
}
// Already has an M3
if(g_sawnoff_shotgun[id] && user_has_weapon(id, CSW_M3))
{
zp_set_user_ammo_packs(id, zp_get_user_ammo_packs(id) + g_SawnOff_Cost)
client_print(id, print_chat, "[ZP] You already have a Sawn-Off Shotgun")
return;
}
// Array
g_sawnoff_shotgun[id] = true
// Weapon
ham_give_weapon(id, "weapon_m3")
// Message
client_print(id, print_chat, "[ZP] You now have a Sawn-Off Shotgun")
}
}
public zp_user_infected_post(infected, infector)
{
// Infected has a M3
if(g_sawnoff_shotgun[infected])
g_sawnoff_shotgun[infected] = false;
}
public zp_user_humanized_post(player)
{
// Is Survivor
if(zp_get_user_survivor(player) && g_sawnoff_shotgun[player])
g_sawnoff_shotgun[player] = false;
}
/*================================================================================
[Stocks]
=================================================================================*/
stock ham_give_weapon(id, weapon[])
{
if(!equal(weapon,"weapon_",7))
return 0
new wEnt = create_entity(weapon)
if(!is_valid_ent(wEnt))
return 0
entity_set_int(wEnt, EV_INT_spawnflags, SF_NORESPAWN)
DispatchSpawn(wEnt)
if(!ExecuteHamB(Ham_AddPlayerItem,id,wEnt))
{
if(is_valid_ent(wEnt)) entity_set_int(wEnt, EV_INT_flags, entity_get_int(wEnt, EV_INT_flags) | FL_KILLME)
return 0
}
ExecuteHamB(Ham_Item_AttachToPlayer,wEnt,id)
return 1
}
stock ham_strip_weapon(id, weapon[])
{
if(!equal(weapon,"weapon_",7))
return 0
new wId = get_weaponid(weapon)
if(!wId) return 0
new wEnt
while((wEnt = find_ent_by_class(wEnt, weapon)) && entity_get_edict(wEnt, EV_ENT_owner) != id) {}
if(!wEnt) return 0
if(get_user_weapon(id) == wId)
ExecuteHamB(Ham_Weapon_RetireWeapon,wEnt);
if(!ExecuteHamB(Ham_RemovePlayerItem,id,wEnt))
return 0
ExecuteHamB(Ham_Item_Kill, wEnt)
entity_set_int(id, EV_INT_weapons, entity_get_int(id, EV_INT_weapons) & ~(1<<wId))
return 1
}
stock fm_set_weapon_ammo(entity, amount)
{
set_pdata_int(entity, OFFSET_CLIPAMMO, amount, OFFSET_LINUX_WEAPONS);
}
stock fm_get_user_lastprimaryitem(id) // Thanks to joaquimandrade
{
if(get_pdata_cbase(id, OFFSET_LASTPRIMARYITEM) != -1)
return 1;
return 0;
}