From 6df6be624d197108ea9dcf8ce5f3504ddfb027d8 Mon Sep 17 00:00:00 2001 From: neon <> Date: Thu, 22 Aug 2019 11:42:25 +0200 Subject: [PATCH] is this abuse? --- Turret/scripting/Turret.sp | 596 +++++++++++++++++++++++++++++++++++++ 1 file changed, 596 insertions(+) create mode 100644 Turret/scripting/Turret.sp diff --git a/Turret/scripting/Turret.sp b/Turret/scripting/Turret.sp new file mode 100644 index 00000000..30f2f2ca --- /dev/null +++ b/Turret/scripting/Turret.sp @@ -0,0 +1,596 @@ +#include +#include +#include +#include +#include +#include + +#pragma semicolon 1 +#pragma newdecls required + +int g_iVelocity; +int g_iCurrentTick; +int g_iTicksSinceLastAttack; + +#define MAX_TURRETS 65 + +int g_iTurrets[MAX_TURRETS] = {INVALID_ENT_REFERENCE,...}; +int g_iMarkers[MAX_TURRETS] = {INVALID_ENT_REFERENCE,...}; +int g_iGunfire[MAX_TURRETS] = {INVALID_ENT_REFERENCE,...}; +int g_iExplosion[MAX_TURRETS] = {INVALID_ENT_REFERENCE,...}; +int g_iOwner[MAX_TURRETS]; +bool g_bCanPlace[MAX_TURRETS]; +bool g_bPlaced[MAX_TURRETS]; + +float g_fMaxRange; +float g_fMinAccuracy; +float g_fMaxAccuracy; +float g_fDestroyRange; +float g_fKnockback; +int g_iDamage; +int g_iTicksToSkip; + +//---------------------------------------------------------------------------------------------------- +// Purpose: +//---------------------------------------------------------------------------------------------------- +public Plugin myinfo = +{ + name = "Turrets", + author = "Neon", + description = "", + version = "1.0.0", + url = "https://steamcommunity.com/id/n3ontm" +}; + +//---------------------------------------------------------------------------------------------------- +// Purpose: +//---------------------------------------------------------------------------------------------------- +public void OnPluginStart() +{ + //RegConsoleCmd("sm_turret", Command_Turret); + RegAdminCmd("sm_turret", Command_Turret, ADMFLAG_RCON); + HookEvent("round_end", OnRound); + HookEvent("round_start", OnRound); + + ConVar cvar; + HookConVarChange((cvar = CreateConVar("sm_turrets_max_range", "1500", "")), Cvar_MaxRange); + g_fMaxRange = cvar.FloatValue; + HookConVarChange((cvar = CreateConVar("sm_turrets_min_accuracy", "0.7", "")), Cvar_MinAccuracy); + g_fMinAccuracy = cvar.FloatValue; + HookConVarChange((cvar = CreateConVar("sm_turrets_max_accuracy", "0.99", "")), Cvar_MaxAccuracy); + g_fMaxAccuracy = cvar.FloatValue; + HookConVarChange((cvar = CreateConVar("sm_turrets_destroy_range", "100", "")), Cvar_DestroyRange); + g_fDestroyRange = cvar.FloatValue; + HookConVarChange((cvar = CreateConVar("sm_turrets_knockback", "20", "")), Cvar_Knockback); + g_fKnockback = cvar.FloatValue; + HookConVarChange((cvar = CreateConVar("sm_turrets_damage", "10", "")), Cvar_Damage); + g_iDamage = cvar.IntValue; + HookConVarChange((cvar = CreateConVar("sm_turrets_ticks_to_skip", "3", "")), Cvar_TicksToSkip); // to decrease CPU usage + g_iTicksToSkip = cvar.IntValue; + delete cvar; +} + +//---------------------------------------------------------------------------------------------------- +// Purpose: +//---------------------------------------------------------------------------------------------------- +public void OnMapStart() +{ + g_iVelocity = FindDataMapInfo(0, "m_vecAbsVelocity"); + + PrecacheModel("models/unloze/dronegun/dronegun.mdl"); + AddFileToDownloadsTable("models/unloze/dronegun/dronegun.dx90.vtx"); + AddFileToDownloadsTable("models/unloze/dronegun/dronegun.dx80.vtx"); + AddFileToDownloadsTable("models/unloze/dronegun/dronegun.mdl"); + AddFileToDownloadsTable("models/unloze/dronegun/dronegun.phy"); + AddFileToDownloadsTable("models/unloze/dronegun/dronegun.sw.vtx"); + AddFileToDownloadsTable("models/unloze/dronegun/dronegun.vvd"); + AddFileToDownloadsTable("materials/models/unloze/dronegun/dronegun.vmt"); + AddFileToDownloadsTable("materials/models/unloze/dronegun/dronegun.vtf"); + AddFileToDownloadsTable("materials/models/unloze/dronegun/dronegun_laser.vmt"); + AddFileToDownloadsTable("materials/models/unloze/dronegun/dronegun_laser.vtf"); + AddFileToDownloadsTable("materials/models/unloze/dronegun/dronegun_selfillum.vtf"); + AddFileToDownloadsTable("materials/models/unloze/weapons/w_models/w_mach_m249para/m249.vmt"); + AddFileToDownloadsTable("materials/models/unloze/weapons/w_models/w_mach_m249para/m249.vtf"); + AddFileToDownloadsTable("materials/models/unloze/weapons/w_models/w_mach_m249para/m249_exponent.vtf"); +} + +//---------------------------------------------------------------------------------------------------- +// Purpose: +//---------------------------------------------------------------------------------------------------- +public void OnPluginEnd() +{ + for (int i = 0; i < MAX_TURRETS; i++) + { + if (g_iTurrets[i] == INVALID_ENT_REFERENCE) + continue; + + ClearTurret(i); + } +} + +//---------------------------------------------------------------------------------------------------- +// Purpose: +//---------------------------------------------------------------------------------------------------- +public void OnRound(Event hEvent, const char[] sEvent, bool bDontBroadcast) +{ + for (int i = 0; i < MAX_TURRETS; i++) + { + g_iTurrets[i] = INVALID_ENT_REFERENCE; + g_iMarkers[i] = INVALID_ENT_REFERENCE; + g_iGunfire[i] = INVALID_ENT_REFERENCE; + g_iExplosion[i] = INVALID_ENT_REFERENCE; + g_iOwner[i] = 0; + g_bCanPlace[i] = false; + g_bPlaced[i] = false; + } +} + +//---------------------------------------------------------------------------------------------------- +// Purpose: +//---------------------------------------------------------------------------------------------------- +public Action Command_Turret(int client, int args) +{ + if (!ZR_IsClientHuman(client)) + { + ReplyToCommand(client, "[ZR] You need to be human to use this command."); + return Plugin_Handled; + } + + // Clear old turret + for (int j = 0; j < MAX_TURRETS; j++) + { + if ((g_iOwner[j] != 0) && (g_iOwner[j] == client)) + { + ClearTurret(j); + ReplyToCommand(client, "[ZR] Turret Removed."); + return Plugin_Handled; + } + } + + // find free index + int i; + for (i = 0; i < MAX_TURRETS; i++) + { + if (g_iTurrets[i] == INVALID_ENT_REFERENCE) + break; + + if (i == (MAX_TURRETS -1)) + { + ReplyToCommand(client, "[ZR] Too many turrets active already."); + return Plugin_Handled; + } + } + + float vecOrigin[3]; + GetClientAbsOrigin(client, vecOrigin); + + g_iTurrets[i] = CreateEntityAtOrigin("prop_dynamic_override", vecOrigin); + SetEntityModel(g_iTurrets[i], "models/unloze/dronegun/dronegun.mdl"); + DispatchKeyFormat(g_iTurrets[i], "targetname", "turret_%d", i); + DispatchKeyFormat(g_iTurrets[i], "solid", "0"); + DispatchKeyFormat(g_iTurrets[i], "modelscale", "1.0"); + DispatchKeyFormat(g_iTurrets[i], "disableshadows", "1"); + DispatchKeyFormat(g_iTurrets[i], "disablereceiveshadows", "1"); + DispatchKeyFormat(g_iTurrets[i], "disablebonefollowers", "1"); + DispatchKeyFormat(g_iTurrets[i], "OnUser1", "gunfire_%d,Kill,,0,1", i); + DispatchKeyFormat(g_iTurrets[i], "OnUser1", "marker_%d,Kill,,0,1", i); + DispatchKeyFormat(g_iTurrets[i], "OnUser1", "!self,Kill,,0,1"); + DispatchKeyFormat(g_iTurrets[i], "OnUser2", "explosion_%d,Explode,,0,1", i); + SpawnAndActivate(g_iTurrets[i]); + + //traget for env_gunfire to aim at + g_iMarkers[i] = CreateEntityAtOrigin("path_track", vecOrigin); + DispatchKeyFormat(g_iMarkers[i], "targetname", "marker_%d", i); + SpawnAndActivate(g_iMarkers[i]); + + vecOrigin[2] += 42.0; // "middle" of turret + g_iGunfire[i] = CreateEntityAtOrigin("env_gunfire", vecOrigin); + DispatchKeyFormat(g_iGunfire[i], "targetname", "gunfire_%d", i); + DispatchKeyFormat(g_iGunfire[i], "target", "marker_%d", i); + DispatchKeyFormat(g_iGunfire[i], "StartDisabled", "1"); + DispatchKeyFormat(g_iGunfire[i], "spread", "0"); + DispatchKeyFormat(g_iGunfire[i], "collisions", "1"); + DispatchKeyFormat(g_iGunfire[i], "rateoffire", "10"); + SpawnAndActivate(g_iGunfire[i]); + ParentToEntity(g_iGunfire[i], g_iTurrets[i]); + + g_iExplosion[i] = CreateEntityAtOrigin("env_explosion", vecOrigin); + DispatchKeyFormat(g_iExplosion[i], "targetname", "explosion_%d", i); + DispatchKeyFormat(g_iExplosion[i], "fireballsprite", "sprites/zerogxplode.spr"); + DispatchKeyFormat(g_iExplosion[i], "rendermode", "0"); + DispatchKeyFormat(g_iExplosion[i], "iMagnitude", "100"); + DispatchKeyFormat(g_iExplosion[i], "spawnflags", "1"); + SpawnAndActivate(g_iExplosion[i]); + ParentToEntity(g_iExplosion[i], g_iTurrets[i]); + + g_iOwner[i] = client; + ReplyToCommand(client, "[ZR] Press E to place a turret."); + return Plugin_Handled; +} + +//---------------------------------------------------------------------------------------------------- +// Purpose: +//---------------------------------------------------------------------------------------------------- +public void OnGameFrame() // Tick Turrets +{ + g_iCurrentTick++; + g_iTicksSinceLastAttack++; + if (g_iCurrentTick < g_iTicksToSkip) + return; + + g_iCurrentTick = 0; + + bool bAttack = false; + if (g_iTicksSinceLastAttack > 15) + bAttack = true; + + for (int i = 0; i < MAX_TURRETS; i++) + { + if (g_iTurrets[i] == INVALID_ENT_REFERENCE) + continue; + + if (!g_bPlaced[i]) // not placed yet + { + PlaceTurret(i); + continue; + } + + float vecOriginClient[3]; + float vecOriginTurret[3]; + GetEntPropVector(g_iTurrets[i], Prop_Send, "m_vecOrigin", vecOriginTurret); + vecOriginTurret[2] += 42.0; + + int iNearestZombie; + float fNearestDistance; + + for (int client = 1; client <= MaxClients; client++) + { + if (!IsClientInGame(client) || !IsPlayerAlive(client) || !ZR_IsClientZombie(client)) + continue; + + GetClientAbsOrigin(client, vecOriginClient); + vecOriginClient[2] += 50.0; //aim for chest + + Handle hTraceRay = TR_TraceRayFilterEx(vecOriginClient, vecOriginTurret, MASK_ALL, RayType_EndPoint, TraceEntityFilter, g_iTurrets[i]); + + if(TR_DidHit(hTraceRay)) + { + delete hTraceRay; + continue; + } + delete hTraceRay; + + float vecVector[3]; + float vecAngles[3]; + MakeVectorFromPoints(vecOriginTurret, vecOriginClient, vecVector); + GetVectorAngles(vecVector, vecAngles); + + if (!((vecAngles[0] <= 45.0) || (vecAngles[0] >= 315.0))) + continue; + + float fDistance = GetVectorLength(vecVector, false); + + if ((fDistance < fNearestDistance) || (iNearestZombie == 0)) + { + iNearestZombie = client; + fNearestDistance = fDistance; + } + } + + if (iNearestZombie == 0) // no target found + continue; + + // ZM too close, destroy turret + if (fNearestDistance <= g_fDestroyRange) + { + ClearTurret(i, true); + continue; + } + + float vecVector[3]; + float vecAngles[3]; + GetClientAbsOrigin(iNearestZombie, vecOriginClient); + vecOriginClient[2] += 50.0; //aim for chest + MakeVectorFromPoints(vecOriginTurret, vecOriginClient, vecVector); + GetVectorAngles(vecVector, vecAngles); + + float fA = ((vecAngles[1]+180.0)/360.0); + if (fA > 1.0) + fA -= 1.0; + + float fB; + if (vecAngles[0] <= 45.0) + { + fB = ((1.0/90.0) * vecAngles[0]) + 0.5; + } + else if (vecAngles[0] >= 315.0) + { + fB = ((1.0/90.0) * (vecAngles[0] - 315.0)) + 0.0; + } + + // why the fuck can i only set one of those angles???? + //SetEntPropFloat(g_iTurrets[i], Prop_Data, "m_flPoseParameter", fB, 1); + //SetEntPropFloat(g_iTurrets[i], Prop_Send, "m_flCycle", 1.0); + SetEntPropFloat(g_iTurrets[i], Prop_Data, "m_flPoseParameter", fA, 0); + SetEntPropFloat(g_iTurrets[i], Prop_Send, "m_flCycle", 0.0); + + // randomly spread the bullets + vecOriginClient[0] += GetRandomFloat(-15.0, 15.0); + vecOriginClient[1] += GetRandomFloat(-15.0, 15.0); + vecOriginClient[2] += GetRandomFloat(-20.0, 20.0); + TeleportEntity(g_iMarkers[i], vecOriginClient, NULL_VECTOR, NULL_VECTOR); + + if (bAttack) + { + g_iTicksSinceLastAttack = 0; + + // check for max range + float fDistance = GetVectorDistance(vecOriginClient, vecOriginTurret, false); + if (fDistance > g_fMaxRange) + { + AcceptEntityInput(g_iGunfire[i], "Disable"); + continue; + } + AcceptEntityInput(g_iGunfire[i], "Enable"); + + // Accuracy + float fAccuracy = (((-(g_fMaxAccuracy - g_fMinAccuracy))/g_fMaxRange) * fDistance) + g_fMaxAccuracy; + float R = GetRandomFloat(0.0, 100.0); + if (FloatCompare(R, fAccuracy) == -1) + continue; + + // DMG + int iHealth = GetClientHealth(iNearestZombie); + if(iHealth > g_iDamage) + SetEntityHealth(iNearestZombie, iHealth - g_iDamage); + else + ForcePlayerSuicide(iNearestZombie); + + // KB + MakeVectorFromPoints(vecOriginTurret, vecOriginClient, vecVector); + NormalizeVector(vecVector, vecVector); + ScaleVector(vecVector, g_fKnockback); + float fClientVelocity[3]; + GetEntDataVector(iNearestZombie, g_iVelocity, fClientVelocity); + AddVectors(fClientVelocity, vecVector, fClientVelocity); + SetEntDataVector(iNearestZombie, g_iVelocity, fClientVelocity); + } + } +} + +//---------------------------------------------------------------------------------------------------- +// Purpose: +//---------------------------------------------------------------------------------------------------- +public void PlaceTurret(int i) +{ + if (g_iTurrets[i] == INVALID_ENT_REFERENCE) // no turret + return; + + int client = g_iOwner[i]; + if (!IsValidClient(client)) + { + ClearTurret(i); + return; + } + + if (!(IsPlayerAlive(client) && ZR_IsClientHuman(client))) + { + ClearTurret(i); + return; + } + + float vecEyeAngles[3]; + float vecEyeOrigin[3]; + + GetClientEyeAngles(client, vecEyeAngles); + GetClientEyePosition(client, vecEyeOrigin); + + Handle hTraceRay = TR_TraceRayFilterEx(vecEyeOrigin, vecEyeAngles, MASK_ALL, RayType_Infinite, TraceEntityFilter, client); + + g_bCanPlace[i] = false; + if(TR_DidHit(hTraceRay)) + { + float vecEndPosAim[3]; + TR_GetEndPosition(vecEndPosAim, hTraceRay); + + float vecDown[3] = {90.0, 0.0, 0.0}; + delete hTraceRay; + hTraceRay = TR_TraceRayFilterEx(vecEndPosAim, vecDown, MASK_ALL, RayType_Infinite, TraceEntityFilter, client); + + if(TR_DidHit(hTraceRay)) + { + float vecEndPosDown[3]; + TR_GetEndPosition(vecEndPosDown, hTraceRay); + TeleportEntity(g_iTurrets[i], vecEndPosDown, NULL_VECTOR, NULL_VECTOR); + + if (GetVectorDistance(vecEyeOrigin, vecEndPosDown, false) > 500) // maximum distance to place a turret + { + delete hTraceRay; + SetEntityRenderColor(g_iTurrets[i], 255, 0, 0, 0); + return; + } + vecEndPosDown[2] += 5.0; + vecEndPosAim[2] += 5.0; + + float vecMins[3] = {-30.0, -30.0, 0.0}; + float vecMaxs[3] = {30.0, 30.0, 63.0}; + + delete hTraceRay; + hTraceRay = TR_TraceHullFilterEx(vecEndPosDown, vecEndPosAim, vecMins, vecMaxs, MASK_ALL, TraceEntityFilter, client); + if(!TR_DidHit(hTraceRay)) + g_bCanPlace[i] = true; + } + } + delete hTraceRay; + + if(g_bCanPlace[i]) + SetEntityRenderColor(g_iTurrets[i], 0, 255, 0, 0); + else + SetEntityRenderColor(g_iTurrets[i], 255, 0, 0, 0); +} + +//---------------------------------------------------------------------------------------------------- +// Purpose: +//---------------------------------------------------------------------------------------------------- +public void OnPlayerRunCmdPost(int client, int buttons) +{ + for (int i = 0; i < MAX_TURRETS; i++) + { + if (g_iTurrets[i] == INVALID_ENT_REFERENCE) // no turret + continue; + + if (g_bPlaced[i]) // already placed + continue; + + if(!g_bCanPlace[i]) // cant be placed atm + continue; + + if (g_iOwner[i] == client) + { + if (buttons & IN_USE) + { + SetEntityRenderColor(g_iTurrets[i], 255, 255, 255, 0); + //g_iOwner[i] = 0; + g_bPlaced[i] = true; + } + break; + } + } +} + +//---------------------------------------------------------------------------------------------------- +// Purpose: +//---------------------------------------------------------------------------------------------------- +stock bool TraceEntityFilter(int entity, int contentsMask, int turret) +{ + if ((entity == turret) || (0 <= entity <= MaxClients)) + return false; + + return true; +} + +//---------------------------------------------------------------------------------------------------- +// Purpose: +//---------------------------------------------------------------------------------------------------- +stock int CreateEntityAtOrigin(const char[] classname, const float origin[3]) +{ + int entity = CreateEntityByName(classname); + + TeleportEntity(entity, origin, NULL_VECTOR, NULL_VECTOR); + + return entity; +} + +//---------------------------------------------------------------------------------------------------- +// Purpose: +//---------------------------------------------------------------------------------------------------- +stock bool DispatchKeyFormat(int entity, const char[] key, const char[] value, any ...) +{ + char buffer[1024]; + VFormat(buffer, sizeof(buffer), value, 4); + + DispatchKeyValue(entity, key, buffer); +} + +//---------------------------------------------------------------------------------------------------- +// Purpose: +//---------------------------------------------------------------------------------------------------- +stock void SpawnAndActivate(int entity) +{ + DispatchSpawn(entity); + ActivateEntity(entity); +} + +//---------------------------------------------------------------------------------------------------- +// Purpose: +//---------------------------------------------------------------------------------------------------- +stock void ParentToEntity(int entity, int parent) +{ + SetVariantString("!activator"); + AcceptEntityInput(entity, "SetParent", parent, parent); +} + +//---------------------------------------------------------------------------------------------------- +// Purpose: +//---------------------------------------------------------------------------------------------------- +void ClearTurret(int index, bool bExplode = false) +{ + if (bExplode) + AcceptEntityInput(g_iTurrets[index], "FireUser2"); + + AcceptEntityInput(g_iTurrets[index], "FireUser1"); + g_iTurrets[index] = INVALID_ENT_REFERENCE; + g_iMarkers[index] = INVALID_ENT_REFERENCE; + g_iGunfire[index] = INVALID_ENT_REFERENCE; + g_iExplosion[index] = INVALID_ENT_REFERENCE; + g_iOwner[index] = 0; + g_bCanPlace[index] = false; + g_bPlaced[index] = false; +} + +//---------------------------------------------------------------------------------------------------- +// Purpose: +//---------------------------------------------------------------------------------------------------- +stock bool IsValidClient(int client, bool nobots = true) +{ + if (client <= 0 || client > MaxClients || !IsClientConnected(client) || (nobots && IsFakeClient(client))) + return false; + + return IsClientInGame(client); +} + +//---------------------------------------------------------------------------------------------------- +// Purpose: +//---------------------------------------------------------------------------------------------------- +public void Cvar_MaxRange(ConVar convar, const char[] oldValue, const char[] newValue) +{ + g_fMaxRange = convar.FloatValue; +} + +//---------------------------------------------------------------------------------------------------- +// Purpose: +//---------------------------------------------------------------------------------------------------- +public void Cvar_MinAccuracy(ConVar convar, const char[] oldValue, const char[] newValue) +{ + g_fMinAccuracy = convar.FloatValue; +} + +//---------------------------------------------------------------------------------------------------- +// Purpose: +//---------------------------------------------------------------------------------------------------- +public void Cvar_MaxAccuracy(ConVar convar, const char[] oldValue, const char[] newValue) +{ + g_fMaxAccuracy = convar.FloatValue; +} + +//---------------------------------------------------------------------------------------------------- +// Purpose: +//---------------------------------------------------------------------------------------------------- +public void Cvar_DestroyRange(ConVar convar, const char[] oldValue, const char[] newValue) +{ + g_fDestroyRange = convar.FloatValue; +} + +//---------------------------------------------------------------------------------------------------- +// Purpose: +//---------------------------------------------------------------------------------------------------- +public void Cvar_Knockback(ConVar convar, const char[] oldValue, const char[] newValue) +{ + g_fKnockback = convar.FloatValue; +} + +//---------------------------------------------------------------------------------------------------- +// Purpose: +//---------------------------------------------------------------------------------------------------- +public void Cvar_Damage(ConVar convar, const char[] oldValue, const char[] newValue) +{ + g_iDamage = convar.IntValue; +} + +//---------------------------------------------------------------------------------------------------- +// Purpose: +//---------------------------------------------------------------------------------------------------- +public void Cvar_TicksToSkip(ConVar convar, const char[] oldValue, const char[] newValue) +{ + g_iTicksToSkip = convar.IntValue; +} \ No newline at end of file