743 lines
33 KiB
Plaintext
743 lines
33 KiB
Plaintext
/*==============================================================================
|
|
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();
|
|
};
|
|
|