class JuggernautBody: Actor
{
	default
	{
		+THRUACTORS
		+NOGRAVITY
		+NOCLIP
		species "mancubus";
		radius 112;
		height 40;
		speed 0;
		Scale 1.5;
	}
	states
	{
	spawn:
		BS1T A 2 { A_SetRenderStyle(1.0, STYLE_None); }
		loop;
	standby:
		BS1T A 1 { A_SetRenderStyle(1.0, STYLE_Normal); }
		goto standby;
	fire_fast:
		BS1T A 2 { A_SetRenderStyle(1.0, STYLE_Normal); A_FaceTarget(); }
		goto fire_loop;
	fire:
		BS1T A 8 { A_SetRenderStyle(1.0, STYLE_Normal); A_FaceTarget(); }
	fire_loop:
		BS1T B 1 { A_SetRenderStyle(1.0, STYLE_Normal); A_FaceTarget(); }
		goto fire_loop;
	}
}
class Juggernaut: Fatso
{
	const treads_damage = 50;
	const treads_trample_radius_multiplier = 1.5;
	
	double  runstraight_length;
	int     runstraight_fallback_timeout;
	Vector2 runstraight_startpoint;
	
	Actor   attachedbody;
	
	default
	{
		+NOICEDEATH
		+MISSILEMORE
		+MISSILEEVENMORE
		+DONTHARMSPECIES
		
		species "mancubus";
		scale 1.5;
		health 8000;
		mass 12000;
		
		painsound "juggernaut/pain";
		deathsound "juggernaut/death";
		activesound "juggernaut/roam";
		seesound "juggernaut/see";
		
		obituary "%o was destroyed by the Juggernaut";
		
		maxstepheight 24;
		maxdropoffheight 32;
		deathheight 4;
		burnheight 0;
		speed 2;
		height 88;
		radius 48;
		
		meleerange 24;
		meleethreshold 350;
		
		painchance 10;
		minmissilechance 15;
		
		damage 0;
		damagetype "trample";
	}

	override void BeginPlay(void)
	{
		attachedbody = Spawn("JuggernautBody", self.pos);
	}

	override string GetObituary(Actor victim, Actor inflictor, name mod, bool playerattack)
	{
		string hitobituaries[] =
		{
			"Juggernaut stomped %o."
		};
		string obituaries[] =
		{
			obituary
		};

		if (mod == damagetype)
			return hitobituaries[Random(0, hitobituaries.Size() - 1)];
		else
			return obituaries[Random(0, obituaries.Size() - 1)];
	}

	action bool ActorAlive(Actor a)
	{
		return (a && a.health > 0);
	}

	override void Tick(void)
	{
		super.Tick();
		
		attachedbody.SetOrigin(pos, false);
		
		double l = sqrt(vel.x*vel.x + vel.y*vel.y);
		if (l > 1.0)
		{
			float dist = float(radius)*treads_trample_radius_multiplier;
			BlockThingsIterator it = BlockThingsIterator.Create(self, dist);
			
			while (it.next())
			{
				Actor a = it.thing;
				
				if (!a || !a.bSolid || distance2d(a) > dist || a.species == species)
				{
					continue;
				}
				
				int sp = speed*2; // One from chasing and one from recoil.
				int d = treads_damage/((sp*sp)/l);
				a.DamageMobj(self, self, d, damagetype);
			}
		}
		
		bSolid = !(InStateSequence(CurState, ResolveState("see")));
	}
	
	action void Engine(void)
	{
		if (target && distance2d(target) > 450 && random(1, 2) == 1)
		{
			A_FastChase();
			A_Recoil(-5.0);
		}
		A_Chase();
		A_Recoil(-speed);
		if (target && distance2d(target) < 350)
		{
			A_FaceTarget();
			A_Recoil(-speed);
		}
	}
	
	action void
	A_JuggernautBullets(bool fireing_side, bool recoil = false)
	{
		if (recoil)
		{
			A_Recoil(-speed*2);
			if (random(1, 5) == 1)
			{
				A_Turn(random(-45, 45));
			}
		}
		
		int xoffset = 50;
		
		if (fireing_side)
		{
			xoffset = -50;
		}
		A_CustomMissile("Juggernaut_Bullet", 78, xoffset, random(-6, 6), 0);
	}

	states
	{
	spawn:
		BS1W AC 10 A_Look;
		loop;
	melee:
		BS1W B 2 Engine; // Shouldn't really happen.
	see:
		BS1W A 0 A_PlaySound("juggernaut/engine");
		BS1W A 0 { attachedbody.setstatelabel("spawn"); } 
		BS1W A 2 Engine;
		BS1W B 2 Engine;
		BS1W A 2 Engine;
		BS1W B 2 Engine;

		BS1W C 2 Engine;
		BS1W D 2 Engine;
		BS1W C 2 Engine;
		BS1W D 2 Engine;
		loop;
	missile:
		BS1B A 0
		{
			attachedbody.target = target;
			attachedbody.setstatelabel("standby");
			A_PlaySound("juggernaut/engine");
		}
		BS1B A 6 { A_Recoil(-speed*4); }
		BS1B A 6 { A_Recoil(-speed*4); }
		BS1B A 6 { A_Recoil(-speed*4); }
		---- A 0
		{
			int r = random(1, 10);
			
			if (r > 7)
			{
				setstatelabel("missile_hell");
			}
			else if (r > 5)
			{
				setstatelabel("missile_once");
			}
		}
		---- A 0 { attachedbody.setstatelabel("fire_loop"); }
	bullets:
		BS1B A 16 A_JuggernautBullets(true, true);
		BS1B A 16 A_JuggernautBullets(false, false);
		BS1B A 16 A_JuggernautBullets(true, true);
		BS1B A 16 A_JuggernautBullets(false, false);
		---- A 0 A_JumpIf((random(1, 10) <= 8), "bullets");
		goto see;
	missile_once:
		BS1B A 0
		{
			attachedbody.setstatelabel("fire_loop");
			A_CustomMissile("Juggernaut_Rocket", 78,  42, random(-3, 3), 0);
			A_CustomMissile("Juggernaut_Rocket", 78, -42, random(-3, 3), 0);
		}
		goto see;
	missile_hell:
		---- A 0 { A_Recoil(-speed*2); attachedbody.setstatelabel("fire_fast"); }
		BS1B A 9 { A_CustomMissile("Juggernaut_Rocket", 78,  42, random(-3, 3), 0); }
		---- A 0 { A_Recoil(-speed*2); attachedbody.setstatelabel("fire_fast"); }
		BS1B A 9 { A_CustomMissile("Juggernaut_Rocket", 78, -42, random(-3, 3), 0); }
		BS1B A 18 FAST
		{
			A_Recoil(-speed);
			if (random(1, 10) > 4)
			{
				setstatelabel("missile_hell");
			}
		}
		goto see;
	pain:
		BS1W A 4 A_Pain;
		goto see;
	death:
		BS1B B 5 Radius_Quake (6, 100, 0, 22, 0);
		BS1B B -1;
		stop;
	taunt_trample:
		BS1W A    2 { A_Recoil(-2.0); A_PlaySound("xdeath",  CHAN_AUTO); }
		BS1W ABCD 8 { A_Recoil(-2.0); A_PlaySound("xdeaths", CHAN_AUTO); }
		BS1W A    8 A_PlaySound("juggernaut/say", CHAN_AUTO);
		BS1W BCD  8;
		goto see;
	}
}
