/*
* 怪物实体属性修改器 / Monster entity attribute modifier
* 作者(Author): Ice Box
* Steam: https://steamcommunity.com/id/ibox666/
* 如需使用此脚本请联系作者 / If you need to use this script, please contact the author
*/

namespace PointMonsterModifier
{

const int SF_START_OFF = 1 << 0;
const int SF_PASS_ACTIVATOR = 1 << 1;
const int SF_TRIGGER_ONCE = 1 << 2;
const int SF_MATCH_CLASSNAME = 1 << 3;
const int SF_REMOVE_ON_USE = 1 << 4;

const bool DEBUG_MODE = false;

const int MAX_KEYVALUE_PAIRS = 5;

class KeyValuePair
{
	string key;
	string value;

	KeyValuePair()
	{
		key = "";
		value = "";
	}

	KeyValuePair(const string& in k, const string& in v)
	{
		key = k;
		value = v;
	}

	bool IsValid()
	{
		return key != "" && value != "";
	}
}

class CPointMonsterModifier : ScriptBaseEntity
{
	private bool m_bEnabled = true;
	private bool m_bHasTriggered = false;
	private float m_flDelay = 0.0;
	private string m_szMonsterTargetname = "";
	private string m_szKillTarget = "";
	private array<KeyValuePair> m_KeyValuePairs;
	private EHandle m_hActivator;

	bool KeyValue(const string& in szKey, const string& in szValue)
	{
		if(szKey == "monster_targetname")
		{
			m_szMonsterTargetname = szValue;
			return true;
		}
		else if(szKey == "delay")
		{
			m_flDelay = atof(szValue);
			if(m_flDelay < 0)
				m_flDelay = 0.0;
			return true;
		}
		else if(szKey == "killtarget")
		{
			m_szKillTarget = szValue;
			return true;
		}
		else if(szKey.Length() >= 4)
		{
			if(szKey.SubString(0, 3) == "key")
			{
				string numStr = szKey.SubString(3);
				int num = atoi(numStr);

				if(num >= 1 && num <= MAX_KEYVALUE_PAIRS)
				{
					while(int(m_KeyValuePairs.length()) < num)
					{
						m_KeyValuePairs.insertLast(KeyValuePair());
					}

					m_KeyValuePairs[num - 1].key = szValue;

					return true;
				}
			}
			else if(szKey.SubString(0, 5) == "value")
			{
				string numStr = szKey.SubString(5);
				int num = atoi(numStr);

				if(num >= 1 && num <= MAX_KEYVALUE_PAIRS)
				{
					while(int(m_KeyValuePairs.length()) < num)
					{
						m_KeyValuePairs.insertLast(KeyValuePair());
					}

					m_KeyValuePairs[num - 1].value = 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;

		g_EntityFuncs.SetOrigin(self, self.pev.origin);

		if(self.pev.SpawnFlagBitSet(SF_START_OFF))
		{
			m_bEnabled = false;
		}
	}

	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;
				return;
			}
			case USE_KILL:
			{
				g_EntityFuncs.Remove(self);
				return;
			}
		}

		if(!m_bEnabled)
		{
			return;
		}

		if(self.pev.SpawnFlagBitSet(SF_TRIGGER_ONCE) && m_bHasTriggered)
		{
			return;
		}

		if(pActivator is null)
		{
			return;
		}

		if(pActivator.IsPlayer())
		{
			return;
		}

		string activatorTargetname = pActivator.GetTargetname();
		if(m_szMonsterTargetname != "" && activatorTargetname != m_szMonsterTargetname)
		{
			return;
		}

		if(self.pev.SpawnFlagBitSet(SF_MATCH_CLASSNAME))
		{
			string classname = pActivator.pev.classname;
			if(classname.Length() < 8 || classname.SubString(0, 8) != "monster_")
			{
				return;
			}
		}

		m_bHasTriggered = true;

		m_hActivator = EHandle(pActivator);

		if(m_flDelay > 0)
		{
			g_Scheduler.SetTimeout(this, "DelayedModify", m_flDelay);
		}
		else
		{
			ModifyMonster();
		}
	}

	void DelayedModify()
	{
		ModifyMonster();
	}

	void ModifyMonster()
	{
		CBaseEntity@ pMonster = m_hActivator.GetEntity();

		if(pMonster is null)
		{
			return;
		}

		int modifiedCount = 0;
		for(uint i = 0; i < m_KeyValuePairs.length(); i++)
		{
			if(!m_KeyValuePairs[i].IsValid())
				continue;

			string key = m_KeyValuePairs[i].key;
			string value = m_KeyValuePairs[i].value;

			bool success = ApplyKeyValue(pMonster, key, value);

			if(success)
				modifiedCount++;
		}

		if(m_szKillTarget != "")
		{
			CBaseEntity@ pKillEntity = null;

			while((@pKillEntity = g_EntityFuncs.FindEntityByTargetname(pKillEntity, m_szKillTarget)) !is null)
			{
				g_EntityFuncs.Remove(pKillEntity);
			}
		}

		if(self.pev.target != "" && self.pev.target != self.GetTargetname())
		{
			CBaseEntity@ pActivator = null;

			if(self.pev.SpawnFlagBitSet(SF_PASS_ACTIVATOR))
			{
				@pActivator = pMonster;
			}

			g_EntityFuncs.FireTargets(self.pev.target, pActivator, self, USE_TOGGLE, 0.0f);
		}
		
		if((self.pev.spawnflags & SF_REMOVE_ON_USE) != 0)
		{
			g_EntityFuncs.Remove(self);
		}
	}

	bool ApplyKeyValue(CBaseEntity@ pEntity, const string& in key, const string& in value)
	{
		if(pEntity is null || key == "" || value == "")
			return false;

		if(key == "health")
		{
			float newHealth = atof(value);
			pEntity.pev.health = newHealth;
			pEntity.pev.max_health = newHealth;

			return true;
		}
		else if(key == "max_health")
		{
			pEntity.pev.max_health = atof(value);
			return true;
		}
		else if(key == "model")
		{
			g_EntityFuncs.SetModel(pEntity, value);
			return true;
		}
		else if(key == "scale")
		{
			pEntity.pev.scale = atof(value);
			return true;
		}
		else if(key == "rendermode")
		{
			pEntity.pev.rendermode = atoi(value);
			return true;
		}
		else if(key == "renderamt")
		{
			pEntity.pev.renderamt = atof(value);
			return true;
		}
		else if(key == "rendercolor")
		{
			array<string> rgb = value.Split(" ");
			if(rgb.length() >= 3)
			{
				pEntity.pev.rendercolor.x = atof(rgb[0]);
				pEntity.pev.rendercolor.y = atof(rgb[1]);
				pEntity.pev.rendercolor.z = atof(rgb[2]);
				return true;
			}
			return false;
		}
		else if(key == "skin")
		{
			pEntity.pev.skin = atoi(value);
			return true;
		}
		else if(key == "body")
		{
			pEntity.pev.body = atoi(value);
			return true;
		}
		else if(key == "speed")
		{
			pEntity.pev.speed = atof(value);
			return true;
		}
		else if(key == "targetname")
		{
			pEntity.pev.targetname = value;
			return true;
		}
		else if(key == "target")
		{
			pEntity.pev.target = value;
			return true;
		}
		else if(key == "netname")
		{
			pEntity.pev.netname = value;
			return true;
		}
		else if(key == "message")
		{
			pEntity.pev.message = value;
			return true;
		}
		else
		{
			return false;
		}
	}

	void UpdateOnRemove()
	{
		m_bEnabled = false;

		BaseClass.UpdateOnRemove();
	}
}

void Register()
{
	g_CustomEntityFuncs.RegisterCustomEntity("PointMonsterModifier::CPointMonsterModifier", "point_monster_modifier");
}

}