#pragma semicolon 1
#include <sourcemod>
#include <sdktools>
#include <sdkhooks>
#define TURRET_MODEL "models/Combine_turrets/Floor_turret.mdl"
public Plugin:myinfo =
{
name = "Turret",
author = "wS / Schmidt",
description = "Турель - автоматическая стрельба по врагам",
version = "1.3",
url = ""
};
new TurretsNum;
new Handle:TurretTimer[1500];
new MaxTurretIndex;
new Float:MaxWorldLength;
new bool:Infected[MAXPLAYERS+1];
new String:MyTurrets[MAXPLAYERS+1][100];
new bool:turret_direction;
new bool:turret_no_ct_attack;
public OnPluginStart()
{
RegConsoleCmd("turret", turret);
HookEvent("round_start", round_start, EventHookMode_PostNoCopy);
HookEvent("player_spawn", player_spawn);
for (new i = 1; i <= MaxClients; i++)
{
if (IsClientInGame(i)) OnClientPutInServer(i);
}
CreateConVar("Turret_version", "1.3", "Turret version [ Plugin by _wS_ ]", FCVAR_NOTIFY);
new Handle:wS = CreateConVar("turret_direction", "0", "1 = самонаводящаяся ракета, 0 = нет", FCVAR_NOTIFY, true, 0.0, true, 1.0);
turret_direction = GetConVarBool(wS); HookConVarChange(wS, cvar_turret_direction);
wS = CreateConVar("turret_no_ct_attack", "1", "1 = пушка наносит вред только террористам, 0 = нет", FCVAR_NOTIFY, true, 0.0, true, 1.0);
turret_no_ct_attack = GetConVarBool(wS); HookConVarChange(wS, cvar_turret_no_ct_attack);
}
public cvar_turret_direction(Handle:var, const String:old[], const String:NewValue[])
{
turret_direction = StringToInt(NewValue) == 1 ? true : false;
}
public cvar_turret_no_ct_attack(Handle:var, const String:old[], const String:NewValue[])
{
turret_no_ct_attack = StringToInt(NewValue) == 1 ? true : false;
}
public OnMapStart()
{
PrecacheModel(TURRET_MODEL, true);
PrecacheModel("models/weapons/w_missile_launch.mdl", true);
PrecacheSound("weapons/rpg/rocketfire1.wav", true);
PrecacheSound("weapons/explode3.wav", true);
decl Float:WorldMinHull[3], Float:WorldMaxHull[3];
GetEntPropVector(0, Prop_Send, "m_WorldMins", WorldMinHull);
GetEntPropVector(0, Prop_Send, "m_WorldMaxs", WorldMaxHull);
MaxWorldLength = GetVectorDistance(WorldMinHull, WorldMaxHull);
}
///
public round_start(Handle:event, const String:name[], bool:dontBroadcast)
{
TurretsNum = 0;
if (MaxTurretIndex > 0)
{
for (new i = MaxClients + 1; i <= MaxTurretIndex; i++)
{
if (TurretTimer[i] != INVALID_HANDLE)
{
KillTimer(TurretTimer[i]); TurretTimer[i] = INVALID_HANDLE;
}
}
MaxTurretIndex = 0;
}
}
public OnEntityDestroyed(entity)
{
if (MaxTurretIndex > 0 && entity < 1500 && TurretTimer[entity] != INVALID_HANDLE)
{
KillTimer(TurretTimer[entity]); TurretTimer[entity] = INVALID_HANDLE;
if (TurretsNum > 0) TurretsNum -= 1;
}
}
///
public Action:turret(client, args)
{
if (client > 0 && args < 1 && GetClientTeam(client) == 3 && IsPlayerAlive(client)) SpawnTurret(client);
return Plugin_Handled;
}
SpawnTurret(client)
{
decl Float:origin[3], Float:angles[3];
GetClientEyePosition(client, origin); GetClientEyeAngles(client, angles);
TR_TraceRayFilter(origin, angles, MASK_SOLID, RayType_Infinite, wS_TraceFilter, client);
new entity = TR_GetEntityIndex();
if (entity > 0)
{
if (entity <= MaxClients)
{
PrintToChat(client, "Уберите прицел с игрока");
return;
}
decl String:name[15]; name[0] = '\0';
GetEntPropString(entity, Prop_Data, "m_iName", name, 15);
if (StrEqual(name, "wS_Turret"))
{
new vladelec_id = GetEntProp(entity, Prop_Send, "m_PredictableID");
if (vladelec_id == GetClientUserId(client))
{
PrintToChat(client, "\x04Вы забрали свою пушку");
AcceptEntityInput(entity, "Kill");
}
else
{
new vladelec_client = GetClientOfUserId(vladelec_id);
if (vladelec_client > 0 && GetClientTeam(vladelec_client) == 3) PrintToChat(client, "Владелец пушки: %N", vladelec_client);
else
{
PrintToChat(client, "\x04Вы забрали чужую пушку (владелец не найден)");
AcceptEntityInput(entity, "Kill");
}
}
return;
}
}
if (TurretsNum > 1)
{
PrintToChat(client, "\x04Лимит пушек: 2");
return;
}
TR_GetEndPosition(origin);
TR_GetPlaneNormal(INVALID_HANDLE, angles); GetVectorAngles(angles, angles); angles[0] += 90.0;
entity = CreateEntityByName("prop_physics_override");
DispatchKeyValue(entity, "targetname", "wS_Turret");
DispatchKeyValueVector(entity, "origin", origin);
DispatchKeyValue(entity, "model", TURRET_MODEL);
DispatchKeyValue(entity, "ExplodeDamage", "150");
DispatchKeyValue(entity, "ExplodeRadius", "300");
DispatchSpawn(entity);
SetEntityMoveType(entity, MOVETYPE_NONE);
SetEntProp(entity, Prop_Data, "m_takedamage", 2);
SetEntProp(entity, Prop_Data, "m_iHealth", 500);
SetEntProp(entity, Prop_Send, "m_PredictableID", GetClientUserId(client));
SDKHook(entity, SDKHook_OnTakeDamage, OnTakeDamage_Hook);
if (entity > MaxTurretIndex) MaxTurretIndex = entity;
TurretTimer[entity] = CreateTimer(5.0, TurretShot, entity, TIMER_REPEAT | TIMER_FLAG_NO_MAPCHANGE);
if (StrContains(MyTurrets[client], ",") < 0) Format(MyTurrets[client], 100, "%d,", entity);
else Format(MyTurrets[client], 100, "%s%d,", MyTurrets[client], entity);
TurretsNum += 1;
}
public bool:wS_TraceFilter(ent, mask, any:client) return client != ent;
public Action:TurretShot(Handle:timer, any:turret)
{
if (!IsValidEntity(turret))
{
TurretTimer[turret] = INVALID_HANDLE;
return Plugin_Stop;
}
decl Float:origin[3], Float:angles[3], Float:target_pos[3];
GetEntPropVector(turret, Prop_Send, "m_vecOrigin", origin); origin[2] += 75.0;
new target = FindAliveTarget(turret, origin, angles, target_pos);
if (target < 1)
{
//PrintToChatAll("цель не найдена");
return Plugin_Continue;
}
RocketAttack(turret, origin, angles);
return Plugin_Continue;
}
FindAliveTarget(turret, const Float:turret_pos[3], Float:turret_angles[3], Float:target_pos[3])
{
decl Float:VecPoints[3], Float:Atan, index;
for (new i = 1; i <= MaxClients; i++)
{
if (IsClientInGame(i) && IsPlayerAlive(i) && GetClientTeam(i) == 2)
{
GetClientAbsOrigin(i, target_pos); target_pos[2] += 55.0;
MakeVectorFromPoints(turret_pos, target_pos, VecPoints);
Atan = RadToDeg(ArcTangent(VecPoints[1] / VecPoints[0]));
if (VecPoints[0] < 0) turret_angles[1] = Atan + 180.0;
else if (VecPoints[1] < 0) turret_angles[1] = Atan + 360.0;
else turret_angles[1] = Atan;
turret_angles[2] = target_pos[2];
turret_angles[0] = 0.0 - RadToDeg(ArcTangent(VecPoints[2] / SquareRoot(Pow(VecPoints[1], 2.0) + Pow(VecPoints[0], 2.0))));
TR_TraceRayFilter(turret_pos, turret_angles, MASK_SOLID, RayType_Infinite, wS_TraceFilter, turret);
if ((index = TR_GetEntityIndex()) > 0 && index <= MaxClients)
{
return index;
}
}
}
return 0;
}
RocketAttack(turret, Float:turret_pos[3], Float:turret_angles[3])
{
decl Float:anglevector[3];
GetAngleVectors(turret_angles, anglevector, NULL_VECTOR, NULL_VECTOR);
NormalizeVector(anglevector, anglevector);
NormalizeVector(anglevector, anglevector);
ScaleVector(anglevector, 1500.0);
new rocket = CreateEntityByName("hegrenade_projectile");
DispatchKeyValue(rocket, "spawnflags", "16");
DispatchKeyValue(rocket, "model", "models/weapons/w_missile_launch.mdl");
DispatchSpawn(rocket);
SetEntPropEnt(rocket, Prop_Send, "m_hOwnerEntity", turret);
SetEntPropEnt(rocket, Prop_Send, "m_hThrower", GetClientOfUserId(GetEntProp(turret, Prop_Send, "m_PredictableID")));
SetEntityMoveType(rocket, MOVETYPE_FLY);
SetEntPropVector(rocket, Prop_Send, "m_vecMins", Float:{-4.0, -4.0, -4.0});
SetEntPropVector(rocket, Prop_Send, "m_vecMaxs", Float:{4.0, 4.0, 4.0});
SetEntityModel(rocket, "models/weapons/w_missile_launch.mdl");
TeleportEntity(rocket, turret_pos, turret_angles, anglevector);
new gascloud = CreateEntityByName("env_rockettrail");
DispatchKeyValueVector(gascloud, "origin", turret_pos);
DispatchKeyValueVector(gascloud, "angles", turret_angles);
new Float:smokecolor[3] = {1.0, 1.0, 1.0};
SetEntPropVector(gascloud, Prop_Send, "m_StartColor", smokecolor);
SetEntPropFloat(gascloud, Prop_Send, "m_Opacity", 0.5);
SetEntPropFloat(gascloud, Prop_Send, "m_SpawnRate", 100.0);
SetEntPropFloat(gascloud, Prop_Send, "m_ParticleLifetime", 0.5);
SetEntPropFloat(gascloud, Prop_Send, "m_StartSize", 5.0);
SetEntPropFloat(gascloud, Prop_Send, "m_EndSize", 30.0);
SetEntPropFloat(gascloud, Prop_Send, "m_SpawnRadius", 0.0);
SetEntPropFloat(gascloud, Prop_Send, "m_MinSpeed", 0.0);
SetEntPropFloat(gascloud, Prop_Send, "m_MaxSpeed", 10.0);
SetEntPropFloat(gascloud, Prop_Send, "m_flFlareScale", 1.0);
DispatchSpawn(gascloud);
decl String:Name[64]; Format(Name, 64, "gren_%f", GetGameTime());
DispatchKeyValue(rocket, "targetname", Name);
SetVariantString(Name);
AcceptEntityInput(gascloud, "SetParent");
SetEntPropEnt(rocket, Prop_Send, "m_hEffectEntity", gascloud);
EmitSoundToAll("weapons/rpg/rocketfire1.wav", rocket, SNDCHAN_AUTO, SNDLEVEL_NORMAL, SND_NOFLAGS, SNDVOL_NORMAL, SNDPITCH_NORMAL, -1, turret_pos);
///
if (turret_direction)
{
HookSingleEntityOutput(rocket, "OnUser2", MissileThink);
SetVariantString("OnUser1 !self:FireUser2::0.1:-1");
AcceptEntityInput(rocket, "AddOutput"); AcceptEntityInput(rocket, "FireUser1");
}
///
SDKHook(rocket, SDKHook_StartTouch, RocketTouchHook);
}
public Action:RocketTouchHook(entity, other) CreateExplosion(entity);
public Action:OnTakeDamage_Hook(victim, &attacker, &inflictor, &Float:damage, &damagetype)
{
if (attacker < 1 || attacker > MaxClients || !IsClientInGame(attacker) || GetClientTeam(attacker) == 3)
{
return Plugin_Handled;
}
return Plugin_Continue;
}
public OnClientPutInServer(client)
{
SDKHook(client, SDKHook_OnTakeDamage, OnTakeDamage_Hook_Player);
}
public MissileThink(const String:output[], caller, activator, Float:delay)
{
decl Float:CheckVec[3];
GetEntPropVector(caller, Prop_Send, "m_vecVelocity", CheckVec);
if ((CheckVec[0] == 0.0) && (CheckVec[1] == 0.0) && (CheckVec[2] == 0.0))
{
CreateExplosion(caller);
return;
}
decl Float:NadePos[3], Float:EnemyPos[3];
GetEntPropVector(caller, Prop_Send, "m_vecOrigin", NadePos);
new Float:ClosestDistance = MaxWorldLength, Tclient = 0, Float:EnemyDistance;
for (new i = 1; i <= MaxClients; i++)
{
if (IsClientInGame(i) && IsPlayerAlive(i) && GetClientTeam(i) == 2)
{
GetClientAbsOrigin(i, EnemyPos); EnemyPos[2] += 55.0;
TR_TraceHullFilter(NadePos, EnemyPos, Float:{-2.5, -2.5, -2.5}, Float:{2.5, 2.5, 2.5}, MASK_SOLID, wS_TraceFilter, caller);
if (TR_GetEntityIndex() == i)
{
EnemyDistance = GetVectorDistance(NadePos, EnemyPos);
if (EnemyDistance < ClosestDistance)
{
Tclient = i;
ClosestDistance = EnemyDistance;
}
}
}
}
if (Tclient < 1)
{
AcceptEntityInput(caller, "FireUser1");
return;
}
decl Float:TargetVec[3];
GetClientAbsOrigin(Tclient, EnemyPos); EnemyPos[2] += 55.0;
MakeVectorFromPoints(NadePos, EnemyPos, TargetVec);
NormalizeVector(TargetVec, TargetVec);
ScaleVector(TargetVec, 500.0);
decl Float:FinalAng[3]; GetVectorAngles(TargetVec, FinalAng);
TeleportEntity(caller, NULL_VECTOR, FinalAng, TargetVec);
AcceptEntityInput(caller, "FireUser1");
}
public player_spawn(Handle:event, const String:name[], bool:dontBroadcast)
{
new client = GetClientOfUserId(GetEventInt(event, "userid"));
Infected[client] = false; MyTurrets[client] = "";
}
KillPlayerTurrets(client)
{
new userid = GetClientUserId(client), index;
decl String:buf[3][15];
new max = ExplodeString(MyTurrets[client], ",", buf, 3, 15);
for (new i = 0; i < max; i++)
{
if ((index = StringToInt(buf[i])) > MaxClients && IsValidEntity(index) && GetEntProp(index, Prop_Send, "m_PredictableID") == userid)
{
AcceptEntityInput(index, "Kill");
}
}
}
CreateExplosion(rocket)
{
UnhookSingleEntityOutput(rocket, "OnUser2", MissileThink);
SDKUnhook(rocket, SDKHook_StartTouch, RocketTouchHook);
// владелец пушки и летящей ракеты
new rocket_client = GetEntPropEnt(rocket, Prop_Data, "m_hThrower");
decl Float:origin[3]; GetEntPropVector(rocket, Prop_Send, "m_vecOrigin", origin);
AcceptEntityInput(rocket, "Kill");
new index = CreateEntityByName("env_explosion");
if (index > 0)
{
DispatchKeyValue(index, "targetname", "wS_Expl");
DispatchKeyValueVector(index, "origin", origin);
DispatchKeyValue(index, "spawnflags", "6146");
DispatchKeyValue(index, "iMagnitude", "50");
DispatchKeyValue(index, "iRadiusOverride", "250");
DispatchSpawn(index);
if (rocket_client > 0) SetEntPropEnt(index, Prop_Send, "m_hOwnerEntity", rocket_client);
AcceptEntityInput(index, "Explode");
AcceptEntityInput(index, "Kill");
EmitSoundToAll("weapons/explode3.wav", 0, SNDCHAN_AUTO, SNDLEVEL_NORMAL, SND_NOFLAGS, SNDVOL_NORMAL, SNDPITCH_NORMAL, -1, origin);
}
}
public Action:OnTakeDamage_Hook_Player(victim, &attacker, &inflictor, &Float:damage, &damagetype)
{
if (attacker > 0 && attacker <= MaxClients && IsClientInGame(attacker))
{
new attacker_team = GetClientTeam(attacker);
if (attacker_team == 3 && inflictor > MaxClients)
{
decl String:name[15]; name[0] = '\0';
GetEntPropString(inflictor, Prop_Data, "m_iName", name, 15);
if (StrEqual(name, "wS_Expl"))
{
new victim_team = GetClientTeam(victim);
// блокируем повреждение, если жертва ct
if (victim_team == 3 && turret_no_ct_attack) return Plugin_Handled;
// сообщаем владельцу пушки о нанесенном уроне
if (victim_team == 2)
{
new int_damage = RoundToZero(damage);
if (int_damage > 0) PrintCenterText(attacker, "- %d hp (%N)", int_damage, victim);
}
}
}
else if (TurretsNum > 0 && attacker_team == 2 && GetClientTeam(victim) == 3 && !Infected[victim])
{
Infected[victim] = true; KillPlayerTurrets(victim);
}
}
return Plugin_Continue;
}