/*
* 自定义倒计时实体 / Custom countdown timer entity
* 作者(Author): Ice Box
* Steam: https://steamcommunity.com/id/ibox666/
* 如需使用此脚本请联系作者 / If you need to use this script, please contact the author
*/

namespace PointCountdown
{

const int SF_START_OFF = 1 << 0;
const int SF_PASS_ACTIVATOR = 1 << 1;
const int SF_TRIGGER_ONCE = 1 << 2;
const int SF_SHOW_PROGRESS = 1 << 3;
const int SF_REMOVE_ON_USE = 1 << 4;

class CPointCountdown : ScriptBaseEntity
{
	private bool m_bEnabled = true;
	private bool m_bHasTriggered = false;
	private bool m_bCountingDown = false;
	private float m_flCountdownTime = 10.0;
	private float m_flDelay = 0.0;
	private float m_flStartTime = 0.0;
	private string m_szKillTarget = "";
	private string m_szDisplayText = "Time Remaining:";
	private int m_iMessageType = -1;
	private EHandle m_hActivator;
	private CScheduledFunction@ m_pCountdownThink;
	private CScheduledFunction@ m_pProgressThink;
	private CScheduledFunction@ m_pDelayedTrigger;

	bool KeyValue(const string& in szKey, const string& in szValue)
	{
		if(szKey == "countdown_time")
		{
			m_flCountdownTime = atof(szValue);
			if(m_flCountdownTime <= 0.0)
				m_flCountdownTime = 10.0;
			return true;
		}
		else if(szKey == "delay")
		{
			m_flDelay = atof(szValue);
			if(m_flDelay < 0.0)
				m_flDelay = 0.0;
			return true;
		}
		else if(szKey == "killtarget")
		{
			m_szKillTarget = szValue;
			return true;
		}
		else if(szKey == "display_text")
		{
			m_szDisplayText = szValue;
			return true;
		}
		else if(szKey == "message_type")
		{
			m_iMessageType = atoi(szValue);
			return true;
		}

		return BaseClass.KeyValue(szKey, szValue);
	}

	void Spawn()
	{
		self.pev.solid = SOLID_NOT;
		self.pev.movetype = MOVETYPE_NONE;
		self.pev.effects |= EF_NODRAW;
		
		if((self.pev.spawnflags & SF_START_OFF) != 0)
		{
			m_bEnabled = false;
		}
	}

	void UpdateOnRemove()
	{
		if(m_pCountdownThink !is null)
		{
			g_Scheduler.RemoveTimer(m_pCountdownThink);
			@m_pCountdownThink = null;
		}
		
		if(m_pProgressThink !is null)
		{
			g_Scheduler.RemoveTimer(m_pProgressThink);
			@m_pProgressThink = null;
		}
		
		if(m_pDelayedTrigger !is null)
		{
			g_Scheduler.RemoveTimer(m_pDelayedTrigger);
			@m_pDelayedTrigger = null;
		}
		
		BaseClass.UpdateOnRemove();
	}

	void Use(CBaseEntity@ pActivator, CBaseEntity@ pCaller, USE_TYPE useType, float flValue)
	{
		switch(useType)
		{
			case USE_ON:
			{
				m_bEnabled = true;
				return;
			}
			case USE_OFF:
			{
				m_bEnabled = false;
				StopCountdown();
				return;
			}
			case USE_KILL:
			{
				g_EntityFuncs.Remove(self);
				return;
			}
			case USE_SET:
			{
				if(!m_bEnabled)
				{
					return;
				}

				m_bHasTriggered = false;
				StartCountdown(pActivator);
				return;
			}
		}

		if(!m_bEnabled)
		{
			return;
		}

		if(m_bCountingDown)
		{
			return;
		}

		if((self.pev.spawnflags & SF_TRIGGER_ONCE) != 0 && m_bHasTriggered)
		{
			return;
		}

		StartCountdown(pActivator);
	}

	void StartCountdown(CBaseEntity@ pActivator)
	{
		if(pActivator !is null)
		{
			m_hActivator = EHandle(pActivator);
		}
		
		StopCountdown();
		
		m_bCountingDown = true;
		m_flStartTime = g_Engine.time;
		
		@m_pCountdownThink = g_Scheduler.SetTimeout(this, "CountdownFinished", m_flCountdownTime);
		
		if((self.pev.spawnflags & SF_SHOW_PROGRESS) != 0)
		{
			@m_pProgressThink = g_Scheduler.SetInterval(this, "ShowProgress", 1.0);
		}
	}

	void StopCountdown()
	{
		if(!m_bCountingDown)
			return;
		
		m_bCountingDown = false;
		
		if(m_pCountdownThink !is null)
		{
			g_Scheduler.RemoveTimer(m_pCountdownThink);
			@m_pCountdownThink = null;
		}
		
		if(m_pProgressThink !is null)
		{
			g_Scheduler.RemoveTimer(m_pProgressThink);
			@m_pProgressThink = null;
		}
		
		if(m_pDelayedTrigger !is null)
		{
			g_Scheduler.RemoveTimer(m_pDelayedTrigger);
			@m_pDelayedTrigger = null;
		}
	}

	void CountdownFinished()
	{
		m_bCountingDown = false;
		m_bHasTriggered = true;

		if(m_pProgressThink !is null)
		{
			g_Scheduler.RemoveTimer(m_pProgressThink);
			@m_pProgressThink = null;
		}

		string szMessage = string(self.pev.message);
		if(szMessage != "")
		{
			switch(m_iMessageType)
			{
				case 0:
				{
					g_PlayerFuncs.ClientPrintAll(HUD_PRINTTALK, szMessage + "\n");
					break;
				}
				case 1:
				{
					g_PlayerFuncs.ClientPrintAll(HUD_PRINTCONSOLE, szMessage + "\n");
					break;
				}
				case 2:
				{
					g_PlayerFuncs.ClientPrintAll(HUD_PRINTCENTER, szMessage + "\n");
					break;
				}
				case 3:
				{
					g_PlayerFuncs.ClientPrintAll(HUD_PRINTNOTIFY, szMessage + "\n");
					break;
				}
				default:
				{
					HUDTextParams textParams;
					textParams.x = -1.0;
					textParams.y = 0.15;
					textParams.effect = 0;
					textParams.r1 = 255;
					textParams.g1 = 255;
					textParams.b1 = 255;
					textParams.a1 = 255;
					textParams.r2 = 255;
					textParams.g2 = 255;
					textParams.b2 = 255;
					textParams.a2 = 255;
					textParams.fadeinTime = 0.0;
					textParams.fadeoutTime = 0.5;
					textParams.holdTime = 3.0;
					textParams.fxTime = 0.0;
					textParams.channel = 3;

					g_PlayerFuncs.HudMessageAll(textParams, szMessage);
					break;
				}
			}
		}
		
		if(m_flDelay > 0.0)
		{
			@m_pDelayedTrigger = g_Scheduler.SetTimeout(this, "DelayedTrigger", m_flDelay);
		}
		else
		{
			DelayedTrigger();
		}
	}

	void DelayedTrigger()
	{
		CBaseEntity@ pActivator = null;
		if((self.pev.spawnflags & SF_PASS_ACTIVATOR) != 0)
		{
			@pActivator = m_hActivator.GetEntity();
		}
		
		if(self.pev.target != "")
		{
			g_EntityFuncs.FireTargets(string(self.pev.target), pActivator, self, USE_TOGGLE, 0.0);
		}
		
		if(m_szKillTarget != "")
		{
			CBaseEntity@ pKillTarget = null;
			while((@pKillTarget = g_EntityFuncs.FindEntityByTargetname(pKillTarget, m_szKillTarget)) !is null)
			{
				g_EntityFuncs.Remove(pKillTarget);
			}
		}
		
		if((self.pev.spawnflags & SF_REMOVE_ON_USE) != 0)
		{
			g_EntityFuncs.Remove(self);
		}
	}

	void ShowProgress()
	{
		if(!m_bCountingDown)
			return;

		float flElapsed = g_Engine.time - m_flStartTime;
		float flRemaining = m_flCountdownTime - flElapsed;

		if(flRemaining <= 0.0)
		{
			flRemaining = 0.0;
		}

		int totalSeconds = int(Math.Ceil(flRemaining));
		int minutes = totalSeconds / 60;
		int seconds = totalSeconds % 60;

		string progressMsg = m_szDisplayText + " ";

		if(minutes > 0)
		{
			progressMsg += string(minutes) + " minute" + (minutes != 1 ? "s" : "");
			progressMsg += " " + string(seconds) + " second" + (seconds != 1 ? "s" : "");
		}
		else
		{
			progressMsg += string(seconds) + " second" + (seconds != 1 ? "s" : "");
		}

		HUDTextParams textParams;
		textParams.x = -1.0;
		textParams.y = 0.15;
		textParams.effect = 0;
		textParams.r1 = 255;
		textParams.g1 = 255;
		textParams.b1 = 255;
		textParams.a1 = 255;
		textParams.r2 = 255;
		textParams.g2 = 255;
		textParams.b2 = 255;
		textParams.a2 = 255;
		textParams.fadeinTime = 0.0;
		textParams.fadeoutTime = 0.0;
		textParams.holdTime = 1.1;
		textParams.fxTime = 0.0;
		textParams.channel = 3;

		g_PlayerFuncs.HudMessageAll(textParams, progressMsg);
	}
}

void Register()
{
	g_CustomEntityFuncs.RegisterCustomEntity("PointCountdown::CPointCountdown", "point_countdown");
}

}