/*==============================================================================
ZOMBIE
==============================================================================*/
$cd id1/models/zombie

$origin	0 0 24

$base base
$skin skin

$frame stand1 stand2 stand3 stand4 stand5 stand6 stand7 stand8
$frame stand9 stand10 stand11 stand12 stand13 stand14 stand15

$frame walk1 walk2 walk3 walk4 walk5 walk6 walk7 walk8 walk9 walk10 walk11
$frame walk12 walk13 walk14 walk15 walk16 walk17 walk18 walk19

$frame run1 run2 run3 run4 run5 run6 run7 run8 run9 run10 run11 run12
$frame run13 run14 run15 run16 run17 run18

$frame atta1 atta2 atta3 atta4 atta5 atta6 atta7 atta8 atta9 atta10 atta11
$frame atta12 atta13

$frame attb1 attb2 attb3 attb4 attb5 attb6 attb7 attb8 attb9 attb10 attb11
$frame attb12 attb13 attb14

$frame attc1 attc2 attc3 attc4 attc5 attc6 attc7 attc8 attc9 attc10 attc11
$frame attc12

$frame paina1 paina2 paina3 paina4 paina5 paina6 paina7 paina8 paina9 paina10
$frame paina11 paina12

$frame painb1 painb2 painb3 painb4 painb5 painb6 painb7 painb8 painb9 painb10
$frame painb11 painb12 painb13 painb14 painb15 painb16 painb17 painb18 painb19
$frame painb20 painb21 painb22 painb23 painb24 painb25 painb26 painb27 painb28

$frame painc1 painc2 painc3 painc4 painc5 painc6 painc7 painc8 painc9 painc10
$frame painc11 painc12 painc13 painc14 painc15 painc16 painc17 painc18

$frame paind1 paind2 paind3 paind4 paind5 paind6 paind7 paind8 paind9 paind10
$frame paind11 paind12 paind13

$frame paine1 paine2 paine3 paine4 paine5 paine6 paine7 paine8 paine9 paine10
$frame paine11 paine12 paine13 paine14 paine15 paine16 paine17 paine18 paine19
$frame paine20 paine21 paine22 paine23 paine24 paine25 paine26 paine27 paine28
$frame paine29 paine30

$frame cruc_1 cruc_2 cruc_3 cruc_4 cruc_5 cruc_6

void(float type) zombie_sound;

//=============================================================================
void() zombie_stand1	=[	$stand1,		zombie_stand2	] {
	zombie_sound(2); self.solid = SOLID_SLIDEBOX; ai_stand();
};
void() zombie_stand2	=[	$stand2,		zombie_stand3	] {ai_stand();};
void() zombie_stand3	=[	$stand3,		zombie_stand4	] {ai_stand();};
void() zombie_stand4	=[	$stand4,		zombie_stand5	] {ai_stand();};
void() zombie_stand5	=[	$stand5,		zombie_stand6	] {ai_stand();};
void() zombie_stand6	=[	$stand6,		zombie_stand7	] {ai_stand();};
void() zombie_stand7	=[	$stand7,		zombie_stand8	] {ai_stand();};
void() zombie_stand8	=[	$stand8,		zombie_stand9	] {ai_stand();};
void() zombie_stand9	=[	$stand9,		zombie_stand10	] {ai_stand();};
void() zombie_stand10	=[	$stand10,		zombie_stand11	] {ai_stand();};
void() zombie_stand11	=[	$stand11,		zombie_stand12	] {ai_stand();};
void() zombie_stand12	=[	$stand12,		zombie_stand13	] {ai_stand();};
void() zombie_stand13	=[	$stand13,		zombie_stand14	] {ai_stand();};
void() zombie_stand14	=[	$stand14,		zombie_stand15	] {ai_stand();};
void() zombie_stand15	=[	$stand15,		zombie_stand1	] {ai_stand();};

//============================================================================
void() zombie_walk1		=[	$walk1,		zombie_walk2	] {
	self.inpain = 0; self.solid = SOLID_SLIDEBOX; ai_walk(0);
};
void() zombie_walk2		=[	$walk2,		zombie_walk3	] {monster_footstep(TRUE); ai_walk(2);};
void() zombie_walk3		=[	$walk3,		zombie_walk4	] {ai_walk(3);};
void() zombie_walk4		=[	$walk4,		zombie_walk5	] {ai_walk(2);};
void() zombie_walk5		=[	$walk5,		zombie_walk6	] {ai_walk(1);};
void() zombie_walk6		=[	$walk6,		zombie_walk7	] {ai_walk(0);};
void() zombie_walk7		=[	$walk7,		zombie_walk8	] {ai_walk(0);};
void() zombie_walk8		=[	$walk8,		zombie_walk9	] {ai_walk(0);};
void() zombie_walk9		=[	$walk9,		zombie_walk10	] {ai_walk(0);};
void() zombie_walk10	=[	$walk10,	zombie_walk11	] {ai_walk(0);};
void() zombie_walk11	=[	$walk11,	zombie_walk12	] {ai_walk(2);};
void() zombie_walk12	=[	$walk12,	zombie_walk13	] {monster_footstep(FALSE); ai_walk(2);};
void() zombie_walk13	=[	$walk13,	zombie_walk14	] {ai_walk(1);};
void() zombie_walk14	=[	$walk14,	zombie_walk15	] {ai_walk(0);};
void() zombie_walk15	=[	$walk15,	zombie_walk16	] {ai_walk(0);};
void() zombie_walk16	=[	$walk16,	zombie_walk17	] {ai_walk(0);};
void() zombie_walk17	=[	$walk17,	zombie_walk18	] {ai_walk(0);};
void() zombie_walk18	=[	$walk18,	zombie_walk19	] {ai_walk(0);};
void() zombie_walk19	=[	$walk19,	zombie_walk1	] {zombie_sound(2);};

//============================================================================
void() zombie_run1		=[	$run1,		zombie_run2	] {
	self.inpain = 0; self.solid = SOLID_SLIDEBOX; ai_run(1);
};
void() zombie_run2		=[	$run2,		zombie_run3	] {ai_run(1);};
void() zombie_run3		=[	$run3,		zombie_run4	] {ai_run(0);};
void() zombie_run4		=[	$run4,		zombie_run5	] {ai_run(1);};
void() zombie_run5		=[	$run5,		zombie_run6	] {ai_run(2);};
void() zombie_run6		=[	$run6,		zombie_run7	] {ai_run(3);};
void() zombie_run7		=[	$run7,		zombie_run8	] {ai_run(4);};
void() zombie_run8		=[	$run8,		zombie_run9	] {ai_run(4);};
void() zombie_run9		=[	$run9,		zombie_run10] {monster_footstep(FALSE); ai_run(2);};
void() zombie_run10		=[	$run10,		zombie_run11] {ai_run(0);};
void() zombie_run11		=[	$run11,		zombie_run12] {ai_run(0);};
void() zombie_run12		=[	$run12,		zombie_run13] {ai_run(0);};
void() zombie_run13		=[	$run13,		zombie_run14] {ai_run(2);};
void() zombie_run14		=[	$run14,		zombie_run15] {ai_run(4);};
void() zombie_run15		=[	$run15,		zombie_run16] {ai_run(6);};
void() zombie_run16		=[	$run16,		zombie_run17] {ai_run(7);};
void() zombie_run17		=[	$run17,		zombie_run18] {monster_footstep(FALSE); ai_run(3);};
void() zombie_run18		=[	$run18,		zombie_run1	] {zombie_sound(3);	ai_run(8); };

//======================================================================
// Zombie Range Attack
//======================================================================
void(vector st) ZombieThrowFlesh =
{
	local vector org, dir, ang, avel;

	if (self.health < 0) return;
	
	// Throw the flesh missle from the hand above the head
	makevectors (self.angles);
	org = self.origin + attack_vector(st);

	// Is Z aware enabled (AI track player much better)
	if ( query_configflag(SVR_ZAWARE) || self.no_zaware ) {
		dir = normalize(self.enemy.origin - org);
		dir = dir * SPEED_ZOMBFLESH;
		dir_z = ELEV_ZAXIS;
	}
	else {
		// One final angle adjustment (based on actual projectile origin)
		self.attack_speed = SPEED_ZOMBFLESH + (skill * SPEED_ZOMBIESKILL);
		self.attack_elev = SUB_Elevation(self.attack_elev, org, self.enemy.origin, self.attack_speed);
		ang = vectoangles(self.enemy.origin - org);
		ang_x = -self.attack_elev;
		makevectors (ang);
 		dir = v_forward * self.attack_speed;
	}

	avel = vecrand(100,200,FALSE);
	Launch_Grenade(org, dir, avel, CT_PROJ_FLESH);
};

//----------------------------------------------------------------------
void() zombie_atta1		=[	$atta1,		zombie_atta2	] {ai_face();};
void() zombie_atta2		=[	$atta2,		zombie_atta3	] {ai_face();};
void() zombie_atta3		=[	$atta3,		zombie_atta4	] {ai_face();};
void() zombie_atta4		=[	$atta4,		zombie_atta5	] {ai_face();};
void() zombie_atta5		=[	$atta5,		zombie_atta6	] {ai_face();};
void() zombie_atta6		=[	$atta6,		zombie_atta7	] {ai_face();};
void() zombie_atta7		=[	$atta7,		zombie_atta8	] {ai_face();};
void() zombie_atta8		=[	$atta8,		zombie_atta9	] {ai_face();};
void() zombie_atta9		=[	$atta9,		zombie_atta10	] {ai_face();};
void() zombie_atta10	=[	$atta10,	zombie_atta11	] {ai_face();
	self.attack_speed = SPEED_ZOMBFLESH + (skill * SPEED_ZOMBIESKILL);
	self.attack_elev = SUB_Elevation(ELEV_DEFAULT, self.origin, self.enemy.origin, self.attack_speed); };
void() zombie_atta11	=[	$atta11,	zombie_atta12	] {ai_face();
	self.attack_speed = SPEED_ZOMBFLESH + (skill * SPEED_ZOMBIESKILL);
	self.attack_elev = SUB_Elevation(self.attack_elev, self.origin, self.enemy.origin, self.attack_speed); };
void() zombie_atta12	=[	$atta12,	zombie_atta13	] {ai_face();
	ZombieThrowFlesh('8 12 28');};
void() zombie_atta13	=[	$atta13,	zombie_run1	] {};

//----------------------------------------------------------------------
void() zombie_attb1		=[	$attb1,		zombie_attb2	] {ai_face();};
void() zombie_attb2		=[	$attb2,		zombie_attb3	] {ai_face();};
void() zombie_attb3		=[	$attb3,		zombie_attb4	] {ai_face();};
void() zombie_attb4		=[	$attb4,		zombie_attb5	] {ai_face();};
void() zombie_attb5		=[	$attb5,		zombie_attb6	] {ai_face();};
void() zombie_attb6		=[	$attb6,		zombie_attb7	] {ai_face();};
void() zombie_attb7		=[	$attb7,		zombie_attb8	] {ai_face();};
void() zombie_attb8		=[	$attb8,		zombie_attb9	] {ai_face();};
void() zombie_attb9		=[	$attb9,		zombie_attb10	] {ai_face();};
void() zombie_attb10	=[	$attb10,	zombie_attb11	] {ai_face();};
void() zombie_attb11	=[	$attb11,	zombie_attb12	] {ai_face();
	self.attack_elev = SUB_Elevation(ELEV_DEFAULT, self.origin, self.enemy.origin, SPEED_ZOMBFLESH); };
void() zombie_attb12	=[	$attb12,	zombie_attb13	] {ai_face();
	self.attack_elev = SUB_Elevation(self.attack_elev, self.origin, self.enemy.origin, SPEED_ZOMBFLESH); };
void() zombie_attb13	=[	$attb13,	zombie_attb14	] {ai_face();
	ZombieThrowFlesh('6 -6 26');};
void() zombie_attb14	=[	$attb13,	zombie_run1	] {};

//----------------------------------------------------------------------
void() zombie_attc1		=[	$attc1,		zombie_attc2	] {ai_face();};
void() zombie_attc2		=[	$attc2,		zombie_attc3	] {ai_face();};
void() zombie_attc3		=[	$attc3,		zombie_attc4	] {ai_face();};
void() zombie_attc4		=[	$attc4,		zombie_attc5	] {ai_face();};
void() zombie_attc5		=[	$attc5,		zombie_attc6	] {ai_face();};
void() zombie_attc6		=[	$attc6,		zombie_attc7	] {ai_face();};
void() zombie_attc7		=[	$attc7,		zombie_attc8	] {ai_face();};
void() zombie_attc8		=[	$attc8,		zombie_attc9	] {ai_face();};
void() zombie_attc9		=[	$attc9,		zombie_attc10	] {ai_face();
	self.attack_elev = SUB_Elevation(ELEV_DEFAULT, self.origin, self.enemy.origin, SPEED_ZOMBFLESH); };
void() zombie_attc10	=[	$attc10,	zombie_attc11	] {ai_face();
	self.attack_elev = SUB_Elevation(self.attack_elev, self.origin, self.enemy.origin, SPEED_ZOMBFLESH); };
void() zombie_attc11	=[	$attc11,	zombie_attc12	] {ai_face();
	ZombieThrowFlesh('18 13 24');};
void() zombie_attc12	=[	$attc12,	zombie_run1		] {};

//----------------------------------------------------------------------
void() zombie_missile =
{
	self.lip = self.meleeattack;
	// Don't pick the same attack twice in a row
	while (self.lip == self.meleeattack) {
		self.lip = rint(random()*3);
	}

	self.meleeattack = self.lip;
	if (self.meleeattack == 1) zombie_atta1 ();
	else if (self.meleeattack == 2) zombie_attb1 ();
	else zombie_attc1 ();
};

//======================================================================
// PAIN
//======================================================================
void() zombie_paina1	=[	$paina1,	zombie_paina2	] {zombie_sound(4);};
void() zombie_paina2	=[	$paina2,	zombie_paina3	] {ai_painforward(3);};
void() zombie_paina3	=[	$paina3,	zombie_paina4	] {ai_painforward(1);};
void() zombie_paina4	=[	$paina4,	zombie_paina5	] {ai_pain(1);};
void() zombie_paina5	=[	$paina5,	zombie_paina6	] {ai_pain(3);};
void() zombie_paina6	=[	$paina6,	zombie_paina7	] {ai_pain(1);};
void() zombie_paina7	=[	$paina7,	zombie_paina8	] {};
void() zombie_paina8	=[	$paina8,	zombie_paina9	] {};
void() zombie_paina9	=[	$paina9,	zombie_paina10	] {};
void() zombie_paina10	=[	$paina10,	zombie_paina11	] {};
void() zombie_paina11	=[	$paina11,	zombie_paina12	] {};
void() zombie_paina12	=[	$paina12,	zombie_run1		] {};

//----------------------------------------------------------------------
void() zombie_painc1	=[	$painc1,	zombie_painc2	] {zombie_sound(4);};
void() zombie_painc2	=[	$painc2,	zombie_painc3	] {};
void() zombie_painc3	=[	$painc3,	zombie_painc4	] {ai_pain(3);};
void() zombie_painc4	=[	$painc4,	zombie_painc5	] {ai_pain(1);};
void() zombie_painc5	=[	$painc5,	zombie_painc6	] {};
void() zombie_painc6	=[	$painc6,	zombie_painc7	] {};
void() zombie_painc7	=[	$painc7,	zombie_painc8	] {};
void() zombie_painc8	=[	$painc8,	zombie_painc9	] {};
void() zombie_painc9	=[	$painc9,	zombie_painc10	] {};
void() zombie_painc10	=[	$painc10,	zombie_painc11	] {};
void() zombie_painc11	=[	$painc11,	zombie_painc12	] {ai_painforward(1);};
void() zombie_painc12	=[	$painc12,	zombie_painc13	] {ai_painforward(1);};
void() zombie_painc13	=[	$painc13,	zombie_painc14	] {};
void() zombie_painc14	=[	$painc14,	zombie_painc15	] {};
void() zombie_painc15	=[	$painc15,	zombie_painc16	] {};
void() zombie_painc16	=[	$painc16,	zombie_painc17	] {};
void() zombie_painc17	=[	$painc17,	zombie_painc18	] {};
void() zombie_painc18	=[	$painc18,	zombie_run1	] {};

//----------------------------------------------------------------------
void() zombie_paind1	=[	$paind1,	zombie_paind2	] {zombie_sound(4);};
void() zombie_paind2	=[	$paind2,	zombie_paind3	] {};
void() zombie_paind3	=[	$paind3,	zombie_paind4	] {};
void() zombie_paind4	=[	$paind4,	zombie_paind5	] {};
void() zombie_paind5	=[	$paind5,	zombie_paind6	] {};
void() zombie_paind6	=[	$paind6,	zombie_paind7	] {};
void() zombie_paind7	=[	$paind7,	zombie_paind8	] {};
void() zombie_paind8	=[	$paind8,	zombie_paind9	] {};
void() zombie_paind9	=[	$paind9,	zombie_paind10	] {ai_pain(1);};
void() zombie_paind10	=[	$paind10,	zombie_paind11	] {};
void() zombie_paind11	=[	$paind11,	zombie_paind12	] {};
void() zombie_paind12	=[	$paind12,	zombie_paind13	] {};
void() zombie_paind13	=[	$paind13,	zombie_run1	] {};

//----------------------------------------------------------------------
// Fall down - B : random pain, E : large amount of damage
//----------------------------------------------------------------------
void() zombie_painb1	=[	$painb1,	zombie_painb2	] {self.inpain = 2;};
void() zombie_painb2	=[	$painb2,	zombie_painb3	] {ai_pain(2);};
void() zombie_painb3	=[	$painb3,	zombie_painb4	] {ai_pain(8);};
void() zombie_painb4	=[	$painb4,	zombie_painb5	] {ai_pain(6);};
void() zombie_painb5	=[	$painb5,	zombie_painb6	] {ai_pain(2);};
void() zombie_painb6	=[	$painb6,	zombie_painb7	] {};
void() zombie_painb7	=[	$painb7,	zombie_painb8	] {zombie_sound(5);};
void() zombie_painb8	=[	$painb8,	zombie_painb9	] {self.solid = SOLID_NOT;};
void() zombie_painb9	=[	$painb9,	zombie_painb9	] {
	zombie_onground(MONAI_ZOMBIEUPB);};

// Start of get up sequence
void() zombie_painb10	=[	$painb10,	zombie_painb11	] {};
void() zombie_painb11	=[	$painb11,	zombie_painb12	] {};
void() zombie_painb12	=[	$painb12,	zombie_painb13	] {};
void() zombie_painb13	=[	$painb13,	zombie_painb14	] {};
void() zombie_painb14	=[	$painb14,	zombie_painb15	] {};
void() zombie_painb15	=[	$painb15,	zombie_painb16	] {};
void() zombie_painb16	=[	$painb16,	zombie_painb17	] {};
void() zombie_painb17	=[	$painb17,	zombie_painb18	] {};
void() zombie_painb18	=[	$painb18,	zombie_painb19	] {};
void() zombie_painb19	=[	$painb19,	zombie_painb20	] {};
void() zombie_painb20	=[	$painb20,	zombie_painb21	] {};
void() zombie_painb21	=[	$painb21,	zombie_painb22	] {};
void() zombie_painb22	=[	$painb22,	zombie_painb23	] {};
void() zombie_painb23	=[	$painb23,	zombie_painb24	] {};
void() zombie_painb24	=[	$painb24,	zombie_painb25	] {};
void() zombie_painb25	=[	$painb25,	zombie_painb26	] {monster_footstep(FALSE); ai_painforward(1);};
void() zombie_painb26	=[	$painb26,	zombie_painb27	] {};
void() zombie_painb27	=[	$painb27,	zombie_painb28	] {};
void() zombie_painb28	=[	$painb28,	zombie_run1		] {
	// If getting up for the first time (onfloor) check for targets
	if (self.spawnflags & MON_ONFLOOR) {
		self.spawnflags = self.spawnflags - MON_ONFLOOR;
		monster_targets();
	}
};

//----------------------------------------------------------------------
void() zombie_paine1	=[	$paine1,	zombie_paine2	] {self.inpain = 2;};
void() zombie_paine2	=[	$paine2,	zombie_paine3	] {ai_pain(8);};
void() zombie_paine3	=[	$paine3,	zombie_paine4	] {ai_pain(5);};
void() zombie_paine4	=[	$paine4,	zombie_paine5	] {ai_pain(3);};
void() zombie_paine5	=[	$paine5,	zombie_paine6	] {ai_pain(1);};
void() zombie_paine6	=[	$paine6,	zombie_paine7	] {ai_pain(2);};
void() zombie_paine7	=[	$paine7,	zombie_paine8	] {ai_pain(1);};
void() zombie_paine8	=[	$paine8,	zombie_paine9	] {ai_pain(1);};
void() zombie_paine9	=[	$paine9,	zombie_paine10	] {ai_pain(2);};
void() zombie_paine10	=[	$paine10,	zombie_paine11	] {zombie_sound(5);};
void() zombie_paine11	=[	$paine11,	zombie_paine12	] {self.solid = SOLID_NOT;};
void() zombie_paine12	=[	$paine12,	zombie_paine12	] {
	zombie_onground(MONAI_ZOMBIEUPE);};

// Start of get up sequence
void() zombie_paine13	=[	$paine13,	zombie_paine14	] {};
void() zombie_paine14	=[	$paine14,	zombie_paine15	] {};
void() zombie_paine15	=[	$paine15,	zombie_paine16	] {};
void() zombie_paine16	=[	$paine16,	zombie_paine17	] {};
void() zombie_paine17	=[	$paine17,	zombie_paine18	] {};
void() zombie_paine18	=[	$paine18,	zombie_paine19	] {};
void() zombie_paine19	=[	$paine19,	zombie_paine20	] {};
void() zombie_paine20	=[	$paine20,	zombie_paine21	] {};
void() zombie_paine21	=[	$paine21,	zombie_paine22	] {};
void() zombie_paine22	=[	$paine22,	zombie_paine23	] {};
void() zombie_paine23	=[	$paine23,	zombie_paine24	] {};
void() zombie_paine24	=[	$paine24,	zombie_paine25	] {monster_footstep(FALSE);};
void() zombie_paine25	=[	$paine25,	zombie_paine26	] {ai_painforward(5);};
void() zombie_paine26	=[	$paine26,	zombie_paine27	] {ai_painforward(3);};
void() zombie_paine27	=[	$paine27,	zombie_paine28	] {ai_painforward(1);};
void() zombie_paine28	=[	$paine28,	zombie_paine29	] {ai_pain(1);};
void() zombie_paine29	=[	$paine29,	zombie_paine30	] {};
void() zombie_paine30	=[	$paine30,	zombie_run1		] {
	// If getting up for the first time (onfloor) check for targets
	if (self.spawnflags & MON_ONFLOOR) {
		self.spawnflags = self.spawnflags - MON_ONFLOOR;
		monster_targets();
	}
};

/*======================================================================
 ZOMBIE PAIN
 * All damage must come through pain function to reset health
 * Be careful blocking zombie pain function with pain_finished
 * zombies react in 2 ways, minor pain (a,c,d) and full knockdown (b,e)
======================================================================*/
void(entity inflictor, entity attacker, float take) zombie_pain =
{
	// Is the zombie in the process of dying?
	if (self.deadflag > DEAD_NO) return;
	// Always reset health
	self.health = self.max_health;

	// Check for invulnerability frames and shadow axe
	if (self.inpain > 0 && self.axhitme == 2) {
		self.axhitme = 0;				// Reset axe
		self.health = self.gibhealth;	// Reset Health
		Killed (self, attacker);		// Gib time
		return;
	}
	else self.axhitme = 0;	// Reset axe

	//----------------------------------------------------------------------
	// Pain/damage too low OR down on ground, totally ignore
	//----------------------------------------------------------------------
	if (take < MONAI_ZOMBIELOW_DAM || self.inpain == 2) return;

	//----------------------------------------------------------------------
	// Damage 29-60, drop straight away to ground (SSG, Quad NG)
	// This has to be a single large hit over 0.1 frame
	//----------------------------------------------------------------------
	if (take > MONAI_ZOMBIEHGH_DAM) {
		zombie_paine1();
		return;
	}

	//----------------------------------------------------------------------
	// Projectile shotguns pellets don't all hit at same time
	// they accumulate over time and can distort damage values
	// Need to block damage over time to detect second hit
	// Cannot use pain_finished because it blocks the pain function
	// and the health needs to be reset all the time
	// Using 'lefty' because zombies don't use it for anything
	if (self.lefty < time && self.inpain == 1) {
		// Second hit, drop to ground
		zombie_paine1 ();
		return;
	}

	//----------------------------------------------------------------------
	// Damage 9-25 random pain animation (random chance of knockdown painb)
	//----------------------------------------------------------------------
	if (self.inpain) return;	// Already in minor pain
	self.inpain = 1;			// Minor pain active
	self.lefty = time + 0.5;	// Wait for second hit
	self.lip = random();
	if (self.lip < 0.25) zombie_paina1 ();		// 12 frames (bent over, short)
	else if (self.lip < 0.5) zombie_painb1 ();	// 28 frames (9 = on ground)
	else if (self.lip < 0.75) zombie_painc1 ();	// 18 frames (bent over, long)
	else zombie_paind1 ();						// 13 frames (slight hit)
};

/*=============================================================================
 ZOMBIE WAKEUP (check if can get up)
=============================================================================*/
void() zombie_wakeup	= {
	if (self.gibbed) return;			// Do nothing dead
	
	self.use = SUB_Null;				// No more using at this point
	if (!self.enemy) FindTarget();		// If no enemy, look around?

	// Make sure bounding box is correct, if blocked can be set 0,0,0
	setsize (self, self.bbmins, self.bbmaxs);
	// Turn monster collision on and test if can walk forward
	self.solid = SOLID_SLIDEBOX;
	if (!walkmove (0, 0))
	{
		self.inpain = 2;				// On ground
		self.nextthink = time + 0.1;	// Keep checking
		self.think = self.th_wakeup;	// Same function
		self.solid = SOLID_NOT;			// No world interaction yet
		// Check if something has been blocking the zombie from getting up
		// This is a check for weird world/bmodel geo or monster/players
		// standing on zombies while on the ground trying to get up!
		self.count = self.count + 1;
		if (self.count > MONAI_ZOMBGRDBLOCK) {
			self.health = self.gibhealth;	// Gib time
			Killed(self, self);				// Register death
			return;
		}
	}
	else {
		self.bodyonflr = "";			// Body is chop proof!
		self.inpain = 2;				// Animation not finished
		zombie_sound(6);				// Wake up sound
		self.nextthink = time + 0.1;
		self.use = monster_use;			// Just in case interruption
		if (self.zombieflr == MONAI_ZOMBIEUPB) self.think = zombie_painb10;
		else self.think = zombie_paine13;
	}
};

//----------------------------------------------------------------------
// Puts the zombie on the floor with a random Yaw rotation
// paintype = 0 Setup on floor with use trigger
// paintype > 0 On floor and waiting to get back up
//----------------------------------------------------------------------
void(float frameno) zombie_onground = {
	self.health = self.max_health;	// reset health
	self.inpain = 2;				// Lying on floor, no pain
	self.count = 0;					// Reset get up tries
	self.solid = SOLID_NOT;			// No world interaction
	self.bodyonflr = MON_ONFLR;		// mark body for the chop

	// Does the zombie start on the ground?
	if (frameno == MONAI_ZOMBIEFLR) {
		// Do nothing else while on the floor
		self.nextthink = self.pausetime;
		self.think = SUB_Null;

		// Check for spawning onfloor orientation flag
		// aflag = 1 Forward = 2 Backward
		if (self.aflag < 1 || self.aflag > 2) {
			if (random() < 0.5) self.aflag = 1;
			else self.aflag = 2;
		}

		// Pick random starting pose
		if (self.aflag == 1) {
			self.zombieflr = MONAI_ZOMBIEUPB;
			self.frame = $painb9;
		}
		else {
			self.zombieflr = MONAI_ZOMBIEUPE;
			self.frame = $paine12;
		}
		// If no angle set, Random fall direction
		if (self.angles_y < 1) self.angles_y = rint(random()*359);
		self.use = self.th_wakeup;
		self.fixangle = TRUE;
		// Reset onspawn fall down angle (only used once)
		self.aflag = 0;
	}
	else {
		self.zombieflr = frameno;	// Wakeup pose for later
		// Keep zombies on the ground and check again later
		self.nextthink = self.nextthink + MONAI_ZOMBGRDTIMER;
		self.think = self.th_wakeup;
	}
};

/*============================================================================
 All sounds used
 1 = sticking around, crucified
 2 = strutting the stuff (walking)
 3 = running (in slow motion)
 4 = all pain routines (zombie_paina1, _painb1, _painc1, _paind1, _paine1)
 5 = its a knockout!
 6 = get up and moan about it
 7 = fire zombie gib
============================================================================*/
void(float type) zombie_sound =
{
	// check for gibbed or idle sound block
	if (self.health < 1) return;
	if (self.spawnflags & MON_SPAWN_NOIDLE && type < 3) return;
	
	// Random sound check
 	self.lip = random();
	if (type == 1) {
		if (self.lip < 0.1) 
			sound (self, CHAN_VOICE, "zombie/idle_w2.wav", 1, ATTN_STATIC);
	}
	else if (type == 2 && self.idletimer < time) {
	 	self.idletimer = time + 1 + (random()*2);
		if (self.lip < 0.2)
			sound (self, CHAN_VOICE, "zombie/z_idle.wav", 1, ATTN_IDLE);
	}
	else if (type == 3 && self.idletimer < time) {
	 	self.idletimer = time + 1 + (random()*2);
		if (self.lip < 0.2) sound (self, CHAN_VOICE, "zombie/z_idle.wav", 1, ATTN_IDLE);
		if (self.lip > 0.8) sound (self, CHAN_VOICE, "zombie/z_idle1.wav", 1, ATTN_IDLE);
	}
	else if (type == 4) {
		if (self.lip < 0.25) sound (self, CHAN_VOICE, self.pain_sound, 1, ATTN_NORM);
		else if (self.lip < 0.5) sound (self, CHAN_VOICE, self.pain_sound2, 1, ATTN_NORM);
	}
	else if (type == 5) {
		sound (self, CHAN_BODY, "zombie/z_fall.wav", 1, ATTN_NORM);
	}
	else if (type == 6) {
		if (self.lip < 0.5) sound (self, CHAN_VOICE, "zombie/z_idle.wav", 1, ATTN_IDLE);
		else sound (self, CHAN_VOICE, "zombie/z_idle1.wav", 1, ATTN_IDLE);
	}
	else if (type == 7) {
		sound (self, CHAN_WEAPON, "zombie/z_shot1.wav", 1, ATTN_NORM);
	}
};

//============================================================================
void() zombie_die =
{
	self.health = self.gibhealth; // Force gib
	monster_death_precheck();
};

//============================================================================
void() zombie_cruc1	= [$cruc_1,zombie_cruc2] {zombie_sound(1);};
void() zombie_cruc2	= [$cruc_2,zombie_cruc3] {self.nextthink = time + 0.1 + random()*0.1;};
void() zombie_cruc3	= [$cruc_3,zombie_cruc4] {self.nextthink = time + 0.1 + random()*0.1;};
void() zombie_cruc4	= [$cruc_4,zombie_cruc5] {self.nextthink = time + 0.1 + random()*0.1;};
void() zombie_cruc5	= [$cruc_5,zombie_cruc6] {self.nextthink = time + 0.1 + random()*0.1;};
void() zombie_cruc6	= [$cruc_6,zombie_cruc1] {self.nextthink = time + 0.1 + random()*0.1;};

//----------------------------------------------------------------------
void(entity inflictor, entity attacker, float damage) zombie_cruc_pain =
{
	self.health = self.max_health;				// reset health	
	// Any pain to moan about?
	if (self.pain_finished < time) zombie_sound(4);
	self.pain_finished = time + 1 + random();
};

//----------------------------------------------------------------------
void() zombie_cruc_spawn =
{
	self.use = SUB_Null;				// No more triggers
	self.solid = SOLID_BBOX;			// Interact with objects
	self.movetype = MOVETYPE_FLY;		// Cannot be movetype_none
	setmodel(self, self.mdl);			// Nail to cross
	setsize (self, self.bbmins, self.bbmaxs);

	// Setup exact/randon skin choices
	self.randomskin = 4;
	if (self.exactskin > 0) self.skin = rint(self.exactskin);
	else self.skin = rint(random()*(self.randomskin-1));
	if (self.skin < 0) self.skin = 0;	// Double check no negatives	
	
	self.takedamage = DAMAGE_AIM;		// Can receive damage
	self.velocity = '0 0 0';			// Make sure stationary
	self.deadflag = DEAD_NO;			// used to stop death re-triggering
	self.view_ofs = '0 0 -24';			// Standard setup
	self.pain_timeout = 1;				// Default
	
	zombie_cruc1 ();					// Time to do some moaning
};

//----------------------------------------------------------------------
void() zombie_cruc_setup =
{
	// Setup AI functions
	self.th_stand = self.th_walk = self.th_run = zombie_cruc1;
	self.th_pain = zombie_cruc_pain; self.th_die = zombie_die;
	
	self.gibbed = FALSE;				// Still in one piece
	self.health = self.max_health = 60;	// Save for later
	self.gibhealth = 0 - self.health;	// Work out damage trigger
	self.pain_flinch = 10;				// Always in pain
	self.nomonstercount = TRUE;			// Don't include in initial total

	// Zombies cannot be crucified and on the floor at once!
	self.spawnflags = self.spawnflags - (self.spawnflags & MON_ONFLOOR);
	
	self.flags = FL_MONSTER;			// Always reset this flag
	self.effects = 0;					// Always reset
	self.oldorigin = self.origin;		// Save origin
	self.bbmins = '-8 -8 -24';			// Narrow pole
	self.bbmaxs = '8 8 32';

	if (self.spawnflags & MON_SPAWN_DELAY) {
		setmodel(self, string_null);
		self.solid = SOLID_NOT;				// No world interaction
		self.use = zombie_cruc_spawn;		// Wait for trigger
	}
	else {
		// Variable start delay on all monsters to reduce packet errors
		self.nextthink = time + 0.1 + random()*0.4;
		self.think = zombie_cruc_spawn;
	}
};

/*======================================================================
 QUAKED monster_zombie (1 0 0) (-16 -16 -24) (16 16 32) Crucified ambush FLOOR
If crucified, stick the bounding box 12 pixels back into a wall to look right.
======================================================================*/
void() monster_zombie =
{
	if (deathmatch) { remove(self); return; }

	// Stupid ID getting the crucified and ambush back to front on zombies
	// Lets fix the problem and reverse the flags to match everything else
	if (self.classtype != CT_MONMUMMY) {
		if (self.spawnflags & MON_ZOMCRUCIFIED || self.spawnflags & MON_ZOMBAMBUSH) {
			self.health = 0;		// Temporarily use this variable
			if (self.spawnflags & MON_ZOMCRUCIFIED) self.health = self.health + MON_CRUCIFIED;
			if (self.spawnflags & MON_ZOMBAMBUSH) self.health = self.health + MON_AMBUSH;
			
			// Removed the old bits and then add the new one's
			self.spawnflags = self.spawnflags - (self.spawnflags & MON_ZOMIDHACK);
			self.spawnflags = self.spawnflags + self.health;
		}
	}

	self.mdl = "progs/mon_zombie.mdl";
	self.headmdl = "progs/h_zombie.mdl";
	precache_model (self.mdl);
	precache_model (self.headmdl);
	precache_model (MODEL_PROJ_FLESH); 	// Also in world.qc

	precache_sound ("zombie/z_idle.wav");	// Idle A
	precache_sound ("zombie/z_idle1.wav");	// Idle B
	precache_sound ("zombie/idle_w2.wav");	// Crucified

	self.pain_sound = "zombie/z_pain.wav";
	self.pain_sound2 = "zombie/z_pain1.wav";
	precache_sound (self.pain_sound);
	precache_sound (self.pain_sound2);

	precache_sound ("zombie/z_shot1.wav");	// Swipe sound
	precache_sound ("zombie/z_fall.wav");	// Impact - floor
	precache_sound ("zombie/z_miss.wav");	// Impact - miss
	precache_sound ("zombie/z_hit.wav");	// Impact - hit
	precache_sound ("zombie/z_gib.wav");	// Death sound

	self.sight_sound = "zombie/z_idle.wav";
	precache_sound (self.sight_sound);

	// Check for poisonous entity flag
	if (self.poisonous) {
		precache_poisongibs();				// precache gibs
		self.gibtype = GIBTYPE_POISON;		// Poisonous blood trails
		precache_model (MODEL_PROJ_FLESHP);	// Green flesh!?!
	}

	self.solid = SOLID_NOT;					// No interaction with world
	self.movetype = MOVETYPE_NONE;			// Static item, no movement
	if (self.bboxtype < 1) self.bboxtype = BBOX_SHORT;
	if (!self.classtype) self.classtype = CT_MONZOMBIE;
	self.classgroup = CG_ZOMBIE;			// One big happy zombie family!
	self.classmove = MON_MOVEWALK;
	if (!self.exactskin) self.randomskin = 4;
	if (self.deathstring == "")
		self.deathstring = " joins the Zombies\n";

	// Always reset Ammo Resistance to be consistent
	self.resist_shells = self.resist_nails = 0;
	self.resist_rockets = self.resist_cells = 0;

	// Setup crucified zombies
	if (self.spawnflags & MON_CRUCIFIED) zombie_cruc_setup();
	else {
		// Setup zombie ready for placement
		self.health = 60;						// Basic health (cannot override)
		self.gibhealth = -60;					// Gib value, not used
		self.gibbed = FALSE;					// In one piece
		self.pain_flinch = MONAI_ZOMBIEHGH_DAM;
		self.steptype = FS_TYPESLOW;			// Small leg
		self.altsteptype = FS_TYPEDRAG;			// Clubfoot
		self.pain_timeout = -5;					// Always go into pain (health reset)
		if (!self.movespeed) self.movespeed = 1;// Adjustable speed via skill level
		self.inpain = 0;						// Zombie starts with no pain lock
		self.count = 0;							// Reset get up timer

		self.th_stand = zombie_stand1;
		self.th_walk = zombie_walk1;
		self.th_run = zombie_run1;
		self.th_pain = zombie_pain;
		self.th_die = zombie_die;
		self.th_missile = zombie_missile;
		self.th_wakeup = zombie_wakeup;			// Get off floor
		
		monster_start();
	}
};

/*======================================================================
 QUAKED monster_mummy (1 0 0) (-16 -16 -24) (16 16 32) ambush x FLOOR
Poisonous Zombie that explodes poisonous gibs on death
======================================================================*/
void() monster_mummy =
{
	self.classtype = CT_MONMUMMY;			// Special poison zombie
	self.exactskin = 6;						// Mouldly bandages
	self.no_liquiddmg = TRUE;				// Immune to slime/lava
	self.spawnflags  = self.spawnflags - (self.spawnflags & MON_CRUCIFIED);
	self.deathstring = " was Mummified\n";
	
	// The mummy is just poisonous, it is still a zombie
	monster_zombie();
};

