/*====================================================================== 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(); };