namespace BP
{
	//Control Lock Flags
	const uint CLF_WEAPON = 1 << 0;
	const uint CLF_AILMENT = 1 << 1;
	const uint CLF_CUTSCENE = 1 << 2;
	
	//Move Lock Flags
	const uint MLF_WEAPON = 1 << 0;
	const uint MLF_AILMENT = 1 << 1;
	const uint MLF_CUTSCENE = 1 << 2;
	
	//noWeaponFlags
	const uint NWF_CUTSCENE = 1 << 0;
	
	namespace LocalPlayer
	{
		const array<kStr> KillTaunts = { "A003", "A004", "A005", "A006", "A007", "A009", "A012", "A013", "A017", "A021", "A025",
			"A026", "A030", "A032", "A036", "A038", "A040", "A041", "A042", "A046", "A048", "A050", "D008", "V002", "V003",
			"V004", "V005",	"V006", "V009", "V010", "V012", "V013", "V014" };
		const array<kStr> DeathTaunts = { "A015", "A018", "A022", "A043", "A044", "A047", "D001", "D002", "D003", "D005",
			"D007", "D009", "D011", "D013" };
		const array<kStr> HurtTaunts = { "A001", "A007", "A023", "A002", "A016", "A028", "A033", "D004", "D006", "D014" };
		
		const float TAUNT_MAX_TIME = 3.5f; //time before any taunt can be played again
		const float TAUNT_KILL_CHANCE = 0.35f; //chance of triggering the taunt (1.0f = 100% chance)
		const int TAUNT_HURT_COUNT = 2; //number of times before the taunt has a chance to play again
		const float TAUNT_HURT_CHANCE = 0.2f; //chance of triggering the taunt (1.0f = 100% chance)
		
		kActor@ Actor;
		BP::Player@ Script;
		uint controlLockFlags; //Serialize
		uint moveLockFlags; //Serialize
		uint noWeaponFlags; //Serialize
		
		array<int> availKillTaunts;
		array<int> availDeathTaunts;
		array<int> availHurtTaunts;
		float tauntTime;
		int hurtTauntCount;
		//------------------------------------------------------------------------------------------------------------------------
		void ScreenFlash(const float red = 0.0f, const float green = 0.0f, const float blue = 0.0f, const float alpha = 255.0f,
							const float attackTime = 0.0f, const float sustainTime = 0.0f, const float decayTime = 0.0f)
		{
			//kVec3 flashPos = BP::Actor::CenterOrigin(@Actor, 0.75f) + BP::Actor::Forward(@Actor) * 1000.0f;
			Event.RunAction(@Actor, null, ACTION_SCREEN_FLASH, Actor.Origin(), alpha, red, green, blue, attackTime, sustainTime, decayTime);
		}
		//------------------------------------------------------------------------------------------------------------------------
		bool IsNoWeapon()
		{
			return BP::UI::isMenuOpen || noWeaponFlags > 0;
		}
		//------------------------------------------------------------------------------------------------------------------------
		void NoWeapon(const uint nwfFlag, const bool noWeapon)
		{
			if (noWeapon)
			{
				noWeaponFlags |= nwfFlag;
			}
			else
			{
				noWeaponFlags &= ~nwfFlag;
			}
		}
		//------------------------------------------------------------------------------------------------------------------------
		bool IsControlsLocked()
		{
			return BP::UI::isMenuOpen || controlLockFlags > 0;
		}
		//------------------------------------------------------------------------------------------------------------------------
		void LockControls(kWeapon@ weapon, const uint clfFlag, const bool controlLock)
		{
			if (controlLock)
			{
				controlLockFlags |= clfFlag;
			}
			else
			{
				controlLockFlags &= ~clfFlag;
			}
			
			if (IsControlsLocked())
			{
				weapon.LockControls(true);
			}
			else
			{
				weapon.LockControls(false);
			}
		}
		//------------------------------------------------------------------------------------------------------------------------
		bool IsMovementLocked()
		{
			return BP::UI::isMenuOpen || moveLockFlags > 0;
		}
		//------------------------------------------------------------------------------------------------------------------------
		void LockMovement(const uint mlfFlag, const bool moveLock)
		{
			if (moveLock)
			{
				moveLockFlags |= mlfFlag;
			}
			else
			{
				moveLockFlags &= ~mlfFlag;
			}
		}
		//------------------------------------------------------------------------------------------------------------------------
		bool CanPlayTaunt()
		{
			return tauntTime <= 0.0f;
		}
		//------------------------------------------------------------------------------------------------------------------------
		kVec3 ViewHeightPosition()
		{
			float pHeight = ((LocalPlayer.Actor().PlayerFlags() & PF_CRAWLING) != 0) ? 50.0f : 100.0f;
			return Actor.Origin() + kVec3(0.0f, 0.0f, pHeight);
		}
		//------------------------------------------------------------------------------------------------------------------------
		kVec3 ViewHeight()
		{
			float pHeight = ((LocalPlayer.Actor().PlayerFlags() & PF_CRAWLING) != 0) ? 50.0f : 100.0f;
			return kVec3(0.0f, 0.0f, pHeight);
		}
		//------------------------------------------------------------------------------------------------------------------------
		void PlayKillTaunt(const bool forcePlay = false)
		{
			if (forcePlay || (CanPlayTaunt() && Math::RandFloat() <= TAUNT_KILL_CHANCE))
			{
				tauntTime = TAUNT_MAX_TIME;
				Actor.PlaySound("sounds/shaders/BP/TalSet/TalSet" + BP::Array::GetUniqueElement(KillTaunts, availKillTaunts) + ".ksnd");
			}
		}
		//------------------------------------------------------------------------------------------------------------------------
		void PlayDeathTaunt(const bool forcePlay = false)
		{
			if (forcePlay || CanPlayTaunt())
			{
				tauntTime = TAUNT_MAX_TIME;
				Actor.PlaySound("sounds/shaders/BP/TalSet/TalSet" + BP::Array::GetUniqueElement(DeathTaunts, availDeathTaunts) + ".ksnd");
			}
		}
		//------------------------------------------------------------------------------------------------------------------------
		void PlayHurtTaunt(const bool forcePlay = false)
		{
			hurtTauntCount = MIN(hurtTauntCount + 1, TAUNT_HURT_COUNT);
			if (forcePlay || (CanPlayTaunt() && !BP::Actor::IsDead(Actor) && hurtTauntCount == TAUNT_HURT_COUNT &&
				Math::RandFloat() <= TAUNT_HURT_CHANCE))
			{
				hurtTauntCount = 0;
				tauntTime = TAUNT_MAX_TIME;
				Actor.PlaySound("sounds/shaders/BP/TalSet/TalSet" + BP::Array::GetUniqueElement(HurtTaunts, availHurtTaunts) + ".ksnd");
			}
		}
		//------------------------------------------------------------------------------------------------------------------------
		void GiveHealth(const float amount)
		{
			if (Actor.Health() > 0.0f)
			{
				Actor.Health() = MIN(Actor.Health() + amount, BP::Game::playerMaxHealth);
			}
		}
		//------------------------------------------------------------------------------------------------------------------------
		bool HasFullHealth()
		{
			return Actor.Health() >= BP::Game::playerMaxHealth;
		}
		//------------------------------------------------------------------------------------------------------------------------
	}
}
