1 /*
2 ==============================================================================
3 
4 GUNNER
5 
6 ==============================================================================
7 */
8 
9 #include "g_local.h"
10 #include "m_gunner.h"
11 
12 
13 static int	sound_pain;
14 static int	sound_pain2;
15 static int	sound_death;
16 static int	sound_idle;
17 static int	sound_open;
18 static int	sound_search;
19 static int	sound_sight;
20 
21 
gunner_idlesound(edict_t * self)22 void gunner_idlesound (edict_t *self)
23 {
24 	gi.sound (self, CHAN_VOICE, sound_idle, 1, ATTN_IDLE, 0);
25 }
26 
gunner_sight(edict_t * self,edict_t * other)27 void gunner_sight (edict_t *self, edict_t *other)
28 {
29 	gi.sound (self, CHAN_VOICE, sound_sight, 1, ATTN_NORM, 0);
30 }
31 
gunner_search(edict_t * self)32 void gunner_search (edict_t *self)
33 {
34 	gi.sound (self, CHAN_VOICE, sound_search, 1, ATTN_NORM, 0);
35 }
36 
37 
38 qboolean visible (edict_t *self, edict_t *other);
39 void GunnerGrenade (edict_t *self);
40 void GunnerFire (edict_t *self);
41 void gunner_fire_chain(edict_t *self);
42 void gunner_refire_chain(edict_t *self);
43 void GunnerPlasma (edict_t *self);
44 void gunner_fire_plasma(edict_t *self);
45 void gunner_refire_plasma(edict_t *self);
46 
47 void gunner_stand (edict_t *self);
48 
49 mframe_t gunner_frames_fidget [] =
50 {
51 	ai_stand, 0, NULL,
52 	ai_stand, 0, NULL,
53 	ai_stand, 0, NULL,
54 	ai_stand, 0, NULL,
55 	ai_stand, 0, NULL,
56 	ai_stand, 0, NULL,
57 	ai_stand, 0, NULL,
58 	ai_stand, 0, gunner_idlesound,
59 	ai_stand, 0, NULL,
60 
61 	ai_stand, 0, NULL,
62 	ai_stand, 0, NULL,
63 	ai_stand, 0, NULL,
64 	ai_stand, 0, NULL,
65 	ai_stand, 0, NULL,
66 	ai_stand, 0, NULL,
67 	ai_stand, 0, NULL,
68 	ai_stand, 0, NULL,
69 	ai_stand, 0, NULL,
70 	ai_stand, 0, NULL,
71 
72 	ai_stand, 0, NULL,
73 	ai_stand, 0, NULL,
74 	ai_stand, 0, NULL,
75 	ai_stand, 0, NULL,
76 	ai_stand, 0, NULL,
77 	ai_stand, 0, NULL,
78 	ai_stand, 0, NULL,
79 	ai_stand, 0, NULL,
80 	ai_stand, 0, NULL,
81 	ai_stand, 0, NULL,
82 
83 	ai_stand, 0, NULL,
84 	ai_stand, 0, NULL,
85 	ai_stand, 0, NULL,
86 	ai_stand, 0, NULL,
87 	ai_stand, 0, NULL,
88 	ai_stand, 0, NULL,
89 	ai_stand, 0, NULL,
90 	ai_stand, 0, NULL,
91 	ai_stand, 0, NULL,
92 	ai_stand, 0, NULL,
93 
94 	ai_stand, 0, NULL,
95 	ai_stand, 0, NULL,
96 	ai_stand, 0, NULL,
97 	ai_stand, 0, NULL,
98 	ai_stand, 0, NULL,
99 	ai_stand, 0, NULL,
100 	ai_stand, 0, NULL,
101 	ai_stand, 0, NULL,
102 	ai_stand, 0, NULL,
103 	ai_stand, 0, NULL
104 };
105 mmove_t	gunner_move_fidget = {FRAME_stand31, FRAME_stand70, gunner_frames_fidget, gunner_stand};
106 
gunner_fidget(edict_t * self)107 void gunner_fidget (edict_t *self)
108 {
109 	if (self->monsterinfo.aiflags & AI_STAND_GROUND)
110 		return;
111 	if (random() <= 0.05)
112 		self->monsterinfo.currentmove = &gunner_move_fidget;
113 }
114 
115 mframe_t gunner_frames_stand [] =
116 {
117 	ai_stand, 0, NULL,
118 	ai_stand, 0, NULL,
119 	ai_stand, 0, NULL,
120 	ai_stand, 0, NULL,
121 	ai_stand, 0, NULL,
122 	ai_stand, 0, NULL,
123 	ai_stand, 0, NULL,
124 	ai_stand, 0, NULL,
125 	ai_stand, 0, NULL,
126 	ai_stand, 0, gunner_fidget,
127 
128 	ai_stand, 0, NULL,
129 	ai_stand, 0, NULL,
130 	ai_stand, 0, NULL,
131 	ai_stand, 0, NULL,
132 	ai_stand, 0, NULL,
133 	ai_stand, 0, NULL,
134 	ai_stand, 0, NULL,
135 	ai_stand, 0, NULL,
136 	ai_stand, 0, NULL,
137 	ai_stand, 0, gunner_fidget,
138 
139 	ai_stand, 0, NULL,
140 	ai_stand, 0, NULL,
141 	ai_stand, 0, NULL,
142 	ai_stand, 0, NULL,
143 	ai_stand, 0, NULL,
144 	ai_stand, 0, NULL,
145 	ai_stand, 0, NULL,
146 	ai_stand, 0, NULL,
147 	ai_stand, 0, NULL,
148 	ai_stand, 0, gunner_fidget
149 };
150 mmove_t	gunner_move_stand = {FRAME_stand01, FRAME_stand30, gunner_frames_stand, NULL};
151 
gunner_stand(edict_t * self)152 void gunner_stand (edict_t *self)
153 {
154 		self->monsterinfo.currentmove = &gunner_move_stand;
155 }
156 
157 
158 mframe_t gunner_frames_walk [] =
159 {
160 	ai_walk, 0, NULL,
161 	ai_walk, 3, NULL,
162 	ai_walk, 4, NULL,
163 	ai_walk, 5, NULL,
164 	ai_walk, 7, NULL,
165 	ai_walk, 2, NULL,
166 	ai_walk, 6, NULL,
167 	ai_walk, 4, NULL,
168 	ai_walk, 2, NULL,
169 	ai_walk, 7, NULL,
170 	ai_walk, 5, NULL,
171 	ai_walk, 7, NULL,
172 	ai_walk, 4, NULL
173 };
174 mmove_t gunner_move_walk = {FRAME_walk07, FRAME_walk19, gunner_frames_walk, NULL};
175 
gunner_walk(edict_t * self)176 void gunner_walk (edict_t *self)
177 {
178 	self->monsterinfo.currentmove = &gunner_move_walk;
179 }
180 
181 mframe_t gunner_frames_run [] =
182 {
183 	ai_run, 26, NULL,
184 	ai_run, 9,  NULL,
185 	ai_run, 9,  NULL,
186 	ai_run, 9,  NULL,
187 	ai_run, 15, NULL,
188 	ai_run, 10, NULL,
189 	ai_run, 13, NULL,
190 	ai_run, 6,  NULL
191 };
192 
193 mmove_t gunner_move_run = {FRAME_run01, FRAME_run08, gunner_frames_run, NULL};
194 
gunner_run(edict_t * self)195 void gunner_run (edict_t *self)
196 {
197 	if (self->monsterinfo.aiflags & AI_STAND_GROUND)
198 		self->monsterinfo.currentmove = &gunner_move_stand;
199 	else
200 		self->monsterinfo.currentmove = &gunner_move_run;
201 }
202 
203 mframe_t gunner_frames_runandshoot [] =
204 {
205 	ai_run, 32, NULL,
206 	ai_run, 15, NULL,
207 	ai_run, 10, NULL,
208 	ai_run, 18, NULL,
209 	ai_run, 8,  NULL,
210 	ai_run, 20, NULL
211 };
212 
213 mmove_t gunner_move_runandshoot = {FRAME_runs01, FRAME_runs06, gunner_frames_runandshoot, NULL};
214 
gunner_runandshoot(edict_t * self)215 void gunner_runandshoot (edict_t *self)
216 {
217 	self->monsterinfo.currentmove = &gunner_move_runandshoot;
218 }
219 
220 mframe_t gunner_frames_pain3 [] =
221 {
222 	ai_move, -3, NULL,
223 	ai_move, 1,	 NULL,
224 	ai_move, 1,	 NULL,
225 	ai_move, 0,	 NULL,
226 	ai_move, 1,	 NULL
227 };
228 mmove_t gunner_move_pain3 = {FRAME_pain301, FRAME_pain305, gunner_frames_pain3, gunner_run};
229 
230 mframe_t gunner_frames_pain2 [] =
231 {
232 	ai_move, -2, NULL,
233 	ai_move, 11, NULL,
234 	ai_move, 6,	 NULL,
235 	ai_move, 2,	 NULL,
236 	ai_move, -1, NULL,
237 	ai_move, -7, NULL,
238 	ai_move, -2, NULL,
239 	ai_move, -7, NULL
240 };
241 mmove_t gunner_move_pain2 = {FRAME_pain201, FRAME_pain208, gunner_frames_pain2, gunner_run};
242 
243 mframe_t gunner_frames_pain1 [] =
244 {
245 	ai_move, 2,	 NULL,
246 	ai_move, 0,	 NULL,
247 	ai_move, -5, NULL,
248 	ai_move, 3,	 NULL,
249 	ai_move, -1, NULL,
250 	ai_move, 0,	 NULL,
251 	ai_move, 0,	 NULL,
252 	ai_move, 0,	 NULL,
253 	ai_move, 0,	 NULL,
254 	ai_move, 1,	 NULL,
255 	ai_move, 1,	 NULL,
256 	ai_move, 2,	 NULL,
257 	ai_move, 1,	 NULL,
258 	ai_move, 0,	 NULL,
259 	ai_move, -2, NULL,
260 	ai_move, -2, NULL,
261 	ai_move, 0,	 NULL,
262 	ai_move, 0,	 NULL
263 };
264 mmove_t gunner_move_pain1 = {FRAME_pain101, FRAME_pain118, gunner_frames_pain1, gunner_run};
265 
gunner_pain(edict_t * self,edict_t * other,float kick,int damage)266 void gunner_pain (edict_t *self, edict_t *other, float kick, int damage)
267 {
268 	if (self->health < (self->max_health / 2))
269 		self->s.skinnum = 1;
270 
271 	if (level.time < self->pain_debounce_time)
272 		return;
273 
274 	self->pain_debounce_time = level.time + 3;
275 
276 	if (rand()&1)
277 		gi.sound (self, CHAN_VOICE, sound_pain, 1, ATTN_NORM, 0);
278 	else
279 		gi.sound (self, CHAN_VOICE, sound_pain2, 1, ATTN_NORM, 0);
280 
281 	if (skill->value == 3)
282 		return;		// no pain anims in nightmare
283 
284 	if (damage <= 10)
285 		self->monsterinfo.currentmove = &gunner_move_pain3;
286 	else if (damage <= 25)
287 		self->monsterinfo.currentmove = &gunner_move_pain2;
288 	else
289 		self->monsterinfo.currentmove = &gunner_move_pain1;
290 }
291 
gunner_dead(edict_t * self)292 void gunner_dead (edict_t *self)
293 {
294 	VectorSet (self->mins, -16, -16, -24);
295 	VectorSet (self->maxs, 16, 16, -8);
296 	self->movetype = MOVETYPE_TOSS;
297 	self->svflags |= SVF_DEADMONSTER;
298 	self->nextthink = 0;
299 
300 	self->think=FadeDieSink;
301 	self->nextthink=level.time+FADETIME+random()*5;
302 	self->floater=1;
303 
304 	gi.linkentity (self);
305 }
306 
307 mframe_t gunner_frames_death [] =
308 {
309 	ai_move, 0,	 NULL,
310 	ai_move, 0,	 NULL,
311 	ai_move, 0,	 NULL,
312 	ai_move, -7, NULL,
313 	ai_move, -3, NULL,
314 	ai_move, -5, NULL,
315 	ai_move, 8,	 NULL,
316 	ai_move, 6,	 NULL,
317 	ai_move, 0,	 NULL,
318 	ai_move, 0,	 NULL,
319 	ai_move, 0,	 NULL
320 };
321 mmove_t gunner_move_death = {FRAME_death01, FRAME_death11, gunner_frames_death, gunner_dead};
322 
gunner_die(edict_t * self,edict_t * inflictor,edict_t * attacker,int damage,vec3_t point)323 void gunner_die (edict_t *self, edict_t *inflictor, edict_t *attacker, int damage, vec3_t point)
324 {
325 	int		n;
326 
327 	switch (meansOfDeath & ~MOD_FRIENDLY_FIRE)
328 	{
329 		case MOD_ROCKET:
330 		case MOD_BFG_LASER:
331 		case MOD_BFG_BLAST:
332 		case MOD_HANDGRENADE:
333 		case MOD_HELD_GRENADE:
334 		case MOD_BOMB:
335 		case MOD_C4:
336 		case MOD_GAS_BOOM:
337 			self->health = self->gib_health;
338 			break;
339 		case MOD_FLAME:
340 		case MOD_DISCHARGE:
341 		case MOD_LAVA:
342 			self->health -= damage * 2;
343 			break;
344 		case MOD_HG_SPLASH:
345 		case MOD_R_SPLASH:
346 		case MOD_G_SPLASH:
347 			self->health -= damage * 5;
348 			break;
349 		case MOD_R_BFG_SPLASH:
350 			self->health -= damage * 10;
351 			break;
352 	}
353 
354 // check for gib
355 	if (self->health <= self->gib_health)
356 	{
357 		gi.sound (self, CHAN_VOICE, gi.soundindex ("misc/udeath.wav"), 1, ATTN_NORM, 0);
358 		for (n= 0; n < 2; n++)
359 			ThrowGib (self, "models/objects/gibs/bone/tris.md2", damage, GIB_ORGANIC);
360 		for (n= 0; n < 4; n++)
361 			ThrowGib (self, "models/objects/gibs/sm_meat/tris.md2", damage, GIB_ORGANIC);
362 		ThrowHead (self, "models/objects/gibs/head2/tris.md2", damage, GIB_ORGANIC);
363 		self->deadflag = DEAD_DEAD;
364 		return;
365 	}
366 
367 	if (self->deadflag == DEAD_DEAD)
368 		return;
369 
370 // regular death
371 	gi.sound (self, CHAN_VOICE, sound_death, 1, ATTN_NORM, 0);
372 	self->deadflag = DEAD_DEAD;
373 	self->takedamage = DAMAGE_YES;
374 	self->monsterinfo.currentmove = &gunner_move_death;
375 }
376 
377 
gunner_duck_down(edict_t * self)378 void gunner_duck_down (edict_t *self)
379 {
380 	if (self->monsterinfo.aiflags & AI_DUCKED)
381 		return;
382 	self->monsterinfo.aiflags |= AI_DUCKED;
383 	if (skill->value >= 2)
384 	{
385 		if (random() > 0.5)
386 			GunnerGrenade (self);
387 	}
388 
389 	self->maxs[2] -= 32;
390 	self->takedamage = DAMAGE_YES;
391 	self->monsterinfo.pausetime = level.time + 1;
392 	gi.linkentity (self);
393 }
394 
gunner_duck_hold(edict_t * self)395 void gunner_duck_hold (edict_t *self)
396 {
397 	if (level.time >= self->monsterinfo.pausetime)
398 		self->monsterinfo.aiflags &= ~AI_HOLD_FRAME;
399 	else
400 		self->monsterinfo.aiflags |= AI_HOLD_FRAME;
401 }
402 
gunner_duck_up(edict_t * self)403 void gunner_duck_up (edict_t *self)
404 {
405 	self->monsterinfo.aiflags &= ~AI_DUCKED;
406 	self->maxs[2] += 32;
407 	self->takedamage = DAMAGE_AIM;
408 	gi.linkentity (self);
409 }
410 
411 mframe_t gunner_frames_duck [] =
412 {
413 	ai_move, 1,  gunner_duck_down,
414 	ai_move, 1,  NULL,
415 	ai_move, 1,  gunner_duck_hold,
416 	ai_move, 0,  NULL,
417 	ai_move, -1, NULL,
418 	ai_move, -1, NULL,
419 	ai_move, 0,  gunner_duck_up,
420 	ai_move, -1, NULL
421 };
422 mmove_t	gunner_move_duck = {FRAME_duck01, FRAME_duck08, gunner_frames_duck, gunner_run};
423 
gunner_dodge(edict_t * self,edict_t * attacker,float eta)424 void gunner_dodge (edict_t *self, edict_t *attacker, float eta)
425 {
426 	if (random() > 0.25)
427 		return;
428 
429 	if (!self->enemy)
430 		self->enemy = attacker;
431 
432 	self->monsterinfo.currentmove = &gunner_move_duck;
433 }
434 
435 
gunner_opengun(edict_t * self)436 void gunner_opengun (edict_t *self)
437 {
438 	gi.sound (self, CHAN_VOICE, sound_open, 1, ATTN_IDLE, 0);
439 }
440 
GunnerFire(edict_t * self)441 void GunnerFire (edict_t *self)
442 {
443 	vec3_t	start;
444 	vec3_t	forward, right;
445 	vec3_t	target;
446 	vec3_t	aim;
447 	int		flash_number, distance;
448 
449 	flash_number = MZ2_GUNNER_MACHINEGUN_1 + (self->s.frame - FRAME_attak216);
450 
451 	AngleVectors (self->s.angles, forward, right, NULL);
452 	G_ProjectSource (self->s.origin, monster_flash_offset[flash_number], forward, right, start);
453 
454 	// project enemy back a bit and target there
455 	VectorCopy (self->enemy->s.origin, target);
456 	VectorMA (target, -0.2, self->enemy->velocity, target);
457 	target[2] += self->enemy->viewheight;
458 
459 	VectorSubtract (target, start, aim);
460 	distance = VectorLength(aim);
461 	VectorNormalize (aim);
462 
463 	monster_fire_bullet (self, start, aim, 20, 4, DEFAULT_BULLET_HSPREAD, DEFAULT_BULLET_VSPREAD, flash_number);
464 }
465 
GunnerPlasma(edict_t * self)466 void GunnerPlasma (edict_t *self)
467 {
468 	vec3_t	start;
469 	vec3_t	forward, right;
470 	vec3_t	target, targ_temp;
471 	vec3_t	aim;
472 	int		flash_number, distance;
473 
474 	flash_number = MZ2_GUNNER_MACHINEGUN_1 + (self->s.frame - FRAME_attak216);
475 
476 	AngleVectors (self->s.angles, forward, right, NULL);
477 	G_ProjectSource (self->s.origin, monster_flash_offset[flash_number], forward, right, start);
478 
479 	// project enemy back a bit and target there
480 	VectorCopy (self->enemy->s.origin, target);
481 	predictTargPos (self, start, target, self->enemy->velocity, 1500, false);
482 
483 	VectorSubtract (target, start, aim);
484 	distance = VectorLength(aim);
485 	VectorNormalize (aim);
486 
487 	aim[2]+=(distance)/1500;
488 	monster_fire_plasma (self, start, aim, 1, 1500, EF_BLASTER);
489 	gi.sound(self, CHAN_AUTO, gi.soundindex("brain/brnatck2.wav"), 0.8, ATTN_IDLE, 0);
490 
491 }
492 
GunnerGrenade(edict_t * self)493 void GunnerGrenade (edict_t *self)
494 {
495 	vec3_t	start;
496 	vec3_t	forward, right;
497 	vec3_t	aim;
498 	int		flash_number;
499 	int damage;
500 
501 
502 
503 	if (self->s.frame == FRAME_attak105)
504 		flash_number = MZ2_GUNNER_GRENADE_1;
505 	else if (self->s.frame == FRAME_attak108)
506 		flash_number = MZ2_GUNNER_GRENADE_2;
507 	else if (self->s.frame == FRAME_attak111)
508 		flash_number = MZ2_GUNNER_GRENADE_3;
509 	else // (self->s.frame == FRAME_attak114)
510 		flash_number = MZ2_GUNNER_GRENADE_4;
511 
512 	AngleVectors (self->s.angles, forward, right, NULL);
513 	G_ProjectSource (self->s.origin, monster_flash_offset[flash_number], forward, right, start);
514 
515 	//FIXME : do a spread -225 -75 75 225 degrees around forward
516 	VectorCopy (forward, aim);
517 
518 	damage = 30 + (int)(random() * 10.0);
519 	monster_fire_flame (self, start, forward, damage, 600, flash_number);
520 }
521 
522 mframe_t gunner_frames_attack_chain [] =
523 {
524 	/*
525 	ai_charge, 0, NULL,
526 	ai_charge, 0, NULL,
527 	ai_charge, 0, NULL,
528 	ai_charge, 0, NULL,
529 	ai_charge, 0, NULL,
530 	ai_charge, 0, NULL,
531 	ai_charge, 0, NULL,
532 	ai_charge, 0, NULL,
533 	*/
534 	ai_charge, 0, gunner_opengun,
535 	ai_charge, 0, NULL,
536 	ai_charge, 0, NULL,
537 	ai_charge, 0, NULL,
538 	ai_charge, 0, NULL,
539 	ai_charge, 0, NULL,
540 	ai_charge, 0, NULL
541 };
542 mmove_t gunner_move_attack_chain = {FRAME_attak209, FRAME_attak215, gunner_frames_attack_chain, gunner_fire_chain};
543 
544 mframe_t gunner_frames_attack_plasma [] =
545 {
546 	/*
547 	ai_charge, 0, NULL,
548 	ai_charge, 0, NULL,
549 	ai_charge, 0, NULL,
550 	ai_charge, 0, NULL,
551 	ai_charge, 0, NULL,
552 	ai_charge, 0, NULL,
553 	ai_charge, 0, NULL,
554 	ai_charge, 0, NULL,
555 	*/
556 	ai_charge, 0, gunner_opengun,
557 	ai_charge, 0, NULL,
558 	ai_charge, 0, NULL,
559 	ai_charge, 0, NULL,
560 	ai_charge, 0, NULL,
561 	ai_charge, 0, NULL,
562 	ai_charge, 0, NULL
563 };
564 mmove_t gunner_move_attack_plasma = {FRAME_attak209, FRAME_attak215, gunner_frames_attack_plasma, gunner_fire_plasma};
565 
566 //Machine Gun
567 
568 mframe_t gunner_frames_fire_chain [] =
569 {
570 	ai_charge,   0, GunnerFire,
571 	ai_charge,   0, GunnerFire,
572 	ai_charge,   0, GunnerFire,
573 	ai_charge,   0, GunnerFire,
574 	ai_charge,   0, GunnerFire,
575 	ai_charge,   0, GunnerFire,
576 	ai_charge,   0, GunnerFire,
577 	ai_charge,   0, GunnerFire
578 };
579 mmove_t gunner_move_fire_chain = {FRAME_attak216, FRAME_attak223, gunner_frames_fire_chain, gunner_refire_chain};
580 
581 mframe_t gunner_frames_endfire_chain [] =
582 {
583 	ai_charge, 0, NULL,
584 	ai_charge, 0, NULL,
585 	ai_charge, 0, NULL,
586 	ai_charge, 0, NULL,
587 	ai_charge, 0, NULL,
588 	ai_charge, 0, NULL,
589 	ai_charge, 0, NULL
590 };
591 mmove_t gunner_move_endfire_chain = {FRAME_attak224, FRAME_attak230, gunner_frames_endfire_chain, gunner_run};
592 
593 //Plasma Rifle
594 //*
595 mframe_t gunner_frames_fire_plasma [] =
596 {
597 	ai_charge,   0, GunnerPlasma,
598 	ai_charge,   0, GunnerPlasma,
599 	ai_charge,   0, GunnerPlasma,
600 	ai_charge,   0, GunnerPlasma,
601 	ai_charge,   0, GunnerPlasma,
602 	ai_charge,   0, GunnerPlasma,
603 	ai_charge,   0, GunnerPlasma,
604 	ai_charge,   0, GunnerPlasma
605 };
606 mmove_t gunner_move_fire_plasma = {FRAME_attak216, FRAME_attak223, gunner_frames_fire_plasma, gunner_refire_plasma};
607 
608 mframe_t gunner_frames_endfire_plasma [] =
609 {
610 	ai_charge, 0, NULL,
611 	ai_charge, 0, NULL,
612 	ai_charge, 0, NULL,
613 	ai_charge, 0, NULL,
614 	ai_charge, 0, NULL,
615 	ai_charge, 0, NULL,
616 	ai_charge, 0, NULL
617 };
618 mmove_t gunner_move_endfire_plasma = {FRAME_attak224, FRAME_attak230, gunner_frames_endfire_plasma, gunner_run};
619 //*/
620 //Grenade Launcher
621 
622 mframe_t gunner_frames_attack_grenade [] =
623 {
624 	ai_charge, 0, NULL,
625 	ai_charge, 0, NULL,
626 	ai_charge, 0, NULL,
627 	ai_charge, 0, NULL,
628 	ai_charge, 0, GunnerGrenade,
629 	ai_charge, 0, GunnerGrenade,
630 	ai_charge, 0, GunnerGrenade,
631 	ai_charge, 0, GunnerGrenade,
632 	ai_charge, 0, GunnerGrenade,
633 	ai_charge, 0, GunnerGrenade,
634 	ai_charge, 0, GunnerGrenade,
635 	ai_charge, 0, GunnerGrenade,
636 	ai_charge, 0, GunnerGrenade,
637 	ai_charge, 0, GunnerGrenade,
638 	ai_charge, 0, NULL,
639 	ai_charge, 0, NULL,
640 	ai_charge, 0, NULL,
641 	ai_charge, 0, NULL,
642 	ai_charge, 0, NULL,
643 	ai_charge, 0, NULL,
644 	ai_charge, 0, NULL
645 };
646 mmove_t gunner_move_attack_grenade = {FRAME_attak101, FRAME_attak121, gunner_frames_attack_grenade, gunner_run};
647 
gunner_attack(edict_t * self)648 void gunner_attack(edict_t *self)
649 {
650 	if (range (self, self->enemy) == RANGE_MELEE)
651 		self->monsterinfo.currentmove = &gunner_move_attack_grenade;
652 	else if (range (self, self->enemy) == RANGE_NEAR)
653 		self->monsterinfo.currentmove = &gunner_move_attack_plasma;//gunner_move_attack_grenade;
654 	else if (range (self, self->enemy) == RANGE_MID)
655 		self->monsterinfo.currentmove = &gunner_move_attack_plasma;
656 	else if (range (self, self->enemy) == RANGE_FAR)
657 		self->monsterinfo.currentmove = &gunner_move_attack_chain;
658 }
659 
gunner_fire_chain(edict_t * self)660 void gunner_fire_chain(edict_t *self)
661 {
662 	self->monsterinfo.currentmove = &gunner_move_fire_chain;
663 }
664 
gunner_refire_chain(edict_t * self)665 void gunner_refire_chain(edict_t *self)
666 {
667 	if (self->enemy->health > 0)
668 		if ( visible (self, self->enemy) )
669 			if (random() <= 0.5)
670 			{
671 				self->monsterinfo.currentmove = &gunner_move_fire_chain;
672 				return;
673 			}
674 	self->monsterinfo.currentmove = &gunner_move_endfire_chain;
675 }
676 
gunner_fire_plasma(edict_t * self)677 void gunner_fire_plasma(edict_t *self)
678 {
679 	self->monsterinfo.currentmove = &gunner_move_fire_plasma;
680 }
681 
gunner_refire_plasma(edict_t * self)682 void gunner_refire_plasma(edict_t *self)
683 {
684 	if (self->enemy->health > 0)
685 		if ( visible (self, self->enemy) )
686 			if (random() <= 0.5)
687 			{
688 				self->monsterinfo.currentmove = &gunner_move_fire_plasma;
689 				return;
690 			}
691 	self->monsterinfo.currentmove = &gunner_move_endfire_plasma;
692 }
693 
694 /*QUAKED monster_gunner (1 .5 0) (-16 -16 -24) (16 16 32) Ambush Trigger_Spawn Sight
695 */
SP_monster_gunner(edict_t * self)696 void SP_monster_gunner (edict_t *self)
697 {
698 	if (deathmatch->value)
699 	{
700 		G_FreeEdict (self);
701 		return;
702 	}
703 
704 	sound_death = gi.soundindex ("gunner/death1.wav");
705 	sound_pain = gi.soundindex ("gunner/gunpain2.wav");
706 	sound_pain2 = gi.soundindex ("gunner/gunpain1.wav");
707 	sound_idle = gi.soundindex ("gunner/gunidle1.wav");
708 	sound_open = gi.soundindex ("gunner/gunatck1.wav");
709 	sound_search = gi.soundindex ("gunner/gunsrch1.wav");
710 	sound_sight = gi.soundindex ("gunner/sight1.wav");
711 
712 	gi.soundindex ("gunner/gunatck2.wav");
713 	gi.soundindex ("gunner/gunatck3.wav");
714 
715 	self->movetype = MOVETYPE_STEP;
716 	self->solid = SOLID_BBOX;
717 	self->s.modelindex = gi.modelindex ("models/monsters/gunner/tris.md2");
718 	VectorSet (self->mins, -16, -16, -24);
719 	VectorSet (self->maxs, 16, 16, 32);
720 
721 	self->health = 125;
722 	self->gib_health = -700;
723 	self->mass = 200;
724 
725 	self->max_health = self->health;
726 
727 	self->pain = gunner_pain;
728 	self->die = gunner_die;
729 
730 	self->monsterinfo.stand = gunner_stand;
731 	self->monsterinfo.walk = gunner_walk;
732 	self->monsterinfo.run = gunner_run;
733 	self->monsterinfo.dodge = gunner_dodge;
734 	self->monsterinfo.attack = gunner_attack;
735 	self->monsterinfo.melee = NULL;
736 	self->monsterinfo.sight = gunner_sight;
737 	self->monsterinfo.search = gunner_search;
738 
739 	gi.linkentity (self);
740 
741 	self->monsterinfo.currentmove = &gunner_move_stand;
742 	self->monsterinfo.scale = MODEL_SCALE;
743 
744 	walkmonster_start (self);
745 }
746