Created
February 26, 2011 17:32
-
-
Save icequeenzz/845406 to your computer and use it in GitHub Desktop.
Laser Sentry
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#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; | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment