class hordemarine: doomplayer
{
	/* Custom properties can't be changed, afaik.
	 * By overriding DamageMobj, we can change damage factors on-the-fly.
	 * Order of damage factors is important!
	 * The order is the same as defined in mapinfo lump.
	 */
	double[9] dmgfactors;
	double[9] dmgaccumulator;
	double[9] dmgaccumulator_factor;
	
	bool ripper_grab_head;
	actor last_attacker;

	default
	{
		+ADDITIVEPOISONDAMAGE;
		+ADDITIVEPOISONDURATION;

		species "human";
		health 100;
		player.maxhealth 300;
		player.forwardmove 0.5, 0.5;
		player.sidemove 0.5, 0.5;
		Player.StartItem "CombatKnife";
		player.GruntSpeed 22;
		player.ViewBob 0.25;

		painchance "decapitate", 255;
	}

	override void
	BeginPlay(void)
	{
		switch (skill)
		{
		default:
		case 0:
			dmgfactors[DTY_EAT] = 1.0;
			dmgfactors[DTY_DEVOUR] = 1.0;
			dmgfactors[DTY_BITE] = 1.0;
			dmgfactors[DTY_TEAR] = 1.0;
			dmgfactors[DTY_EXPLOSION] = 0.5;
			dmgfactors[DTY_DECAPITATE] = 1.0;
			dmgfactors[DTY_STOMP] = 1.0;
			dmgfactors[DTY_TRAMPLE] = 1.0;
			
			dmgaccumulator_factor[DTY_EAT] = 0.0;
			dmgaccumulator_factor[DTY_DEVOUR] = 0.0;
			dmgaccumulator_factor[DTY_BITE] = 0.0;
			dmgaccumulator_factor[DTY_TEAR] = 0.1;
			dmgaccumulator_factor[DTY_EXPLOSION] = 0.0;
			dmgaccumulator_factor[DTY_DECAPITATE] = 0.5;
			dmgaccumulator_factor[DTY_STOMP] = 0.0;
			dmgaccumulator_factor[DTY_TRAMPLE] = 0.15;
			break;
		case 1:
			dmgfactors[DTY_EAT] = 1.0;
			dmgfactors[DTY_DEVOUR] = 1.0;
			dmgfactors[DTY_BITE] = 1.0;
			dmgfactors[DTY_TEAR] = 2.0;
			dmgfactors[DTY_EXPLOSION] = 1.0;
			dmgfactors[DTY_DECAPITATE] = 1.5;
			dmgfactors[DTY_STOMP] = 1.0;
			dmgfactors[DTY_TRAMPLE] = 1.5;
			
			dmgaccumulator_factor[DTY_EAT] = 0.0;
			dmgaccumulator_factor[DTY_DEVOUR] = 0.0;
			dmgaccumulator_factor[DTY_BITE] = 0.0;
			dmgaccumulator_factor[DTY_TEAR] = 0.1;
			dmgaccumulator_factor[DTY_EXPLOSION] = 0.0;
			dmgaccumulator_factor[DTY_DECAPITATE] = 1.0;
			dmgaccumulator_factor[DTY_STOMP] = 0.0;
			dmgaccumulator_factor[DTY_TRAMPLE] = 1.25;
			
			health = 50;
			break;
		}
		
		super.BeginPlay();
	}
	
	void
	Ripper_GrabHead(bool grab, sripper ripper)
	{
		ripper_grab_head = grab;
	}
	
	void
	Ripper_BringCloser(Actor ripper)
	{
		float offset = 14;
		vector3 newpos = ripper.pos;
		
		newpos.x += cos(ripper.angle) * offset;
		newpos.y += sin(ripper.angle) * offset;
		newpos.z += 32;
		SetXYZ(newpos);
	}
	
	void
	Ripper_ThrowHead(void)
	{
		A_SkullPop("MarineHead");
	}
	
	override void
	Tick()
	{
		if (health > 0)
		{
			Ripper_GrabHead(false, null);
		}
		else
		{
			if (last_attacker && sripper(last_attacker) && !ripper_grab_head)
			{
				ACS_NamedExecute("PitchCamera", 0, -3553);
			}
		}
		
		//console.printf("gh= %d", ripper_grab_head);
		//console.printf("%f", dmgaccumulator[DTY_TEAR]);
		if (dmgaccumulator[DTY_TEAR] > 0.0)    { dmgaccumulator[DTY_TEAR]    -= 0.25;  }
		else                                   { dmgaccumulator[DTY_TEAR]     = 0.0; }
		if (dmgaccumulator[DTY_TRAMPLE] > 0.0) { dmgaccumulator[DTY_TRAMPLE] -= 1;  }
		else                                   { dmgaccumulator[DTY_TRAMPLE]  = 0.0; }
		if (dmgaccumulator[DTY_DECAPITATE] > 0.0) { dmgaccumulator[DTY_DECAPITATE] -= 1;  }
		else                                   { dmgaccumulator[DTY_DECAPITATE]  = 0.0; }
		Super.Tick();
	}

	override int
	DamageMobj(Actor inflictor, Actor source, int damage, Name mod, int flags, double angle)
	{
		let arm = FindInventory("BasicArmor", true);
		int armour = BasicArmor(arm).ActualSaveAmount;
		
		last_attacker = source;
		
		if (inflictor && source && source.target)
		{
			// Cancel attack if the player guarded well.
			double a_delta = AbsAngle(source.target.angle+180.0, source.angle);
			
			if (a_delta < 60.0)
			{		
				CombatKnife w_ck = CombatKnife(player.ReadyWeapon);
				if (w_ck && w_ck.defending)
				{	
					if (source == inflictor)
					{
						inflictor.A_Recoil(2);
					}
					A_Recoil(2);
					A_StartSound("weapon/combatknife/guard", CHAN_WEAPON);
					w_ck.SuccessfulGuard();
					return 0;
				}
			}
			
			// Damage accumulation and armour damage reduction (multiplication)
			int debug_x = 0;
			if (mod == "tear")
			{
				damage += dmgaccumulator[DTY_TEAR]*dmgaccumulator_factor[DTY_TEAR];
				damage *= dmgfactors[DTY_TEAR];
				
				if (armour <= 0)
				{
					damage *= 2;
				}
				
				dmgaccumulator[DTY_TEAR] += damage;
				debug_x = dmgaccumulator[DTY_TEAR];
			}
			if (mod == "trample")
			{
				damage += dmgaccumulator[DTY_TRAMPLE]*dmgaccumulator_factor[DTY_TRAMPLE];
				damage *= dmgfactors[DTY_TRAMPLE];
				
				if (armour <= 0)
				{
					damage *= 2;
				}
				
				dmgaccumulator[DTY_TRAMPLE] += damage;
				debug_x = dmgaccumulator[DTY_TRAMPLE];
			}
			if (mod == "explosion")
			{
				damage += dmgaccumulator[DTY_EXPLOSION]*dmgaccumulator_factor[DTY_EXPLOSION];
				damage *= dmgfactors[DTY_EXPLOSION];
				
				if (armour <= 0)
				{
					damage *= 2;
				}
				
				dmgaccumulator[DTY_EXPLOSION] += damage;
				debug_x = dmgaccumulator[DTY_EXPLOSION];
			}
			if (mod == "decapitate")
			{
				damage += dmgaccumulator[DTY_DECAPITATE]*dmgaccumulator_factor[DTY_DECAPITATE];
				damage *= dmgfactors[DTY_DECAPITATE];
				
				if (armour <= 0)
				{
					damage *= 2;
				}
				
				dmgaccumulator[DTY_DECAPITATE] += damage;
				debug_x = dmgaccumulator[DTY_DECAPITATE];
			}
			
			console.printf("<< Receive [%s]%d accu=%d actor=%s delta=%f ", mod, damage, debug_x, source.species, a_delta);
		}
		else
		{
		}
		
		return super.DamageMobj(inflictor, source, damage, mod, flags, angle);
	}

	states
	{
	death.eat:
		---- A 0 A_Log("Eat death");
		goto death;
	death.acid:
		---- A 0 A_Log("Acid death");
		---- A 0 A_PlaySound("Melting");
		PMET ABCDEFG 33;
		PMET HI 62;
		PMET JKLM 10;
		PMET M -1;
		stop;
	death.devour:
		---- A 0 A_Log("devour death");
		XPL2 A 6
		{
			A_Stop();
		}
		XPL2 B 20;
		XPL2 CDE 6;
		XPL2 F -1;
		stop;
	death.bite:
		---- A 0 A_Log("bite death");
		goto death;
	death.tear:
		HPLA A 6
		{
			A_Stop();
			A_Face(target);
			A_StartSound("Bonecrack0", CHAN_BODY);
			A_SpawnProjectile("MarineBottom", 4, -16, random(-40, 40), 2, random(10, 60));
			A_SpawnProjectile("Blood_Guts", 35, 0, random(-45, 45), 2, random(10, 65));
			A_SpawnProjectile("Blood_Guts", 24, 0, random(-45, 45), 2, random(10, 65));
			A_SpawnProjectile("Blood_Guts", 35, 0, random(-45, 45), 2, random(10, 65));
			A_SpawnProjectile("Blood_Guts", 45, 0, random(-45, 45), 2, random(10, 65));
			for (int i = 0; i < 20; i++)
			{
				A_SpawnProjectile("Blood_Gib_Small", 36, 0, random(-45, 45), 2, random(20, 25));
				A_SpawnProjectile("Blood_Gib_Small", 36, 0, random(-45, 45), 2, random(20, 45));
				A_SpawnProjectile("Blood_Gib_Small", 36, 0, random(-45, 45), 2, random(20, 55));
			}
			
			// Prevent cheating. :p
			// C++ source: m_cheat.cpp#L362
			if (ripper_grab_head)
			{
				A_SpawnProjectile("MarineTop_NoHead", 32, -16, random(-30, 30), 2, random(10, 60));
				SetStateLabel("death.tear_dec");
				Ripper_BringCloser(target);
				ACS_NamedExecute("RollCamera", 0, 50);
			}
			else
			{
				//ACS_NamedExecute("PitchCamera", 0, 7553); // 36 degrees
			}
		}
		HPLA AAAAA 4
		{
			for (int i = 0; i < 5; i++)
			{
				A_SpawnProjectile("Blood_Gib_Small", 38, -56, random(-25, 25), 2, random(40, 75));
				A_SpawnProjectile("Blood_Gib_Small", 38, 56, random(-25, 25), 2, random(40, 75));
			}
			A_PlaySound("xdeaths", CHAN_AUTO);
		}
		HPLA A -1;
		stop;
	/* Wait for other actor to tell this "fake" actor to conitnue. */
	death.tear_dec:
		TNT1 A 1;
		loop;
	death.explosion:
		---- A 0 A_Log("Explosion death");
		XPL6 A 6
		{
			A_SpawnProjectile("MarineArm", 32, -16, random(-30, 30), 2, random (10, 60));
			A_SpawnProjectile("MarineArm", 32, +16, random(-30, 30), 2, random (10, 60));
			A_SpawnProjectile("MarineLeg", 32, +16, random(-30, 30), 2, random (10, 60));
			A_Stop();
			A_SkullPop("MarineHead");
			// 0, random (0, 360), 2, random (10, 90)
		}
		XPL6 BCDE 8;
		XPL6 F -1;
		stop;
	death.decapitate:
		XPL3 A 6
		{
			A_Stop();
			A_Recoil(-5.0);
			A_SkullPop("MarineHead");
			A_SpawnProjectile("MarineArm", 32, +16, random(30, 45), 2, random (30, 60));
			//A_Stop();
		}
		XPL3 BBBBB 4 A_PlaySound("xdeaths", CHAN_AUTO);
		XPL3 C 8;
		XPL3 DEF 6;
		XPL3 F -1;
		stop;
	death.stomp:
	death.trample:
		GIBS Z -1
		{
			A_SkullPop("MarineTeeth");
			A_PlaySound("Bonecrack0", CHAN_AUTO);
			A_Stop();
		}
		stop;
	death:
		PLAY H 10;
		PLAY I 10 A_PlayerScream;
		PLAY J 10 A_NoBlocking;
		PLAY KLM 10;
		PLAY N -1;
		stop;
	}
}
