// Formerly, SWRipper

class SRipper: Actor
{
	int ripheart_beats, ripheart_maxbeats;
	int chargedamage;
	bool charging;
	hordemarine last_marine;
	string item_organ;
	
	property ChargeDamage: chargedamage;
	property HeartBeats: ripheart_maxbeats;
	property ItemOrgan: item_organ;
	
	enum ECheckSolidFootingFlags
	{
		CSF_SOLIDGROUND = 1,
		CSF_SOLIDACTORS = 2,
		
		CSF_ALL = CSF_SOLIDGROUND|CSF_SOLIDACTORS,
	}
	
	default
	{
		+FLOORCLIP
		+DONTHARMCLASS
		MONSTER;
		
		species "Ripper";
		Health 150;
		Speed 15;
		Radius 18;
		Height 58;
		Scale 0.8;
		Mass 400;
		PainChance 90;
		
		MeleeThreshold 280;
		MeleeRange 58;
		Damage 20;
		SRipper.ChargeDamage 35;
		DamageType "tear";
		
		SRipper.HeartBeats 8;
		SRipper.ItemOrgan "Blood_Heart";
		
		PainChance "knife", 255;
		
		SeeSound    "swripper/sight";
		PainSound   "swripper/pain";
		DeathSound  "swripper/death";
		ActiveSound "swripper/active";
		MeleeSound  "swripper/attack";
		
		Obituary "%o was torn apart by a ripper.";
	}
	
	override void
	BeginPlay(void)
	{
		super.BeginPlay();
		
		switch (skill)
		{
		default:
		case SK_REGULAR:
			break;
		case SK_SPECIAL:
			break;
		}
	}
	
	/*
	 * If charging, hit all enemies in melee radius until we either hit the
	 * ground (not in "missile" state anymore) or we hit the target we want.
	 * In case the target is hit whilst in air, the state won't change until we
	 * hit the ground.
	 */
	override void
	Tick(void)
	{
		if (charging)
		{
			BlockThingsIterator it = BlockThingsIterator.Create(self, meleerange);
			
			while (it.next())
			{
				Actor a = it.thing;
				
				if (!a || !a.bSolid || distance2d(a) > meleerange || a.species == species)
				{
					continue;
				}
				
				if (Attack(a, chargedamage, (a == target)))
				{
					A_Stop();
				}
				
				if ((a == target))
				{
					charging = false;
				}
			}
			
			if (!InStateSequence(CurState, ResolveState("missile")))
			{
				charging = false;
			}
		}
		
		super.Tick();
	}
	
	override int
	DamageMobj(Actor inflictor, Actor source, int damage, Name mod, int flags, double angle)
	{
		//console.printf("<< Receive [%s]%d %f*", mod, damage, angle);
		return super.DamageMobj(inflictor, source, damage, mod, flags, angle);
	}
	
	virtual bool
	Attack(Actor who, int hitamount, bool rip_heart = true)
	{
		if (who == null || who.health <= 0 || distance2d(who) > meleerange)
		{
			A_StartSound("swripper/miss", CHAN_WEAPON);
			return false;
		}
		
		bool attack_head = (random(1, 2) == 1);
		
		hordemarine p = hordemarine(who);
		last_marine = p;
		
		p.Ripper_GrabHead(attack_head, self);
			
		int d = who.DamageMobj(self, self, hitamount, damagetype);
		if (d > 0)
		{
			A_StartSound("swripper/attack", CHAN_WEAPON);
			
			if (p && who.health <= 0)
			{
				if (attack_head == false)
				{
					if (rip_heart)
					{
						SetStateLabel("ripheart");
					}
				}
				else
				{
					if (rip_heart)
					{
						SetStateLabel("riphead");
					}
				}
				return true;
			}
		}
		return false;
	}
	
	action void
	A_RipperPrepareClaws(void)
	{
		A_Recoil(-5);
		if (random(1, 2) == 1)
		{
			invoker.scale.x = -invoker.scale.x;
		}
	}
	
	void
	RipperClaws(void)
	{
		A_FaceTarget();
		Attack(target, damage);
		A_StartSound("sswing", CHAN_VOICE);
	}
	
	action void
	A_RipperClawsPullBack(void)
	{
		A_Recoil(-4);
		if (skill == SK_SPECIAL)
		{
			A_FaceTarget();
			A_Recoil(-15);
			if (target && distance2d(target) <= meleerange+radius && random(1, 2) == 1)
			{
				SetStateLabel("melee");
			}
		}
	}
	
	action void
	A_RipperJump(void)
	{
		ThrustThingZ(0, 30, 0, 1);
		A_FaceTarget();
		A_Recoil(-25.0);
	}
	
	action void
	A_RipperChase(void)
	{
		if (random(1, 5) < 3)
		{
			A_FastChase();
		}
		else
		{
			A_Chase();
		}
		
		if (target && (random(1, 3) == 1) && distance2d(target) < meleethreshold)
		{
			A_FaceTarget();
			A_Recoil(-7);
		}
	}
	
	action void
	A_RipperRippedHeartBeat(void)
	{
		A_FaceTarget();
		invoker.ripheart_beats++;
		if (invoker.ripheart_beats >= invoker.ripheart_maxbeats)
		{
			invoker.ripheart_beats = 0;
			SetStateLabel("ripheart_throw");
		}
		else
		{
			A_StartSound("swripper/heart", CHAN_ITEM);
		}
	}
	
	action void
	A_RipperThrowHead(void)
	{
		if (invoker.last_marine)
		{
			invoker.last_marine.Ripper_ThrowHead();
			invoker.last_marine = null;
			A_StartSound("swripper/miss", CHAN_WEAPON);
		}
	}
	
	action void
	A_RipperThrowOrgan(void)
	{
		invoker.ripheart_beats = 0;
		A_StartSound("swripper/miss", CHAN_WEAPON);
		A_SpawnProjectile(invoker.item_organ, 32, 0, random(-30, 30), 2, random(0, 10));
	}
	
	action void
	A_RipperLaugh(int chance = 100)
	{
		if (chance == 100 || random(0, 100) <= chance)
		{
			A_StartSound("swripper/active", CHAN_VOICE);
		}
	}
	
	/*
	 * If on special mode or randomly picked, recoil left or right from the
	 * target.
	 * Randomly jump towards the target (missile state)
	 */
	action void
	A_RipperPain(void)
	{
		if (skill == SK_SPECIAL || random(1, 3) != 1)
		{
			int mul = 1;
			int recoil = -12.0;
			
			if (random(1, 2) == 1)
			{
				mul = -1;
			}
			
			if (skill == SK_SPECIAL)
			{
				recoil -= 2.0;
			}
			
			A_FaceTarget();
			A_SetAngle(angle+90*mul);
			A_Recoil(-12.0);
		}
		if (random(1, 100) < 25)
		{
			SetStateLabel("missile");
		}
		A_Pain();
	}

	States
	{
	spawn:
		GRIP A 10 A_Look;
		loop;
	see:
		GRIP AABBCCDD 4 A_RipperChase();
		GRIP EEFFGGH  4 A_RipperChase();
		GRIP H        4 FAST A_FastChase();
		loop;
	melee:
		GRIP P  0 A_RipperPrepareClaws();
		GRIP PQ 8 FAST A_FaceTarget();
		GRIP R  4 RipperClaws();
		GRIP R  1 A_RipperClawsPullBack();
		GRIP R  1 A_JumpIf((random(1, 3) == 1), 4);
		GRIP R  2 A_JumpIf((random(1, 4) == 1), 3);
		GRIP R  3 A_JumpIf((random(1, 5) == 1), 2);
		GRIP R  4 A_JumpIf((random(1, 5) == 1), 1);
		GRIP RR 1 A_Recoil(-6);
		goto see;
	missile:
		---- A 0 A_JumpIf((random(1, 5) == 1), "chest");
		GRIP L 8 FAST A_FaceTarget();
		GRIP M 5 A_FaceTarget();
		GRIP N 5 A_RipperJump();
		---- A 0 { charging = true; }
		GRIP O 1 A_CheckFloor("see");
		goto missile+5;
	chest:
		GRIP I 7 A_FaceTarget();
		---- A 0 A_StartSound("swripper/chesthitting");
		GRIP JKJKJ 4 A_FaceTarget();
		Goto See;
	ripheart:
		RIPH A 15 A_RipperRippedHeartBeat();
		RIPH B 16 A_Look();
		RIPH A 15 A_RipperRippedHeartBeat();
		RIPH B 16 A_RipperLaugh(15);
		loop;
	ripheart_throw:
		GRIP PQ 6;
		GRIP R  6 A_RipperThrowOrgan();
		goto see;
	riphead:
		RIPX B  16 A_Look();
		RIPX B  16 A_RipperLaugh(100);
		GRIP PQ 6;
		GRIP R  6 A_RipperThrowHead();
		goto see;
	pain:
		GRIP S 4 A_RipperPain;
		GRIP S 4;
		goto see;
	xdeath:
	death:
		GRIP T 5;
		GRIP U 5 A_Scream;
		GRIP V 5 ;
		GRIP W 5 A_Fall;
		GRIP XYZ 5;
		GRIP [ -1;
		Stop;
	raise:
		GRIP ZYXWVUT 5;
		Goto See;
	}
}

class SRipperB: SRipper
{
	override bool
	Attack(Actor who, int hitamount, bool rip_heart)
	{
		self.health += hitamount/5;

		return Super.Attack(who, hitamount, rip_heart);
	}
}
