#pragma semicolon 1
#pragma newdecls required
#include <sourcemod>
#include <sdktools>
#include <sdkhooks>
#define PLUGIN_VERSION "1.0"
#define CVAR_FLAGS FCVAR_NOTIFY
enum
{
AMMO_NORMAL = 0,
AMMO_EXPLOSIVE,
AMMO_INCENDIARY,
AMMO_SLOWING,
AMMO_HEALING,
AmmoType
};
PluginData plugin;
enum struct PluginCvars
{
ConVar g_cvEnabled;
ConVar g_cvDamage;
ConVar g_cvRadius;
void Init()
{
CreateConVar("sm_keyman_version", PLUGIN_VERSION,"[L4D] Key Man plugin version", CVAR_FLAGS|FCVAR_DONTRECORD);
this.g_cvEnabled = CreateConVar("sm_explosive_on", "1", "Вкл.Выкл.", CVAR_FLAGS);
this.g_cvDamage = CreateConVar("sm_explosive_damage", "50.0", "Наносимый урон зомби.", CVAR_FLAGS);
this.g_cvRadius = CreateConVar("sm_explosive_radius", "20.0", "Радиус охвата.", CVAR_FLAGS);
this.g_cvEnabled.AddChangeHook(ConVarPluginOnChanged);
this.g_cvDamage.AddChangeHook(ConVarsChanged);
this.g_cvRadius.AddChangeHook(ConVarsChanged);
AutoExecConfig(true, "sm_explosive");
}
}
enum struct PluginData
{
PluginCvars cvars;
bool bHooked;
bool bPluginOn;
bool g_bHasCustomAmmo[MAXPLAYERS + 1];
bool StartAmmo[MAXPLAYERS + 1];
bool g_bMessageSent[MAXPLAYERS + 1];
bool g_hasChosenMode[MAXPLAYERS + 1];
int g_iAmmoType[MAXPLAYERS + 1];
int g_iSpecialAmmoCount[MAXPLAYERS + 1];
float fDamage;
float fRadius;
float victimPos[3];
void Init()
{
this.cvars.Init();
}
void RegCmds()
{
RegConsoleCmd("sm_upgrade", Command_ChooseUpgrade);
}
void ConVarsChanged()
{
this.fDamage = this.cvars.g_cvDamage.FloatValue;
this.fRadius = this.cvars.g_cvRadius.FloatValue;
}
void IsAllowed()
{
this.bPluginOn = this.cvars.g_cvEnabled.BoolValue;
if(!this.bHooked && this.bPluginOn)
{
this.bHooked = true;
HookEvent("weapon_fire", Events);
HookEvent("infected_hurt", Events);
HookEvent("bullet_impact", Events);
HookEvent("player_spawn", Events);
for(int i = 0; i <= MAXPLAYERS; i++)
{
this.StartAmmo[i] = false;
}
}
else if(this.bHooked && !this.bPluginOn)
{
this.bHooked = false;
UnhookEvent("weapon_fire", Events);
UnhookEvent("infected_hurt", Events);
UnhookEvent("bullet_impact", Events);
UnhookEvent("player_spawn", Events);
for(int i = 0; i <= MAXPLAYERS; i++)
{
this.StartAmmo[i] = false;
}
}
}
}
public void OnPluginStart()
{
plugin.Init();
plugin.RegCmds();
}
public void OnConfigsExecuted()
{
plugin.IsAllowed();
}
void ConVarPluginOnChanged(ConVar convar, const char[] oldValue, const char[] newValue)
{
plugin.IsAllowed();
}
void ConVarsChanged(ConVar convar, const char[] oldValue, const char[] newValue)
{
plugin.ConVarsChanged();
}
Action Events(Event event, char[] name, bool dontBroadcast)
{
if (strcmp(name, "weapon_fire") == 0)
{
int client = GetClientOfUserId(event.GetInt("userid"));
char weapon[64];
event.GetString("weapon", weapon, sizeof(weapon));
if (IsValidClient(client) && plugin.g_bHasCustomAmmo[client] && plugin.g_iSpecialAmmoCount[client] > 0)
{
if (StrContains(weapon, "shotgun", false) == -1 || StrContains(weapon, "weapon_autoshotgun", false) == -1 || StrContains(weapon, "weapon_pumpshotgun", false) == -1)
{
plugin.StartAmmo[client] = true;
}
}
}
else if (strcmp(name, "infected_hurt") == 0)
{
int client = GetClientOfUserId(event.GetInt("attacker"));
int target = event.GetInt("entityid");
if (IsValidClient(client) && plugin.StartAmmo[client] && plugin.g_iSpecialAmmoCount[client] > 0)
{
switch (plugin.g_iAmmoType[client])
{
case AMMO_NORMAL:
{
plugin.g_bHasCustomAmmo[client] = false;
}
case AMMO_INCENDIARY:
{
IgniteEntity(target, 120.0, false);
plugin.g_iSpecialAmmoCount[client]--;
}
case AMMO_SLOWING:
{
SlowEntity(target, 0.5, 5.0);
plugin.g_iSpecialAmmoCount[client]--;
}
case AMMO_HEALING:
{
HealEntity(target, 10);
plugin.g_iSpecialAmmoCount[client]--;
}
}
if(plugin.g_iSpecialAmmoCount[client] <= 0)
{
plugin.g_bHasCustomAmmo[client] = false;
plugin.g_iAmmoType[client] = 0;
PrintToChat(client, "\x01Специальные патроны закончились! Теперь вы используете обычные патроны.");
}
}
}
else if (strcmp(name, "bullet_impact") == 0)
{
int client = GetClientOfUserId(event.GetInt("userid"));
if(IsValidClient(client) && plugin.g_bHasCustomAmmo[client])
{
if(plugin.g_iAmmoType[client] == 2 && plugin.g_iSpecialAmmoCount[client] > 0)
{
float pos[3];
pos[0] = event.GetFloat("x");
pos[1] = event.GetFloat("y");
pos[2] = event.GetFloat("z");
DealDamage(client, pos, plugin.fRadius, plugin.fDamage);
plugin.g_iSpecialAmmoCount[client]--;
}
}
}
else if (strcmp(name, "player_spawn") == 0)
{
int client = GetClientOfUserId(event.GetInt("userid"));
if(IsValidClient(client))
{
plugin.g_bMessageSent[client] = false;
CreateTimer(10.0, Timer_SendMessage, client);
}
}
return Plugin_Continue;
}
public void OnClientPutInServer(int client)
{
if(plugin.bHooked && client > 0 && !IsFakeClient(client))
{
plugin.g_hasChosenMode[client] = false;
}
}
Action Timer_SendMessage(Handle timer, any client)
{
if(plugin.bHooked && IsValidClient(client) && !plugin.g_bMessageSent[client])
{
PrintToChat(client, "\x01Выберите желаемый режим, для более комфортной игры.");
PrintToChat(client, "\x01Введите \x04!upgrade");
plugin.g_bMessageSent[client] = true;
}
return Plugin_Stop;
}
Action Command_ChooseUpgrade(int client, int args)
{
if(plugin.bHooked && IsValidClient(client))
{
if(plugin.g_hasChosenMode[client])
{
PrintToChat(client, "Вы уже выбрали режим, дождитесь окончания карты");
return Plugin_Handled;
}
ShowMenu(client);
}
return Plugin_Handled;
}
void ShowMenu(int client)
{
Menu menu = new Menu(UpgradeMenuHandler);
menu.SetTitle("Выберите режим:");
menu.AddItem("0", "Терминатор");
menu.AddItem("1", "Пуля");
menu.AddItem("2", "Ловкач");
menu.AddItem("3", "Убийца");
menu.AddItem("4", "Черный плащ");
menu.Display(client, MENU_TIME_FOREVER);
}
int UpgradeMenuHandler(Menu menu, MenuAction action, int client, int itemNum)
{
if(action == MenuAction_Select)
{
switch(itemNum)
{
case 0:
{
GiveOrRemoveUpgrade(client, 0, false);
PrintToChat(client, "\x01Выбран режим \x03Терминатор");
PrintToChat(client, "\x01Возможности режима \x03Большая обойма, \x04Оптика, \x05Зажигательные патроны.");
plugin.g_iAmmoType[client] = 2;
plugin.g_bHasCustomAmmo[client] = true;
plugin.g_hasChosenMode[client] = true;
plugin.g_iSpecialAmmoCount[client] = 100000;
GiveOrRemoveUpgrade(client, 1048576, true);
GiveOrRemoveUpgrade(client, 16777216, true);
}
case 1:
{
GiveOrRemoveUpgrade(client, 0, false);
PrintToChat(client, "\x01Выбран режим \x03Пуля");
PrintToChat(client, "\x01Возможности режима \x03Кеды-скороходы, \x04Второе дыхание, \x05Разрывные патроны.");
plugin.g_iAmmoType[client] = 1;
plugin.g_bHasCustomAmmo[client] = true;
plugin.g_hasChosenMode[client] = true;
plugin.g_iSpecialAmmoCount[client] = 100000;
GiveOrRemoveUpgrade(client, 32768, true);
GiveOrRemoveUpgrade(client, 4096, true);
}
case 2:
{
GiveOrRemoveUpgrade(client, 0, false);
PrintToChat(client, "\x01Выбран режим \x03Ловкач");
PrintToChat(client, "\x01Возможности режима \x03Ловкость рук, \x04Мел для лазания, \x05Замедляющие патроны.");
plugin.g_iAmmoType[client] = 3;
plugin.g_bHasCustomAmmo[client] = true;
plugin.g_hasChosenMode[client] = true;
plugin.g_iSpecialAmmoCount[client] = 100000;
GiveOrRemoveUpgrade(client, 536870912, true);
GiveOrRemoveUpgrade(client, 2048, true);
}
case 3:
{
GiveOrRemoveUpgrade(client, 0, false);
PrintToChat(client, "\x01Выбран режим \x03Убийца");
PrintToChat(client, "\x01Возможности режима \x03Нож, \x04Нашатырь, \x05Разрывные патроны.");
plugin.g_iAmmoType[client] = 1;
plugin.g_bHasCustomAmmo[client] = true;
plugin.g_hasChosenMode[client] = true;
plugin.g_iSpecialAmmoCount[client] = 100000;
GiveOrRemoveUpgrade(client, 67108864, true);
GiveOrRemoveUpgrade(client, 134217728, true);
}
case 4:
{
GiveOrRemoveUpgrade(client, 0, false);
PrintToChat(client, "\x01Выбран режим \x03Черный плащ");
PrintToChat(client, "\x01Возможности режима \x03Никотиновый пластырь, \x04Дождевик, \x05Зажигательные патроны.");
plugin.g_iAmmoType[client] = 2;
plugin.g_iSpecialAmmoCount[client] = 100000;
plugin.g_bHasCustomAmmo[client] = true;
plugin.g_hasChosenMode[client] = true;
GiveOrRemoveUpgrade(client, 512, true);
GiveOrRemoveUpgrade(client, 256, true);
}
}
}
else if(action == MenuAction_End)
{
delete menu;
}
return 0;
}
void GiveOrRemoveUpgrade(int client, int up, bool set)
{
if(set)
{
SetEntProp(client, Prop_Send, "m_upgradeBitVec", GetEntProp(client, Prop_Send, "m_upgradeBitVec") + up, 4);
}
else
{
SetEntProp(client, Prop_Send, "m_upgradeBitVec", 0, 4);
}
}
void DealDamage(int attacker, float pos[3], float radius, float damage)
{
for(int i = 1; i <= MaxClients; i++)
{
if(IsValidClient(i) && IsPlayerAlive(i) && GetClientTeam(i) == 3)
{
GetClientAbsOrigin(i, plugin.victimPos);
if(GetVectorDistance(pos, plugin.victimPos) <= radius)
{
SDKHooks_TakeDamage(i, attacker, attacker, damage, DMG_BLAST);
}
}
}
int entity = -1;
while((entity = FindEntityByClassname(entity, "infected")) != -1)
{
GetEntPropVector(entity, Prop_Data, "m_vecAbsOrigin", plugin.victimPos);
if(GetVectorDistance(pos, plugin.victimPos) <= radius)
{
SDKHooks_TakeDamage(entity, attacker, attacker, damage, DMG_BLAST);
}
}
}
bool IsValidClient(int client)
{
return client > 0 && client <= MaxClients && IsClientInGame(client);
}
void SlowEntity(int entity, float amount, float duration)
{
float speed = GetEntPropFloat(entity, Prop_Data, "m_flLaggedMovementValue");
SetEntPropFloat(entity, Prop_Data, "m_flLaggedMovementValue", speed * amount);
CreateTimer(duration, Timer_ResetSpeed, entity);
}
Action Timer_ResetSpeed(Handle timer, any entity)
{
if(IsValidEntity(entity))
{
SetEntPropFloat(entity, Prop_Data, "m_flLaggedMovementValue", 1.0);
}
return Plugin_Stop;
}
void HealEntity(int client, int amount)
{
int health = GetClientHealth(client);
int maxHealth = GetEntProp(client, Prop_Data, "m_iMaxHealth");
SetEntityHealth(client, health + amount > maxHealth ? maxHealth : health + amount);
}