Files
quakemapping/mod_ad/my_progs/mon_zombiek.qc
2019-12-30 22:24:44 +01:00

873 lines
41 KiB
Plaintext

/*======================================================================
Zombie KNIGHT (undead version of original knight)
======================================================================*/
$cd id1/models/zombiek
$origin 0 0 24
$base base
$skin skin
// (001 - 015) Default stand - breathing
$frame stand1 stand2 stand3 stand4 stand5 stand6 stand7 stand8
$frame stand9 stand10 stand11 stand12 stand13 stand14 stand15
// (016 - 029) Default walk dragging left foot
$frame walk1 walk2 walk3 walk4 walk5 walk6 walk7 walk8
$frame walk9 walk10 walk11 walk12 walk13 walk14
// (030 - 040) Default run, fast for a zombie
$frame run1 run2 run3 run4 run5 run6 run7 run8 run9 run10 run11
// (041 - 052) Still moving forward
$frame paina1 paina2 paina3 paina4 paina5 paina6 paina7 paina8
$frame paina9 paina10 paina11 paina12
// (053 - 077) Stagger backwards, long animation
$frame painb1 painb2 painb3 painb4 painb5 painb6 painb7 painb8
$frame painb9 painb10 painb11 painb12 painb13 painb14 painb15 painb16
$frame painb17 painb18 painb19 painb20 painb21 painb22 painb23 painb24 painb25
// (078 - 098) Fall down to knees and get back up
$frame painc1 painc2 painc3 painc4 painc5 painc6 painc7 painc8
$frame painc9 painc10 painc11 painc12 painc13 painc14 painc15 painc16
$frame painc17 painc18 painc19 painc20 painc21
// (099 - 121) Fall down FORWARD (paind12 = on floor)
$frame paind1 paind2 paind3 paind4 paind5 paind6 paind7 paind8
$frame paind9 paind10 paind11 paind12 paind13 paind14 paind15 paind16
$frame paind17 paind18 paind19 paind20 paind21 paind22 paind23
// (122 - 152) Fall down BACKWARD (paine12 = on floor)
$frame paine1 paine2 paine3 paine4 paine5 paine6 paine7 paine8
$frame paine9 paine10 paine11 paine12 paine13 paine14 paine15 paine16
$frame paine17 paine18 paine19 paine20 paine21 paine22 paine23 paine24
$frame paine25 paine26 paine27 paine28 paine29 paine30 paine31
// (153 - 171) Melee Attack 1 - Smash (chop overhead to ground)
$frame atta1 atta2 atta3 atta4 atta5 atta6 atta7 atta8
$frame atta9 atta10 atta11 atta12 atta13 atta14 atta15 atta16 atta17 atta18 atta19
// (172 - 188) Melee Attack 2 - Stationary over arm swing
$frame attb1 attb2 attb3 attb4 attb5 attb6 attb7 attb8
$frame attb9 attb10 attb11 attb12 attb13 attb14 attb15 attb16 attb17
// (189 - 203) Melee Attack 3 - Stationary sideways swing
$frame attc1 attc2 attc3 attc4 attc5 attc6 attc7 attc8
$frame attc9 attc10 attc11 attc12 attc13 attc14 attc15
// (204 - 223) idle 2 - scratch brains
$frame idleb1 idleb2 idleb3 idleb4 idleb5 idleb6 idleb7 idleb8
$frame idleb9 idleb10 idleb11 idleb12 idleb13 idleb14 idleb15 idleb16
$frame idleb17 idleb18 idleb19 idleb20
// (224 - 238) idle 3 - swing head LEFT
$frame idlec1 idlec2 idlec3 idlec4 idlec5 idlec6 idlec7 idlec8
$frame idlec9 idlec10 idlec11 idlec12 idlec13 idlec14 idlec15
// (239 - 253) idle 4 - swing head RIGHT
$frame idled1 idled2 idled3 idled4 idled5 idled6 idled7 idled8
$frame idled9 idled10 idled11 idled12 idled13 idled14 idled15
void(float type) zombiek_sound;
void() zombiek_knockdown;
//=============================================================================
void() zombiek_standB1 =[ $idleb1, zombiek_standB2 ] {ai_stand();};
void() zombiek_standB2 =[ $idleb2, zombiek_standB3 ] {ai_stand();};
void() zombiek_standB3 =[ $idleb3, zombiek_standB4 ] {ai_stand();};
void() zombiek_standB4 =[ $idleb4, zombiek_standB5 ] {ai_stand();};
void() zombiek_standB5 =[ $idleb5, zombiek_standB6 ] {ai_stand();};
void() zombiek_standB6 =[ $idleb6, zombiek_standB7 ] {ai_stand();};
void() zombiek_standB7 =[ $idleb7, zombiek_standB8 ] {ai_stand();};
void() zombiek_standB8 =[ $idleb8, zombiek_standB9 ] {ai_stand();};
void() zombiek_standB9 =[ $idleb9, zombiek_standB10 ] {ai_stand();};
void() zombiek_standB10 =[ $idleb10, zombiek_standB11 ] {ai_stand();};
void() zombiek_standB11 =[ $idleb11, zombiek_standB12 ] {ai_stand();};
void() zombiek_standB12 =[ $idleb12, zombiek_standB13 ] {ai_stand();};
void() zombiek_standB13 =[ $idleb13, zombiek_standB14 ] {ai_stand();};
void() zombiek_standB14 =[ $idleb14, zombiek_standB15 ] {ai_stand();};
void() zombiek_standB15 =[ $idleb15, zombiek_standB16 ] {ai_stand();};
void() zombiek_standB16 =[ $idleb16, zombiek_standB17 ] {ai_stand();};
void() zombiek_standB17 =[ $idleb17, zombiek_standB18 ] {ai_stand();};
void() zombiek_standB18 =[ $idleb18, zombiek_standB19 ] {ai_stand();};
void() zombiek_standB19 =[ $idleb19, zombiek_standB20 ] {ai_stand();};
void() zombiek_standB20 =[ $idleb20, zombiek_stand1 ] {ai_stand();};
//=============================================================================
void() zombiek_standC1 =[ $idlec1, zombiek_standC2 ] {ai_stand();};
void() zombiek_standC2 =[ $idlec2, zombiek_standC3 ] {ai_stand();};
void() zombiek_standC3 =[ $idlec3, zombiek_standC4 ] {ai_stand();};
void() zombiek_standC4 =[ $idlec4, zombiek_standC5 ] {ai_stand();};
void() zombiek_standC5 =[ $idlec5, zombiek_standC6 ] {ai_stand();};
void() zombiek_standC6 =[ $idlec6, zombiek_standC7 ] {ai_stand();};
void() zombiek_standC7 =[ $idlec7, zombiek_standC8 ] {ai_stand();};
void() zombiek_standC8 =[ $idlec8, zombiek_standC9 ] {ai_stand();};
void() zombiek_standC9 =[ $idlec9, zombiek_standC10 ] {ai_stand();};
void() zombiek_standC10 =[ $idlec10, zombiek_standC11 ] {ai_stand();};
void() zombiek_standC11 =[ $idlec11, zombiek_standC12 ] {ai_stand();};
void() zombiek_standC12 =[ $idlec12, zombiek_standC13 ] {ai_stand();};
void() zombiek_standC13 =[ $idlec13, zombiek_standC14 ] {ai_stand();};
void() zombiek_standC14 =[ $idlec14, zombiek_standC15 ] {ai_stand();};
void() zombiek_standC15 =[ $idlec15, zombiek_stand1 ] {ai_stand();};
//=============================================================================
void() zombiek_standD1 =[ $idled1, zombiek_standD2 ] {ai_stand();};
void() zombiek_standD2 =[ $idled2, zombiek_standD3 ] {ai_stand();};
void() zombiek_standD3 =[ $idled3, zombiek_standD4 ] {ai_stand();};
void() zombiek_standD4 =[ $idled4, zombiek_standD5 ] {ai_stand();};
void() zombiek_standD5 =[ $idled5, zombiek_standD6 ] {ai_stand();};
void() zombiek_standD6 =[ $idled6, zombiek_standD7 ] {ai_stand();};
void() zombiek_standD7 =[ $idled7, zombiek_standD8 ] {ai_stand();};
void() zombiek_standD8 =[ $idled8, zombiek_standD9 ] {ai_stand();};
void() zombiek_standD9 =[ $idled9, zombiek_standD10 ] {ai_stand();};
void() zombiek_standD10 =[ $idled10, zombiek_standD11 ] {ai_stand();};
void() zombiek_standD11 =[ $idled11, zombiek_standD12 ] {ai_stand();};
void() zombiek_standD12 =[ $idled12, zombiek_standD13 ] {ai_stand();};
void() zombiek_standD13 =[ $idled13, zombiek_standD14 ] {ai_stand();};
void() zombiek_standD14 =[ $idled14, zombiek_standD15 ] {ai_stand();};
void() zombiek_standD15 =[ $idled15, zombiek_stand1 ] {ai_stand();};
//----------------------------------------------------------------------
void() zombiek_standE1 =[ $idlec1, zombiek_standE2 ] {ai_stand();};
void() zombiek_standE2 =[ $idlec2, zombiek_standE3 ] {ai_stand();};
void() zombiek_standE3 =[ $idlec3, zombiek_standE4 ] {ai_stand();};
void() zombiek_standE4 =[ $idlec4, zombiek_standE5 ] {ai_stand();};
void() zombiek_standE5 =[ $idlec5, zombiek_standE6 ] {ai_stand();};
void() zombiek_standE6 =[ $idlec6, zombiek_standE7 ] {ai_stand();};
void() zombiek_standE7 =[ $idlec7, zombiek_standE8 ] {ai_stand();};
void() zombiek_standE8 =[ $idlec8, zombiek_standE9 ] {ai_stand();};
void() zombiek_standE9 =[ $idlec9, zombiek_standE10 ] {ai_stand();};
void() zombiek_standE10 =[ $idlec10, zombiek_standE11 ] {ai_stand();};
void() zombiek_standE11 =[ $idlec11, zombiek_standE12 ] {ai_stand();};
void() zombiek_standE12 =[ $idlec12, zombiek_standE13 ] {ai_stand();};
void() zombiek_standE13 =[ $idlec13, zombiek_standE14 ] {ai_stand();};
void() zombiek_standE14 =[ $idlec14, zombiek_standE15 ] {ai_stand();};
void() zombiek_standE15 =[ $idlec15, zombiek_standE16 ] {ai_stand();};
void() zombiek_standE16 =[ $idled1, zombiek_standE17 ] {ai_stand();};
void() zombiek_standE17 =[ $idled2, zombiek_standE18 ] {ai_stand();};
void() zombiek_standE18 =[ $idled3, zombiek_standE19 ] {ai_stand();};
void() zombiek_standE19 =[ $idled4, zombiek_standE20 ] {ai_stand();};
void() zombiek_standE20 =[ $idled5, zombiek_standE21 ] {ai_stand();};
void() zombiek_standE21 =[ $idled6, zombiek_standE22 ] {ai_stand();};
void() zombiek_standE22 =[ $idled7, zombiek_standE23 ] {ai_stand();};
void() zombiek_standE23 =[ $idled8, zombiek_standE24 ] {ai_stand();};
void() zombiek_standE24 =[ $idled9, zombiek_standE25 ] {ai_stand();};
void() zombiek_standE25 =[ $idled10, zombiek_standE26 ] {ai_stand();};
void() zombiek_standE26 =[ $idled11, zombiek_standE27 ] {ai_stand();};
void() zombiek_standE27 =[ $idled12, zombiek_standE28 ] {ai_stand();};
void() zombiek_standE28 =[ $idled13, zombiek_standE29 ] {ai_stand();};
void() zombiek_standE29 =[ $idled14, zombiek_standE30 ] {ai_stand();};
void() zombiek_standE30 =[ $idled15, zombiek_stand1 ] {ai_stand();};
//----------------------------------------------------------------------
void() zombiek_stand1 =[ $stand1, zombiek_stand2 ] {ai_stand();};
void() zombiek_stand2 =[ $stand2, zombiek_stand3 ] {ai_stand();};
void() zombiek_stand3 =[ $stand3, zombiek_stand4 ] {ai_stand();};
void() zombiek_stand4 =[ $stand4, zombiek_stand5 ] {ai_stand();};
void() zombiek_stand5 =[ $stand5, zombiek_stand6 ] {ai_stand();};
void() zombiek_stand6 =[ $stand6, zombiek_stand7 ] {ai_stand();};
void() zombiek_stand7 =[ $stand7, zombiek_stand8 ] {ai_stand();};
void() zombiek_stand8 =[ $stand8, zombiek_stand9 ] {ai_stand();};
void() zombiek_stand9 =[ $stand9, zombiek_stand10 ] {ai_stand();};
void() zombiek_stand10 =[ $stand10, zombiek_stand11 ] {ai_stand();};
void() zombiek_stand11 =[ $stand11, zombiek_stand12 ] {ai_stand();};
void() zombiek_stand12 =[ $stand12, zombiek_stand13 ] {ai_stand();};
void() zombiek_stand13 =[ $stand13, zombiek_stand14 ] {ai_stand();};
void() zombiek_stand14 =[ $stand14, zombiek_stand15 ] {ai_stand();};
void() zombiek_stand15 =[ $stand15, zombiek_stand1 ] {
self.idlebusy = FALSE;
self.solid = SOLID_SLIDEBOX;
if (random() < MON_IDLE_ANIMATION) {
self.idlebusy = TRUE;
// Make sure the idle animations don't repeat in a row
self.lefty = self.lip;
while (self.lefty == self.lip) { self.lefty = rint(random()*4);}
self.lip = self.lefty;
if (self.lip < 1) self.think = zombiek_standB1; // Pick brains!
else if (self.lip < 2) self.think = zombiek_standE1; // Look BOTH
else if (self.lip < 3) self.think = zombiek_standC1; // Look LEFT
else self.think = zombiek_standD1; // Look RIGHT
}
ai_stand();
};
//============================================================================
void() zombiek_walk1 =[ $walk1, zombiek_walk2 ] {
self.inpain = 0; self.solid = SOLID_SLIDEBOX; ai_walk(1);};
void() zombiek_walk2 =[ $walk2, zombiek_walk3 ] {ai_walk(1);};
void() zombiek_walk3 =[ $walk3, zombiek_walk4 ] {ai_walk(4);};
void() zombiek_walk4 =[ $walk4, zombiek_walk5 ] {ai_walk(4);};
void() zombiek_walk5 =[ $walk5, zombiek_walk6 ] {ai_walk(2);};
void() zombiek_walk6 =[ $walk6, zombiek_walk7 ] {ai_walk(1);};
void() zombiek_walk7 =[ $walk7, zombiek_walk8 ] {ai_walk(1);};
void() zombiek_walk8 =[ $walk8, zombiek_walk9 ] {ai_walk(1);monster_footstep(FALSE);};
void() zombiek_walk9 =[ $walk9, zombiek_walk10] {ai_walk(1);};
void() zombiek_walk10 =[ $walk10, zombiek_walk11] {ai_walk(1);};
void() zombiek_walk11 =[ $walk11, zombiek_walk12] {ai_walk(1);};
void() zombiek_walk12 =[ $walk12, zombiek_walk13] {ai_walk(1);monster_footstep(TRUE);}; // Scrapping Clubfoot
void() zombiek_walk13 =[ $walk13, zombiek_walk14] {ai_walk(1);};
void() zombiek_walk14 =[ $walk14, zombiek_walk1 ] {zombiek_sound(2);ai_walk(1);};
//============================================================================
void() zombiek_run1 =[ $run1, zombiek_run2 ] {
self.inpain = 0; self.solid = SOLID_SLIDEBOX; ai_run(12);};
void() zombiek_run2 =[ $run2, zombiek_run3 ] {ai_run(12);};
void() zombiek_run3 =[ $run3, zombiek_run4 ] {ai_run(13);};
void() zombiek_run4 =[ $run4, zombiek_run5 ] {ai_run(12);};
void() zombiek_run5 =[ $run5, zombiek_run6 ] {ai_run(12);monster_footstep(FALSE);};
void() zombiek_run6 =[ $run6, zombiek_run7 ] {ai_run(12);};
void() zombiek_run7 =[ $run7, zombiek_run8 ] {ai_run(12);};
void() zombiek_run8 =[ $run8, zombiek_run9 ] {ai_run(11);};
void() zombiek_run9 =[ $run9, zombiek_run10 ] {ai_run(14);};
void() zombiek_run10 =[ $run10, zombiek_run11 ] {ai_run(13);};
void() zombiek_run11 =[ $run11, zombiek_run1 ] {ai_run(11);
self.steptype = FS_TYPEHEAVY; // Heavy clubfoot
monster_footstep(FALSE);
self.steptype = FS_TYPESLOW; // Normal zombie foot
};
//===========================================================================
// Melee Attack 2 - Stationary over arm swing (17->12 frames)
// Removed frames 1,3,4,5,7
void() zombiek_attb1 =[ $attb2, zombiek_attb6 ] {ai_face();};
void() zombiek_attb6 =[ $attb6, zombiek_attb8 ] {ai_face();};
void() zombiek_attb8 =[ $attb8, zombiek_attb9 ] {ai_face();zombiek_sound(7);};
void() zombiek_attb9 =[ $attb9, zombiek_attb10] {ai_face();};
void() zombiek_attb10=[ $attb10, zombiek_attb11] {ai_face();ai_melee();};
void() zombiek_attb11=[ $attb11, zombiek_attb12] {ai_melee();};
void() zombiek_attb12=[ $attb12, zombiek_attb13] {ai_melee();};
void() zombiek_attb13=[ $attb13, zombiek_attb14] {};
void() zombiek_attb14=[ $attb14, zombiek_attb15] {};
void() zombiek_attb15=[ $attb15, zombiek_attb16] {};
void() zombiek_attb16=[ $attb16, zombiek_attb17] {};
void() zombiek_attb17=[ $attb17, zombiek_run1 ] {};
//----------------------------------------------------------------------
// Melee Attack 3 - Stationary sideways swing (15->12 frames)
// Removed frames 1,3,15
void() zombiek_attc1 =[ $attc2, zombiek_attc4 ] {ai_face();};
void() zombiek_attc4 =[ $attc4, zombiek_attc5 ] {ai_face();};
void() zombiek_attc5 =[ $attc5, zombiek_attc6 ] {zombiek_sound(7); ai_face();};
void() zombiek_attc6 =[ $attc6, zombiek_attc7 ] {ai_face();};
void() zombiek_attc7 =[ $attc7, zombiek_attc8 ] {ai_face();ai_melee();};
void() zombiek_attc8 =[ $attc8, zombiek_attc9 ] {ai_melee();};
void() zombiek_attc9 =[ $attc9, zombiek_attc10] {ai_melee();};
void() zombiek_attc10=[ $attc10, zombiek_attc11] {};
void() zombiek_attc11=[ $attc11, zombiek_attc12] {};
void() zombiek_attc12=[ $attc12, zombiek_attc13] {};
void() zombiek_attc13=[ $attc13, zombiek_attc14] {};
void() zombiek_attc14=[ $attc14, zombiek_run1 ] {};
//----------------------------------------------------------------------
void() zombiek_melee =
{
ai_face (); // Turn towards enemy target
walkmove (self.ideal_yaw, 20);
// Randomly select melee attacks
if (random() < 0.5) zombiek_attb1(); // Stationary over arm swing
else zombiek_attc1(); // Stationary sideways swing
};
//============================================================================
// Jump + melee attack
// Melee Attack 1 - Smash, chop overhead to ground (19->10/11 frames)
//============================================================================
void() zombiek_JumpTouch =
{
local float ldmg;
if (self.health < 1) return;
ai_jumpbreakable(20); // Damage any breakables
self.touch = SUB_Null; // No more touching
self.think = self.th_jumpexit; // Exit frame
self.jumptouch = other; // Keep track of touch target
if ( CanDamage(other, self) ) {
if ( vlen(self.velocity) > 300 ) {
ldmg = 10 + 10*random();
T_Damage (other, self, self, ldmg, DAMARMOR);
spawn_touchblood (self, self.enemy, ldmg*3);
// Check for poisonous attribute (new poison version)
if (self.poisonous) PoisonDeBuff(self.enemy);
}
}
// Is the zombie knight floating in the air?
if (!checkbottom(self)) {
// Is the zombie knight standing on something?
if (self.flags & FL_ONGROUND) {
// Do an extra jump if got the count
if (self.count < 2) self.think = self.th_jump;
}
}
// Next timer
self.nextthink = time + 0.1;
};
//----------------------------------------------------------------------
void() zombiek_jump1 =[ $atta1, zombiek_jump2 ] {ai_charge(12);
self.jump_flag = time + MONAI_JUMPZOMBTIME;
zombiek_sound(3); // Moan about jumping forward
};
void() zombiek_jump2 =[ $atta2, zombiek_jump3 ] {ai_charge(16);};
void() zombiek_jump3 =[ $atta3, zombiek_jump4 ] {
ai_face();
self.jump_flag = time + MONAI_JUMPZOMBTIME;
self.touch = zombiek_JumpTouch;
makevectors (self.angles);
self.velocity = v_forward * (150 + random() * 50) + '0 0 200';
self.origin_z = self.origin_z + 4;
self.flags = self.flags - (self.flags & FL_ONGROUND);
self.oldorigin = self.origin;
};
// Flying through the air waiting to touch something!
void() zombiek_jump4 =[ $atta4, zombiek_jump5 ] {ai_face();};
void() zombiek_jump5 =[ $atta5, zombiek_jump6 ] {ai_face();};
void() zombiek_jump6 =[ $atta6, zombiek_jump6 ] {ai_face();};
void() zombiek_jump7 =[ $atta7, zombiek_jump7 ] {ai_face();};
void() zombiek_jump8 =[ $atta8, zombiek_jump9 ] {ai_face();
// Double check monster is still falling?
if (CheckZeroVector(self.velocity) || self.oldorigin == self.origin) {
if (!checkbottom(self)) {
self.ideal_yaw = random() * 360; //random jump angle
self.think = zombiek_jump3;
}
}
self.oldorigin = self.origin;
};
//----------------------------------------------------------------------
void() zombiek_jump15; // Chance of quick animation exit
void() zombiek_jump9 =[ $atta9, zombiek_jump10] {ai_melee();};
void() zombiek_jump10=[ $atta10, zombiek_jump11] {ai_melee();};
void() zombiek_jump11=[ $atta11, zombiek_jump12] {};
void() zombiek_jump12=[ $atta12, zombiek_jump13] {
if (random() < 0.5) self.think = zombiek_jump15;}; // quick recovery
void() zombiek_jump13=[ $atta13, zombiek_jump14] {};
void() zombiek_jump14=[ $atta14, zombiek_jump16] {};
void() zombiek_jump15=[ $atta15, zombiek_jump16] {};
void() zombiek_jump16=[ $atta16, zombiek_jump18] {};
void() zombiek_jump18=[ $atta18, zombiek_run1 ] {ai_resetangles();};
/*======================================================================
PAIN
========================================================================*/
void() zombiek_paina1 =[ $paina1, zombiek_paina2 ] {zombiek_sound(4);ai_painforward(8);};
void() zombiek_paina2 =[ $paina2, zombiek_paina3 ] {ai_painforward(3);};
void() zombiek_paina3 =[ $paina3, zombiek_paina4 ] {ai_painforward(3);};
void() zombiek_paina4 =[ $paina4, zombiek_paina5 ] {ai_painforward(3);monster_footstep(FALSE);};
void() zombiek_paina5 =[ $paina5, zombiek_paina6 ] {ai_painforward(3);};
void() zombiek_paina6 =[ $paina6, zombiek_paina7 ] {ai_painforward(3);};
void() zombiek_paina7 =[ $paina7, zombiek_paina8 ] {ai_painforward(3);};
void() zombiek_paina8 =[ $paina8, zombiek_paina9 ] {ai_painforward(3);};
void() zombiek_paina9 =[ $paina9, zombiek_paina10 ] {ai_painforward(2);monster_footstep(FALSE);};
void() zombiek_paina10 =[ $paina10, zombiek_paina11 ] {ai_painforward(1);};
void() zombiek_paina11 =[ $paina11, zombiek_paina12 ] {ai_painforward(2);};
void() zombiek_paina12 =[ $paina12, zombiek_run1 ] {ai_painforward(1);self.inpain = 0;};
//----------------------------------------------------------------------
void() zombiek_painb1 =[ $painb1, zombiek_painb2 ] {zombiek_sound(4);ai_painforward(8);};
void() zombiek_painb2 =[ $painb2, zombiek_painb3 ] {ai_pain(1);};
void() zombiek_painb3 =[ $painb3, zombiek_painb4 ] {ai_pain(1);};
void() zombiek_painb4 =[ $painb4, zombiek_painb5 ] {ai_pain(1);};
void() zombiek_painb5 =[ $painb5, zombiek_painb6 ] {ai_pain(1);};
void() zombiek_painb6 =[ $painb6, zombiek_painb7 ] {ai_pain(2);};
void() zombiek_painb7 =[ $painb7, zombiek_painb8 ] {ai_pain(2);};
void() zombiek_painb8 =[ $painb8, zombiek_painb9 ] {ai_pain(4);};
void() zombiek_painb9 =[ $painb9, zombiek_painb10 ] {ai_pain(4);};
void() zombiek_painb10 =[ $painb10, zombiek_painb11 ] {ai_pain(4);};
void() zombiek_painb11 =[ $painb11, zombiek_painb12 ] {ai_pain(2);monster_footstep(FALSE);};
void() zombiek_painb12 =[ $painb12, zombiek_painb13 ] {ai_pain(2);};
void() zombiek_painb13 =[ $painb13, zombiek_painb14 ] {ai_pain(3);};
void() zombiek_painb14 =[ $painb14, zombiek_painb15 ] {};
void() zombiek_painb15 =[ $painb15, zombiek_painb16 ] {};
void() zombiek_painb16 =[ $painb16, zombiek_painb17 ] {};
void() zombiek_painb17 =[ $painb17, zombiek_painb18 ] {};
void() zombiek_painb18 =[ $painb18, zombiek_painb19 ] {ai_painforward(3);};
void() zombiek_painb19 =[ $painb19, zombiek_painb20 ] {ai_painforward(3);};
void() zombiek_painb20 =[ $painb20, zombiek_painb21 ] {ai_painforward(3);};
void() zombiek_painb21 =[ $painb21, zombiek_painb22 ] {ai_painforward(3);};
void() zombiek_painb22 =[ $painb22, zombiek_painb23 ] {ai_painforward(3);};
void() zombiek_painb23 =[ $painb23, zombiek_painb24 ] {ai_painforward(3);};
void() zombiek_painb24 =[ $painb24, zombiek_painb25 ] {ai_painforward(3);};
void() zombiek_painb25 =[ $painb25, zombiek_run1 ] {ai_painforward(3);};
//----------------------------------------------------------------------
void() zombiek_painc1 =[ $painc1, zombiek_painc2 ] {zombiek_sound(4);ai_painforward(8);};
void() zombiek_painc2 =[ $painc2, zombiek_painc3 ] {ai_painforward(6);};
void() zombiek_painc3 =[ $painc3, zombiek_painc4 ] {ai_painforward(5);};
void() zombiek_painc4 =[ $painc4, zombiek_painc5 ] {ai_painforward(7);zombiek_sound(5);};
void() zombiek_painc5 =[ $painc5, zombiek_painc6 ] {ai_painforward(6);};
void() zombiek_painc6 =[ $painc6, zombiek_painc7 ] {ai_painforward(3);};
void() zombiek_painc7 =[ $painc7, zombiek_painc8 ] {ai_painforward(3);};
void() zombiek_painc8 =[ $painc8, zombiek_painc9 ] {};
void() zombiek_painc9 =[ $painc9, zombiek_painc10 ] {};
// Re-entry point for painD wakeup animation
void() zombiek_painc10 =[ $painc10, zombiek_painc11 ] {};
void() zombiek_painc11 =[ $painc11, zombiek_painc12 ] {};
void() zombiek_painc12 =[ $painc12, zombiek_painc13 ] {};
void() zombiek_painc13 =[ $painc13, zombiek_painc14 ] {};
void() zombiek_painc14 =[ $painc14, zombiek_painc15 ] {};
void() zombiek_painc15 =[ $painc15, zombiek_painc16 ] {};
void() zombiek_painc16 =[ $painc16, zombiek_painc17 ] {};
void() zombiek_painc17 =[ $painc17, zombiek_painc18 ] {};
void() zombiek_painc18 =[ $painc18, zombiek_painc19 ] {};
void() zombiek_painc19 =[ $painc19, zombiek_painc20 ] {monster_footstep(FALSE);};
void() zombiek_painc20 =[ $painc20, zombiek_painc21 ] {};
void() zombiek_painc21 =[ $painc21, zombiek_run1 ] {};
//----------------------------------------------------------------------
void() zombiek_paind1 =[ $paind1, zombiek_paind2 ] {
self.inpain = 2;
zombiek_sound(4);
ai_painforward(8);
};
void() zombiek_paind2 =[ $paind2, zombiek_paind3 ] {ai_painforward(4);};
void() zombiek_paind3 =[ $paind3, zombiek_paind4 ] {ai_painforward(4);};
void() zombiek_paind4 =[ $paind4, zombiek_paind5 ] {ai_painforward(4);};
void() zombiek_paind5 =[ $paind5, zombiek_paind6 ] {ai_painforward(3);};
void() zombiek_paind6 =[ $paind6, zombiek_paind7 ] {ai_painforward(2);};
void() zombiek_paind7 =[ $paind7, zombiek_paind8 ] {ai_painforward(2);};
void() zombiek_paind8 =[ $paind8, zombiek_paind9 ] {};
void() zombiek_paind9 =[ $paind9, zombiek_paind10 ] {};
void() zombiek_paind10 =[ $paind10, zombiek_paind11 ] {zombiek_sound(5);};
void() zombiek_paind11 =[ $paind11, zombiek_paind12 ] {self.solid = SOLID_NOT;};
void() zombiek_paind12 =[ $paind12, zombiek_paind12 ] {zombiek_onground(MONAI_ZOMBIEUPD);};
// Start of get up sequence
void() zombiek_paind13 =[ $paind13, zombiek_paind14 ] {};
void() zombiek_paind14 =[ $paind14, zombiek_paind15 ] {};
void() zombiek_paind15 =[ $paind15, zombiek_paind16 ] {};
void() zombiek_paind16 =[ $paind16, zombiek_paind17 ] {};
void() zombiek_paind17 =[ $paind17, zombiek_paind18 ] {
monster_footstep(TRUE);ai_pain(1);}; // Scrapping feet sound while standing up
void() zombiek_paind18 =[ $paind18, zombiek_paind19 ] {ai_pain(1);};
void() zombiek_paind19 =[ $paind19, zombiek_paind20 ] {ai_pain(1);};
void() zombiek_paind20 =[ $paind20, zombiek_paind21 ] {ai_pain(1);};
void() zombiek_paind21 =[ $paind21, zombiek_paind22 ] {ai_pain(1);};
void() zombiek_paind22 =[ $paind22, zombiek_paind23 ] {ai_pain(2);};
void() zombiek_paind23 =[ $paind23, zombiek_painw10 ] {ai_pain(2);};
// Originally re-entry to C, need onfloor check
void() zombiek_painw10 =[ $painc10, zombiek_painw11 ] {};
void() zombiek_painw11 =[ $painc11, zombiek_painw12 ] {};
void() zombiek_painw12 =[ $painc12, zombiek_painw13 ] {};
void() zombiek_painw13 =[ $painc13, zombiek_painw14 ] {};
void() zombiek_painw14 =[ $painc14, zombiek_painw15 ] {};
void() zombiek_painw15 =[ $painc15, zombiek_painw16 ] {};
void() zombiek_painw16 =[ $painc16, zombiek_painw17 ] {};
void() zombiek_painw17 =[ $painc17, zombiek_painw18 ] {};
void() zombiek_painw18 =[ $painc18, zombiek_painw19 ] {};
void() zombiek_painw19 =[ $painc19, zombiek_painw20 ] {monster_footstep(FALSE);};
void() zombiek_painw20 =[ $painc20, zombiek_painw21 ] {};
void() zombiek_painw21 =[ $painc21, zombiek_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() zombiek_paine1 =[ $paine1, zombiek_paine2 ] {
self.inpain = 2;
zombiek_sound(4);
ai_pain(8);
};
void() zombiek_paine2 =[ $paine2, zombiek_paine3 ] {ai_pain(4);};
void() zombiek_paine3 =[ $paine3, zombiek_paine4 ] {ai_pain(3);};
void() zombiek_paine4 =[ $paine4, zombiek_paine5 ] {ai_pain(3);};
void() zombiek_paine5 =[ $paine5, zombiek_paine6 ] {ai_pain(3);};
void() zombiek_paine6 =[ $paine6, zombiek_paine7 ] {ai_pain(2);};
void() zombiek_paine7 =[ $paine7, zombiek_paine8 ] {ai_pain(2);};
void() zombiek_paine8 =[ $paine8, zombiek_paine9 ] {};
void() zombiek_paine9 =[ $paine9, zombiek_paine10 ] {};
void() zombiek_paine10 =[ $paine10, zombiek_paine11 ] {self.solid = SOLID_NOT;};
void() zombiek_paine11 =[ $paine11, zombiek_paine12 ] {zombiek_sound(5);};
void() zombiek_paine12 =[ $paine12, zombiek_paine12 ] {zombiek_onground(MONAI_ZOMBIEUPE);};
// Start of get up sequence
void() zombiek_paine13 =[ $paine13, zombiek_paine14 ] {
monster_footstep(TRUE); // Scrapping feet sound while standing up
};
void() zombiek_paine14 =[ $paine14, zombiek_paine15 ] {};
void() zombiek_paine15 =[ $paine15, zombiek_paine16 ] {};
void() zombiek_paine16 =[ $paine16, zombiek_paine17 ] {};
void() zombiek_paine17 =[ $paine18, zombiek_paine18 ] {};
void() zombiek_paine18 =[ $paine17, zombiek_paine19 ] {};
void() zombiek_paine19 =[ $paine19, zombiek_paine20 ] {
self.steptype = FS_TYPEHEAVY; // Heavy clubfoot
monster_footstep(FALSE);
self.steptype = FS_TYPESLOW; // Normal zombie foot
};
void() zombiek_paine20 =[ $paine20, zombiek_paine21 ] {};
void() zombiek_paine21 =[ $paine21, zombiek_paine22 ] {};
void() zombiek_paine22 =[ $paine22, zombiek_paine23 ] {};
void() zombiek_paine23 =[ $paine23, zombiek_paine24 ] {};
void() zombiek_paine24 =[ $paine24, zombiek_paine25 ] {};
void() zombiek_paine25 =[ $paine25, zombiek_paine26 ] {};
void() zombiek_paine26 =[ $paine26, zombiek_paine27 ] {};
void() zombiek_paine27 =[ $paine27, zombiek_paine28 ] {ai_painforward(3);};
void() zombiek_paine28 =[ $paine28, zombiek_paine29 ] {ai_painforward(3);};
void() zombiek_paine29 =[ $paine29, zombiek_paine30 ] {ai_painforward(3);};
void() zombiek_paine30 =[ $paine30, zombiek_paine31 ] {ai_painforward(3);};
void() zombiek_paine31 =[ $paine31, zombiek_run1 ] {ai_painforward(3);
// 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) zombiek_pain =
{
// Is the zombie in the process of dying?
if (self.deadflag > DEAD_NO) return;
// Always reset health
self.health = self.max_health;
self.attack_elev = targzone(self, attacker);
// 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) {
zombiek_knockdown();
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 zombiek only use it for idle animations
if (self.lefty < time && self.inpain == 1) {
// Second hit, drop to ground
zombiek_knockdown();
return;
}
//----------------------------------------------------------------------
// Damage 9-25 random pain animation (random chance of knockdown)
//----------------------------------------------------------------------
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) zombiek_paina1 (); // 12 frames (drag foot)
else if (self.lip < 0.5) zombiek_knockdown(); // ON THE GROUND
else if (self.lip < 0.75 && self.attack_elev == TARGET_FRONT)
zombiek_painb1 (); // 25 frames (flail arms backwards)
else zombiek_painc1 (); // 21 frames (fall to knees)
};
/*=============================================================================
ZOMBIE WAKEUP (check if can get up)
=============================================================================*/
void() zombiek_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 = string_null; // Body is chop proof!
self.inpain = 2; // Animation not finished
zombiek_sound(6); // Wake up sound
self.nextthink = time + 0.1;
self.use = monster_use; // Just in case interruption
if (self.zombieflr == MONAI_ZOMBIEUPD) self.think = zombiek_paind13;
else self.think = zombiek_paine13;
}
};
//----------------------------------------------------------------------
// Puts the zombie on the floor with a random Yaw rotation
// IF frameno = MONAI_ZOMBIEFLR Setup on floor with use trigger
// ELSE setup next think timer and wait for opportunity to get back up
//----------------------------------------------------------------------
void(float frameno) zombiek_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_ZOMBIEUPD;
self.frame = $paind12;
}
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 {
// Zombie fall down function defines wake up pose
self.zombieflr = frameno;
// Keep zombies on the ground and check again later
self.nextthink = self.nextthink + MONAI_ZOMBGRDTIMER;
self.think = self.th_wakeup;
}
};
//----------------------------------------------------------------------
// Puts the zombie on the floor based on the angle of attack
// 270-360, 360-90 : Fall forward (3 checks Left, middle, right)
// 180-270, 90-180 : Fall backward
//----------------------------------------------------------------------
void() zombiek_knockdown =
{
local float enemy_ang, comp_ang;
// Work out which direction the damage came from (enemy)
enemy_ang = targangle(self, self.enemy, 0, FALSE);
comp_ang = anglemod(enemy_ang + 45); // Shift clockwise (front cone)
//if (self.debuglvl) {
// dprint("Self ("); dprint(ftos(self.angles_y));
// dprint(") Targ ("); dprint(ftos(enemy_ang));
// dprint(") Comp ("); dprint(ftos(comp_ang));
// dprint(")\n");
//}
// NORTH WEST : 270-315 (fall BACKWARD, reverse force)
if (comp_ang > 315) {
//if (self.debuglvl) dprint("\b[KNOCKDOWN]\b HIT from the UPPER LEFT\n");
self.ideal_yaw = anglemod(enemy_ang + 180);
ChangeYaw ();
zombiek_paine1();
}
// SOUTH WEST : 225-270 (fall FORWARD, side force +45)
else if (comp_ang > 270) {
//if (self.debuglvl) dprint("\b[KNOCKDOWN]\b HIT from the LOWER LEFT\n");
self.ideal_yaw = comp_ang;
ChangeYaw ();
zombiek_paind1();
}
// SOUTH : 135-225 (fall FORWARD)
else if (comp_ang > 180) {
//if (self.debuglvl) dprint("\b[KNOCKDOWN]\b HIT from the BACK\n");
self.ideal_yaw = self.angles_y; // Fix for ai_painforward
ChangeYaw ();
zombiek_paind1();
}
// SOUTH EAST : 90-135 (fall FORWARD, side force -45)
else if (comp_ang > 135) {
//if (self.debuglvl) dprint("\b[KNOCKDOWN]\b HIT from the LOWER RIGHT\n");
self.ideal_yaw = anglemod(enemy_ang+315);
ChangeYaw ();
zombiek_paind1();
}
// NORTH EAST : 45-90 (fall BACKWARD, reverse force)
else if (comp_ang > 90) {
//if (self.debuglvl) dprint("\b[KNOCKDOWN]\b HIT from the UPPER RIGHT\n");
self.ideal_yaw = anglemod(enemy_ang + 180);
ChangeYaw ();
zombiek_paine1();
}
// NORTH : 315-45 (fall BACKWARD)
else {
//if (self.debuglvl) dprint("\b[KNOCKDOWN]\b HIT from the FRONT\n");
zombiek_paine1();
}
};
/*============================================================================
All sounds used
2 = strutting the stuff (walking)
3 = running (in slow motion)
4 = all pain routines (zombiek_paina1, _painb1, _painc1, _paind1)
5 = its a knockout!
6 = get up and moan about it
7 = sword swipe
============================================================================*/
void(float type) zombiek_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 == 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) {
if (self.lip < 0.25) sound (self, CHAN_WEAPON, "weapons/sword1a.wav", 1, ATTN_NORM);
else if (self.lip < 0.5) sound (self, CHAN_WEAPON, "weapons/sword2a.wav", 1, ATTN_NORM);
else if (self.lip < 0.75) sound (self, CHAN_WEAPON, "weapons/sword1b.wav", 1, ATTN_NORM);
else sound (self, CHAN_WEAPON, "weapons/sword2b.wav", 1, ATTN_NORM);
}
};
//============================================================================
void() zombiek_die =
{
self.health = self.gibhealth; // Force gib
monster_death_precheck();
};
/*======================================================================
QUAKED monster_zombiek (1 0 0) (-16 -16 -24) (16 16 32) Ambush x FLOOR
======================================================================*/
void() monster_zombiek =
{
if (deathmatch) { remove(self); return; }
self.mdl = "progs/mon_zombiek.mdl"; // Zombie Knight
self.headmdl = "progs/h_zombiek.mdl";
precache_model (self.mdl);
precache_model (self.headmdl);
self.gib1mdl = "progs/w_zombiesword.mdl"; // Unique sword
self.gib1sound = GIB_IMPACT_METALA;
precache_model (self.gib1mdl);
precache_sound ("zombie/z_idle.wav"); // Idle A
precache_sound ("zombie/z_idle1.wav"); // Idle B
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_fall.wav"); // Impact - floor
precache_sound ("zombie/z_gib.wav"); // Death sound
// New sword sweep/slash sounds
precache_sound ("weapons/sword1a.wav");
precache_sound ("weapons/sword1b.wav");
precache_sound ("weapons/sword2a.wav");
precache_sound ("weapons/sword2b.wav");
// New sight sound, mixture of knight + zombie
self.sight_sound = "zombie/zk_sight.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
self.skin = self.exactskin = self.gib1skin = 1;
}
self.solid = SOLID_NOT; // No interaction with world
self.movetype = MOVETYPE_NONE; // Static item, no movement
if (self.bboxtype < 1) self.bboxtype = BBOX_SHORT;
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)
self.inpain = 0; // Zombie starts with no pain lock
self.count = 0; // Reset get up timer
self.deathstring = " was cornered by a Zombie Knight\n";
// Always reset Ammo Resistance to be consistent
self.resist_shells = self.resist_nails = 0;
self.resist_rockets = self.resist_cells = 0;
self.th_checkattack = ZombiekCheckAttack;
self.th_stand = zombiek_stand1;
self.th_walk = zombiek_walk1;
self.th_run = zombiek_run1;
self.th_melee = zombiek_melee; // two melee attacks (stationary)
self.th_jump = zombiek_jump1; // Leap attack
self.th_jumpexit = zombiek_jump9; // Exit animation for jump
self.th_pain = zombiek_pain;
self.th_die = zombiek_die;
self.th_wakeup = zombiek_wakeup; // Get off floor
self.classtype = CT_MONZOMBIEK;
self.classgroup = CG_ZOMBIE; // One big happy zombie family!
self.classmove = MON_MOVEWALK;
monster_start();
};