1511 lines
		
	
	
		
			37 KiB
		
	
	
	
		
			SourcePawn
		
	
	
	
	
	
			
		
		
	
	
			1511 lines
		
	
	
		
			37 KiB
		
	
	
	
		
			SourcePawn
		
	
	
	
	
	
#pragma semicolon 1
 | 
						|
#pragma newdecls required
 | 
						|
 | 
						|
#include <sourcemod>
 | 
						|
#include <sdkhooks>
 | 
						|
#include <sdktools>
 | 
						|
#include <outputinfo>
 | 
						|
#include <BossHP>
 | 
						|
 | 
						|
#include <basic>
 | 
						|
#include "CConfig.inc"
 | 
						|
#include "CBoss.inc"
 | 
						|
 | 
						|
bool g_bLate = true;
 | 
						|
 | 
						|
ArrayList g_aConfig;
 | 
						|
ArrayList g_aBoss;
 | 
						|
StringMap g_aHadOnce;
 | 
						|
 | 
						|
Handle g_hFwd_OnBossInitialized;
 | 
						|
Handle g_hFwd_OnBossDamaged;
 | 
						|
Handle g_hFwd_OnBossKilled;
 | 
						|
 | 
						|
ConVar g_hCvar_DebugMode;
 | 
						|
 | 
						|
char g_sHUDText[256];
 | 
						|
 | 
						|
public Plugin myinfo =
 | 
						|
{
 | 
						|
	name 			= "BossHP",
 | 
						|
	author 			= "BotoX",
 | 
						|
	description 	= "",
 | 
						|
	version 		= "0.2",
 | 
						|
	url 			= ""
 | 
						|
};
 | 
						|
 | 
						|
public void OnPluginStart()
 | 
						|
{
 | 
						|
	g_hFwd_OnBossInitialized = CreateGlobalForward("OnBossInitialized", ET_Ignore, Param_Any, Param_Any);
 | 
						|
	g_hFwd_OnBossDamaged = CreateGlobalForward("OnBossDamaged", ET_Ignore, Param_Any, Param_Any, Param_Cell, Param_Float);
 | 
						|
	g_hFwd_OnBossKilled = CreateGlobalForward("OnBossKilled", ET_Ignore, Param_Any, Param_Any, Param_Cell);
 | 
						|
 | 
						|
	g_hCvar_DebugMode = CreateConVar("bosshp_debug", "0", _, _, true, 0.0, true, 1.0);
 | 
						|
 | 
						|
	HookEvent("round_end", Event_RoundEnd, EventHookMode_PostNoCopy);
 | 
						|
	HookEntityOutput("env_entity_maker", "OnEntitySpawned", OnEnvEntityMakerEntitySpawned);
 | 
						|
}
 | 
						|
 | 
						|
void LogDebugMessage(const char[] message, any ...)
 | 
						|
{
 | 
						|
	if(g_hCvar_DebugMode.BoolValue)
 | 
						|
	{
 | 
						|
		char buffer[1024];
 | 
						|
		VFormat(buffer, sizeof(buffer), message, 2);
 | 
						|
 | 
						|
		LogMessage(buffer);
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
public void OnPluginEnd()
 | 
						|
{
 | 
						|
	Cleanup();
 | 
						|
}
 | 
						|
 | 
						|
void Cleanup()
 | 
						|
{
 | 
						|
	if(g_aBoss)
 | 
						|
	{
 | 
						|
		for(int i = 0; i < g_aBoss.Length; i++)
 | 
						|
		{
 | 
						|
			CBoss Boss = g_aBoss.Get(i);
 | 
						|
 | 
						|
			Call_StartForward(g_hFwd_OnBossKilled);
 | 
						|
			Call_PushCell(Boss);
 | 
						|
			Call_PushCell(Boss.dConfig);
 | 
						|
			Call_PushCell(0);
 | 
						|
			Call_Finish();
 | 
						|
 | 
						|
			delete Boss;
 | 
						|
		}
 | 
						|
		delete g_aBoss;
 | 
						|
	}
 | 
						|
 | 
						|
	if(g_aConfig)
 | 
						|
	{
 | 
						|
		for(int i = 0; i < g_aConfig.Length; i++)
 | 
						|
		{
 | 
						|
			CConfig Config = g_aConfig.Get(i);
 | 
						|
			delete Config;
 | 
						|
		}
 | 
						|
		delete g_aConfig;
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
public void OnMapEnd()
 | 
						|
{
 | 
						|
	Cleanup();
 | 
						|
}
 | 
						|
 | 
						|
public void OnMapStart()
 | 
						|
{
 | 
						|
	bool bLate = g_bLate;
 | 
						|
	g_bLate = false;
 | 
						|
 | 
						|
	char sMapName[PLATFORM_MAX_PATH];
 | 
						|
	GetCurrentMap(sMapName, sizeof(sMapName));
 | 
						|
 | 
						|
	char sConfigFile[PLATFORM_MAX_PATH];
 | 
						|
	BuildPath(Path_SM, sConfigFile, sizeof(sConfigFile), "configs/bosshp/%s.cfg", sMapName);
 | 
						|
	if(!FileExists(sConfigFile))
 | 
						|
	{
 | 
						|
		LogMessage("Could not find mapconfig: \"%s\"", sConfigFile);
 | 
						|
		return;
 | 
						|
	}
 | 
						|
	LogMessage("Found mapconfig: \"%s\"", sConfigFile);
 | 
						|
 | 
						|
	KeyValues KvConfig = new KeyValues("bosses");
 | 
						|
	if(!KvConfig.ImportFromFile(sConfigFile))
 | 
						|
	{
 | 
						|
		delete KvConfig;
 | 
						|
		LogError("ImportFromFile() failed!");
 | 
						|
		return;
 | 
						|
	}
 | 
						|
	KvConfig.Rewind();
 | 
						|
 | 
						|
	if(!KvConfig.GotoFirstSubKey())
 | 
						|
	{
 | 
						|
		delete KvConfig;
 | 
						|
		LogError("GotoFirstSubKey() failed!");
 | 
						|
		return;
 | 
						|
	}
 | 
						|
 | 
						|
	g_aConfig = new ArrayList();
 | 
						|
 | 
						|
	do
 | 
						|
	{
 | 
						|
		char sSection[64];
 | 
						|
		KvConfig.GetSectionName(sSection, sizeof(sSection));
 | 
						|
 | 
						|
		char sName[64];
 | 
						|
		KvConfig.GetString("name", sName, sizeof(sName));
 | 
						|
		if(!sName[0])
 | 
						|
		{
 | 
						|
			LogError("Could not find \"name\" in \"%s\"", sSection);
 | 
						|
			continue;
 | 
						|
		}
 | 
						|
 | 
						|
		char sMethod[64];
 | 
						|
		KvConfig.GetString("method", sMethod, sizeof(sMethod));
 | 
						|
		if(!sMethod[0])
 | 
						|
		{
 | 
						|
			LogError("Could not find \"method\" in \"%s\"", sSection);
 | 
						|
			continue;
 | 
						|
		}
 | 
						|
 | 
						|
		char sTrigger[64 * 2];
 | 
						|
		KvConfig.GetString("trigger", sTrigger, sizeof(sTrigger));
 | 
						|
		if(!sTrigger[0])
 | 
						|
		{
 | 
						|
			LogError("Could not find \"trigger\" in \"%s\"", sSection);
 | 
						|
			continue;
 | 
						|
		}
 | 
						|
 | 
						|
		int iTriggerDelim;
 | 
						|
		if((iTriggerDelim = FindCharInString(sTrigger, ':')) == -1)
 | 
						|
		{
 | 
						|
			LogError("Delimiter ':' not found in \"trigger\"(%s) in \"%s\"", sTrigger, sSection);
 | 
						|
			continue;
 | 
						|
		}
 | 
						|
		sTrigger[iTriggerDelim] = 0;
 | 
						|
 | 
						|
		float fTriggerDelay = 0.0;
 | 
						|
		int iTriggerDelayDelim;
 | 
						|
		if((iTriggerDelayDelim = FindCharInString(sTrigger[iTriggerDelim + 1], ':')) != -1)
 | 
						|
		{
 | 
						|
			iTriggerDelayDelim += iTriggerDelim + 1;
 | 
						|
			fTriggerDelay = StringToFloat(sTrigger[iTriggerDelayDelim + 1]);
 | 
						|
			sTrigger[iTriggerDelayDelim] = 0;
 | 
						|
		}
 | 
						|
 | 
						|
		char sShowTrigger[64 * 2];
 | 
						|
		int iShowTriggerDelim;
 | 
						|
		float fShowTriggerDelay = 0.0;
 | 
						|
		int iShowTriggerDelayDelim;
 | 
						|
		KvConfig.GetString("showtrigger", sShowTrigger, sizeof(sShowTrigger));
 | 
						|
		if(sShowTrigger[0])
 | 
						|
		{
 | 
						|
			if((iShowTriggerDelim = FindCharInString(sShowTrigger, ':')) == -1)
 | 
						|
			{
 | 
						|
				LogError("Delimiter ':' not found in \"showtrigger\"(%s) in \"%s\"", sShowTrigger, sSection);
 | 
						|
				continue;
 | 
						|
			}
 | 
						|
			sShowTrigger[iShowTriggerDelim] = 0;
 | 
						|
 | 
						|
			if((iShowTriggerDelayDelim = FindCharInString(sShowTrigger[iShowTriggerDelim + 1], ':')) != -1)
 | 
						|
			{
 | 
						|
				iShowTriggerDelayDelim += iShowTriggerDelim + 1;
 | 
						|
				fShowTriggerDelay = StringToFloat(sShowTrigger[iShowTriggerDelayDelim + 1]);
 | 
						|
				sShowTrigger[iShowTriggerDelayDelim] = 0;
 | 
						|
			}
 | 
						|
		}
 | 
						|
 | 
						|
		char sKillTrigger[64 * 2];
 | 
						|
		int iKillTriggerDelim;
 | 
						|
		float fKillTriggerDelay = 0.0;
 | 
						|
		int iKillTriggerDelayDelim;
 | 
						|
		KvConfig.GetString("killtrigger", sKillTrigger, sizeof(sKillTrigger));
 | 
						|
		if(sKillTrigger[0])
 | 
						|
		{
 | 
						|
			if((iKillTriggerDelim = FindCharInString(sKillTrigger, ':')) == -1)
 | 
						|
			{
 | 
						|
				LogError("Delimiter ':' not found in \"killtrigger\"(%s) in \"%s\"", sKillTrigger, sSection);
 | 
						|
				continue;
 | 
						|
			}
 | 
						|
			sKillTrigger[iKillTriggerDelim] = 0;
 | 
						|
 | 
						|
			if((iKillTriggerDelayDelim = FindCharInString(sKillTrigger[iKillTriggerDelim + 1], ':')) != -1)
 | 
						|
			{
 | 
						|
				iKillTriggerDelayDelim += iKillTriggerDelim + 1;
 | 
						|
				fKillTriggerDelay = StringToFloat(sKillTrigger[iKillTriggerDelayDelim + 1]);
 | 
						|
				sKillTrigger[iKillTriggerDelayDelim] = 0;
 | 
						|
			}
 | 
						|
		}
 | 
						|
 | 
						|
		char sHurtTrigger[64 * 2];
 | 
						|
		int iHurtTriggerDelim;
 | 
						|
		KvConfig.GetString("hurttrigger", sHurtTrigger, sizeof(sHurtTrigger));
 | 
						|
		if(sHurtTrigger[0])
 | 
						|
		{
 | 
						|
			if((iHurtTriggerDelim = FindCharInString(sHurtTrigger, ':')) == -1)
 | 
						|
			{
 | 
						|
				LogError("Delimiter ':' not found in \"hurttrigger\"(%s) in \"%s\"", sHurtTrigger, sSection);
 | 
						|
				continue;
 | 
						|
			}
 | 
						|
			sHurtTrigger[iHurtTriggerDelim] = 0;
 | 
						|
		}
 | 
						|
 | 
						|
		bool bMultiTrigger = view_as<bool>(KvConfig.GetNum("multitrigger", 0));
 | 
						|
		bool bNameFixup = view_as<bool>(KvConfig.GetNum("namefixup", 0));
 | 
						|
		int iTimeout = KvConfig.GetNum("timeout", -1);
 | 
						|
 | 
						|
		CConfig Config = view_as<CConfig>(INVALID_HANDLE);
 | 
						|
 | 
						|
		if(StrEqual(sMethod, "breakable"))
 | 
						|
		{
 | 
						|
			char sBreakable[64];
 | 
						|
			if(!KvConfig.GetString("breakable", sBreakable, sizeof(sBreakable)))
 | 
						|
			{
 | 
						|
				LogError("Could not find \"breakable\" in \"%s\"", sSection);
 | 
						|
				continue;
 | 
						|
			}
 | 
						|
 | 
						|
			CConfigBreakable BreakableConfig = new CConfigBreakable();
 | 
						|
 | 
						|
			BreakableConfig.SetBreakable(sBreakable);
 | 
						|
 | 
						|
			Config = view_as<CConfig>(BreakableConfig);
 | 
						|
		}
 | 
						|
		else if(StrEqual(sMethod, "counter"))
 | 
						|
		{
 | 
						|
			char sCounter[64];
 | 
						|
			if(!KvConfig.GetString("counter", sCounter, sizeof(sCounter)))
 | 
						|
			{
 | 
						|
				LogError("Could not find \"counter\" in \"%s\"", sSection);
 | 
						|
				continue;
 | 
						|
			}
 | 
						|
 | 
						|
			CConfigCounter CounterConfig = new CConfigCounter();
 | 
						|
 | 
						|
			CounterConfig.SetCounter(sCounter);
 | 
						|
 | 
						|
			Config = view_as<CConfig>(CounterConfig);
 | 
						|
		}
 | 
						|
		else if(StrEqual(sMethod, "hpbar"))
 | 
						|
		{
 | 
						|
			char sIterator[64];
 | 
						|
			if(!KvConfig.GetString("iterator", sIterator, sizeof(sIterator)))
 | 
						|
			{
 | 
						|
				LogError("Could not find \"iterator\" in \"%s\"", sSection);
 | 
						|
				continue;
 | 
						|
			}
 | 
						|
 | 
						|
			char sCounter[64];
 | 
						|
			if(!KvConfig.GetString("counter", sCounter, sizeof(sCounter)))
 | 
						|
			{
 | 
						|
				LogError("Could not find \"counter\" in \"%s\"", sSection);
 | 
						|
				continue;
 | 
						|
			}
 | 
						|
 | 
						|
			char sBackup[64];
 | 
						|
			if(!KvConfig.GetString("backup", sBackup, sizeof(sBackup)))
 | 
						|
			{
 | 
						|
				LogError("Could not find \"backup\" in \"%s\"", sSection);
 | 
						|
				continue;
 | 
						|
			}
 | 
						|
 | 
						|
			CConfigHPBar HPBarConfig = new CConfigHPBar();
 | 
						|
 | 
						|
			HPBarConfig.SetIterator(sIterator);
 | 
						|
			HPBarConfig.SetCounter(sCounter);
 | 
						|
			HPBarConfig.SetBackup(sBackup);
 | 
						|
 | 
						|
			Config = view_as<CConfig>(HPBarConfig);
 | 
						|
		}
 | 
						|
 | 
						|
		if(Config == INVALID_HANDLE)
 | 
						|
		{
 | 
						|
			LogError("Invalid \"method\"(%s) in \"%s\"", sMethod, sSection);
 | 
						|
			continue;
 | 
						|
		}
 | 
						|
 | 
						|
		Config.SetName(sName);
 | 
						|
		Config.bMultiTrigger = bMultiTrigger;
 | 
						|
		Config.bNameFixup = bNameFixup;
 | 
						|
		Config.iTimeout = iTimeout;
 | 
						|
 | 
						|
		Config.SetTrigger(sTrigger);
 | 
						|
		Config.SetOutput(sTrigger[iTriggerDelim + 1]);
 | 
						|
		Config.fTriggerDelay = fTriggerDelay;
 | 
						|
 | 
						|
		if(sShowTrigger[0])
 | 
						|
		{
 | 
						|
			Config.SetShowTrigger(sShowTrigger);
 | 
						|
			Config.SetShowOutput(sShowTrigger[iShowTriggerDelim + 1]);
 | 
						|
			Config.fShowTriggerDelay = fShowTriggerDelay;
 | 
						|
		}
 | 
						|
 | 
						|
		if(sKillTrigger[0])
 | 
						|
		{
 | 
						|
			Config.SetKillTrigger(sKillTrigger);
 | 
						|
			Config.SetKillOutput(sKillTrigger[iKillTriggerDelim + 1]);
 | 
						|
			Config.fKillTriggerDelay = fKillTriggerDelay;
 | 
						|
		}
 | 
						|
 | 
						|
		if(sHurtTrigger[0])
 | 
						|
		{
 | 
						|
			Config.SetHurtTrigger(sHurtTrigger);
 | 
						|
			Config.SetHurtOutput(sHurtTrigger[iHurtTriggerDelim + 1]);
 | 
						|
		}
 | 
						|
 | 
						|
		g_aConfig.Push(Config);
 | 
						|
	} while(KvConfig.GotoNextKey(false));
 | 
						|
 | 
						|
	delete KvConfig;
 | 
						|
 | 
						|
	if(!g_aConfig.Length)
 | 
						|
	{
 | 
						|
		delete g_aConfig;
 | 
						|
		LogError("Empty mapconfig: \"%s\"", sConfigFile);
 | 
						|
		return;
 | 
						|
	}
 | 
						|
 | 
						|
	g_aBoss = new ArrayList();
 | 
						|
	g_aHadOnce = new StringMap();
 | 
						|
 | 
						|
	/* Late Load */
 | 
						|
	if(bLate)
 | 
						|
	{
 | 
						|
		int entity = INVALID_ENT_REFERENCE;
 | 
						|
		while((entity = FindEntityByClassname(entity, "*")) != INVALID_ENT_REFERENCE)
 | 
						|
		{
 | 
						|
			OnEntitySpawned(entity);
 | 
						|
		}
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
public void Event_RoundEnd(Event event, const char[] name, bool dontBroadcast)
 | 
						|
{
 | 
						|
	if(!g_aConfig)
 | 
						|
		return;
 | 
						|
 | 
						|
	if(g_aBoss)
 | 
						|
	{
 | 
						|
		for(int i = 0; i < g_aBoss.Length; i++)
 | 
						|
		{
 | 
						|
			CBoss Boss = g_aBoss.Get(i);
 | 
						|
			delete Boss;
 | 
						|
		}
 | 
						|
		delete g_aBoss;
 | 
						|
	}
 | 
						|
 | 
						|
	g_aBoss = new ArrayList();
 | 
						|
 | 
						|
	if(g_aHadOnce)
 | 
						|
		delete g_aHadOnce;
 | 
						|
 | 
						|
	g_aHadOnce = new StringMap();
 | 
						|
}
 | 
						|
 | 
						|
public void OnEntityCreated(int entity, const char[] classname)
 | 
						|
{
 | 
						|
	if(!g_aConfig)
 | 
						|
		return;
 | 
						|
 | 
						|
	SDKHook(entity, SDKHook_SpawnPost, OnEntitySpawned);
 | 
						|
}
 | 
						|
 | 
						|
public void OnEntitySpawned(int entity)
 | 
						|
{
 | 
						|
	if(!g_aConfig)
 | 
						|
		return;
 | 
						|
 | 
						|
	char sTargetname[64];
 | 
						|
	GetEntPropString(entity, Prop_Data, "m_iName", sTargetname, sizeof(sTargetname));
 | 
						|
 | 
						|
	int iHammerID = GetEntProp(entity, Prop_Data, "m_iHammerID");
 | 
						|
 | 
						|
	for(int i = 0; i < g_aConfig.Length; i++)
 | 
						|
	{
 | 
						|
		CConfig Config = g_aConfig.Get(i);
 | 
						|
 | 
						|
		char sTrigger[64];
 | 
						|
		Config.GetTrigger(sTrigger, sizeof(sTrigger));
 | 
						|
 | 
						|
		int iTriggerHammerID = -1;
 | 
						|
		if(sTrigger[0] == '#')
 | 
						|
			iTriggerHammerID = StringToInt(sTrigger[1]);
 | 
						|
 | 
						|
		if((iTriggerHammerID == -1 && sTrigger[0] && StrEqual(sTargetname, sTrigger)) || iTriggerHammerID == iHammerID)
 | 
						|
		{
 | 
						|
			char sOutput[64];
 | 
						|
			Config.GetOutput(sOutput, sizeof(sOutput));
 | 
						|
 | 
						|
			if(StrEqual(sOutput, "OnTakeDamage"))
 | 
						|
			{
 | 
						|
				SDKHook(entity, SDKHook_OnTakeDamagePost, OnTakeDamagePost);
 | 
						|
			}
 | 
						|
			else
 | 
						|
			{
 | 
						|
				bool Once = !Config.bMultiTrigger;
 | 
						|
				HookSingleEntityOutput(entity, sOutput, OnEntityOutput, Once);
 | 
						|
			}
 | 
						|
 | 
						|
			LogDebugMessage("Hooked trigger %s:%s", sTrigger, sOutput);
 | 
						|
		}
 | 
						|
 | 
						|
		char sShowTrigger[64];
 | 
						|
		Config.GetShowTrigger(sShowTrigger, sizeof(sShowTrigger));
 | 
						|
 | 
						|
		int iShowTriggerHammerID = -1;
 | 
						|
		if(sShowTrigger[0] == '#')
 | 
						|
			iShowTriggerHammerID = StringToInt(sShowTrigger[1]);
 | 
						|
 | 
						|
		if((iShowTriggerHammerID == -1 && sShowTrigger[0] && StrEqual(sTargetname, sShowTrigger)) || iShowTriggerHammerID == iHammerID)
 | 
						|
		{
 | 
						|
			char sShowOutput[64];
 | 
						|
			Config.GetShowOutput(sShowOutput, sizeof(sShowOutput));
 | 
						|
 | 
						|
			if(StrEqual(sShowOutput, "OnTakeDamage"))
 | 
						|
			{
 | 
						|
				SDKHook(entity, SDKHook_OnTakeDamagePost, OnTakeDamagePostShow);
 | 
						|
			}
 | 
						|
			else
 | 
						|
			{
 | 
						|
				bool Once = !Config.bMultiTrigger;
 | 
						|
				HookSingleEntityOutput(entity, sShowOutput, OnEntityOutputShow, Once);
 | 
						|
			}
 | 
						|
 | 
						|
			LogDebugMessage("Hooked showtrigger %s:%s", sShowTrigger, sShowOutput);
 | 
						|
		}
 | 
						|
 | 
						|
		char sKillTrigger[64];
 | 
						|
		Config.GetKillTrigger(sKillTrigger, sizeof(sKillTrigger));
 | 
						|
 | 
						|
		int iKillTriggerHammerID = -1;
 | 
						|
		if(sKillTrigger[0] == '#')
 | 
						|
			iKillTriggerHammerID = StringToInt(sKillTrigger[1]);
 | 
						|
 | 
						|
		if((iKillTriggerHammerID == -1 && sKillTrigger[0] && StrEqual(sTargetname, sKillTrigger)) || iKillTriggerHammerID == iHammerID)
 | 
						|
		{
 | 
						|
			char sKillOutput[64];
 | 
						|
			Config.GetKillOutput(sKillOutput, sizeof(sKillOutput));
 | 
						|
 | 
						|
			if(StrEqual(sKillOutput, "OnTakeDamage"))
 | 
						|
			{
 | 
						|
				SDKHook(entity, SDKHook_OnTakeDamagePost, OnTakeDamagePostKill);
 | 
						|
			}
 | 
						|
			else
 | 
						|
			{
 | 
						|
				bool Once = !Config.bMultiTrigger;
 | 
						|
				HookSingleEntityOutput(entity, sKillOutput, OnEntityOutputKill, Once);
 | 
						|
			}
 | 
						|
 | 
						|
			LogDebugMessage("Hooked killtrigger %s:%s", sKillTrigger, sKillOutput);
 | 
						|
		}
 | 
						|
 | 
						|
		char sHurtTrigger[64];
 | 
						|
		Config.GetHurtTrigger(sHurtTrigger, sizeof(sHurtTrigger));
 | 
						|
 | 
						|
		int iHurtTriggerHammerID = -1;
 | 
						|
		if(sHurtTrigger[0] == '#')
 | 
						|
			iHurtTriggerHammerID = StringToInt(sHurtTrigger[1]);
 | 
						|
 | 
						|
		if((iHurtTriggerHammerID == -1 && sHurtTrigger[0] && StrEqual(sTargetname, sHurtTrigger)) || iHurtTriggerHammerID == iHammerID)
 | 
						|
		{
 | 
						|
			char sHurtOutput[64];
 | 
						|
			Config.GetHurtOutput(sHurtOutput, sizeof(sHurtOutput));
 | 
						|
 | 
						|
			if(StrEqual(sHurtOutput, "OnTakeDamage"))
 | 
						|
			{
 | 
						|
				SDKHook(entity, SDKHook_OnTakeDamagePost, OnTakeDamagePostHurt);
 | 
						|
			}
 | 
						|
			else
 | 
						|
			{
 | 
						|
				HookSingleEntityOutput(entity, sHurtOutput, OnEntityOutputHurt);
 | 
						|
			}
 | 
						|
 | 
						|
			LogDebugMessage("Hooked hurttrigger %s:%s", sHurtTrigger, sHurtOutput);
 | 
						|
		}
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
void OnTrigger(int entity, const char[] output, SDKHookType HookType = view_as<SDKHookType>(-1))
 | 
						|
{
 | 
						|
	char sTargetname[64];
 | 
						|
	GetEntPropString(entity, Prop_Data, "m_iName", sTargetname, sizeof(sTargetname));
 | 
						|
 | 
						|
	int iHammerID = GetEntProp(entity, Prop_Data, "m_iHammerID");
 | 
						|
 | 
						|
//	PrintToServer("OnTrigger(%d:\"%s\":#%d, \"%s\")", entity, sTargetname, iHammerID, output);
 | 
						|
 | 
						|
	for(int i = 0; i < g_aConfig.Length; i++)
 | 
						|
	{
 | 
						|
		CConfig Config = g_aConfig.Get(i);
 | 
						|
 | 
						|
		char sTrigger[64];
 | 
						|
		Config.GetTrigger(sTrigger, sizeof(sTrigger));
 | 
						|
 | 
						|
		int iTriggerHammerID = -1;
 | 
						|
		if(sTrigger[0] == '#')
 | 
						|
		{
 | 
						|
			iTriggerHammerID = StringToInt(sTrigger[1]);
 | 
						|
 | 
						|
			if(iTriggerHammerID != iHammerID)
 | 
						|
				continue;
 | 
						|
		}
 | 
						|
		else if(!sTargetname[0] || !StrEqual(sTargetname, sTrigger))
 | 
						|
			continue;
 | 
						|
 | 
						|
		char sOutput[64];
 | 
						|
		Config.GetOutput(sOutput, sizeof(sOutput));
 | 
						|
 | 
						|
		if(!StrEqual(output, sOutput))
 | 
						|
			continue;
 | 
						|
 | 
						|
		bool Once = !Config.bMultiTrigger;
 | 
						|
		char sTemp[8];
 | 
						|
 | 
						|
		if(Once)
 | 
						|
		{
 | 
						|
			IntToString(i, sTemp, sizeof(sTemp));
 | 
						|
			bool bHadOnce = false;
 | 
						|
			if(g_aHadOnce.GetValue(sTemp, bHadOnce) && bHadOnce)
 | 
						|
				continue;
 | 
						|
		}
 | 
						|
 | 
						|
		if(HookType != view_as<SDKHookType>(-1) && Once)
 | 
						|
		{
 | 
						|
			if(HookType == SDKHook_OnTakeDamagePost)
 | 
						|
				SDKUnhook(entity, SDKHook_OnTakeDamagePost, OnTakeDamagePost);
 | 
						|
		}
 | 
						|
 | 
						|
		CBoss Boss = view_as<CBoss>(INVALID_HANDLE);
 | 
						|
 | 
						|
		if(Config.IsBreakable)
 | 
						|
			Boss = new CBossBreakable();
 | 
						|
		else if(Config.IsCounter)
 | 
						|
			Boss = new CBossCounter();
 | 
						|
		else if(Config.IsHPBar)
 | 
						|
			Boss = new CBossHPBar();
 | 
						|
 | 
						|
		if(Boss != INVALID_HANDLE)
 | 
						|
		{
 | 
						|
			Boss.dConfig = Config;
 | 
						|
			Boss.bActive = false;
 | 
						|
 | 
						|
			float fTriggerDelay = Config.fTriggerDelay;
 | 
						|
			if(fTriggerDelay > 0)
 | 
						|
				Boss.fWaitUntil = GetGameTime() + fTriggerDelay;
 | 
						|
 | 
						|
			char sShowTrigger[8];
 | 
						|
			Config.GetShowTrigger(sShowTrigger, sizeof(sShowTrigger));
 | 
						|
			if(sShowTrigger[0])
 | 
						|
				Boss.bShow = false;
 | 
						|
 | 
						|
			g_aBoss.Push(Boss);
 | 
						|
 | 
						|
			if(Once)
 | 
						|
				g_aHadOnce.SetValue(sTemp, true);
 | 
						|
 | 
						|
			if(iTriggerHammerID == -1)
 | 
						|
				LogDebugMessage("Triggered boss %s(%d) from output %s", sTargetname, entity, output);
 | 
						|
			else
 | 
						|
				LogDebugMessage("Triggered boss #%d(%d) from output %s", iTriggerHammerID, entity, output);
 | 
						|
		}
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
void OnShowTrigger(int entity, const char[] output, SDKHookType HookType = view_as<SDKHookType>(-1))
 | 
						|
{
 | 
						|
	char sTargetname[64];
 | 
						|
	GetEntPropString(entity, Prop_Data, "m_iName", sTargetname, sizeof(sTargetname));
 | 
						|
 | 
						|
	int iHammerID = GetEntProp(entity, Prop_Data, "m_iHammerID");
 | 
						|
 | 
						|
	int iTemplateNum = -1;
 | 
						|
	int iTemplateLoc = FindCharInString(sTargetname, '&', true);
 | 
						|
	if(iTemplateLoc != -1)
 | 
						|
	{
 | 
						|
		iTemplateNum = StringToInt(sTargetname[iTemplateLoc + 1]);
 | 
						|
		sTargetname[iTemplateLoc] = 0;
 | 
						|
	}
 | 
						|
 | 
						|
	for(int i = 0; i < g_aConfig.Length; i++)
 | 
						|
	{
 | 
						|
		CConfig Config = g_aConfig.Get(i);
 | 
						|
 | 
						|
		char sShowTrigger[64];
 | 
						|
		Config.GetShowTrigger(sShowTrigger, sizeof(sShowTrigger));
 | 
						|
 | 
						|
		if(!sShowTrigger[0])
 | 
						|
			continue;
 | 
						|
 | 
						|
		int iShowTriggerHammerID = -1;
 | 
						|
		if(sShowTrigger[0] == '#')
 | 
						|
		{
 | 
						|
			iShowTriggerHammerID = StringToInt(sShowTrigger[1]);
 | 
						|
 | 
						|
			if(iShowTriggerHammerID != iHammerID)
 | 
						|
				continue;
 | 
						|
		}
 | 
						|
		else if(!sTargetname[0] || !StrEqual(sTargetname, sShowTrigger))
 | 
						|
			continue;
 | 
						|
 | 
						|
		char sShowOutput[64];
 | 
						|
		Config.GetShowOutput(sShowOutput, sizeof(sShowOutput));
 | 
						|
 | 
						|
		if(!StrEqual(output, sShowOutput))
 | 
						|
			continue;
 | 
						|
 | 
						|
		if(iShowTriggerHammerID == -1)
 | 
						|
			LogDebugMessage("Triggered show boss %s(%d) from output %s", sTargetname, entity, output);
 | 
						|
		else
 | 
						|
			LogDebugMessage("Triggered show boss #%d(%d) from output %s", iShowTriggerHammerID, entity, output);
 | 
						|
 | 
						|
		if(HookType != view_as<SDKHookType>(-1) && !Config.bMultiTrigger)
 | 
						|
		{
 | 
						|
			if(HookType == SDKHook_OnTakeDamagePost)
 | 
						|
				SDKUnhook(entity, SDKHook_OnTakeDamagePost, OnTakeDamagePostShow);
 | 
						|
		}
 | 
						|
 | 
						|
		float fShowTriggerDelay = Config.fShowTriggerDelay;
 | 
						|
 | 
						|
		for(int j = 0; j < g_aBoss.Length; j++)
 | 
						|
		{
 | 
						|
			CBoss Boss = g_aBoss.Get(j);
 | 
						|
 | 
						|
			if(Boss.dConfig != Config)
 | 
						|
				continue;
 | 
						|
 | 
						|
			if(Boss.iTemplateNum != iTemplateNum)
 | 
						|
				continue;
 | 
						|
 | 
						|
			if(fShowTriggerDelay > 0)
 | 
						|
			{
 | 
						|
				Boss.fShowAt = GetGameTime() + fShowTriggerDelay;
 | 
						|
				LogDebugMessage("Scheduled show(%f) boss %d", fShowTriggerDelay, j);
 | 
						|
			}
 | 
						|
			else
 | 
						|
			{
 | 
						|
				Boss.bShow = true;
 | 
						|
				LogDebugMessage("Showing boss %d", j);
 | 
						|
			}
 | 
						|
		}
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
void OnKillTrigger(int entity, const char[] output, SDKHookType HookType = view_as<SDKHookType>(-1))
 | 
						|
{
 | 
						|
	char sTargetname[64];
 | 
						|
	GetEntPropString(entity, Prop_Data, "m_iName", sTargetname, sizeof(sTargetname));
 | 
						|
 | 
						|
	int iHammerID = GetEntProp(entity, Prop_Data, "m_iHammerID");
 | 
						|
 | 
						|
	int iTemplateNum = -1;
 | 
						|
	int iTemplateLoc = FindCharInString(sTargetname, '&', true);
 | 
						|
	if(iTemplateLoc != -1)
 | 
						|
	{
 | 
						|
		iTemplateNum = StringToInt(sTargetname[iTemplateLoc + 1]);
 | 
						|
		sTargetname[iTemplateLoc] = 0;
 | 
						|
	}
 | 
						|
 | 
						|
	for(int i = 0; i < g_aConfig.Length; i++)
 | 
						|
	{
 | 
						|
		CConfig Config = g_aConfig.Get(i);
 | 
						|
 | 
						|
		char sKillTrigger[64];
 | 
						|
		Config.GetKillTrigger(sKillTrigger, sizeof(sKillTrigger));
 | 
						|
 | 
						|
		if(!sKillTrigger[0])
 | 
						|
			continue;
 | 
						|
 | 
						|
		int iKillTriggerHammerID = -1;
 | 
						|
		if(sKillTrigger[0] == '#')
 | 
						|
		{
 | 
						|
			iKillTriggerHammerID = StringToInt(sKillTrigger[1]);
 | 
						|
 | 
						|
			if(iKillTriggerHammerID != iHammerID)
 | 
						|
				continue;
 | 
						|
		}
 | 
						|
		else if(!sTargetname[0] || !StrEqual(sTargetname, sKillTrigger))
 | 
						|
			continue;
 | 
						|
 | 
						|
		char sKillOutput[64];
 | 
						|
		Config.GetKillOutput(sKillOutput, sizeof(sKillOutput));
 | 
						|
 | 
						|
		if(!StrEqual(output, sKillOutput))
 | 
						|
			continue;
 | 
						|
 | 
						|
		if(iKillTriggerHammerID == -1)
 | 
						|
			LogDebugMessage("Triggered kill boss %s(%d) from output %s", sTargetname, entity, output);
 | 
						|
		else
 | 
						|
			LogDebugMessage("Triggered kill boss #%d(%d) from output %s", iKillTriggerHammerID, entity, output);
 | 
						|
 | 
						|
		if(HookType != view_as<SDKHookType>(-1) && !Config.bMultiTrigger)
 | 
						|
		{
 | 
						|
			if(HookType == SDKHook_OnTakeDamagePost)
 | 
						|
				SDKUnhook(entity, SDKHook_OnTakeDamagePost, OnTakeDamagePostKill);
 | 
						|
		}
 | 
						|
 | 
						|
		float fKillTriggerDelay = Config.fKillTriggerDelay;
 | 
						|
 | 
						|
		for(int j = 0; j < g_aBoss.Length; j++)
 | 
						|
		{
 | 
						|
			CBoss Boss = g_aBoss.Get(j);
 | 
						|
 | 
						|
			if(Boss.dConfig != Config)
 | 
						|
				continue;
 | 
						|
 | 
						|
			if(Boss.iTemplateNum != iTemplateNum)
 | 
						|
				continue;
 | 
						|
 | 
						|
			if(fKillTriggerDelay > 0)
 | 
						|
			{
 | 
						|
				Boss.fKillAt = GetGameTime() + fKillTriggerDelay;
 | 
						|
				LogDebugMessage("Scheduled kill(%f) boss %d", fKillTriggerDelay, j);
 | 
						|
			}
 | 
						|
			else
 | 
						|
			{
 | 
						|
				LogDebugMessage("Killed boss %d", j);
 | 
						|
 | 
						|
				Call_StartForward(g_hFwd_OnBossKilled);
 | 
						|
				Call_PushCell(Boss);
 | 
						|
				Call_PushCell(Boss.dConfig);
 | 
						|
				Call_PushCell(1);
 | 
						|
				Call_Finish();
 | 
						|
 | 
						|
				delete Boss;
 | 
						|
				g_aBoss.Erase(j);
 | 
						|
				j--;
 | 
						|
			}
 | 
						|
		}
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
void OnHurtTrigger(int entity, const char[] output, int activator, float damage = 1.0)
 | 
						|
{
 | 
						|
	char sTargetname[64];
 | 
						|
	GetEntPropString(entity, Prop_Data, "m_iName", sTargetname, sizeof(sTargetname));
 | 
						|
 | 
						|
	int iHammerID = GetEntProp(entity, Prop_Data, "m_iHammerID");
 | 
						|
 | 
						|
	int iTemplateNum = -1;
 | 
						|
	int iTemplateLoc = FindCharInString(sTargetname, '&', true);
 | 
						|
	if(iTemplateLoc != -1)
 | 
						|
	{
 | 
						|
		iTemplateNum = StringToInt(sTargetname[iTemplateLoc + 1]);
 | 
						|
		sTargetname[iTemplateLoc] = 0;
 | 
						|
	}
 | 
						|
 | 
						|
	for(int i = 0; i < g_aConfig.Length; i++)
 | 
						|
	{
 | 
						|
		CConfig Config = g_aConfig.Get(i);
 | 
						|
 | 
						|
		char sHurtTrigger[64];
 | 
						|
		Config.GetHurtTrigger(sHurtTrigger, sizeof(sHurtTrigger));
 | 
						|
 | 
						|
		if(!sHurtTrigger[0])
 | 
						|
			continue;
 | 
						|
 | 
						|
		int iHurtTriggerHammerID = -1;
 | 
						|
		if(sHurtTrigger[0] == '#')
 | 
						|
		{
 | 
						|
			iHurtTriggerHammerID = StringToInt(sHurtTrigger[1]);
 | 
						|
 | 
						|
			if(iHurtTriggerHammerID != iHammerID)
 | 
						|
				continue;
 | 
						|
		}
 | 
						|
		else if(!sTargetname[0] || !StrEqual(sTargetname, sHurtTrigger))
 | 
						|
			continue;
 | 
						|
 | 
						|
		char sHurtOutput[64];
 | 
						|
		Config.GetHurtOutput(sHurtOutput, sizeof(sHurtOutput));
 | 
						|
 | 
						|
		if(!StrEqual(output, sHurtOutput))
 | 
						|
			continue;
 | 
						|
 | 
						|
		if(iHurtTriggerHammerID == -1)
 | 
						|
			LogDebugMessage("Triggered hurt boss %s(%d) from output %s", sTargetname, entity, output);
 | 
						|
		else
 | 
						|
			LogDebugMessage("Triggered hurt boss #%d(%d) from output %s", iHurtTriggerHammerID, entity, output);
 | 
						|
 | 
						|
		for(int j = 0; j < g_aBoss.Length; j++)
 | 
						|
		{
 | 
						|
			CBoss Boss = g_aBoss.Get(j);
 | 
						|
 | 
						|
			if(Boss.dConfig != Config)
 | 
						|
				continue;
 | 
						|
 | 
						|
			if(Boss.iTemplateNum != iTemplateNum)
 | 
						|
				continue;
 | 
						|
 | 
						|
			Call_StartForward(g_hFwd_OnBossDamaged);
 | 
						|
			Call_PushCell(Boss);
 | 
						|
			Call_PushCell(Boss.dConfig);
 | 
						|
			Call_PushCell(activator);
 | 
						|
			Call_PushFloat(damage);
 | 
						|
			Call_Finish();
 | 
						|
		}
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
public void OnEnvEntityMakerEntitySpawned(const char[] output, int caller, int activator, float delay)
 | 
						|
{
 | 
						|
	if(!g_aConfig)
 | 
						|
		return;
 | 
						|
 | 
						|
	char sClassname[64];
 | 
						|
	if(!GetEntityClassname(caller, sClassname, sizeof(sClassname)))
 | 
						|
		return;
 | 
						|
 | 
						|
	if(!StrEqual(sClassname, "env_entity_maker"))
 | 
						|
	{
 | 
						|
		LogError("[SOURCEMOD BUG] output: \"%s\", caller: %d, activator: %d, delay: %f, classname: \"%s\"",
 | 
						|
			output, caller, activator, delay, sClassname);
 | 
						|
		return;
 | 
						|
	}
 | 
						|
 | 
						|
	char sPointTemplate[64];
 | 
						|
	if(GetEntPropString(caller, Prop_Data, "m_iszTemplate", sPointTemplate, sizeof(sPointTemplate)) <= 0)
 | 
						|
		return;
 | 
						|
 | 
						|
	int iPointTemplate = FindEntityByTargetname(INVALID_ENT_REFERENCE, sPointTemplate, "point_template");
 | 
						|
	if(iPointTemplate == INVALID_ENT_REFERENCE)
 | 
						|
		return;
 | 
						|
 | 
						|
	OnEntityOutput("OnEntitySpawned", iPointTemplate, caller, delay);
 | 
						|
}
 | 
						|
 | 
						|
public void OnEntityOutput(const char[] output, int caller, int activator, float delay)
 | 
						|
{
 | 
						|
	OnTrigger(caller, output);
 | 
						|
}
 | 
						|
 | 
						|
public void OnEntityOutputShow(const char[] output, int caller, int activator, float delay)
 | 
						|
{
 | 
						|
	OnShowTrigger(caller, output);
 | 
						|
}
 | 
						|
 | 
						|
public void OnEntityOutputKill(const char[] output, int caller, int activator, float delay)
 | 
						|
{
 | 
						|
	OnKillTrigger(caller, output);
 | 
						|
}
 | 
						|
 | 
						|
public void OnEntityOutputHurt(const char[] output, int caller, int activator, float delay)
 | 
						|
{
 | 
						|
	OnHurtTrigger(caller, output, activator);
 | 
						|
}
 | 
						|
 | 
						|
public void OnTakeDamagePost(int victim, int attacker, int inflictor, float damage, int damagetype)
 | 
						|
{
 | 
						|
	OnTrigger(victim, "OnTakeDamage", SDKHook_OnTakeDamagePost);
 | 
						|
}
 | 
						|
 | 
						|
public void OnTakeDamagePostShow(int victim, int attacker, int inflictor, float damage, int damagetype)
 | 
						|
{
 | 
						|
	OnShowTrigger(victim, "OnTakeDamage", SDKHook_OnTakeDamagePost);
 | 
						|
}
 | 
						|
 | 
						|
public void OnTakeDamagePostKill(int victim, int attacker, int inflictor, float damage, int damagetype)
 | 
						|
{
 | 
						|
	OnKillTrigger(victim, "OnTakeDamage", SDKHook_OnTakeDamagePost);
 | 
						|
}
 | 
						|
 | 
						|
public void OnTakeDamagePostHurt(int victim, int attacker, int inflictor, float damage, int damagetype)
 | 
						|
{
 | 
						|
	OnHurtTrigger(victim, "OnTakeDamage", attacker, damage);
 | 
						|
}
 | 
						|
 | 
						|
public void OnGameFrame()
 | 
						|
{
 | 
						|
	if(!g_aBoss)
 | 
						|
		return;
 | 
						|
 | 
						|
	static bool s_bLastHudPrinted = false;
 | 
						|
	g_sHUDText[0] = 0;
 | 
						|
 | 
						|
	for(int i = 0; i < g_aBoss.Length; i++)
 | 
						|
	{
 | 
						|
		CBoss Boss = g_aBoss.Get(i);
 | 
						|
 | 
						|
		if(Boss.fKillAt && Boss.fKillAt < GetGameTime())
 | 
						|
		{ // Delete Boss
 | 
						|
			LogDebugMessage("Deleting boss %d (KillAt)", i);
 | 
						|
 | 
						|
			Call_StartForward(g_hFwd_OnBossKilled);
 | 
						|
			Call_PushCell(Boss);
 | 
						|
			Call_PushCell(Boss.dConfig);
 | 
						|
			Call_PushCell(1);
 | 
						|
			Call_Finish();
 | 
						|
 | 
						|
			delete Boss;
 | 
						|
			g_aBoss.Erase(i);
 | 
						|
			i--;
 | 
						|
 | 
						|
			continue;
 | 
						|
		}
 | 
						|
 | 
						|
		if(!Boss.bActive)
 | 
						|
		{
 | 
						|
			if(Boss.fWaitUntil)
 | 
						|
			{
 | 
						|
				if(Boss.fWaitUntil > GetGameTime())
 | 
						|
					continue;
 | 
						|
				Boss.fWaitUntil = 0.0;
 | 
						|
			}
 | 
						|
 | 
						|
			if(!BossInit(Boss))
 | 
						|
				continue;
 | 
						|
		}
 | 
						|
 | 
						|
		if(!Boss.bProcessing)
 | 
						|
		{
 | 
						|
			// Mark boss as processing, this will stay true on errors, preventing spam due to OnGameFrame otherwise constantly trying again.
 | 
						|
			Boss.bProcessing = true;
 | 
						|
 | 
						|
			if(!BossProcess(Boss))
 | 
						|
			{ // Delete Boss
 | 
						|
				LogDebugMessage("Deleting boss %d (dead)", i);
 | 
						|
 | 
						|
				Call_StartForward(g_hFwd_OnBossKilled);
 | 
						|
				Call_PushCell(Boss);
 | 
						|
				Call_PushCell(Boss.dConfig);
 | 
						|
				Call_PushCell(2);
 | 
						|
				Call_Finish();
 | 
						|
 | 
						|
				delete Boss;
 | 
						|
				g_aBoss.Erase(i);
 | 
						|
				i--;
 | 
						|
 | 
						|
				continue;
 | 
						|
			}
 | 
						|
 | 
						|
			// Unmark Boss as processing.
 | 
						|
			Boss.bProcessing = false;
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	if(!IsVoteInProgress())
 | 
						|
	{
 | 
						|
		if(g_sHUDText[0])
 | 
						|
		{
 | 
						|
			for(int client = 1; client <= MaxClients; client++)
 | 
						|
			{
 | 
						|
				if(IsClientInGame(client))
 | 
						|
				{
 | 
						|
					PrintHintText(client, g_sHUDText);
 | 
						|
					StopSound(client, SNDCHAN_STATIC, "UI/hint.wav");
 | 
						|
				}
 | 
						|
			}
 | 
						|
			s_bLastHudPrinted = true;
 | 
						|
		}
 | 
						|
		else if(s_bLastHudPrinted)
 | 
						|
		{
 | 
						|
			for(int client = 1; client <= MaxClients; client++)
 | 
						|
			{
 | 
						|
				if(IsClientInGame(client))
 | 
						|
				{
 | 
						|
					PrintHintText(client, "");
 | 
						|
					StopSound(client, SNDCHAN_STATIC, "UI/hint.wav");
 | 
						|
				}
 | 
						|
			}
 | 
						|
			s_bLastHudPrinted = false;
 | 
						|
		}
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
bool BossInit(CBoss _Boss)
 | 
						|
{
 | 
						|
	CConfig _Config = _Boss.dConfig;
 | 
						|
	bool bNameFixup = _Config.bNameFixup;
 | 
						|
	int iTemplateNum = -1;
 | 
						|
 | 
						|
	if(_Boss.IsBreakable)
 | 
						|
	{
 | 
						|
		CBossBreakable Boss = view_as<CBossBreakable>(_Boss);
 | 
						|
		CConfigBreakable Config = view_as<CConfigBreakable>(_Config);
 | 
						|
 | 
						|
		char sBreakable[64];
 | 
						|
		Config.GetBreakable(sBreakable, sizeof(sBreakable));
 | 
						|
 | 
						|
		int iBreakableEnt = INVALID_ENT_REFERENCE;
 | 
						|
 | 
						|
		if(!bNameFixup)
 | 
						|
		{
 | 
						|
			iBreakableEnt = FindEntityByTargetname(iBreakableEnt, sBreakable, "*");
 | 
						|
			if(iBreakableEnt == INVALID_ENT_REFERENCE)
 | 
						|
				return false;
 | 
						|
		}
 | 
						|
		else
 | 
						|
		{
 | 
						|
			StrCat(sBreakable, sizeof(sBreakable), "&*");
 | 
						|
			while((iBreakableEnt = FindEntityByTargetname(iBreakableEnt, sBreakable, "*")) != INVALID_ENT_REFERENCE)
 | 
						|
			{
 | 
						|
				bool bSkip = false;
 | 
						|
				for(int i = 0; i < g_aBoss.Length; i++)
 | 
						|
				{
 | 
						|
					CBoss _tBoss = g_aBoss.Get(i);
 | 
						|
					if(!_tBoss.IsBreakable)
 | 
						|
						continue;
 | 
						|
 | 
						|
					CBossBreakable tBoss = view_as<CBossBreakable>(_tBoss);
 | 
						|
					if(tBoss.iBreakableEnt == iBreakableEnt)
 | 
						|
					{
 | 
						|
						bSkip = true;
 | 
						|
						break;
 | 
						|
					}
 | 
						|
				}
 | 
						|
 | 
						|
				if(!bSkip)
 | 
						|
					break;
 | 
						|
			}
 | 
						|
 | 
						|
			if(iBreakableEnt == INVALID_ENT_REFERENCE)
 | 
						|
				return false;
 | 
						|
 | 
						|
			GetEntPropString(iBreakableEnt, Prop_Data, "m_iName", sBreakable, sizeof(sBreakable));
 | 
						|
 | 
						|
			int iTemplateLoc = FindCharInString(sBreakable, '&', true);
 | 
						|
			if(iTemplateLoc == -1)
 | 
						|
				return false;
 | 
						|
 | 
						|
			iTemplateNum = StringToInt(sBreakable[iTemplateLoc + 1]);
 | 
						|
		}
 | 
						|
 | 
						|
		Boss.iBreakableEnt = iBreakableEnt;
 | 
						|
	}
 | 
						|
	else if(_Boss.IsCounter)
 | 
						|
	{
 | 
						|
		CBossCounter Boss = view_as<CBossCounter>(_Boss);
 | 
						|
		CConfigCounter Config = view_as<CConfigCounter>(_Config);
 | 
						|
 | 
						|
		char sCounter[64];
 | 
						|
		Config.GetCounter(sCounter, sizeof(sCounter));
 | 
						|
 | 
						|
		int iCounterEnt = INVALID_ENT_REFERENCE;
 | 
						|
 | 
						|
		if(!bNameFixup)
 | 
						|
		{
 | 
						|
			iCounterEnt = FindEntityByTargetname(iCounterEnt, sCounter, "math_counter");
 | 
						|
			if(iCounterEnt == INVALID_ENT_REFERENCE)
 | 
						|
				return false;
 | 
						|
		}
 | 
						|
		else
 | 
						|
		{
 | 
						|
			StrCat(sCounter, sizeof(sCounter), "&*");
 | 
						|
			while((iCounterEnt = FindEntityByTargetname(iCounterEnt, sCounter, "math_counter")) != INVALID_ENT_REFERENCE)
 | 
						|
			{
 | 
						|
				char sBuf[64];
 | 
						|
				GetEntPropString(iCounterEnt, Prop_Data, "m_iName", sBuf, sizeof(sBuf));
 | 
						|
 | 
						|
				bool bSkip = false;
 | 
						|
				for(int i = 0; i < g_aBoss.Length; i++)
 | 
						|
				{
 | 
						|
					CBoss _tBoss = g_aBoss.Get(i);
 | 
						|
					if(!_tBoss.IsCounter)
 | 
						|
						continue;
 | 
						|
 | 
						|
					CBossCounter tBoss = view_as<CBossCounter>(_tBoss);
 | 
						|
					if(tBoss.iCounterEnt == iCounterEnt)
 | 
						|
					{
 | 
						|
						bSkip = true;
 | 
						|
						break;
 | 
						|
					}
 | 
						|
				}
 | 
						|
 | 
						|
				if(!bSkip)
 | 
						|
					break;
 | 
						|
			}
 | 
						|
 | 
						|
			if(iCounterEnt == INVALID_ENT_REFERENCE)
 | 
						|
				return false;
 | 
						|
 | 
						|
			GetEntPropString(iCounterEnt, Prop_Data, "m_iName", sCounter, sizeof(sCounter));
 | 
						|
 | 
						|
			int iTemplateLoc = FindCharInString(sCounter, '&', true);
 | 
						|
			if(iTemplateLoc == -1)
 | 
						|
				return false;
 | 
						|
 | 
						|
			iTemplateNum = StringToInt(sCounter[iTemplateLoc + 1]);
 | 
						|
		}
 | 
						|
 | 
						|
		Boss.iCounterEnt = iCounterEnt;
 | 
						|
 | 
						|
		int iCounterOnHitMinCount = GetOutputCount(iCounterEnt, "m_OnHitMin");
 | 
						|
		int iCounterOnHitMaxCount = GetOutputCount(iCounterEnt, "m_OnHitMax");
 | 
						|
 | 
						|
		if(iCounterOnHitMinCount == iCounterOnHitMaxCount)
 | 
						|
		{
 | 
						|
			int iMinDiff = RoundFloat(GetOutputValueFloat(iCounterEnt, "m_OutValue") - GetEntPropFloat(iCounterEnt, Prop_Data, "m_flMin"));
 | 
						|
			int iMaxDiff = RoundFloat(GetEntPropFloat(iCounterEnt, Prop_Data, "m_flMax") - GetOutputValueFloat(iCounterEnt, "m_OutValue"));
 | 
						|
 | 
						|
			Config.bCounterReverse = iMaxDiff > iMinDiff;
 | 
						|
		}
 | 
						|
		else
 | 
						|
			Config.bCounterReverse = iCounterOnHitMaxCount > iCounterOnHitMinCount;
 | 
						|
	}
 | 
						|
	else if(_Boss.IsHPBar)
 | 
						|
	{
 | 
						|
		CBossHPBar Boss = view_as<CBossHPBar>(_Boss);
 | 
						|
		CConfigHPBar Config = view_as<CConfigHPBar>(_Config);
 | 
						|
 | 
						|
		char sIterator[64];
 | 
						|
		char sCounter[64];
 | 
						|
		char sBackup[64];
 | 
						|
 | 
						|
		Config.GetIterator(sIterator, sizeof(sIterator));
 | 
						|
		Config.GetCounter(sCounter, sizeof(sCounter));
 | 
						|
		Config.GetBackup(sBackup, sizeof(sBackup));
 | 
						|
 | 
						|
		int iIteratorEnt = INVALID_ENT_REFERENCE;
 | 
						|
		int iCounterEnt = INVALID_ENT_REFERENCE;
 | 
						|
		int iBackupEnt = INVALID_ENT_REFERENCE;
 | 
						|
 | 
						|
		if(!bNameFixup)
 | 
						|
		{
 | 
						|
			iIteratorEnt = FindEntityByTargetname(iIteratorEnt, sIterator, "math_counter");
 | 
						|
			if(iIteratorEnt == INVALID_ENT_REFERENCE)
 | 
						|
				return false;
 | 
						|
 | 
						|
			iCounterEnt = FindEntityByTargetname(iCounterEnt, sCounter, "math_counter");
 | 
						|
			if(iCounterEnt == INVALID_ENT_REFERENCE)
 | 
						|
				return false;
 | 
						|
 | 
						|
			iBackupEnt = FindEntityByTargetname(iBackupEnt, sBackup, "math_counter");
 | 
						|
			if(iBackupEnt == INVALID_ENT_REFERENCE)
 | 
						|
				return false;
 | 
						|
		}
 | 
						|
		else
 | 
						|
		{
 | 
						|
			StrCat(sIterator, sizeof(sIterator), "&*");
 | 
						|
			while((iIteratorEnt = FindEntityByTargetname(iIteratorEnt, sIterator, "math_counter")) != INVALID_ENT_REFERENCE)
 | 
						|
			{
 | 
						|
				bool bSkip = false;
 | 
						|
				for(int i = 0; i < g_aBoss.Length; i++)
 | 
						|
				{
 | 
						|
					CBoss _tBoss = g_aBoss.Get(i);
 | 
						|
					if(!_tBoss.IsHPBar)
 | 
						|
						continue;
 | 
						|
 | 
						|
					CBossHPBar tBoss = view_as<CBossHPBar>(_tBoss);
 | 
						|
					if(tBoss.iIteratorEnt == iIteratorEnt)
 | 
						|
					{
 | 
						|
						bSkip = true;
 | 
						|
						break;
 | 
						|
					}
 | 
						|
				}
 | 
						|
 | 
						|
				if(!bSkip)
 | 
						|
					break;
 | 
						|
			}
 | 
						|
 | 
						|
			if(iIteratorEnt == INVALID_ENT_REFERENCE)
 | 
						|
				return false;
 | 
						|
 | 
						|
			GetEntPropString(iIteratorEnt, Prop_Data, "m_iName", sIterator, sizeof(sIterator));
 | 
						|
 | 
						|
			int iTemplateLoc = FindCharInString(sIterator, '&', true);
 | 
						|
			if(iTemplateLoc == -1)
 | 
						|
				return false;
 | 
						|
 | 
						|
			StrCat(sCounter, sizeof(sCounter), sIterator[iTemplateLoc]);
 | 
						|
			StrCat(sBackup, sizeof(sBackup), sIterator[iTemplateLoc]);
 | 
						|
 | 
						|
			iCounterEnt = FindEntityByTargetname(iCounterEnt, sCounter, "math_counter");
 | 
						|
			if(iCounterEnt == INVALID_ENT_REFERENCE)
 | 
						|
				return false;
 | 
						|
 | 
						|
			iBackupEnt = FindEntityByTargetname(iBackupEnt, sBackup, "math_counter");
 | 
						|
			if(iBackupEnt == INVALID_ENT_REFERENCE)
 | 
						|
				return false;
 | 
						|
 | 
						|
			iTemplateNum = StringToInt(sIterator[iTemplateLoc + 1]);
 | 
						|
		}
 | 
						|
 | 
						|
		Boss.iIteratorEnt = iIteratorEnt;
 | 
						|
		Boss.iCounterEnt = iCounterEnt;
 | 
						|
		Boss.iBackupEnt = iBackupEnt;
 | 
						|
 | 
						|
		int iIteratorOnHitMinCount = GetOutputCount(iIteratorEnt, "m_OnHitMin");
 | 
						|
		int iIteratorOnHitMaxCount = GetOutputCount(iIteratorEnt, "m_OnHitMax");
 | 
						|
 | 
						|
		if(iIteratorOnHitMinCount == iIteratorOnHitMaxCount)
 | 
						|
		{
 | 
						|
			int iMinDiff = RoundFloat(GetOutputValueFloat(iIteratorEnt, "m_OutValue") - GetEntPropFloat(iIteratorEnt, Prop_Data, "m_flMin"));
 | 
						|
			int iMaxDiff = RoundFloat(GetEntPropFloat(iIteratorEnt, Prop_Data, "m_flMax") - GetOutputValueFloat(iIteratorEnt, "m_OutValue"));
 | 
						|
 | 
						|
			Config.bIteratorReverse = iMaxDiff > iMinDiff;
 | 
						|
		}
 | 
						|
		else
 | 
						|
			Config.bIteratorReverse = iIteratorOnHitMaxCount > iIteratorOnHitMinCount;
 | 
						|
 | 
						|
		int iCounterOnHitMinCount = GetOutputCount(iCounterEnt, "m_OnHitMin");
 | 
						|
		int iCounterOnHitMaxCount = GetOutputCount(iCounterEnt, "m_OnHitMax");
 | 
						|
 | 
						|
		if(iCounterOnHitMinCount == iCounterOnHitMaxCount)
 | 
						|
		{
 | 
						|
			int iMinDiff = RoundFloat(GetOutputValueFloat(iCounterEnt, "m_OutValue") - GetEntPropFloat(iCounterEnt, Prop_Data, "m_flMin"));
 | 
						|
			int iMaxDiff = RoundFloat(GetEntPropFloat(iCounterEnt, Prop_Data, "m_flMax") - GetOutputValueFloat(iCounterEnt, "m_OutValue"));
 | 
						|
 | 
						|
			Config.bCounterReverse = iMaxDiff > iMinDiff;
 | 
						|
		}
 | 
						|
		else
 | 
						|
			Config.bCounterReverse = iCounterOnHitMaxCount > iCounterOnHitMinCount;
 | 
						|
	}
 | 
						|
 | 
						|
	_Boss.bActive = true;
 | 
						|
 | 
						|
	if(iTemplateNum != -1)
 | 
						|
	{
 | 
						|
		_Boss.iTemplateNum = iTemplateNum;
 | 
						|
 | 
						|
		char sShowTrigger[64];
 | 
						|
		_Config.GetShowTrigger(sShowTrigger, sizeof(sShowTrigger));
 | 
						|
 | 
						|
		if(sShowTrigger[0])
 | 
						|
		{
 | 
						|
			Format(sShowTrigger, sizeof(sShowTrigger), "%s&%04d", sShowTrigger, iTemplateNum);
 | 
						|
 | 
						|
			char sShowOutput[64];
 | 
						|
			_Config.GetShowOutput(sShowOutput, sizeof(sShowOutput));
 | 
						|
 | 
						|
			int entity = INVALID_ENT_REFERENCE;
 | 
						|
			while((entity = FindEntityByTargetname(entity, sShowTrigger)) != INVALID_ENT_REFERENCE)
 | 
						|
			{
 | 
						|
				if(StrEqual(sShowOutput, "OnTakeDamage"))
 | 
						|
				{
 | 
						|
					SDKHook(entity, SDKHook_OnTakeDamagePost, OnTakeDamagePostShow);
 | 
						|
				}
 | 
						|
				else
 | 
						|
				{
 | 
						|
					bool Once = !_Config.bMultiTrigger;
 | 
						|
					HookSingleEntityOutput(entity, sShowOutput, OnEntityOutputShow, Once);
 | 
						|
				}
 | 
						|
 | 
						|
				LogDebugMessage("Hooked showtrigger %s:%s", sShowTrigger, sShowOutput);
 | 
						|
			}
 | 
						|
		}
 | 
						|
 | 
						|
		char sKillTrigger[64];
 | 
						|
		_Config.GetKillTrigger(sKillTrigger, sizeof(sKillTrigger));
 | 
						|
 | 
						|
		if(sKillTrigger[0])
 | 
						|
		{
 | 
						|
			Format(sKillTrigger, sizeof(sKillTrigger), "%s&%04d", sKillTrigger, iTemplateNum);
 | 
						|
 | 
						|
			char sKillOutput[64];
 | 
						|
			_Config.GetKillOutput(sKillOutput, sizeof(sKillOutput));
 | 
						|
 | 
						|
			int entity = INVALID_ENT_REFERENCE;
 | 
						|
			while((entity = FindEntityByTargetname(entity, sKillTrigger)) != INVALID_ENT_REFERENCE)
 | 
						|
			{
 | 
						|
				if(StrEqual(sKillOutput, "OnTakeDamage"))
 | 
						|
				{
 | 
						|
					SDKHook(entity, SDKHook_OnTakeDamagePost, OnTakeDamagePostKill);
 | 
						|
				}
 | 
						|
				else
 | 
						|
				{
 | 
						|
					bool Once = !_Config.bMultiTrigger;
 | 
						|
					HookSingleEntityOutput(entity, sKillOutput, OnEntityOutputKill, Once);
 | 
						|
				}
 | 
						|
 | 
						|
				LogDebugMessage("Hooked killtrigger %s:%s", sKillTrigger, sKillOutput);
 | 
						|
			}
 | 
						|
		}
 | 
						|
 | 
						|
		char sHurtTrigger[64];
 | 
						|
		_Config.GetHurtTrigger(sHurtTrigger, sizeof(sHurtTrigger));
 | 
						|
 | 
						|
		if(sHurtTrigger[0])
 | 
						|
		{
 | 
						|
			Format(sHurtTrigger, sizeof(sHurtTrigger), "%s&%04d", sHurtTrigger, iTemplateNum);
 | 
						|
 | 
						|
			char sHurtOutput[64];
 | 
						|
			_Config.GetHurtOutput(sHurtOutput, sizeof(sHurtOutput));
 | 
						|
 | 
						|
			int entity = INVALID_ENT_REFERENCE;
 | 
						|
			while((entity = FindEntityByTargetname(entity, sHurtTrigger)) != INVALID_ENT_REFERENCE)
 | 
						|
			{
 | 
						|
				if(StrEqual(sHurtOutput, "OnTakeDamage"))
 | 
						|
				{
 | 
						|
					SDKHook(entity, SDKHook_OnTakeDamagePost, OnTakeDamagePostHurt);
 | 
						|
				}
 | 
						|
				else
 | 
						|
				{
 | 
						|
					HookSingleEntityOutput(entity, sHurtOutput, OnEntityOutputHurt);
 | 
						|
				}
 | 
						|
 | 
						|
				LogDebugMessage("Hooked hurttrigger %s:%s", sHurtTrigger, sHurtOutput);
 | 
						|
			}
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	char sBoss[64];
 | 
						|
	_Config.GetName(sBoss, sizeof(sBoss));
 | 
						|
	LogDebugMessage("Initialized boss %s (template = %d)", sBoss, iTemplateNum);
 | 
						|
 | 
						|
	Call_StartForward(g_hFwd_OnBossInitialized);
 | 
						|
	Call_PushCell(_Boss);
 | 
						|
	Call_PushCell(_Boss.dConfig);
 | 
						|
	Call_Finish();
 | 
						|
 | 
						|
	return true;
 | 
						|
}
 | 
						|
 | 
						|
bool BossProcess(CBoss _Boss)
 | 
						|
{
 | 
						|
	CConfig _Config = _Boss.dConfig;
 | 
						|
 | 
						|
	bool bInvalid = false;
 | 
						|
	int iHealth = 0;
 | 
						|
	int iLastHealth = _Boss.iHealth;
 | 
						|
	int iLastChange = _Boss.iLastChange;
 | 
						|
 | 
						|
	if(_Boss.IsBreakable)
 | 
						|
	{
 | 
						|
		CBossBreakable Boss = view_as<CBossBreakable>(_Boss);
 | 
						|
 | 
						|
		int iBreakableEnt = Boss.iBreakableEnt;
 | 
						|
 | 
						|
		if(IsValidEntity(iBreakableEnt))
 | 
						|
			iHealth = GetEntProp(iBreakableEnt, Prop_Data, "m_iHealth");
 | 
						|
		else
 | 
						|
			bInvalid = true;
 | 
						|
	}
 | 
						|
	else if(_Boss.IsCounter)
 | 
						|
	{
 | 
						|
		CBossCounter Boss = view_as<CBossCounter>(_Boss);
 | 
						|
		CConfigCounter Config = view_as<CConfigCounter>(_Config);
 | 
						|
 | 
						|
		int iCounterEnt = Boss.iCounterEnt;
 | 
						|
 | 
						|
		if(IsValidEntity(iCounterEnt))
 | 
						|
		{
 | 
						|
			int iCounterVal = RoundFloat(GetOutputValueFloat(iCounterEnt, "m_OutValue"));
 | 
						|
 | 
						|
			if(!Config.bCounterReverse)
 | 
						|
			{
 | 
						|
				int iCounterMin = RoundFloat(GetEntPropFloat(iCounterEnt, Prop_Data, "m_flMin"));
 | 
						|
				iHealth = iCounterVal - iCounterMin;
 | 
						|
			}
 | 
						|
			else
 | 
						|
			{
 | 
						|
				int iCounterMax = RoundFloat(GetEntPropFloat(iCounterEnt, Prop_Data, "m_flMax"));
 | 
						|
				iHealth = iCounterMax - iCounterVal;
 | 
						|
			}
 | 
						|
		}
 | 
						|
		else
 | 
						|
			bInvalid = true;
 | 
						|
	}
 | 
						|
	else if(_Boss.IsHPBar)
 | 
						|
	{
 | 
						|
		CBossHPBar Boss = view_as<CBossHPBar>(_Boss);
 | 
						|
		CConfigHPBar Config = view_as<CConfigHPBar>(_Config);
 | 
						|
 | 
						|
		int iIteratorEnt = Boss.iIteratorEnt;
 | 
						|
		int iCounterEnt = Boss.iCounterEnt;
 | 
						|
		int iBackupEnt = Boss.iBackupEnt;
 | 
						|
 | 
						|
		if(IsValidEntity(iIteratorEnt) && IsValidEntity(iCounterEnt) && IsValidEntity(iBackupEnt))
 | 
						|
		{
 | 
						|
			int iIteratorVal = RoundFloat(GetOutputValueFloat(iIteratorEnt, "m_OutValue"));
 | 
						|
			int iCounterVal = RoundFloat(GetOutputValueFloat(iCounterEnt, "m_OutValue"));
 | 
						|
			int iBackupVal = RoundFloat(GetOutputValueFloat(iBackupEnt, "m_OutValue"));
 | 
						|
 | 
						|
			if(!Config.bIteratorReverse)
 | 
						|
			{
 | 
						|
				int iIteratorMin = RoundFloat(GetEntPropFloat(iIteratorEnt, Prop_Data, "m_flMin"));
 | 
						|
				iHealth = (iIteratorVal - iIteratorMin - 1) * iBackupVal;
 | 
						|
			}
 | 
						|
			else
 | 
						|
			{
 | 
						|
				int iIteratorMax = RoundFloat(GetEntPropFloat(iIteratorEnt, Prop_Data, "m_flMax"));
 | 
						|
				iHealth = (iIteratorMax - iIteratorVal - 1) * iBackupVal;
 | 
						|
			}
 | 
						|
 | 
						|
			if(!Config.bCounterReverse)
 | 
						|
			{
 | 
						|
				int iCounterMin = RoundFloat(GetEntPropFloat(iCounterEnt, Prop_Data, "m_flMin"));
 | 
						|
				iHealth += iCounterVal - iCounterMin;
 | 
						|
			}
 | 
						|
			else
 | 
						|
			{
 | 
						|
				int iCounterMax = RoundFloat(GetEntPropFloat(iCounterEnt, Prop_Data, "m_flMax"));
 | 
						|
				iHealth += iCounterMax - iCounterVal;
 | 
						|
			}
 | 
						|
		}
 | 
						|
		else
 | 
						|
			bInvalid = true;
 | 
						|
	}
 | 
						|
 | 
						|
	if(iHealth < 0)
 | 
						|
		iHealth = 0;
 | 
						|
 | 
						|
	if(iHealth != iLastHealth)
 | 
						|
	{
 | 
						|
		iLastChange = GetTime();
 | 
						|
		_Boss.iLastChange = iLastChange;
 | 
						|
	}
 | 
						|
 | 
						|
	// Boss hasn't initialized HP yet.
 | 
						|
	if(iHealth == 0 && iLastHealth == 0)
 | 
						|
	{
 | 
						|
		// Boss invalid: Delete boss
 | 
						|
		if(bInvalid)
 | 
						|
			return false;
 | 
						|
 | 
						|
		return true;
 | 
						|
	}
 | 
						|
 | 
						|
	_Boss.iHealth = iHealth;
 | 
						|
 | 
						|
	bool bShow = _Boss.bShow;
 | 
						|
	if(!bShow && _Boss.fShowAt && _Boss.fShowAt < GetGameTime())
 | 
						|
	{
 | 
						|
		bShow = true;
 | 
						|
		_Boss.bShow = true;
 | 
						|
	}
 | 
						|
 | 
						|
	if(bShow)
 | 
						|
	{
 | 
						|
		int iTimeout = _Config.iTimeout;
 | 
						|
		if(iTimeout < 0 || GetTime() - iLastChange < iTimeout)
 | 
						|
		{
 | 
						|
			char sFormat[64];
 | 
						|
			if(g_sHUDText[0])
 | 
						|
			{
 | 
						|
				sFormat[0] = '\n';
 | 
						|
				_Config.GetName(sFormat[1], sizeof(sFormat) - 1);
 | 
						|
			}
 | 
						|
			else
 | 
						|
				_Config.GetName(sFormat, sizeof(sFormat));
 | 
						|
 | 
						|
			int FormatLen = strlen(sFormat);
 | 
						|
			sFormat[FormatLen++] = ':';
 | 
						|
			sFormat[FormatLen++] = ' ';
 | 
						|
 | 
						|
			FormatLen += IntToString(iHealth, sFormat[FormatLen], sizeof(sFormat) - FormatLen);
 | 
						|
			sFormat[FormatLen] = 0;
 | 
						|
 | 
						|
			StrCat(g_sHUDText, sizeof(g_sHUDText), sFormat);
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	// Boss dead/invalid: Delete boss
 | 
						|
	if(!iHealth || bInvalid)
 | 
						|
		return false;
 | 
						|
 | 
						|
	return true;
 | 
						|
}
 | 
						|
 | 
						|
int FindEntityByTargetname(int entity, const char[] sTargetname, const char[] sClassname="*")
 | 
						|
{
 | 
						|
	if(sTargetname[0] == '#') // HammerID
 | 
						|
	{
 | 
						|
		int HammerID = StringToInt(sTargetname[1]);
 | 
						|
 | 
						|
		while((entity = FindEntityByClassname(entity, sClassname)) != INVALID_ENT_REFERENCE)
 | 
						|
		{
 | 
						|
			if(GetEntProp(entity, Prop_Data, "m_iHammerID") == HammerID)
 | 
						|
				return entity;
 | 
						|
		}
 | 
						|
	}
 | 
						|
	else // Targetname
 | 
						|
	{
 | 
						|
		int Wildcard = FindCharInString(sTargetname, '*');
 | 
						|
		char sTargetnameBuf[64];
 | 
						|
 | 
						|
		while((entity = FindEntityByClassname(entity, sClassname)) != INVALID_ENT_REFERENCE)
 | 
						|
		{
 | 
						|
			if(GetEntPropString(entity, Prop_Data, "m_iName", sTargetnameBuf, sizeof(sTargetnameBuf)) <= 0)
 | 
						|
				continue;
 | 
						|
 | 
						|
			if(strncmp(sTargetnameBuf, sTargetname, Wildcard) == 0)
 | 
						|
				return entity;
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	return INVALID_ENT_REFERENCE;
 | 
						|
}
 |