class Enforcer : Actor
{

enum AttackType
{
	ATTACK_GUN,
	ATTACK_SPIT,
	ATTACK_JUMP,
};

private double target_tracing_angle;
private string sound_gun;

private int spit_chance;

private int gun_bulletsmax;
private int gun_bulletscounter;

private AttackType last_attack;

private string message_gun;
private string message_spit;
private string message_jump;

property spitchance : spit_chance; /* [0, 100] */
property messagegun : message_gun;
property messagespit : message_spit;
property messagejump : message_jump;
property tracingangle : target_tracing_angle;
property gunsound : sound_gun;
property maxbullets : gun_bulletsmax;

private state
ChooseAttack(void)
{
	if (target && distance2d(target) < 512)
	{
		return (random(1, 100) > spit_chance ? ResolveState("gun") : ResolveState("spit"));
	}
	else
	{
		return ResolveState("gun");
	}
}

private state
PrepareAttack(void)
{
	state newstate = ChooseAttack();
	
	gun_bulletscounter = 0;
	
	A_FaceTarget();
	SetState(newstate);
	
	return newstate;
}

private bool
CheckFireSight(void)
{
	return CheckIfTargetInLOS(target_tracing_angle);
}

private bool
ReFire(void)
{
	bool fire = false;
	
	if (gun_bulletscounter < gun_bulletsmax)
	{	
		if (target && CheckFireSight())
		{
			SetStateLabel("gun");
			fire = true;
		}
	}
	
	return fire;
}

private int
FireGun(void)
{
	int damage_done = 0;
	
	gun_bulletscounter++;
	A_FaceTarget();
	A_StartSound(sound_gun, CHAN_WEAPON);
	if (self.target && CheckFireSight())
	{
		last_attack = ATTACK_GUN;
		damage_done = self.target.DamageMObj(self, self, 4, "bullet", DMG_THRUSTLESS);
	}
	
	return damage_done;
}

override string
GetObituary(Actor victim, Actor inflictor, name mod, bool playerattack)
{
	switch (last_attack)
	{
	default:
	case ATTACK_GUN: return message_gun;
	case ATTACK_SPIT: return message_spit;
	case ATTACK_JUMP: return message_jump;
	}
}

private int
sign(int x)
{
	if (x > 0.0)
		return 1.0;
	else if (x < 0.0)
		return -1.0;
	return 0.0;
}

private void
Spit(void)
{
	double distancetopitchratio = 90.0;
	double addpitch = 0.0;
	double predict_angle = 0.0;
	double n = 0.0;
	int addpitch_constant = 25;
	if (target)
	{
		n = self.vec2to(target).length() / 512.0;
		addpitch = (n-0.35) * distancetopitchratio;
		vector2 targetvelocity;
		targetvelocity.x = target.vel.x;
		targetvelocity.y = target.vel.y;
		predict_angle = aproximateFireAngle(self.x, self.y, target.x, target.y, targetvelocity);
		if (n > 0.0)
		{
			addpitch_constant = 25;
		}
		else
		{
			addpitch_constant = 5;
		}
	}
		
	A_StartSound("lizardtroop/spit", CHAN_WEAPON);
	
	int spit_amount = random(2, 4);
	for (int i = 0; i < spit_amount; i++)
	{
		A_SpawnProjectile("GreenGrenade", 28, 0, random(-10,10)+predict_angle, CMF_ABSOLUTEPITCH, -random(addpitch, addpitch+addpitch_constant));
	}
	A_FaceTarget();
	last_attack = ATTACK_SPIT;
}
	
private int
aproximateFireAngle(int sx, int sy, int tx, int ty, vector2 velocity)
{
	int len = sqrt(velocity.Length());
	if (len > 15.0)
		len = 15.0;
	vector2 v0;
	v0.x = sx - tx;
	v0.y = sy - ty;
	vector2 v1;
	v1.x = sx - (tx + velocity.x);
	v1.y = sy - (ty + velocity.y);
	int b0 = atan2(v0.y, v0.x);
	int b1 = atan2(v1.y, v1.x);
	int alpha = len * 8 * sign(b1 - b0);
	return alpha;
}

default
{
	MONSTER;
	+FLOORCLIP
	+STAYONLIFT
	+TELESTOMP
	+DONTHARMCLASS
	+DONTHARMSPECIES
	
	health 120;
	radius 20;
	height 56;
	scale 0.8;
	speed 10;
	fastspeed 12;
	painchance 100;
	minmissilechance 210;
	meleerange 100;
	
	maxtargetrange 1024;
	
	dropitem "AmmoBox";
	
	species "lizard";
	Tag "$FN_LIZARD";
	
	seesound    "lizardtroop/active";
	painsound   "lizardtroop/pain";
	deathsound  "lizardtroop/death";
	activesound "lizardtroop/active";
	
	Enforcer.spitchance 20;
	Enforcer.tracingangle 40.0;
	Enforcer.maxbullets 35;
	Enforcer.gunsound "lizardtroop/dnchaingun";
	Enforcer.messagegun "%o was riddled with holes by a lizard.";
	Enforcer.messagespit "A lizard spat at %o.";
	Enforcer.messagejump "A lizard latched onto %o.";
}

states
{
spawn:
	F09M A 10 A_Look();
	loop;
see:
	F09W AABBCCDD 4 A_Chase("jump", "range");
	loop;
jump:
	F09C A   6 { A_FaceTarget(); }
	F09J A   6 { Thrust(5.0, self.angle); vel.z += 5; }
	F09J B   6 { Thrust(3.0, self.angle); vel.z += 4; }
	F09J C   6 { Thrust(2.0, self.angle); vel.z += 1; }
	---- A   0
	{
		if (target && distance2d(target) < meleerange)
		{
			last_attack = ATTACK_JUMP;
			
			int damage_done = target.DamageMObj(self, self, 65, "melee", DMG_THRUSTLESS);
			
			if (damage_done > 0 && target.health <= 0)
			{
				SetStateLabel("spit");
			}
		}
	}
	goto see;
range:
	---- A 0 PrepareAttack();
gun:
	F09M B 2 BRIGHT FireGun();
	F09M A 2 FAST;
	---- A 0 ReFire();
	goto see;
spit:
	F09C A 6 A_FaceTarget();
	F09C AAA 6;
	F09C A 6 A_FaceTarget();
	F09C A 6;
	F09C B 5 Spit();
	F09C AAA 6;
	goto see;
pain:
	F09M A 3;
	F09M A 3 A_Pain();
	goto see;
death:
	F09D A 5;
	F09D B 5 A_Scream();
	F09D C 5 A_Fall();
	F09D DE 5;
	F09D F -1;
	stop;
XDeath:
	TNT1 A 0;
	TNT1 A 0 A_PlaySound("other/gibdeath");
	TNT1 AAAAAAAAAAAA 0 A_TossGib();
	TNT1 A 0
	{
		A_CustomMissile("LizardCGunnerHead",random(20,50),0,random(0,359));
		A_CustomMissile("LizardCGunnerArm",random(20,50),0,random(0,359));
		A_CustomMissile("LizardCGunnerLeg",random(20,50),0,random(0,359));
		A_CustomMissile("LizardCGunnerLeg2",random(20,50),0,random(0,359));
	}
	TNT1 A 1 A_Fall();
	stop;
raise:
	F09D FEDCBA 5;
	goto see;
}
}

class GreenGrenade: Actor
{
override void beginplay()
{
	double addscale = random(0, 5) / 10.0;
	speed   += random(0, 10);
	scale.x += addscale;
	scale.y += addscale;
}
default
{
	PROJECTILE;
	-NOGRAVITY
	
	radius 4;
	height 4;
	speed 10;
	damage 4;
	
	poisondamage 15;
	poisondamagetype "acid";
	
	damagetype "acid";
	
	//deathsound "slimeball/splat";
	scale 0.5;
	//decal "PlasmaScorchLower";
}
states
{
spawn:
	BOGY ABC 2 bright;
	loop;
death:
	BOGY D 0 BRIGHT A_NoGravity;
	BOGY DEF 4 BRIGHT;
	stop;
}
}

class LizardTroopGib : Actor
{
default
{
	-SOLID
	+DROPOFF
	+NOTELEPORT
	+CORPSE

	radius 6;
	height 5;
	speed 7;
}
}

class LizardCGunnerHead : LizardTroopGib
{
states
{
spawn:
	F09Z BBBB 1 NODELAY ThrustThingZ(0,10,0,1);
	F09Z CDE 4;
	F09Z BCDE 4;
	goto Spawn+11;
crash:
	F09Z B 800 A_NoBlocking();
	F09Z B 1 { A_FadeOut(); A_QueueCorpse(); }
	wait;
}
}

class LizardCGunnerArm : LizardTroopGib
{
states
{
spawn:
	F09Z FFFF 1 NODELAY ThrustThingZ(0,8,0,1);
	F09Z GHI 4;
	F09Z FGHI 4;
	Goto spawn+11;
crash:
	F09Z F 550 A_NoBlocking;
	F09Z F 1 { A_FadeOut(); A_QueueCorpse(); }
	wait;
}
}

class LizardCGunnerLeg : LizardTroopGib
{
states
{
spawn:
	TNT1 AAAA 0;
	F09Z JJJJ 1 ThrustThingZ(0,8,0,1);
	F09Z KLM 4;
	F09Z JKLM 4;
	goto spawn+11;
crash:
	F09Z J 450 A_NoBlocking;
	F09Z J 1 { A_FadeOut(); A_QueueCorpse(); }
	wait;
}
}

class LizardCGunnerLeg2 : LizardTroopGib
{
states
{
spawn:
	TNT1 AAAA 0;
	F09Z NNNN 1 ThrustThingZ(0,8,0,1);
	F09Z OPQ 4;
	F09Z NOPQ 4;
	goto spawn+11;
crash:
	F09Z N 450 A_NoBlocking;
	F09Z N 1 { A_FadeOut(); A_QueueCorpse(); }
	wait;
}
}