Skip to content

Instantly share code, notes, and snippets.

@icequeenzz
Created February 26, 2011 17:32
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save icequeenzz/845406 to your computer and use it in GitHub Desktop.
Save icequeenzz/845406 to your computer and use it in GitHub Desktop.
Laser Sentry
#pragma semicolon 1
#include <sourcemod>
#include <sdktools>
#include <tf2_stocks>
#include <sdkhooks>
#define TEAM_RED 2
#define TEAM_BLU 3
#define MP 33
#define VERSION "1.0"
#define LASER_SPRITE "sprites/laser.vmt"
#define SOUND_LASER "lasersentry/lasersound.mp3"
#define SOUND_UPGRADE "lasersentry/upgrade_complete.wav"
// shells: 144
new String:gBeamColor[4][16] = {"0 0 0",
"0 0 0",
"255 0 0", // Red
"0 0 255" // Blue
};
new g_iSentryRocketIndex = -1;
new g_iLaserCount;
new ChargeAmouth[MP];
new LaserKill[MP] = -1;
new Sentry[MP];
new ClientHit[MP] = -1;
new Float:StartPos[3], Float:Angles[3], Float:EndPos[3];
new Handle:chargeHUD[MP] = {INVALID_HANDLE, ...};
new Handle:chargeCount[MP] = {INVALID_HANDLE, ...};
new Handle:hudcharge;
// Cvar handles
new Handle:cvar_initialdamage = INVALID_HANDLE;
new Handle:cvar_additionaldamage = INVALID_HANDLE;
new Handle:cvar_chargetime = INVALID_HANDLE;
public Plugin:myinfo =
{
name = "The LaserGun",
author = "Icequeenzz",
description = "Fires Laser beams",
version = VERSION,
url = ""
}
public OnPluginStart()
{
// hook events
HookEvent("player_builtobject", Event_Build);
HookEvent("player_death", Event_PlayerDeath, EventHookMode_Pre);
HookEvent("object_destroyed", Event_RemoveBuild);
HookEvent("object_removed", Event_RemoveBuild);
// Plugin version public Cvar
CreateConVar("sm_lasersentry_version", VERSION, "Laser Sentry Version", FCVAR_PLUGIN|FCVAR_SPONLY|FCVAR_REPLICATED|FCVAR_NOTIFY|FCVAR_DONTRECORD);
// declare cvars
cvar_initialdamage = CreateConVar("sm_initial_damage", "80", "Initial damage of the laser beam.", FCVAR_PLUGIN);
cvar_additionaldamage = CreateConVar("sm_additional_damage", "5", "Extra damage each second of the laser beam.", FCVAR_PLUGIN);
cvar_chargetime = CreateConVar("sm_chargetime", "60", "Seconds to charge laser.", FCVAR_PLUGIN);
// hook sound output
AddNormalSoundHook(NormalSHook:sound_hook);
// create hudsynchronizer
hudcharge = CreateHudSynchronizer();
// make config file
AutoExecConfig(true, "lasersentry");
}
public OnMapStart()
{
//precache sound and add to download table
PrecacheSound(SOUND_LASER);
PrecacheSound(SOUND_UPGRADE);
AddToDownload(SOUND_LASER);
AddToDownload(SOUND_UPGRADE);
PrecacheModel(LASER_SPRITE);
g_iLaserCount = 0;
}
public OnGameFrame()
{
static numberOfFrames = 0;
if (g_iSentryRocketIndex > -1)
{
numberOfFrames ++;
if (numberOfFrames == 1)
{
new client,sentrygun;
GetEntPropVector(g_iSentryRocketIndex, Prop_Send, "m_vecOrigin", StartPos);
GetEntPropVector(g_iSentryRocketIndex, Prop_Send, "m_angRotation", Angles); //initiate
sentrygun = GetEntPropEnt(g_iSentryRocketIndex, Prop_Send, "m_hOwnerEntity");
if(sentrygun > -1)
{
client = GetEntPropEnt(sentrygun, Prop_Send, "m_hBuilder");
RemoveEdict(g_iSentryRocketIndex);
CreateLaser(client);
}
else
{
//when for some reason the sentygun index is given instead of the rockets
new rocket = GetMatchingRocket(g_iSentryRocketIndex);
client = GetEntPropEnt(g_iSentryRocketIndex, Prop_Send, "m_hBuilder");
GetEntPropVector(rocket, Prop_Send, "m_vecOrigin", StartPos);
GetEntPropVector(rocket, Prop_Send, "m_angRotation", Angles);
RemoveEdict(rocket);
CreateLaser(client);
}
g_iSentryRocketIndex = -1;
numberOfFrames = 0;
}
}
}
//////////////
// Events //
//////////////
public OnEntityCreated(entity, const String:classname[])
{
if(strcmp(classname, "tf_projectile_sentryrocket") == 0 || StrContains(classname, "tf_projectile_sentryrocket", false) != -1)
{
SDKHook(entity, SDKHook_Spawn, OnEntityCreateRockets);
}
}
public OnClientConnected(client)
{
LaserKill[client] = -1;
}
public Action:Event_PlayerDeath(Handle:event, const String:name[], bool:dontBroadcast)
{
new victim = GetClientOfUserId(GetEventInt(event, "userid"));
ClientHit[victim] = -1;
if(LaserKill[victim] != -1)
{
new inflictor = LaserKill[victim];
new String:WeaponUsed[128], String:weaponstring[128];
//check if kill is not made by world
if(inflictor != 0)
if(IsPlayerAlive(inflictor))
GetClientWeapon(inflictor, WeaponUsed, 128);
// check what weapon is used to kill (normal sentry or wrangler)
if(StrContains(WeaponUsed, "Laser", false) != -1)
weaponstring = "wrangler_kill";
else
weaponstring = "obj_sentrygun3";
// set new event variables
SetEventString(event, "weapon", weaponstring);
SetEventInt(event, "attacker", GetClientUserId(inflictor));
SetEventInt(event, "weaponid", 22);
SetEventString(event, "weapon_logclassname", weaponstring);
LaserKill[victim] = -1;
}
return Plugin_Continue;
}
//Check if building is being build
public Action:Event_Build(Handle:event, const String:name[], bool:dontBroadcast)
{
new String:classname[64];
GetEdictClassname(GetEventInt(event, "index"), classname, sizeof(classname));
if (!strcmp(classname, "obj_sentrygun"))
{
new client = GetClientOfUserId(GetEventInt(event, "userid"));
if(chargeCount[client] == INVALID_HANDLE)
{
chargeCount[client] = CreateTimer(1.0, timer_LaserCharge, client, TIMER_REPEAT);
chargeHUD[client] = CreateTimer(1.0, DrawHud, client);
}
//SentryCheck(GetEventInt(event, "index"));
Sentry[client] = GetEventInt(event, "index");
// check if player want lasergun
// set model to lasergun
}
return Plugin_Continue;
}
public Action:Event_RemoveBuild(Handle:event, const String:name[], bool:dontBroadcast)
{
new String:classname[64];
GetEdictClassname(GetEventInt(event, "index"), classname, sizeof(classname));
if (!strcmp(classname, "obj_sentrygun"))
{
new client = GetEntPropEnt(GetEventInt(event, "index"), Prop_Send, "m_hBuilder");
ChargeAmouth[client] = 0;
Sentry[client] = -1;
chargeHUD[client] = INVALID_HANDLE;
chargeCount[client] = INVALID_HANDLE;
}
}
// change sentry sounds
public Action:sound_hook(clients[64], &numClients, String:sample[PLATFORM_MAX_PATH], &entity, &channel, &Float:volume, &level, &pitch, &flags)
{
if(StrEqual(sample,"weapons/sentry_empty.wav"))
{
return Plugin_Handled;
}
else if(StrEqual(sample,")weapons/sentry_rocket.wav"))
{
//emit my sound
new sentrygun = GetEntPropEnt(entity, Prop_Send, "m_hOwnerEntity");
if(sentrygun > -1)
EmitSoundToAll(SOUND_LASER, sentrygun, _, SNDLEVEL_AIRCRAFT);
else
EmitSoundToAll(SOUND_LASER, entity, _, SNDLEVEL_AIRCRAFT);
//security check on entity rockets
OnEntityCreateRockets(entity);
return Plugin_Handled;
}
else if(StrEqual(sample,"weapons/wrench_hit_build_success1.wav") || StrEqual(sample,"weapons/wrench_hit_build_success2.wav"))
{
/*
new sentrygun;
if((sentrygun = GetClientAimTarget(entity)) > -1)
{
SetEntProp(sentrygun, Prop_Send, "m_iAmmoShells", 0);
}
*/
}
else if(StrEqual(sample,")weapons/sentry_finish.wav"))
{
EmitSoundToAll(SOUND_UPGRADE, entity, _, SNDLEVEL_AIRCRAFT);
//SetSentry(entity);
return Plugin_Handled;
}
return Plugin_Continue;
}
//if building is sentry
public SentryCheck(ent)
{
new String:classname[64];
GetEdictClassname(ent, classname, sizeof(classname));
if (!strcmp(classname, "obj_sentrygun"))
{
LaserSentrySetup(ent);
}
}
public beamTouched(const String:output[], caller, activator, Float:delay)
{
new String:tempclient[128];
GetEntPropString(caller, Prop_Data, "m_iName", tempclient, 128);
new client = StringToInt(tempclient,10);
if(ClientHit[activator] != client)
{
if(GetClientTeam(activator) != GetClientTeam(client))
{
new damage = GetConVarInt(cvar_initialdamage) + ChargeAmouth[client]*GetConVarInt(cvar_additionaldamage);
HurtPlayer(activator, client, damage);
}
AcceptEntityInput(caller, "TurnOff");
AcceptEntityInput(caller, "TurnOn");
}
}
public OnEntityCreateRockets(entity)
{
g_iSentryRocketIndex = entity;
}
/////////////////
// Functions //
/////////////////
HurtPlayer(victim, attacker, damage)
{
if (IsClientInGame(victim) && IsPlayerAlive(victim))
{
if(!CheckCond(victim, 5) && !CheckCond(victim, 14))
{
if (GetClientHealth(victim) - damage <= 0)
{
LaserKill[victim] = attacker;
ForcePlayerSuicide(victim);
AddPlayerPoint(attacker);
// adding kill to sentrygun (for revenge critz)
decl currentkills;
currentkills = GetEntProp(Sentry[attacker], Prop_Send, "m_iKills");
currentkills++;
SetEntProp(Sentry[attacker], Prop_Send, "m_iKills", currentkills);
ClientHit[victim] = -1;
}
else
{
SetEntityHealth(victim, GetClientHealth(victim) - damage);
TF2_IgnitePlayer(victim, attacker);
ClientHit[victim] = attacker;
}
}
}
}
CreateBeam(const String:startname[],const String:endname[], const Float:start[3], const Float:end[3], client)
{
// create laser beam
new beam_ent = CreateEntityByName("env_beam");
new startpoint_ent = CreateEntityByName("env_beam");
new endpoint_ent = CreateEntityByName("env_beam");
new team = GetClientTeam(client);
TeleportEntity(startpoint_ent, start, NULL_VECTOR, NULL_VECTOR);
TeleportEntity(endpoint_ent, end, NULL_VECTOR, NULL_VECTOR);
DispatchKeyValue(startpoint_ent, "targetname", startname);
DispatchKeyValue(endpoint_ent, "targetname", endname);
DispatchSpawn(startpoint_ent);
DispatchSpawn(endpoint_ent);
PrecacheModel(LASER_SPRITE);
SetEntityModel(beam_ent, LASER_SPRITE);
decl String:Client[128];
IntToString(client, Client, 128);
DispatchKeyValue(beam_ent, "targetname", Client);
DispatchKeyValue(beam_ent, "texture", LASER_SPRITE);
DispatchKeyValue(beam_ent, "TouchType", "1");
DispatchKeyValue(beam_ent, "BoltWidth", "10.0");
DispatchKeyValue(beam_ent, "life", "0");
DispatchKeyValue(beam_ent, "rendercolor", gBeamColor[team]);
DispatchKeyValue(beam_ent, "StrikeTime", "0.1");
DispatchKeyValue(beam_ent, "renderamt", "255");
DispatchKeyValue(beam_ent, "HDRColorScale", "1.0");
DispatchKeyValue(beam_ent, "decalname", "redglowfade");
DispatchKeyValue(beam_ent, "TextureScroll", "35");
DispatchKeyValue(beam_ent, "LightningStart", startname);
DispatchKeyValue(beam_ent, "LightningEnd", endname);
DispatchSpawn(beam_ent);
ActivateEntity(beam_ent);
AcceptEntityInput(beam_ent, "TurnOn");
HookSingleEntityOutput(beam_ent, "OnTouchedByEntity", beamTouched, false);
CreateTimer(2.0, timer_KillBeam, beam_ent);
CreateTimer(2.0, timer_KillBeam, startpoint_ent);
CreateTimer(2.0, timer_KillBeam, endpoint_ent);
CreateTimer(2.0, timer_ResetBeamTouched, client);
}
LaserSentrySetup(ent)
{
CreateTimer(11.0, FixModel, ent);
}
public CreateLaser(client)
{
SetTeleportEndPoint();
// Temp laser to view how it should be
//new redColor[4] = {0, 0, 255, 255};
//TE_SetupBeamPoints(StartPos, EndPos, BeamSprite, 0, 0, 15, 3.0, 5.0, 5.0, 3, 0.0, redColor, 100);
//TE_SendToAll(0.0);
// real laser
decl String:namebegin[64] = "LaserBeam0", String:nameend[64] = "LaserBeam_end0", String:number[32];
IntToString(g_iLaserCount, number, 32);
ReplaceString(namebegin, 64, "0", number, false);
ReplaceString(nameend, 64, "0", number, false);
g_iLaserCount++;
CreateBeam(namebegin, nameend, StartPos, EndPos, client);
}
SetTeleportEndPoint()
{
//get endpoint for teleport
new Handle:trace = TR_TraceRayFilterEx(StartPos, Angles, MASK_SHOT, RayType_Infinite, TraceEntityFilterPlayer);
if(TR_DidHit(trace))
{
TR_GetEndPosition(EndPos, trace);
}
else
{
CloseHandle(trace);
return false;
}
CloseHandle(trace);
return true;
}
public bool:TraceEntityFilterPlayer(entity, contentsMask)
{
return entity > GetMaxClients() || !entity;
}
public GetPlayerScore(client)
{
// All the difficult in getting the **total** player score in Source plugins is resolved by this (Sourcemod) function ;-)
return TF2_GetPlayerResourceData(client, TFResource_TotalScore) ;
}
// adding a point the the players score
AddPlayerPoint(client)
{
decl String:user_name[255];
GetClientName(client, user_name, sizeof(user_name));
new user_slot = GetClientUserId(client); // the "slot" (as shown in the logs after the player name) is the "userid", not the "client" !
decl String:user_auth[32];
GetClientAuthString(client, user_auth, sizeof(user_auth));
decl String:user_team[16];
GetTeamName(GetClientTeam(client), user_team, sizeof(user_team));
new user_score = GetPlayerScore(client);
LogToGame("\"%s<%d><%s><%s>\" current score \"%d\"", user_name, user_slot, user_auth, user_team, user_score);
// Create a "player_score" event
new Handle:event = CreateEvent("player_score", true);
if (event == INVALID_HANDLE)
{
LogToGame("Cannot create a \"player_score\" event");
PrintToChatAll("FAIL TO SAVE PLAYERPOINT");
return;
}
SetEventInt(event, "userid", user_slot);
SetEventInt(event, "kills", GetClientFrags(client));
SetEventInt(event, "deaths", GetClientDeaths(client));
SetEventInt(event, "score", user_score); // **Total** player score as shown in the client scoreboard
// Fires the "player_score" event
FireEvent(event);
TF2_SetPlayerResourceData(client, TFResource_TotalScore, (user_score + 1));
}
public GetMatchingRocket(entity)
{
new ent = -1;
while((ent = FindEntityByClassname(ent, "tf_projectile_sentryrocket")) != -1)
{
if(IsValidEntity(ent))
{
new compareowner = GetEntPropEnt(ent, Prop_Send, "m_hOwnerEntity");
if(compareowner == entity)
return ent;
}
}
return -1;
}
AddToDownload(const String:file[])
{
new String:input[PLATFORM_MAX_PATH];
Format(input, sizeof(input), "sound/%s", file);
AddFileToDownloadsTable(input);
}
SetSentry(ent)
{
if (ent > 0 && IsValidEntity(ent))
{
decl String:sModel[128];
sModel = "models/buildables/sentry3.mdl";
decl iShells, iHealth, iRockets;
iShells = 0;
iHealth = 180;
iRockets = 20;
SetEntProp(ent, Prop_Send, "m_iAmmoShells", iShells);
SetEntProp(ent, Prop_Send, "m_iMaxHealth", iHealth);
SetEntProp(ent, Prop_Send, "m_iHealth", iHealth);
SetEntProp(ent, Prop_Send, "m_iUpgradeLevel", 3);
SetEntProp(ent, Prop_Send, "m_iAmmoRockets", iRockets);
SetEntityModel(ent,sModel);
}
}
//////////////
// Timers //
//////////////
public Action:timer_KillBeam(Handle:timer, any:beam)
{
new String:tempclient[32];
GetEntPropString(beam, Prop_Data, "m_iName", tempclient, 32);
new client = StringToInt(tempclient,10);
ChargeAmouth[client] = 0;
RemoveEdict(beam);
}
public Action:timer_ResetBeamTouched(Handle:timer, any:client)
{
for (new i = 1; i < MP; i++)
{
if(ClientHit[i] == client)
{
ClientHit[i] = -1;
}
}
}
public Action:FixModel(Handle:hTimer,any:ent)
{
if (ent > 0 && IsValidEntity(ent))
{
decl String:sModel[128];
sModel = "models/buildables/sentry3.mdl";
decl iShells, iHealth, iRockets;
iShells = 0;
iHealth = 180;
iRockets = 20;
SetEntProp(ent, Prop_Send, "m_iAmmoShells", iShells, 4);
SetEntProp(ent, Prop_Send, "m_iMaxHealth", iHealth, 4);
SetEntProp(ent, Prop_Send, "m_iHealth", iHealth, 4);
SetEntProp(ent, Prop_Send, "m_iUpgradeLevel", 3, 4);
SetEntProp(ent, Prop_Send, "m_iAmmoRockets", iRockets, 4);
SetEntityModel(ent,sModel);
return Plugin_Continue;
}
return Plugin_Stop;
}
public Action:timer_LaserCharge(Handle:hTimer,any:client)
{
if(IsClientInGame(client))
{
if(Sentry[client] == -1)
return Plugin_Stop;
if(ChargeAmouth[client] < GetConVarInt(cvar_chargetime) && GetEntProp(Sentry[client], Prop_Send, "m_bHasSapper") != 1)
{
ChargeAmouth[client]++;
}
}
return Plugin_Continue;
}
///////////////////
//D R A W H U D //
///////////////////
public Action:DrawHud(Handle:timer, any:client)
{
if(IsClientInGame(client) && IsPlayerAlive(client))
{
if(TF2_GetPlayerClass(client) != TFClass_Engineer)
{
Sentry[client] = -1;
ChargeAmouth[client] = 0;
chargeCount[client] = INVALID_HANDLE;
return Plugin_Handled;
}
new String:message[128];
for(new i = 0; i < (ChargeAmouth[client]/(GetConVarInt(cvar_chargetime)/4)); i++)
{
StrCat(message, 128, "=");
}
if(ChargeAmouth[client] >= GetConVarInt(cvar_chargetime))
{
SetHudTextParams(0.11, 0.06, 2.0, 0, 255, 0, 255);
}
else if(ChargeAmouth[client] >= (GetConVarInt(cvar_chargetime)/4)*3)
{
SetHudTextParams(0.11, 0.06, 2.0, 255, 255, 0, 255);
}
else
{
SetHudTextParams(0.11, 0.06, 2.0, 255, 0, 0, 255);
}
ShowSyncHudText(client, hudcharge, message);
}
chargeHUD[client] = CreateTimer(2.0, DrawHud, client);
return Plugin_Handled;
}
public bool:CheckCond(client, cond)
{
if (IsClientInGame(client) && GetEntData(client, FindSendPropInfo("CTFPlayer", "m_nPlayerCond")) & (1 << cond))
return true;
return false;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment