/*
	This file has been recently reworked, and as such the Imp's brain is now *slightly* different. See imp_old.txt for the original version that
	was based on converted DECORATE code. I mean, this is too, but I redid the logic so it's not as awful.
*/
class BabelImp : SyncEnabledMonster Replaces DoomImp
{
	int user_loopCounter;
	int baseHealth;
	string chosenProjectile; //allows us to cut the number of attack states down significantly
	bool fireLeft; //controls fire arm switching
	default
	{
		Health 60;
		Radius 20;
		Height 56;
		Mass 100;
		Speed 8;
		PainChance 200;
		Monster;
		+FLOORCLIP;
		SeeSound "imp/sight";
		PainSound "imp/pain";
		DeathSound "imp/death";
		ActiveSound "imp/active";
		HitObituary "$OB_IMPHIT";
		Obituary "$OB_IMP";
		//custom
		+MISSILEMORE;
		+MISSILEEVENMORE;
		Species "Imp";
		ReactionTime 4;
		PainChance "PlayerPistol", 255;
		DamageType "Monster";
		Tag "Imp (Babel)";
		
		BabelMonster.FearEnabled		true;	//Imps have fear enabled
		BabelMonster.FearThreshold		280.0;	//Max fear before being scared, in "fear units"
		BabelMonster.FearMaxValue		350.0;	//Max fear they can hold, this is above the threshold because monsters can still gain fear when scared
		BabelMonster.FearFallOff		1.0;	//How quickly the monster loses fear when not scared. 1.0 is standard
		BabelMonster.FearRecovery		2.5;	//How quickly the monster loses fear when scared.
		BabelMonster.FearResistChance	30.0;	//Chance to avoid fear when crossing threshold 30% is fairly high, which counters the imp's low total capacity
		BabelMonster.SyncChainCheckLOS	true;	//Does this monster try to check Line of sight when synchronizing an attack?
		BabelMonster.AlternatePainSound	"imp/pain2";
	}
	
	override void BeginPlay()
	{
		super.BeginPlay();
		
		baseHealth = health;
		fireLeft = false;
		if(randompick(0, 1) == 0)
		{
			fireLeft = true;
		}
		chosenProjectile = "NormalBall"; //Turns out it's really easy to accidentally forget to assign this.
	}
	
	/*
		Generic logic for all missile decisions
	*/
	action state A_MissileThink(bool continuation = false)
	{
		let t = Actor(target);
		if(t)
		{
			if(t.health <= 0)
			{
				return ResolveState("See");
			}
			if(!CheckSight(t))
			{
				if(continuation && random[ImpBall](0, 7) > 0)
				{
					return ResolveState("TwoHandAttack");
				}
				return ResolveState("See");
			}
			double distanceToTarget = Distance3D(t);
			if(distanceToTarget < 128)
			{
				return ResolveState("TwoHandAttack");
			}
			else 
			{
				if(distanceToTarget >= 512)
				{
					if(continuation && random[ImpBall](0,3) == 0)
					{
						return ResolveState("See");
					}
					invoker.chosenProjectile = "FastBall";
				}
				else
				{
					if(continuation && random[ImpBall](0,7) == 0)
					{
						return ResolveState("See");
					}
					invoker.chosenProjectile = "NormalBall";
				}
				return ResolveState("OneHandMissile");
			}
		}
		else
		{
			//Console.Printf("Error: Imp had a null target.");
			return ResolveState("See");
		}
	}
	
	/*
		Generic Logic for all melee decisions
	*/
	action state A_MeleeThink()
	{
		if(random[ImpBall](0, 3) <= 1)
		{
			if(invoker.isHardest && random[ImpBall](0, 2) == 0)
			{
				invoker.chosenProjectile = "FastBall";
			}
			else
			{
				invoker.chosenProjectile = "NormalBall";
			}
			invoker.fireLeft = !invoker.fireLeft;
			if(invoker.fireLeft)
			{
				return ResolveState("OneHandMeleeLeft");
			}
			return ResolveState("OneHandMeleeRight");
		}
		return ResolveState("TwoHandAttack");
	}
	
	States
	{
	Spawn:
		TNT1 A 0 Nodelay 
		{
			return ResolveState("Look");
		}
	Wander:
		TROO AABBCCDD 3 Fast 
		{
			A_Wander();
			A_Look();
		}
		Loop;
	Look:
		TROO AB 10 A_Look();
		Loop;
	See:
		TNT1 A 0
		{
			ReleaseState();
			return JumpIfAfraid("Fear");
		}
		TROO AABBCCDD 3 Fast A_Chase();
		Goto See;
	Fear:
		//We are afraid
		TROO AABBCCDD 3 Fast
		{
			isAfraid = true;
			bFRIGHTENED = true;
			A_SetSpeed(10);
			A_Chase("Melee", null);
		}
		TNT1 A 0 JumpIfHasFear("Fear");
		//Now we've recovered from fear
		TNT1 A 0 
		{
			currentFear = 0;
			isAfraid = false;
			bFRIGHTENED = false;
			ResetGroupFear();
			A_SetSpeed(8);
		}
		Goto See;
	/* AI Attack Entry Points */
	Melee:
		TNT1 A 0
		{
			HoldState();
			return A_MeleeThink();
		}
	OneHandMeleeRight:
		TROO EF 6 A_FaceTarget();
		TROO G 6 A_CustomComboAttack(chosenProjectile, 32, 3 * random(1, 8), "imp/melee", "Monster");
		Goto See;
	OneHandMeleeLeft:
		TROO VW 6 A_FaceTarget();
		TROO X 6 A_CustomComboAttack(chosenProjectile, 32, 3 * random(1, 8), "imp/melee", "Monster");
		Goto See;
	TwoHandAttack: //Also a missile state
		TROA EF 6 A_FaceTarget();
		TROA G 6 A_CustomComboAttack("StrongBall", 32, 4 * random(1, 8), "imp/melee", "Monster");
		Goto See;
	Missile:
		TNT1 A 0 
		{
			TriggerSync(self.GetClassName(), 38.0);
		}
	MissileNoSignal:
		TNT1 A 0 
		{
			HoldState();
			return A_MissileThink();
		}
	MissileContinuationThink:
		TNT1 A 0 A_MissileThink(true);
		Goto See;
	OneHandMissile:
		TNT1 A 0
		{
			fireLeft = !fireLeft;
			if(fireLeft)
			{
				return ResolveState("OneHandMissileLeft");
			}
			return ResolveState("OneHandMissileRight");
		}
	OneHandMissileRight:
		TROO EF 6 A_FaceTarget();
		TROO G 6 A_CustomComboAttack(chosenProjectile, 32, 3 * random(1, 8), "imp/melee", "Monster");
		Goto MissileContinuationThink;
	OneHandMissileLeft:
		TROO VW 6 A_FaceTarget();
		TROO X 6 A_CustomComboAttack(chosenProjectile, 32, 3 * random(1, 8), "imp/melee", "Monster");
		Goto MissileContinuationThink;
	Pain:
		TROO H 2 Fast;
		TROO H 2 Fast A_BabelPain();
		TNT1 A 0 
		{
			currentFear += random(0, 35);
		}
		TNT1 A 0 JumpIfAfraid("Fear");
		Goto See;
	Death:
		TNT1 A 0 A_Jump(96, "Death.Monster");
		TNT1 A 0 TriggerSync(self.GetClassName(), 38.0);
	Death.Monster:
	XDeath.Massacre:
		TROO I 8;
		TROO J 8 A_Scream();
		TROO K 6;
		TROO L 6 A_NoBlocking;
		TROO M -1;
		Stop;
	XDeath:
		TNT1 A 0 A_Jump(96, "XDeath.Monster");
		TNT1 A 0 TriggerSync(self.GetClassName(), 38.0);
	XDeath.Monster:
		TNT1 A 0
		{
			if(CVar.FindCVar("egr_gore").GetInt())
			{
				for(user_loopCounter = 0; user_loopCounter < 4*CVar.FindCVar("egr_gore_level").GetInt(); user_loopCounter++)
				{
					
					A_SpawnProjectile("Bits", random(24, 48), random(-10, 10), random (0, 360), CMF_OFFSETPITCH, -random (0, 160));
					A_SpawnItemEx("BloodSpew", random(-10, 10), random(-10, 10), random(24, 56));
				}
				for(user_loopCounter = 0; user_loopCounter < CVar.FindCVar("egr_gore_level").GetInt()/2; user_loopCounter++)
				{
					A_SpawnProjectile("Chunks", random(24, 48), random(-10, 10), random (0, 360), CMF_OFFSETPITCH, -random (0, 160));
				}
			}
		}
		TROO N 5;
		TROO O 5 A_XScream();
		TROO P 5;
		TROO Q 5 A_NoBlocking;
		TROO RST 5;
		TROO U -1;
		Stop;
	Raise:
		TROO M 8 
		{
			A_SetSpeed(8);
		}
		TROO L 8;
		TROO KJI 6;
		Goto See;
	}
}

class NormalBall : BabelFastProjectile Replaces DoomImpBall
{
	default
	{
		Radius 6;
		Height 8;
		Speed 10;
		FastSpeed 20;
		Damage 3;
		Projectile;
		+RANDOMIZE;
		RenderStyle "Add";
		Alpha 1;
		SeeSound "imp/attack";
		DeathSound "imp/shotx";
		decal "DoomImpScorch";
		DamageType "Monster";
		
		BabelFastProjectile.HeightCorrection 1.0;
		BabelFastProjectile.LerpOffset 1.0;
		BabelFastProjectile.TrailDetail 1;
		BabelFastProjectile.ParticleColors 0xff0000, 0xff6600, 0xffaa00;
		BabelFastProjectile.ParticleSizeRange 2, 4;
		BabelFastProjectile.ParticleLifeTime 25, 35;
		BabelFastProjectile.ParticleCubeOffsets 2, 2;
		BabelFastProjectile.ParticleCubeAccelerations 0.1, 0.1;
		BabelFastProjectile.StartingAlpha 0.7;
	}
	
	States
	{
	Spawn:
		BAL1 AB 4 Bright;
		Loop;
	Death:
		TNT1 A 0 
		{
			trailSpawn = false;
		}
		BAL1 CDE 6 Bright;
		Stop;
	}
}

class StrongBall : NormalBall
{
	default
	{
		Radius 12;
		Height 16;
		Speed 8;
		FastSpeed 16;
		Damage 11;//6;
		Projectile;
		Scale 2;
		+RANDOMIZE;
		+STRIFEDAMAGE;
		RenderStyle "Add";
		Alpha 1;
		SeeSound "imp/attack";
		DeathSound "imp/shotx";
		decal "BigScorch";
		DamageType "Monster";
		
		BabelFastProjectile.ParticleSizeRange 2, 4;
		BabelFastProjectile.ParticleLifeTime 25, 35;
		BabelFastProjectile.ParticleCubeOffsets 5, 5;
		BabelFastProjectile.ParticleCubeAccelerations 0.1, 0.1;
	}
	
	States
	{
	Spawn:
		BAL1 AB 4 Bright;
		Loop;
	Death:
		TNT1 A 0 
		{
			trailSpawn = false;
		}
		BAL1 CDE 6 Bright;
		Stop;
	}
}

class FastBall : NormalBall
{
	default
	{
		Radius 5;
		Height 8;
		Speed 15;
		FastSpeed 30;
		Damage 2;
		Projectile;
		Scale 0.75;
		+RANDOMIZE;
		RenderStyle "Add";
		Alpha 1;
		SeeSound "imp/attack";
		DeathSound "imp/shotx";
		decal "PlasmaScorchLower";
		DamageType "Monster";
		
		BabelFastProjectile.LerpOffset 0.8;
		BabelFastProjectile.ParticleSizeRange 2, 3;
		BabelFastProjectile.ParticleLifeTime 25, 35;
		BabelFastProjectile.ParticleCubeOffsets 1, 1;
		BabelFastProjectile.ParticleCubeAccelerations 0.15, 0.15;
	}
	
	States
	{
	Spawn:
		BAL1 AB 4 Bright;
		Loop;
	Death:
		TNT1 A 0 
		{
			trailSpawn = false;
		}
		BAL1 CDE 6 Bright;
		Stop;
	}
}