diff --git a/plugins/TF2Sandbox-SecurityLaser.smx b/plugins/TF2Sandbox-SecurityLaser.smx new file mode 100644 index 0000000..24d6e1a Binary files /dev/null and b/plugins/TF2Sandbox-SecurityLaser.smx differ diff --git a/scripting/TF2Sandbox-SecurityLaser.sp b/scripting/TF2Sandbox-SecurityLaser.sp new file mode 100644 index 0000000..3d9cdce --- /dev/null +++ b/scripting/TF2Sandbox-SecurityLaser.sp @@ -0,0 +1,247 @@ +#pragma semicolon 1 + +#define DEBUG + +#define PLUGIN_AUTHOR "BattlefieldDuck" +#define PLUGIN_VERSION "1.0" + +#include +#include +#include +#include +#include + +#pragma newdecls required + +public Plugin myinfo = +{ + name = "[TF2] Sandbox - Security Laser", + author = PLUGIN_AUTHOR, + description = "Security Laser is not expensive in TF2Sandbox", + version = PLUGIN_VERSION, + url = "https://github.com/tf2-sandbox-studio/Module-SecurityLaser" +}; + +#define MODEL_POINTER "models/props_lab/tpplug.mdl" + +ConVar cvfRefreshRate; + +char g_strLaserModel[][] = +{ + "materials/sprites/physbeam.vmt", + "materials/sprites/healbeam.vmt", + "materials/sprites/plasmabeam.vmt", + "materials/sprites/bluelaser1.vmt", + "materials/sprites/crystal_beam1.vmt", + "materials/sprites/laser.vmt", + "materials/sprites/laserbeam.vmt", + "materials/sprites/laserdot.vmt", + "materials/sprites/lgtning.vmt", + "materials/sprites/tp_beam001.vmt" +}; + +char g_strHaloModel[][] = +{ + "materials/sprites/halo01.vmt", + "materials/sprites/halo01.vmt", + "materials/sprites/halo01.vmt", + "materials/sprites/halo01.vmt", + "materials/sprites/halo01.vmt", + "materials/sprites/halo01.vmt", + "materials/sprites/halo01.vmt", + "materials/sprites/halo01.vmt", + "materials/sprites/halo01.vmt", + "materials/sprites/halo01.vmt" +}; + +int g_iModelIndex[sizeof(g_strLaserModel)]; +int g_iHaloIndex[sizeof(g_strHaloModel)]; + +public void OnPluginStart() +{ + RegAdminCmd("sm_laser", Command_SpawnSecurityLaser, 0, "Spawn Security Laser"); + + cvfRefreshRate = CreateConVar("sm_tf2sb_laser_refreshrate", "0.25", "Security Laser refresh rate", 0, true, 0.1, true, 1.5); +} + +public void OnMapStart() +{ + PrecacheModel(MODEL_POINTER); + + for (int i = 0; i < sizeof(g_strLaserModel); i++) + { + g_iModelIndex[i] = PrecacheModel(g_strLaserModel[i]); + g_iHaloIndex[i] = PrecacheModel(g_strHaloModel[i]); + } + + int index = -1; + while ((index = FindEntityByClassname(index, "prop_dynamic")) != -1) + { + char strModel[64]; + GetEntPropString(index, Prop_Data, "m_ModelName", strModel, sizeof(strModel)); + + if (StrEqual(strModel, MODEL_POINTER)) + { + CreateTimer(0.0, Timer_SecurityLaser, EntIndexToEntRef(index)); + } + } +} + +public void OnEntityCreated(int entity, const char[] classname) +{ + if (StrEqual(classname, "prop_dynamic") || StrEqual(classname, "prop_dynamic_override")) + { + SDKHook(entity, SDKHook_SpawnPost, OnLaserPointerSpawn); + } +} + +public void OnLaserPointerSpawn(int entity) +{ + if(IsValidEntity(entity)) + { + char strModel[64]; + GetEntPropString(entity, Prop_Data, "m_ModelName", strModel, sizeof(strModel)); + + if (StrEqual(strModel, MODEL_POINTER)) + { + CreateTimer(0.0, Timer_SecurityLaser, EntIndexToEntRef(entity)); + } + } +} + +public Action Command_SpawnSecurityLaser(int client, int args) +{ + if(client <= 0 || client > MaxClients || !IsClientInGame(client) || !IsPlayerAlive(client)) + { + return Plugin_Continue; + } + + SpawnLaserPointer(client); + + return Plugin_Continue; +} + +public Action Timer_SecurityLaser(Handle timer, int pointerref) +{ + int pointer = EntRefToEntIndex(pointerref); + if (pointer == INVALID_ENT_REFERENCE) + { + return Plugin_Continue; + } + + float fpointerpos[3], fpointerang[3]; + GetEntPropVector(pointer, Prop_Send, "m_vecOrigin", fpointerpos); + GetEntPropVector(pointer, Prop_Data, "m_angRotation", fpointerang); + + float fSize = GetEntPropFloat(pointer, Prop_Send, "m_flModelScale"); + + int iSkin = GetEntProp(pointer, Prop_Send, "m_nSkin"); + if (iSkin < 0) iSkin = 0; + if (iSkin >= sizeof(g_strLaserModel)) iSkin = sizeof(g_strLaserModel) - 1; + + int g_iLaserColor[4]; + GetEntityRenderColor(pointer, g_iLaserColor[0], g_iLaserColor[1], g_iLaserColor[2], g_iLaserColor[3]); + + TE_SetupBeamPoints(fpointerpos, GetPointAimPosition(fpointerpos, fpointerang, 999999.9, pointer), g_iModelIndex[iSkin], g_iHaloIndex[iSkin], 0, 0, cvfRefreshRate.FloatValue*2, fSize, fSize, 0, 0.0, g_iLaserColor, 0); + TE_SendToAll(); + + CreateTimer(cvfRefreshRate.FloatValue, Timer_SecurityLaser, pointerref); + + return Plugin_Continue; +} + +float[] GetClientEyePositionEx(int client) +{ + float pos[3]; + GetClientEyePosition(client, pos); + + return pos; +} + +float[] GetClientEyeAnglesEx(int client) +{ + float angles[3]; + GetClientEyeAngles(client, angles); + + return angles; +} + +float[] GetPointAimPosition(float pos[3], float angles[3], float maxtracedistance, int client) +{ + Handle trace = TR_TraceRayFilterEx(pos, angles, MASK_SOLID, RayType_Infinite, TraceEntityFilter, client); + + if(TR_DidHit(trace)) + { + float endpos[3]; + TR_GetEndPosition(endpos, trace); + + if(!((GetVectorDistance(pos, endpos) <= maxtracedistance) || maxtracedistance <= 0)) + { + float eyeanglevector[3]; + GetAngleVectors(angles, eyeanglevector, NULL_VECTOR, NULL_VECTOR); + NormalizeVector(eyeanglevector, eyeanglevector); + ScaleVector(eyeanglevector, maxtracedistance); + AddVectors(pos, eyeanglevector, endpos); + } + + if (client > MaxClients) + { + float fSize = GetEntPropFloat(client, Prop_Send, "m_flModelScale"); + SetLaserDamageToClient(pos, endpos, fSize); + } + + CloseHandle(trace); + return endpos; + } + + CloseHandle(trace); + return pos; +} + +public bool TraceEntityFilter(int entity, int mask, int client) +{ + return (entity > MaxClients && entity != client); +} + +void SetLaserDamageToClient(float startpos[3], float endpos[3], float damage) +{ + Handle trace = TR_TraceRayFilterEx(startpos, endpos, MASK_SOLID, RayType_EndPoint, SetClientDamageFilter, damage); + CloseHandle(trace); +} + +public bool SetClientDamageFilter(int entity, int mask, float damage) +{ + if (entity > 0 && entity <= MaxClients && IsClientInGame(entity)) + { + SDKHooks_TakeDamage(entity, entity, entity, damage, DMG_BURN); + TF2_AddCondition(entity, TFCond_Bleeding, 2.0); + } + + return false; +} + +int SpawnLaserPointer(int client) +{ + int pointer = CreateEntityByName("prop_dynamic_override"); + + if (IsValidEntity(pointer)) + { + SetEntProp(pointer, Prop_Send, "m_nSolidType", 6); + SetEntProp(pointer, Prop_Data, "m_nSolidType", 6); + + if (Build_RegisterEntityOwner(pointer, client)) + { + SetEntityModel(pointer, MODEL_POINTER); + + TeleportEntity(pointer, GetPointAimPosition(GetClientEyePositionEx(client), GetClientEyeAnglesEx(client), 99999.9, client), NULL_VECTOR, NULL_VECTOR); + + DispatchSpawn(pointer); + + return pointer; + } + + AcceptEntityInput(pointer, "Kill"); + } + + return -1; +} \ No newline at end of file diff --git a/scripting/include/build.inc b/scripting/include/build.inc new file mode 100644 index 0000000..e6c720b --- /dev/null +++ b/scripting/include/build.inc @@ -0,0 +1,140 @@ +#define BUILDMODAPI_VER 3 +#define BUILDMOD_VER "0.75.5" +#define MAX_HOOK_ENTITIES 4096 + +/** + * Register an entity owner. + * + * @param entity_index Entity index. + * @param client_index Client index. + * @param Doll Is prop_ragdoll? + * @return Ture on success. False on failure. + */ +native bool:Build_RegisterEntityOwner(entity_index, client_index, bool:Doll = false); + +/** + * Get an entity owner. + * + * @param entity_index Entity index. + * @return -1 on failure. Any other value indicates a Entity index owner. + */ +native Build_ReturnEntityOwner(entity_index); + +/** + * Set client props limit. + * + * @param client_index Client index. + * @param amount Amount to increase or decrease. If amount = 0 then set limit to 0. + * @param Doll Is prop_ragdoll? + * @noreturn + */ +native Build_SetLimit(client_index, amount, bool:Doll = false); + +/** + * Check client can use BuildMod. + * + * @param client_index Client index. + * @return True on success. False on failure. + */ +native bool:Build_AllowToUse(client_index); + +/** + * Check client can use Fly. + * + * @param client_index Client index. + * @return True on success. False on failure. + */ +native bool:Build_AllowFly(client_index); + +/** + * Get client admin. + * + * @param client_index Client index. + * @param Level2 Level 2 access. + * @return True on admin. False on not. + */ +native bool:Build_IsAdmin(client_index, bool:Level2 = false); + +/** + * Get client aim entity. + * + * @param client_index Client index. + * @param show_message Show a message when entity invalid? + * @param included_clients Allow native to getting clients? + * @return -1 on failure. Any other value indicates a Entity index. + */ +native Build_ClientAimEntity(client_index, bool:show_message = true, bool:included_clients = false); + +/** + * Get an entity of owner is equal client. + * + * @param client_index Client index. + * @param entity_index Entity index. + * @param bIngoreCvar Ingore 'bm_nonowner' cvar? + * @return True on owner. False on not. + */ +native bool:Build_IsEntityOwner(client_index, entity_index, bool:bIngoreCvar = false); + +/** + * Logging commands and args. + * + * @param client_index Client index. + * @param command Command to log. + * @param args Args to log. + * @noreturn + */ +native Build_Logging(client_index, const String:command[], const String:args[]); + +/** + * Prints a message with the BuildMod tag. + * + * @param client_index Client index. + * @param format Formatting rules. + * @param ... Variable number of format parameters. + * @noreturn + */ +native Build_PrintToChat(client_index, const String:format[], any:...); + +/** + * Prints a message to all clients with the BuildMod tag. + * + * @param format Formatting rules. + * @param ... Variable number of format parameters. + * @noreturn + */ +native Build_PrintToAll(const String:format[], any:...); + +/** + * Add client to blacklist. + * + * @param client_index Client index. + * @return True on success. False on failure. + */ +native Build_AddBlacklist(client_index); + +/** + * Remove client from blacklist. + * + * @param client_index Client index. + * @return True on success. False on failure. + */ +native Build_RemoveBlacklist(client_index); + +/** + * Get client is blacklisted. + * + * @param client_index Client index. + * @return True on blacklisted. False on not. + */ +native bool:Build_IsBlacklisted(client_index); + +/** + * Check is target client valid. + * + * @param client_index Client index. + * @param target_index Target index. + * @param Alive Check is target alive. + * @param ReplyTarget Alive result reply target client or self. + * @return True if target valid. Otherwise false. + */ +native bool:Build_IsClientValid(client_index, target_index, bool:Alive = false, bool:ReplyTarget = false);