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