class BabelArachnotron : BabelMonster Replaces Arachnotron
{
	default
	{
		Health 500;
		Radius 64;
		Height 64;
		Mass 600;
		Speed 12;
		Monster;
		+FLOORCLIP
		+BOSSDEATH
		SeeSound "baby/sight";
		PainSound "baby/pain";
		DeathSound "baby/death";
		ActiveSound "baby/active";
		Obituary "$OB_BABY";
		PainChance 64;
		Species "Spider";
		PainChance "PlayerPistol", 128;
		DamageType "Monster";
		Tag "Arachnotron (Babel)";
		
		BabelMonster.FearEnabled		true;
		BabelMonster.FearThreshold		700.0;
		BabelMonster.FearMaxValue		950.0;
		BabelMonster.FearFallOff		2.0;
		BabelMonster.FearRecovery		3.5;
		BabelMonster.FearResistChance	12.0;
		BabelMonster.AlternatePainSound	"baby/pain2";
		BabelMonster.SyncChainWakeDelay	20;
	}
	
	//This is a bad way to handle this but it works for now. Will improve later.
	bool CheckLowLOS()
	{
		if (!target)
		{
			return false;
		}
		FLineTraceData f;
		double dist2D = Distance2D(target);
		double range = Distance3D(target);
		bool hit = LineTrace(angle, range, atan((pos.z - target.pos.z)/dist2D), 0, 18.0, 0, 0, f);
		if(hit)
		{
			if(f.HitActor == target)
			{
				return true;
			}
			else
			{
				if(!f.HitActor)
				{
					//Console.Printf("Trying head-level hitscan");
					//Do another linetrace here from height 32
					if(LineTrace(angle, range, atan((pos.z - target.pos.z)/dist2D), 0, 32.0, 0, 0, f))
					{
						if(!f.HitActor)
						{
							//Console.Printf("Head-level hitscan also hit wall");
							return true;
						}
						//Console.Printf("Head-level hitscan hit actor.");
						return false;
					}
					//Console.Printf("Head-level hitscan hit nothing.");
					return false;
				}
				return true;
			}
		}
		else
		{
			double vecLen = (f.HitLocation-pos).Length() - range;
			if(vecLen < 16.0 && veclen > -16.0)
			{
				return true;
			}
		}
		return false;
	}
	
	action void A_ArachnotronSpread(double spawnheight, double spawnofs_xy, double side_angle)
	{
		let mid = invoker.A_SpawnProjectile("ArachnotronPlasma", spawnheight, spawnofs_xy, 0);
		let left = SideParticleArachnotronPlasma(invoker.A_SpawnProjectile("SideParticleArachnotronPlasma", spawnheight, spawnofs_xy, -side_angle));
		let right = SideParticleArachnotronPlasma(invoker.A_SpawnProjectile("SideParticleArachnotronPlasma", spawnheight, spawnofs_xy, side_angle));
		left.midVelocity = mid.vel;
		right.midVelocity = mid.vel;
	}
	
	States
	{
	Spawn:
		TNT1 A 0 Nodelay 
		{
			if(isHardest)
			{
				return ResolveState("Wander");
			}
			return ResolveState("Look");
		}
	Wander:
		BSPI A 3 Fast A_BabyMetal;
		BSPI ABBCC 3 Fast 
		{
			A_Wander();
			A_Look();
		}
		BSPI D 3 Fast A_BabyMetal;
		BSPI DEEFF 3 Fast 
		{
			A_Wander();
			A_Look();
		}
		Loop;
	Look:
		BSPI AB 10 A_Look();
		Loop;
	See:
		BSPI A 20 Fast ReleaseState();
	WalkLoop:
		TNT1 A 0 
		{
			ReleaseState();
			return JumpIfAfraid("Fear");
		}
		BSPI A 3 Fast A_BabyMetal();
		BSPI ABBCC 3 Fast A_Chase();
		BSPI D 3 Fast A_BabyMetal();
		BSPI DEEFF 3 Fast A_Chase();
		Goto WalkLoop;
	Fear:
		BSPI A 3 Fast
		{
			bFRIGHTENED = true;
			isAfraid = true;
			A_SetSpeed(15);
			A_PlaySound("baby/walk");
			A_Chase(null, null);
		}
		BSPI ABBCC 3 Fast
		{
			bFRIGHTENED = true;
			isAfraid = true;
			A_SetSpeed(15);
			A_Chase(null, null);
		}
		BSPI D 3 Fast
		{
			bFRIGHTENED = true;
			isAfraid = true;
			A_SetSpeed(15);
			A_PlaySound("baby/walk");
			A_Chase(null, null);
		}
		BSPI DEEFF 3 Fast
		{
			bFRIGHTENED = true;
			isAfraid = true;
			A_SetSpeed(15);
			A_Chase(null, null);
		}
		TNT1 A 0 JumpIfHasFear("Fear");
		
		TNT1 A 0 
		{
			currentFear = 0;
			isAfraid = false;
			bFRIGHTENED = false;
			ResetGroupFear();
			A_SetSpeed(12);
		}
		Goto WalkLoop;
		
		
		
	Missile:
		/* Arachnotron gives a fire signal to humans */
		TNT1 A 0 
		{
			TriggerSync("BabelZombieMan", 50.0);
			TriggerSync("BabelChaingunGuy", 50.0);
			TriggerSync("BabelShotgunGuy", 50.0);
			TriggerSync("BabelNazi", 75.0);
			HoldState();
		}
	WindUp:
		BSPI A 20 Fast Bright A_FaceTarget();
	FireLoop:
		TNT1 A 0 A_Jump(256, 2);
		TNT1 A 0 A_JumpIfCloser(512, "Burst");
	FireLine:
		BSPI GGG 1 Bright
		{
			//Compatibility switch
			if(CVar.FindCVar("egr_default_projectile_origins").GetInt() == 1)
			{
				A_SpawnProjectile("ArachnotronPlasma");
			}
			else
			{
				if(CheckLowLOS())
				{
					A_SpawnProjectile("ArachnotronPlasma", 18, 6);
				}
				else
				{
					A_SpawnProjectile("ArachnotronPlasma");
				}
			}
		}
		BSPI H 7 Bright;
		BSPI H 1 Bright A_SpidRefire;
		Goto FireLoop+1;
	Burst:
		BSPI G 6 Bright 
		{
			//Compatibility switch
			if(CVar.FindCVar("egr_default_projectile_origins").GetInt() == 1)
			{
				A_ArachnotronSpread(32, 0, 10);
			}
			else
			{
				if(CheckLowLOS())
				{
					A_ArachnotronSpread(18, 6, 10);
				}
				else
				{
					A_ArachnotronSpread(32, 0, 10);
				}
			}
		}
		BSPI H 2 Bright;
		BSPI H 1 Bright A_SpidRefire;
		Goto FireLoop+1;
	Pain:
		BSPI I 3 Fast;
		BSPI I 3 Fast A_BabelPain();
		TNT1 A 0 AddFear(random(0,95));
		TNT1 A 0 JumpIfAfraid("Fear");
		Goto WalkLoop;
	Death.Massacre:
		BSPI J 20 A_Scream();
		BSPI K 7 A_NoBlocking;
		BSPI LMNO 7;
		BSPI P -1 A_BossDeath;
		Stop;
	Death:
		TNT1 A 0 ScareOthers("BabelMonster", random(171,475));
		TNT1 A 0 A_Jump(192, "Death.Monster");
		TNT1 A 0 
		{
			TriggerSync("BabelZombieMan", 25.0);
			TriggerSync("BabelChaingunGuy", 35.0);
			TriggerSync("BabelShotgunGuy", 30.0);
			TriggerSync("BabelNazi", 75.0);
			TriggerSync("BabelDemon", 40.0);
			TriggerSync("BabelImp", 35.0);
			TriggerSync("BabelCacodemon", 55.0);
			
			TriggerChain("BabelRevenant", 25.0);
			TriggerChain("BabelFatso", 25.0);
		}
	Death.Monster:
		TNT1 A 0 A_Scream();
		TNT1 AAAAA 0
		{
			if(CVar.FindCVar("egr_gore").GetInt())
			{
				A_SpawnProjectile("Bits", random(24, 48), random(-16, 16), random (0, 360), CMF_OFFSETPITCH, -random (0, 160));
				A_SpawnItemEx("BloodSpew", random(-16, 16), random(-16, 16), random(24, 64));
				if(random(0, 1))
				{
					A_SpawnProjectile("Chunks", random(24, 48), random(-16, 16), random (0, 360), CMF_OFFSETPITCH, -random (0, 160));
				}
			}
		}
		BSPI J 20 ;
		BSPI K 7 A_NoBlocking;
		BSPI LMNO 7;
		BSPI P -1 A_BossDeath;
		Stop;
	Raise:
		BSPI P 5 
		{
			A_SetSpeed(12);
		}
		BSPI ONMLKJ 5;
		Goto WalkLoop;
	}
}

class ParticleArachnotronPlasma : BabelFastProjectile Replaces ArachnotronPlasma
{
	default
	{
		Radius 13;
		Height 8;
		Speed 25;
		//Damage 5;
		DamageFunction (randompick(5,10,15,15, 20,20,20,20, 25,25,30,35));
		Projectile;
		+RANDOMIZE;
		RenderStyle "Add";
		Alpha 0.75;
		SeeSound "baby/attack";
		DeathSound "baby/shotx";
		decal "ArachnotronScorch";
		DamageType "Monster";
		
		BabelFastProjectile.ParticleColors 0xccff66, 0xccff66, 0x99ff33;
		BabelFastProjectile.ParticleSizeRange 3, 6;
		BabelFastProjectile.ParticleLifeTime 15, 20;
		BabelFastProjectile.ParticleCubeOffsets 2, 2;
		BabelFastProjectile.ParticleCubeAccelerations 0.05, 0.05;
		BabelFastProjectile.LerpOffset 0.6;
		BabelFastProjectile.TrailDetail 1;
		BabelFastProjectile.HeightCorrection 2.0;
		BabelFastProjectile.StartingAlpha 0.98;
	}
	
	States
	{
	Spawn:
		APLS AB 5 Bright;
		Loop;
	Crash:
	XDeath:
	Death:
		TNT1 A 0
		{
			trailSpawn = false;
		}
		APBX ABCDE 3 Bright;
		Stop;
	}
}


class SideParticleArachnotronPlasma : ParticleArachnotronPlasma
{
	Vector3 midVelocity;
	int framesBeforeVelAdjust;
	bool adjusted;
	override void BeginPlay()
	{
		super.BeginPlay();
		framesBeforeVelAdjust = 15;
		adjusted = false; //optimization, probably
	}
	override void Tick()
	{
		if(!adjusted)
		{
			if(framesBeforeVelAdjust > 0)
			{
				framesBeforeVelAdjust--;
			}
			else
			{
				self.velStore = midVelocity; //adjust trails to match
				self.vel = midVelocity;
				adjusted = true;
			}
		}
		super.Tick();
	}
}