All pastes #1856320 Raw Edit

GhostTank

public cpp v1 · immutable
#1856320 ·published 2010-04-04 03:41 UTC
rendered paste body
#pragma semicolon 1#include <sourcemod>#include <sdktools>#include "includes/constants.sp"#include "includes/survivorindex.sp"#define PLUGIN_VERSION "0.0"#define TANK_SPAWN_TIME 20.0#define TANK_SPAWN_RADIUS 750public Plugin:myinfo = {	name = "Ghost Tank",	author = "Mr. Zero + CanadaRox",	description = "Ghost Mode Tanks!",	version = PLUGIN_VERSION,	url = "..."};// Tank Variablesnew g_iTankClient; // Client number for the active tanknew Float:g_fSpawnTimer; // How long does the tank have to spawn?new bool:g_bTooClose = false; // Is the tank within TANK_SPAWN_RADIUS of the survivors?new bool:g_bActiveTank = false; // Is this tank already active?new bool:g_bPassedToAID = false; // Has it been spawned through ForceSpawn()?new bool:g_bSpawned = false; // Should we be blocking +attack and +attack2?// Plugin Variablesnew bool:g_bPluginIsEnabled; // Is the plugin enabled?new bool:g_bHooked = false; // Have the events been hooked?new Handle:g_hEnable;public OnPluginStart(){	SI_OnModuleStart(); // Start up the survivor indexing stuff		g_hEnable = CreateConVar("l4d2_ghosttank_enable", "1", "Sets whether the plugin is active or not.", FCVAR_PLUGIN);	HookConVarChange(g_hEnable, ConVarChange_Enable);}public OnMapStart(){	// Make the variable match the CVAR	if (GetConVarInt(g_hEnable) != 0)	g_bPluginIsEnabled = true;	else g_bPluginIsEnabled = false;		// Hook/unhook events if they need to be	if (g_bPluginIsEnabled && !g_bHooked) PluginEnable();	else if (!g_bPluginIsEnabled && g_bHooked) PluginDisable();		// Reset all variables	Reset();}////////////////////////////////////////////////////////// Toggle   g_bPluginIsEnabled  so   it  matches  the //// current  ConVar  value  (0 = false,  not 0 = true) //// A check  is  added  so events  with  hooks  aren't //// hooked  and  events  which  are not  hooked  don't //// get unhooked.                                      //////////////////////////////////////////////////////////public ConVarChange_Enable(Handle:convar, const String:oldValue[], const String:newValue[]){	//Make the variable match the CVAR and do any hooking/unhooking required	if (StringToInt(newValue) == 0)	{		if (g_bHooked) PluginDisable();		g_bPluginIsEnabled = false;	}	else	{		if (!g_bHooked) PluginEnable();		g_bPluginIsEnabled = true;	}}////////////////////////////////////////////////////////// Hooks the events and sets g_bHooked to true so the //// events do not get hooked twice.                    //////////////////////////////////////////////////////////PluginEnable(){	HookEvent("round_start", Event_RoundStart);	HookEvent("player_death", Event_PlayerDeath);	HookEvent("tank_spawn", Event_TankSpawn);	g_bHooked = true;}////////////////////////////////////////////////////////// Unhooks the events and  sets g_bHooked to false so //// the events do not get unhooked twice.              //////////////////////////////////////////////////////////PluginDisable(){	UnhookEvent("round_start", Event_RoundStart);	UnhookEvent("player_death", Event_PlayerDeath);	UnhookEvent("tank_spawn", Event_TankSpawn);	g_bHooked = false;}////////////////////////////////////////////////////////// Resets all variables back to their default values. //// Runs  ResetAID  after a  10 second  delay  so auto //// spawned tanks do not get ghost mode.               //////////////////////////////////////////////////////////Reset(){	g_bActiveTank = false;	g_bSpawned = false;	g_fSpawnTimer = TANK_SPAWN_TIME;	CreateTimer(10.0, ResetAID, 0);}////////////////////////////////////////////////////////// Resets g_bPassedToAID for the next tank            //////////////////////////////////////////////////////////public Action:ResetAID(Handle:timer){	g_bPassedToAID = false;}////////////////////////////////////////////////////////// Runs Reset() to reset  all variables  on the start //// of a round.                                        //////////////////////////////////////////////////////////public Action:Event_RoundStart(Handle:event, const String:name[], bool:dontBroadcast) Reset();////////////////////////////////////////////////////////// This is  run when the event tank_spawn occurs.  It //// occurs when the tank is initally spawned and every //// time the tank passes control from client to client //// including the AI tanks before the first player and //// after the second player.                           //// First it checks if the  tank is active to see if a //// player already had control of this tank so when it //// passed control it does not gain ghost mode.        //// Next  it  checks if  it has  been made  through an //// autospawn so that if a tank can't spawn within the //// timer they will  not get a second  chance in ghost //// mode.                                              //// The tank is then put into ghost mode.  If it is AI //// it freezes, assuming it is not already active.     //// If it is passing to a player is unfreezes, and the //// spawn message/timer  is created.  g_bActiveTank is //// set to true.                                       //////////////////////////////////////////////////////////public Action:Event_TankSpawn(Handle:event, const String:name[], bool:dontBroadcast){	new client = GetClientOfUserId(GetEventInt(event, "userid"));	g_iTankClient = client;		if (g_bActiveTank) return; // Don't continue if the tank is already player controlled	if (g_bPassedToAID) // Don't give the tank ghost mode if it was AID spawned	{		g_bSpawned = true;		return;	}		Ghost();		if(!IsFakeClient(client))	{		Unfreeze();		g_bActiveTank = true;		CreateTimer(0.5, SpawnTimer, INVALID_HANDLE, TIMER_REPEAT);	}	else Freeze();}////////////////////////////////////////////////////////// Check if the tank is too close on every frame.     //////////////////////////////////////////////////////////public OnGameFrame() g_bTooClose = CheckLoc();////////////////////////////////////////////////////////// Show the  tank his spawn timer and count  it down. //// If he hasn't spawned  before the end, force it to. //////////////////////////////////////////////////////////public Action:SpawnTimer(Handle:timer){	if (g_fSpawnTimer < 0 && !g_bSpawned) // If he has run out of time and is not yet spawned, force it	{		ForceSpawn();		return Plugin_Stop;	}	else if (g_bSpawned == true) // If he has spawned, stop the timer.	{		return Plugin_Stop;	}		// Show the correct message if they are too close/able to spawn	if (g_bTooClose) PrintHintText(g_iTankClient, "YOU HAVE %.0f SECONDS TO SPAWN THE TANK\nYOU ARE TOO CLOSE TO SURVIVORS", g_fSpawnTimer);	else PrintHintText(g_iTankClient, "YOU HAVE %.0f SECONDS TO SPAWN THE TANK\nPRESS SHOOT TO SPAWN", g_fSpawnTimer);		SetEntProp(g_iTankClient, Prop_Send, "m_frustration", 0); // Lock frustration at 100% during ghost mode		g_fSpawnTimer -= 0.5;	return Plugin_Continue;}////////////////////////////////////////////////////////// Since the  tank_death  event doesn't always  work, //// the player death event is hooked  with a check for //// if the player was the tank.  If they were the tank //// it resets all the variables.                       //////////////////////////////////////////////////////////public Action:Event_PlayerDeath(Handle:event, const String:name[], bool:dontBroadcast){	if (!g_bActiveTank) return;	new client = GetClientOfUserId(GetEventInt(event, "userid"));	if (client != g_iTankClient) return;	Reset();}////////////////////////////////////////////////////////// First  it makes sure  a tank is active  so it wont //// block commands  when there  is no  tank.  Then  it //// checks if the player is  the client, that the tank //// is not spawned and if the button pressed is either //// +attack  or  +attack2.  For  +attack, check if the //// the tank has spawned, and if it has not, check its //// proximity  to  survivors.  If he  can spawn,  then //// spawn him, but  block the command either way so he //// doesn't spawn punching.  And block +attack when he //// is not spawned.                                    //////////////////////////////////////////////////////////public Action:OnPlayerRunCmd(client, &buttons, &impulse, Float:vel[3], Float:angles[3], &weapon){	if (!g_bActiveTank) return Plugin_Continue;		if (client == g_iTankClient && !g_bSpawned && (buttons & IN_ATTACK)) // Has an ghost mode tank pressed +attack?	{		if (g_bTooClose) // And is he too close?		{			g_bSpawned = false;			return Plugin_Handled;		}		else		{			Spawn();			g_bSpawned = true;			return Plugin_Handled;		}	}	else if (client == g_iTankClient && !g_bSpawned && (buttons & IN_ATTACK2)) // Has a ghost moe tank pressed +attack2?	{		return Plugin_Handled;	}	return Plugin_Continue;}////////////////////////////////////////////////////////// Spawn  the tank,  then check if  he is too  close. //// if he  is, tell the tank it is being  autospawned, //// kill it,  remove z_spawn's cheat flag, and spawn a //// tank allowing the director to select its spawn.    //////////////////////////////////////////////////////////ForceSpawn(){	Spawn(); // Spawn it.		if (g_bTooClose) // Is it too close?	{		new flags = GetCommandFlags("z_spawn");		g_bPassedToAID = true;		g_bSpawned = true;		PrintHintText(g_iTankClient, "TANK IS AUTOSPAWNING!");		ForcePlayerSuicide(g_iTankClient);		SetCommandFlags("z_spawn", flags & ~FCVAR_CHEAT);		FakeClientCommand(g_iTankClient, "z_spawn tank auto");		SetCommandFlags("z_spawn", flags);	}}////////////////////////////////////////////////////////// Put the tank into ghost mode.                      //////////////////////////////////////////////////////////Ghost() SetEntProp(g_iTankClient, Prop_Send, "m_isGhost", 1, 1);////////////////////////////////////////////////////////// Remove the tank from ghost mode  and tell him that //// he has  been spawned.  If he has been  autospawned //// the message  will immediately be  replaced by  the //// force spawn message.                               //////////////////////////////////////////////////////////public Spawn(){	SetEntProp(g_iTankClient, Prop_Send, "m_isGhost", 0, 1);	PrintHintText(g_iTankClient, "YOU HAVE SPAWNED!");	g_bSpawned = true;}////////////////////////////////////////////////////////// Freeze for the initial AI tank.                    //////////////////////////////////////////////////////////Freeze() SetEntityMoveType(g_iTankClient, MOVETYPE_NONE);////////////////////////////////////////////////////////// Unfreeze for when the player gains control.        //////////////////////////////////////////////////////////Unfreeze() SetEntityMoveType(g_iTankClient, MOVETYPE_CUSTOM);////////////////////////////////////////////////////////// Calculates the location of the tank, and returns   //// if it is too close to the survivors or not.        //////////////////////////////////////////////////////////bool:CheckLoc(){	decl Float:fTankLoc[3];	decl Float:fSurvLoc[4][3];	new Float:fDistance;		GetClientAbsOrigin(g_iTankClient, fTankLoc);	for (new i = 0; i < NUM_OF_SURVIVORS; i++)	{		GetClientAbsOrigin(iSurvivorIndex[i], fSurvLoc[i]);		fDistance = GetVectorDistance(fTankLoc, fSurvLoc[i]);		if (fDistance <= TANK_SPAWN_RADIUS) return true;	}	return false;}