]> de.git.xonotic.org Git - xonotic/xonotic-data.pk3dir.git/blob - qcsrc/server/monsters/monster/zombie.qc
Replace enforcer model with e-wheel
[xonotic/xonotic-data.pk3dir.git] / qcsrc / server / monsters / monster / zombie.qc
1 /**
2  * Special purpose fields:
3  * .delay - time at which to check if zombie's enemy is still in range
4  * .enemy - enemy of this zombie
5  */
6  
7 // cvars
8 float autocvar_g_monster_zombie;
9 float autocvar_g_monster_zombie_stopspeed;
10 float autocvar_g_monster_zombie_attack_leap_damage;
11 float autocvar_g_monster_zombie_attack_leap_delay;
12 float autocvar_g_monster_zombie_attack_leap_force;
13 float autocvar_g_monster_zombie_attack_leap_speed;
14 float autocvar_g_monster_zombie_attack_stand_damage;
15 float autocvar_g_monster_zombie_attack_stand_delay;
16 float autocvar_g_monster_zombie_health;
17 float autocvar_g_monster_zombie_speed_walk;
18 float autocvar_g_monster_zombie_speed_run;
19
20 // zombie animations
21 #define zombie_anim_attackleap                  0
22 #define zombie_anim_attackrun1                  1
23 #define zombie_anim_attackrun2                  2
24 #define zombie_anim_attackrun3                  3
25 #define zombie_anim_attackstanding1             4
26 #define zombie_anim_attackstanding2             5
27 #define zombie_anim_attackstanding3             6
28 #define zombie_anim_blockend                    7
29 #define zombie_anim_blockstart                  8
30 #define zombie_anim_deathback1                  9
31 #define zombie_anim_deathback2                  10
32 #define zombie_anim_deathback3                  11
33 #define zombie_anim_deathfront1                 12
34 #define zombie_anim_deathfront2                 13
35 #define zombie_anim_deathfront3                 14
36 #define zombie_anim_deathleft1                  15
37 #define zombie_anim_deathleft2                  16
38 #define zombie_anim_deathright1                 17
39 #define zombie_anim_deathright2                 18
40 #define zombie_anim_idle                                19
41 #define zombie_anim_painback1                   20
42 #define zombie_anim_painback2                   21
43 #define zombie_anim_painfront1                  22
44 #define zombie_anim_painfront2                  23
45 #define zombie_anim_runbackwards                24
46 #define zombie_anim_runbackwardsleft    25
47 #define zombie_anim_runbackwardsright   26
48 #define zombie_anim_runforward                  27
49 #define zombie_anim_runforwardleft              28
50 #define zombie_anim_runforwardright             29
51 #define zombie_anim_spawn                               30
52
53 const vector ZOMBIE_MIN                          = '-18 -18 -25';
54 const vector ZOMBIE_MAX                          = '18 18 47';
55
56 void zombie_spawn();
57 void spawnfunc_monster_zombie();
58 void zombie_think();
59
60 void zombie_die ()
61 {
62         Monster_CheckDropCvars ("zombie");
63         
64         self.solid                      = SOLID_NOT;
65         self.takedamage         = DAMAGE_NO;
66         self.event_damage   = func_null;
67         self.enemy                      = world;
68         self.movetype           = MOVETYPE_TOSS;
69         self.think                      = Monster_Fade;
70         self.nextthink          = time + 2.1;
71         self.pain_finished  = self.nextthink;
72         
73         if (random() > 0.5)
74                 self.frame = zombie_anim_deathback1;
75         else
76                 self.frame = zombie_anim_deathfront1;
77                 
78         monster_hook_death(); // for post-death mods
79 }
80
81 void zombie_attack_standing()
82 {
83         float rand = random(), dot = 0, bigdmg = 0;
84
85         self.velocity_x = 0;
86         self.velocity_y = 0;
87         
88         if(self.monster_owner == self.enemy)
89         {
90                 self.enemy = world;
91                 return;
92         }
93         
94         bigdmg = autocvar_g_monster_zombie_attack_stand_damage * self.scale;
95
96         //print("zombie attacks!\n");
97         makevectors (self.angles);
98         dot = normalize (self.enemy.origin - self.origin) * v_forward;
99         if(dot > 0.3)
100         {
101                 Damage(self.enemy, self, self, bigdmg * monster_skill, DEATH_MONSTER_ZOMBIE, self.origin, '0 0 0');
102         }
103         
104         if(self.enemy.health < 1)
105                 self.enemy = world;
106                 
107         if (rand < 0.33)
108                 self.frame = zombie_anim_attackstanding1;
109         else if (rand < 0.66)
110                 self.frame = zombie_anim_attackstanding2;
111         else
112                 self.frame = zombie_anim_attackstanding3;
113
114         self.nextthink = time + autocvar_g_monster_zombie_attack_stand_delay;
115         self.attack_finished_single = self.nextthink;
116 }
117
118 void zombie_attack_leap_touch()
119 {
120         vector angles_face;
121         float bigdmg = autocvar_g_monster_zombie_attack_leap_damage * self.scale;
122         
123         if (other.deadflag != DEAD_NO)
124                 return;
125                 
126         if (self.monster_owner == other)
127                 return;
128         
129         if (other.takedamage == DAMAGE_NO)
130                 return;
131                 
132         //void Damage (entity targ, entity inflictor, entity attacker, float damage, float deathtype, vector hitloc, vector force)
133         traceline(self.origin, other.origin, FALSE, self);
134
135         angles_face = vectoangles(self.moveto - self.origin);
136         angles_face = normalize(angles_face) * autocvar_g_monster_zombie_attack_leap_force;
137         Damage(other, self, self, bigdmg * monster_skill, DEATH_MONSTER_ZOMBIE, trace_endpos, angles_face);     
138                 
139         self.touch = MonsterTouch;
140 }
141
142 float zombie_attack_ranged()
143 {
144         makevectors(self.angles);
145         if(monster_leap(zombie_anim_attackleap, zombie_attack_leap_touch, v_forward * autocvar_g_monster_zombie_attack_leap_speed + '0 0 200', autocvar_g_monster_zombie_attack_leap_delay))
146                 return TRUE;
147                 
148         return FALSE;
149 }
150
151 void zombie_think()
152 {
153         self.think = zombie_think;
154         self.nextthink = time + 0.1;
155
156         monster_move(autocvar_g_monster_zombie_speed_run, autocvar_g_monster_zombie_speed_walk, autocvar_g_monster_zombie_stopspeed, zombie_anim_runforward, zombie_anim_runforward, zombie_anim_idle);
157 }
158
159 void zombie_spawn() 
160 {
161         if not(self.health)
162                 self.health = autocvar_g_monster_zombie_health * self.scale;
163         
164         self.classname                  = "monster_zombie";
165         self.nextthink                  = time + 2.1;
166         self.pain_finished      = self.nextthink;
167         self.frame                              = zombie_anim_spawn;
168         self.think                              = zombie_think;
169         self.sprite_height      = 50 * self.scale;
170         self.checkattack                = GenericCheckAttack;
171         self.attack_melee               = zombie_attack_standing;
172         self.attack_ranged              = zombie_attack_ranged;
173         self.skin                               = rint(random() * 4);
174         
175         monster_hook_spawn(); // for post-spawn mods
176 }
177
178 /*QUAKED monster_zombie (1 0 0) (-18 -18 -25) (18 18 47)
179 Zombie, 60 health points.
180 -------- KEYS --------
181 -------- SPAWNFLAGS --------
182 MONSTERFLAG_APPEAR: monster will spawn when triggered.
183 ---------NOTES----------
184 Original Quake 1 zombie entity used a smaller box ('-16 -16 -24', '16 16 32').
185 -------- MODEL FOR RADIANT ONLY - DO NOT SET THIS AS A KEY --------
186 modeldisabled="models/monsters/zombie.dpm"
187 */
188 void spawnfunc_monster_zombie() 
189 {
190         if not(autocvar_g_monster_zombie) { remove(self); return; }
191         
192         self.monster_spawnfunc = spawnfunc_monster_zombie;
193         
194         if(self.spawnflags & MONSTERFLAG_APPEAR)
195         {
196                 self.think = func_null;
197                 self.nextthink = -1;
198                 self.use = Monster_Appear;
199                 return;
200         }
201         
202         if not (monster_initialize(
203                          "Zombie",
204                          "models/monsters/zombie.dpm",
205                          ZOMBIE_MIN, ZOMBIE_MAX,
206                          FALSE,
207                          zombie_die, zombie_spawn))
208         {
209                 remove(self);
210                 return;
211         }
212 }