File: game\m_soldier.c
1 /*
2 Copyright (C) 1997-2001 Id Software, Inc.
3
4 This program is free software; you can redistribute it and/or
5 modify it under the terms of the GNU General Public License
6 as published by the Free Software Foundation; either version 2
7 of the License, or (at your option) any later version.
8
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12
13 See the GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18
19 */
20 /*
21 ==============================================================================
22
23 SOLDIER
24
25 ==============================================================================
26 */
27
28 #include "g_local.h"
29 #include "m_soldier.h"
30
31
32 static int sound_idle;
33 static int sound_sight1;
34 static int sound_sight2;
35 static int sound_pain_light;
36 static int sound_pain;
37 static int sound_pain_ss;
38 static int sound_death_light;
39 static int sound_death;
40 static int sound_death_ss;
41 static int sound_cock;
42
43
44 void soldier_idle (edict_t *self)
45 {
46 if (random() > 0.8)
47 gi.sound (self, CHAN_VOICE, sound_idle, 1, ATTN_IDLE, 0);
48 }
49
50 void soldier_cock (edict_t *self)
51 {
52 if (self->s.frame == FRAME_stand322)
53 gi.sound (self, CHAN_WEAPON, sound_cock, 1, ATTN_IDLE, 0);
54 else
55 gi.sound (self, CHAN_WEAPON, sound_cock, 1, ATTN_NORM, 0);
56 }
57
58
59 // STAND
60
61 void soldier_stand (edict_t *self);
62
63 mframe_t soldier_frames_stand1 [] =
64 {
65 ai_stand, 0, soldier_idle,
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 ai_stand, 0, NULL,
72 ai_stand, 0, NULL,
73 ai_stand, 0, NULL,
74 ai_stand, 0, NULL,
75
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 ai_stand, 0, NULL,
83 ai_stand, 0, NULL,
84 ai_stand, 0, NULL,
85 ai_stand, 0, NULL,
86
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 ai_stand, 0, NULL,
94 ai_stand, 0, NULL,
95 ai_stand, 0, NULL,
96 ai_stand, 0, NULL
97 };
98 mmove_t soldier_move_stand1 = {FRAME_stand101, FRAME_stand130, soldier_frames_stand1, soldier_stand};
99
100 mframe_t soldier_frames_stand3 [] =
101 {
102 ai_stand, 0, NULL,
103 ai_stand, 0, NULL,
104 ai_stand, 0, NULL,
105 ai_stand, 0, NULL,
106 ai_stand, 0, NULL,
107 ai_stand, 0, NULL,
108 ai_stand, 0, NULL,
109 ai_stand, 0, NULL,
110 ai_stand, 0, NULL,
111 ai_stand, 0, NULL,
112
113 ai_stand, 0, NULL,
114 ai_stand, 0, NULL,
115 ai_stand, 0, NULL,
116 ai_stand, 0, NULL,
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
124 ai_stand, 0, NULL,
125 ai_stand, 0, soldier_cock,
126 ai_stand, 0, NULL,
127 ai_stand, 0, NULL,
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
135 ai_stand, 0, NULL,
136 ai_stand, 0, NULL,
137 ai_stand, 0, NULL,
138 ai_stand, 0, NULL,
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 };
145 mmove_t soldier_move_stand3 = {FRAME_stand301, FRAME_stand339, soldier_frames_stand3, soldier_stand};
146
147 #if 0
148 mframe_t soldier_frames_stand4 [] =
149 {
150 ai_stand, 0, NULL,
151 ai_stand, 0, NULL,
152 ai_stand, 0, NULL,
153 ai_stand, 0, NULL,
154 ai_stand, 0, NULL,
155 ai_stand, 0, NULL,
156 ai_stand, 0, NULL,
157 ai_stand, 0, NULL,
158 ai_stand, 0, NULL,
159 ai_stand, 0, NULL,
160
161 ai_stand, 0, NULL,
162 ai_stand, 0, NULL,
163 ai_stand, 0, NULL,
164 ai_stand, 0, NULL,
165 ai_stand, 0, NULL,
166 ai_stand, 0, NULL,
167 ai_stand, 0, NULL,
168 ai_stand, 0, NULL,
169 ai_stand, 0, NULL,
170 ai_stand, 0, NULL,
171
172 ai_stand, 0, NULL,
173 ai_stand, 0, NULL,
174 ai_stand, 0, NULL,
175 ai_stand, 0, NULL,
176 ai_stand, 0, NULL,
177 ai_stand, 0, NULL,
178 ai_stand, 0, NULL,
179 ai_stand, 0, NULL,
180 ai_stand, 0, NULL,
181 ai_stand, 0, NULL,
182
183 ai_stand, 0, NULL,
184 ai_stand, 0, NULL,
185 ai_stand, 0, NULL,
186 ai_stand, 0, NULL,
187 ai_stand, 0, NULL,
188 ai_stand, 0, NULL,
189 ai_stand, 0, NULL,
190 ai_stand, 0, NULL,
191 ai_stand, 0, NULL,
192 ai_stand, 0, NULL,
193
194 ai_stand, 0, NULL,
195 ai_stand, 0, NULL,
196 ai_stand, 0, NULL,
197 ai_stand, 0, NULL,
198 ai_stand, 0, NULL,
199 ai_stand, 0, NULL,
200 ai_stand, 4, NULL,
201 ai_stand, 1, NULL,
202 ai_stand, -1, NULL,
203 ai_stand, -2, NULL,
204
205 ai_stand, 0, NULL,
206 ai_stand, 0, NULL
207 };
208 mmove_t soldier_move_stand4 = {FRAME_stand401, FRAME_stand452, soldier_frames_stand4, NULL}; 209 #endif
210
211 void soldier_stand (edict_t *self)
212 {
213 if ((self->monsterinfo.currentmove == &soldier_move_stand3) || (random() < 0.8))
214 self->monsterinfo.currentmove = &soldier_move_stand1;
215 else
216 self->monsterinfo.currentmove = &soldier_move_stand3;
217 }
218
219
220 //
221 // WALK
222 //
223
224 void soldier_walk1_random (edict_t *self)
225 {
226 if (random() > 0.1)
227 self->monsterinfo.nextframe = FRAME_walk101;
228 }
229
230 mframe_t soldier_frames_walk1 [] =
231 {
232 ai_walk, 3, NULL,
233 ai_walk, 6, NULL,
234 ai_walk, 2, NULL,
235 ai_walk, 2, NULL,
236 ai_walk, 2, NULL,
237 ai_walk, 1, NULL,
238 ai_walk, 6, NULL,
239 ai_walk, 5, NULL,
240 ai_walk, 3, NULL,
241 ai_walk, -1, soldier_walk1_random,
242 ai_walk, 0, NULL,
243 ai_walk, 0, NULL,
244 ai_walk, 0, NULL,
245 ai_walk, 0, NULL,
246 ai_walk, 0, NULL,
247 ai_walk, 0, NULL,
248 ai_walk, 0, NULL,
249 ai_walk, 0, NULL,
250 ai_walk, 0, NULL,
251 ai_walk, 0, NULL,
252 ai_walk, 0, NULL,
253 ai_walk, 0, NULL,
254 ai_walk, 0, NULL,
255 ai_walk, 0, NULL,
256 ai_walk, 0, NULL,
257 ai_walk, 0, NULL,
258 ai_walk, 0, NULL,
259 ai_walk, 0, NULL,
260 ai_walk, 0, NULL,
261 ai_walk, 0, NULL,
262 ai_walk, 0, NULL,
263 ai_walk, 0, NULL,
264 ai_walk, 0, NULL
265 };
266 mmove_t soldier_move_walk1 = {FRAME_walk101, FRAME_walk133, soldier_frames_walk1, NULL};
267
268 mframe_t soldier_frames_walk2 [] =
269 {
270 ai_walk, 4, NULL,
271 ai_walk, 4, NULL,
272 ai_walk, 9, NULL,
273 ai_walk, 8, NULL,
274 ai_walk, 5, NULL,
275 ai_walk, 1, NULL,
276 ai_walk, 3, NULL,
277 ai_walk, 7, NULL,
278 ai_walk, 6, NULL,
279 ai_walk, 7, NULL
280 };
281 mmove_t soldier_move_walk2 = {FRAME_walk209, FRAME_walk218, soldier_frames_walk2, NULL};
282
283 void soldier_walk (edict_t *self)
284 {
285 if (random() < 0.5)
286 self->monsterinfo.currentmove = &soldier_move_walk1;
287 else
288 self->monsterinfo.currentmove = &soldier_move_walk2;
289 }
290
291
292 //
293 // RUN
294 //
295
296 void soldier_run (edict_t *self);
297
298 mframe_t soldier_frames_start_run [] =
299 {
300 ai_run, 7, NULL,
301 ai_run, 5, NULL
302 };
303 mmove_t soldier_move_start_run = {FRAME_run01, FRAME_run02, soldier_frames_start_run, soldier_run};
304
305 mframe_t soldier_frames_run [] =
306 {
307 ai_run, 10, NULL,
308 ai_run, 11, NULL,
309 ai_run, 11, NULL,
310 ai_run, 16, NULL,
311 ai_run, 10, NULL,
312 ai_run, 15, NULL
313 };
314 mmove_t soldier_move_run = {FRAME_run03, FRAME_run08, soldier_frames_run, NULL};
315
316 void soldier_run (edict_t *self)
317 {
318 if (self->monsterinfo.aiflags & AI_STAND_GROUND)
319 {
320 self->monsterinfo.currentmove = &soldier_move_stand1;
321 return;
322 }
323
324 if (self->monsterinfo.currentmove == &soldier_move_walk1 ||
325 self->monsterinfo.currentmove == &soldier_move_walk2 ||
326 self->monsterinfo.currentmove == &soldier_move_start_run)
327 {
328 self->monsterinfo.currentmove = &soldier_move_run;
329 }
330 else
331 {
332 self->monsterinfo.currentmove = &soldier_move_start_run;
333 }
334 }
335
336
337 //
338 // PAIN
339 //
340
341 mframe_t soldier_frames_pain1 [] =
342 {
343 ai_move, -3, NULL,
344 ai_move, 4, NULL,
345 ai_move, 1, NULL,
346 ai_move, 1, NULL,
347 ai_move, 0, NULL
348 };
349 mmove_t soldier_move_pain1 = {FRAME_pain101, FRAME_pain105, soldier_frames_pain1, soldier_run};
350
351 mframe_t soldier_frames_pain2 [] =
352 {
353 ai_move, -13, NULL,
354 ai_move, -1, NULL,
355 ai_move, 2, NULL,
356 ai_move, 4, NULL,
357 ai_move, 2, NULL,
358 ai_move, 3, NULL,
359 ai_move, 2, NULL
360 };
361 mmove_t soldier_move_pain2 = {FRAME_pain201, FRAME_pain207, soldier_frames_pain2, soldier_run};
362
363 mframe_t soldier_frames_pain3 [] =
364 {
365 ai_move, -8, NULL,
366 ai_move, 10, NULL,
367 ai_move, -4, NULL,
368 ai_move, -1, NULL,
369 ai_move, -3, NULL,
370 ai_move, 0, NULL,
371 ai_move, 3, NULL,
372 ai_move, 0, NULL,
373 ai_move, 0, NULL,
374 ai_move, 0, NULL,
375 ai_move, 0, NULL,
376 ai_move, 1, NULL,
377 ai_move, 0, NULL,
378 ai_move, 1, NULL,
379 ai_move, 2, NULL,
380 ai_move, 4, NULL,
381 ai_move, 3, NULL,
382 ai_move, 2, NULL
383 };
384 mmove_t soldier_move_pain3 = {FRAME_pain301, FRAME_pain318, soldier_frames_pain3, soldier_run};
385
386 mframe_t soldier_frames_pain4 [] =
387 {
388 ai_move, 0, NULL,
389 ai_move, 0, NULL,
390 ai_move, 0, NULL,
391 ai_move, -10, NULL,
392 ai_move, -6, NULL,
393 ai_move, 8, NULL,
394 ai_move, 4, NULL,
395 ai_move, 1, NULL,
396 ai_move, 0, NULL,
397 ai_move, 2, NULL,
398 ai_move, 5, NULL,
399 ai_move, 2, NULL,
400 ai_move, -1, NULL,
401 ai_move, -1, NULL,
402 ai_move, 3, NULL,
403 ai_move, 2, NULL,
404 ai_move, 0, NULL
405 };
406 mmove_t soldier_move_pain4 = {FRAME_pain401, FRAME_pain417, soldier_frames_pain4, soldier_run};
407
408
409 void soldier_pain (edict_t *self, edict_t *other, float kick, int damage)
410 {
411 float r;
412 int n;
413
414 if (self->health < (self->max_health / 2))
415 self->s.skinnum |= 1;
416
417 if (level.time < self->pain_debounce_time)
418 {
419 if ((self->velocity[2] > 100) && ( (self->monsterinfo.currentmove == &soldier_move_pain1) || (self->monsterinfo.currentmove == &soldier_move_pain2) || (self->monsterinfo.currentmove == &soldier_move_pain3)))
420 self->monsterinfo.currentmove = &soldier_move_pain4;
421 return;
422 }
423
424 self->pain_debounce_time = level.time + 3;
425
426 n = self->s.skinnum | 1;
427 if (n == 1)
428 gi.sound (self, CHAN_VOICE, sound_pain_light, 1, ATTN_NORM, 0);
429 else if (n == 3)
430 gi.sound (self, CHAN_VOICE, sound_pain, 1, ATTN_NORM, 0);
431 else
432 gi.sound (self, CHAN_VOICE, sound_pain_ss, 1, ATTN_NORM, 0);
433
434 if (self->velocity[2] > 100)
435 {
436 self->monsterinfo.currentmove = &soldier_move_pain4;
437 return;
438 }
439
440 if (skill->value == 3)
441 return; // no pain anims in nightmare
442
443 r = random();
444
445 if (r < 0.33)
446 self->monsterinfo.currentmove = &soldier_move_pain1;
447 else if (r < 0.66)
448 self->monsterinfo.currentmove = &soldier_move_pain2;
449 else
450 self->monsterinfo.currentmove = &soldier_move_pain3;
451 }
452
453
454 //
455 // ATTACK
456 //
457
458 static int blaster_flash [] = {MZ2_SOLDIER_BLASTER_1, MZ2_SOLDIER_BLASTER_2, MZ2_SOLDIER_BLASTER_3, MZ2_SOLDIER_BLASTER_4, MZ2_SOLDIER_BLASTER_5, MZ2_SOLDIER_BLASTER_6, MZ2_SOLDIER_BLASTER_7, MZ2_SOLDIER_BLASTER_8};
459 static int shotgun_flash [] = {MZ2_SOLDIER_SHOTGUN_1, MZ2_SOLDIER_SHOTGUN_2, MZ2_SOLDIER_SHOTGUN_3, MZ2_SOLDIER_SHOTGUN_4, MZ2_SOLDIER_SHOTGUN_5, MZ2_SOLDIER_SHOTGUN_6, MZ2_SOLDIER_SHOTGUN_7, MZ2_SOLDIER_SHOTGUN_8};
460 static int machinegun_flash [] = {MZ2_SOLDIER_MACHINEGUN_1, MZ2_SOLDIER_MACHINEGUN_2, MZ2_SOLDIER_MACHINEGUN_3, MZ2_SOLDIER_MACHINEGUN_4, MZ2_SOLDIER_MACHINEGUN_5, MZ2_SOLDIER_MACHINEGUN_6, MZ2_SOLDIER_MACHINEGUN_7, MZ2_SOLDIER_MACHINEGUN_8};
461
462 void soldier_fire (edict_t *self, int flash_number)
463 {
464 vec3_t start;
465 vec3_t forward, right, up;
466 vec3_t aim;
467 vec3_t dir;
468 vec3_t end;
469 float r, u;
470 int flash_index;
471
472 if (self->s.skinnum < 2)
473 flash_index = blaster_flash[flash_number];
474 else if (self->s.skinnum < 4)
475 flash_index = shotgun_flash[flash_number];
476 else
477 flash_index = machinegun_flash[flash_number];
478
479 AngleVectors (self->s.angles, forward, right, NULL);
480 G_ProjectSource (self->s.origin, monster_flash_offset[flash_index], forward, right, start);
481
482 if (flash_number == 5 || flash_number == 6)
483 {
484 VectorCopy (forward, aim);
485 }
486 else
487 {
488 VectorCopy (self->enemy->s.origin, end);
489 end[2] += self->enemy->viewheight;
490 VectorSubtract (end, start, aim);
491 vectoangles (aim, dir);
492 AngleVectors (dir, forward, right, up);
493
494 r = crandom()*1000;
495 u = crandom()*500;
496 VectorMA (start, 8192, forward, end);
497 VectorMA (end, r, right, end);
498 VectorMA (end, u, up, end);
499
500 VectorSubtract (end, start, aim);
501 VectorNormalize (aim);
502 }
503
504 if (self->s.skinnum <= 1)
505 {
506 monster_fire_blaster (self, start, aim, 5, 600, flash_index, EF_BLASTER);
507 }
508 else if (self->s.skinnum <= 3)
509 {
510 monster_fire_shotgun (self, start, aim, 2, 1, DEFAULT_SHOTGUN_HSPREAD, DEFAULT_SHOTGUN_VSPREAD, DEFAULT_SHOTGUN_COUNT, flash_index);
511 }
512 else
513 {
514 if (!(self->monsterinfo.aiflags & AI_HOLD_FRAME))
515 self->monsterinfo.pausetime = level.time + (3 + rand() % 8) * FRAMETIME;
516
517 monster_fire_bullet (self, start, aim, 2, 4, DEFAULT_BULLET_HSPREAD, DEFAULT_BULLET_VSPREAD, flash_index);
518
519 if (level.time >= self->monsterinfo.pausetime)
520 self->monsterinfo.aiflags &= ~AI_HOLD_FRAME;
521 else
522 self->monsterinfo.aiflags |= AI_HOLD_FRAME;
523 }
524 }
525
526 // ATTACK1 (blaster/shotgun)
527
528 void soldier_fire1 (edict_t *self)
529 {
530 soldier_fire (self, 0);
531 }
532
533 void soldier_attack1_refire1 (edict_t *self)
534 {
535 if (self->s.skinnum > 1)
536 return;
537
538 if (self->enemy->health <= 0)
539 return;
540
541 if ( ((skill->value == 3) && (random() < 0.5)) || (range(self, self->enemy) == RANGE_MELEE) )
542 self->monsterinfo.nextframe = FRAME_attak102;
543 else
544 self->monsterinfo.nextframe = FRAME_attak110;
545 }
546
547 void soldier_attack1_refire2 (edict_t *self)
548 {
549 if (self->s.skinnum < 2)
550 return;
551
552 if (self->enemy->health <= 0)
553 return;
554
555 if ( ((skill->value == 3) && (random() < 0.5)) || (range(self, self->enemy) == RANGE_MELEE) )
556 self->monsterinfo.nextframe = FRAME_attak102;
557 }
558
559 mframe_t soldier_frames_attack1 [] =
560 {
561 ai_charge, 0, NULL,
562 ai_charge, 0, NULL,
563 ai_charge, 0, soldier_fire1,
564 ai_charge, 0, NULL,
565 ai_charge, 0, NULL,
566 ai_charge, 0, soldier_attack1_refire1,
567 ai_charge, 0, NULL,
568 ai_charge, 0, soldier_cock,
569 ai_charge, 0, soldier_attack1_refire2,
570 ai_charge, 0, NULL,
571 ai_charge, 0, NULL,
572 ai_charge, 0, NULL
573 };
574 mmove_t soldier_move_attack1 = {FRAME_attak101, FRAME_attak112, soldier_frames_attack1, soldier_run};
575
576 // ATTACK2 (blaster/shotgun)
577
578 void soldier_fire2 (edict_t *self)
579 {
580 soldier_fire (self, 1);
581 }
582
583 void soldier_attack2_refire1 (edict_t *self)
584 {
585 if (self->s.skinnum > 1)
586 return;
587
588 if (self->enemy->health <= 0)
589 return;
590
591 if ( ((skill->value == 3) && (random() < 0.5)) || (range(self, self->enemy) == RANGE_MELEE) )
592 self->monsterinfo.nextframe = FRAME_attak204;
593 else
594 self->monsterinfo.nextframe = FRAME_attak216;
595 }
596
597 void soldier_attack2_refire2 (edict_t *self)
598 {
599 if (self->s.skinnum < 2)
600 return;
601
602 if (self->enemy->health <= 0)
603 return;
604
605 if ( ((skill->value == 3) && (random() < 0.5)) || (range(self, self->enemy) == RANGE_MELEE) )
606 self->monsterinfo.nextframe = FRAME_attak204;
607 }
608
609 mframe_t soldier_frames_attack2 [] =
610 {
611 ai_charge, 0, NULL,
612 ai_charge, 0, NULL,
613 ai_charge, 0, NULL,
614 ai_charge, 0, NULL,
615 ai_charge, 0, soldier_fire2,
616 ai_charge, 0, NULL,
617 ai_charge, 0, NULL,
618 ai_charge, 0, soldier_attack2_refire1,
619 ai_charge, 0, NULL,
620 ai_charge, 0, NULL,
621 ai_charge, 0, NULL,
622 ai_charge, 0, NULL,
623 ai_charge, 0, soldier_cock,
624 ai_charge, 0, NULL,
625 ai_charge, 0, soldier_attack2_refire2,
626 ai_charge, 0, NULL,
627 ai_charge, 0, NULL,
628 ai_charge, 0, NULL
629 };
630 mmove_t soldier_move_attack2 = {FRAME_attak201, FRAME_attak218, soldier_frames_attack2, soldier_run};
631
632 // ATTACK3 (duck and shoot)
633
634 void soldier_duck_down (edict_t *self)
635 {
636 if (self->monsterinfo.aiflags & AI_DUCKED)
637 return;
638 self->monsterinfo.aiflags |= AI_DUCKED;
639 self->maxs[2] -= 32;
640 self->takedamage = DAMAGE_YES;
641 self->monsterinfo.pausetime = level.time + 1;
642 gi.linkentity (self);
643 }
644
645 void soldier_duck_up (edict_t *self)
646 {
647 self->monsterinfo.aiflags &= ~AI_DUCKED;
648 self->maxs[2] += 32;
649 self->takedamage = DAMAGE_AIM;
650 gi.linkentity (self);
651 }
652
653 void soldier_fire3 (edict_t *self)
654 {
655 soldier_duck_down (self);
656 soldier_fire (self, 2);
657 }
658
659 void soldier_attack3_refire (edict_t *self)
660 {
661 if ((level.time + 0.4) < self->monsterinfo.pausetime)
662 self->monsterinfo.nextframe = FRAME_attak303;
663 }
664
665 mframe_t soldier_frames_attack3 [] =
666 {
667 ai_charge, 0, NULL,
668 ai_charge, 0, NULL,
669 ai_charge, 0, soldier_fire3,
670 ai_charge, 0, NULL,
671 ai_charge, 0, NULL,
672 ai_charge, 0, soldier_attack3_refire,
673 ai_charge, 0, soldier_duck_up,
674 ai_charge, 0, NULL,
675 ai_charge, 0, NULL
676 };
677 mmove_t soldier_move_attack3 = {FRAME_attak301, FRAME_attak309, soldier_frames_attack3, soldier_run};
678
679 // ATTACK4 (machinegun)
680
681 void soldier_fire4 (edict_t *self)
682 {
683 soldier_fire (self, 3);
684 //
685 // if (self->enemy->health <= 0)
686 // return;
687 //
688 // if ( ((skill->value == 3) && (random() < 0.5)) || (range(self, self->enemy) == RANGE_MELEE) )
689 // self->monsterinfo.nextframe = FRAME_attak402;
690 }
691
692 mframe_t soldier_frames_attack4 [] =
693 {
694 ai_charge, 0, NULL,
695 ai_charge, 0, NULL,
696 ai_charge, 0, soldier_fire4,
697 ai_charge, 0, NULL,
698 ai_charge, 0, NULL,
699 ai_charge, 0, NULL
700 };
701 mmove_t soldier_move_attack4 = {FRAME_attak401, FRAME_attak406, soldier_frames_attack4, soldier_run};
702
703 #if 0
704 // ATTACK5 (prone)
705
706 void soldier_fire5 (edict_t *self)
707 {
708 soldier_fire (self, 4);
709 }
710
711 void soldier_attack5_refire (edict_t *self)
712 {
713 if (self->enemy->health <= 0)
714 return;
715
716 if ( ((skill->value == 3) && (random() < 0.5)) || (range(self, self->enemy) == RANGE_MELEE) )
717 self->monsterinfo.nextframe = FRAME_attak505;
718 }
719
720 mframe_t soldier_frames_attack5 [] =
721 {
722 ai_charge, 8, NULL,
723 ai_charge, 8, NULL,
724 ai_charge, 0, NULL,
725 ai_charge, 0, NULL,
726 ai_charge, 0, soldier_fire5,
727 ai_charge, 0, NULL,
728 ai_charge, 0, NULL,
729 ai_charge, 0, soldier_attack5_refire
730 };
731 mmove_t soldier_move_attack5 = {FRAME_attak501, FRAME_attak508, soldier_frames_attack5, soldier_run}; 732 #endif
733
734 // ATTACK6 (run & shoot)
735
736 void soldier_fire8 (edict_t *self)
737 {
738 soldier_fire (self, 7);
739 }
740
741 void soldier_attack6_refire (edict_t *self)
742 {
743 if (self->enemy->health <= 0)
744 return;
745
746 if (range(self, self->enemy) < RANGE_MID)
747 return;
748
749 if (skill->value == 3)
750 self->monsterinfo.nextframe = FRAME_runs03;
751 }
752
753 mframe_t soldier_frames_attack6 [] =
754 {
755 ai_charge, 10, NULL,
756 ai_charge, 4, NULL,
757 ai_charge, 12, NULL,
758 ai_charge, 11, soldier_fire8,
759 ai_charge, 13, NULL,
760 ai_charge, 18, NULL,
761 ai_charge, 15, NULL,
762 ai_charge, 14, NULL,
763 ai_charge, 11, NULL,
764 ai_charge, 8, NULL,
765 ai_charge, 11, NULL,
766 ai_charge, 12, NULL,
767 ai_charge, 12, NULL,
768 ai_charge, 17, soldier_attack6_refire
769 };
770 mmove_t soldier_move_attack6 = {FRAME_runs01, FRAME_runs14, soldier_frames_attack6, soldier_run};
771
772 void soldier_attack(edict_t *self)
773 {
774 if (self->s.skinnum < 4)
775 {
776 if (random() < 0.5)
777 self->monsterinfo.currentmove = &soldier_move_attack1;
778 else
779 self->monsterinfo.currentmove = &soldier_move_attack2;
780 }
781 else
782 {
783 self->monsterinfo.currentmove = &soldier_move_attack4;
784 }
785 }
786
787
788 //
789 // SIGHT
790 //
791
792 void soldier_sight(edict_t *self, edict_t *other)
793 {
794 if (random() < 0.5)
795 gi.sound (self, CHAN_VOICE, sound_sight1, 1, ATTN_NORM, 0);
796 else
797 gi.sound (self, CHAN_VOICE, sound_sight2, 1, ATTN_NORM, 0);
798
799 if ((skill->value > 0) && (range(self, self->enemy) >= RANGE_MID))
800 {
801 if (random() > 0.5)
802 self->monsterinfo.currentmove = &soldier_move_attack6;
803 }
804 }
805
806 //
807 // DUCK
808 //
809
810 void soldier_duck_hold (edict_t *self)
811 {
812 if (level.time >= self->monsterinfo.pausetime)
813 self->monsterinfo.aiflags &= ~AI_HOLD_FRAME;
814 else
815 self->monsterinfo.aiflags |= AI_HOLD_FRAME;
816 }
817
818 mframe_t soldier_frames_duck [] =
819 {
820 ai_move, 5, soldier_duck_down,
821 ai_move, -1, soldier_duck_hold,
822 ai_move, 1, NULL,
823 ai_move, 0, soldier_duck_up,
824 ai_move, 5, NULL
825 };
826 mmove_t soldier_move_duck = {FRAME_duck01, FRAME_duck05, soldier_frames_duck, soldier_run};
827
828 void soldier_dodge (edict_t *self, edict_t *attacker, float eta)
829 {
830 float r;
831
832 r = random();
833 if (r > 0.25)
834 return;
835
836 if (!self->enemy)
837 self->enemy = attacker;
838
839 if (skill->value == 0)
840 {
841 self->monsterinfo.currentmove = &soldier_move_duck;
842 return;
843 }
844
845 self->monsterinfo.pausetime = level.time + eta + 0.3;
846 r = random();
847
848 if (skill->value == 1)
849 {
850 if (r > 0.33)
851 self->monsterinfo.currentmove = &soldier_move_duck;
852 else
853 self->monsterinfo.currentmove = &soldier_move_attack3;
854 return;
855 }
856
857 if (skill->value >= 2)
858 {
859 if (r > 0.66)
860 self->monsterinfo.currentmove = &soldier_move_duck;
861 else
862 self->monsterinfo.currentmove = &soldier_move_attack3;
863 return;
864 }
865
866 self->monsterinfo.currentmove = &soldier_move_attack3;
867 }
868
869
870 //
871 // DEATH
872 //
873
874 void soldier_fire6 (edict_t *self)
875 {
876 soldier_fire (self, 5);
877 }
878
879 void soldier_fire7 (edict_t *self)
880 {
881 soldier_fire (self, 6);
882 }
883
884 void soldier_dead (edict_t *self)
885 {
886 VectorSet (self->mins, -16, -16, -24);
887 VectorSet (self->maxs, 16, 16, -8);
888 self->movetype = MOVETYPE_TOSS;
889 self->svflags |= SVF_DEADMONSTER;
890 self->nextthink = 0;
891 gi.linkentity (self);
892 }
893
894 mframe_t soldier_frames_death1 [] =
895 {
896 ai_move, 0, NULL,
897 ai_move, -10, NULL,
898 ai_move, -10, NULL,
899 ai_move, -10, NULL,
900 ai_move, -5, NULL,
901 ai_move, 0, NULL,
902 ai_move, 0, NULL,
903 ai_move, 0, NULL,
904 ai_move, 0, NULL,
905 ai_move, 0, NULL,
906
907 ai_move, 0, NULL,
908 ai_move, 0, NULL,
909 ai_move, 0, NULL,
910 ai_move, 0, NULL,
911 ai_move, 0, NULL,
912 ai_move, 0, NULL,
913 ai_move, 0, NULL,
914 ai_move, 0, NULL,
915 ai_move, 0, NULL,
916 ai_move, 0, NULL,
917
918 ai_move, 0, NULL,
919 ai_move, 0, soldier_fire6,
920 ai_move, 0, NULL,
921 ai_move, 0, NULL,
922 ai_move, 0, soldier_fire7,
923 ai_move, 0, NULL,
924 ai_move, 0, NULL,
925 ai_move, 0, NULL,
926 ai_move, 0, NULL,
927 ai_move, 0, NULL,
928
929 ai_move, 0, NULL,
930 ai_move, 0, NULL,
931 ai_move, 0, NULL,
932 ai_move, 0, NULL,
933 ai_move, 0, NULL,
934 ai_move, 0, NULL
935 };
936 mmove_t soldier_move_death1 = {FRAME_death101, FRAME_death136, soldier_frames_death1, soldier_dead};
937
938 mframe_t soldier_frames_death2 [] =
939 {
940 ai_move, -5, NULL,
941 ai_move, -5, NULL,
942 ai_move, -5, NULL,
943 ai_move, 0, NULL,
944 ai_move, 0, NULL,
945 ai_move, 0, NULL,
946 ai_move, 0, NULL,
947 ai_move, 0, NULL,
948 ai_move, 0, NULL,
949 ai_move, 0, NULL,
950
951 ai_move, 0, NULL,
952 ai_move, 0, NULL,
953 ai_move, 0, NULL,
954 ai_move, 0, NULL,
955 ai_move, 0, NULL,
956 ai_move, 0, NULL,
957 ai_move, 0, NULL,
958 ai_move, 0, NULL,
959 ai_move, 0, NULL,
960 ai_move, 0, NULL,
961
962 ai_move, 0, NULL,
963 ai_move, 0, NULL,
964 ai_move, 0, NULL,
965 ai_move, 0, NULL,
966 ai_move, 0, NULL,
967 ai_move, 0, NULL,
968 ai_move, 0, NULL,
969 ai_move, 0, NULL,
970 ai_move, 0, NULL,
971 ai_move, 0, NULL,
972
973 ai_move, 0, NULL,
974 ai_move, 0, NULL,
975 ai_move, 0, NULL,
976 ai_move, 0, NULL,
977 ai_move, 0, NULL
978 };
979 mmove_t soldier_move_death2 = {FRAME_death201, FRAME_death235, soldier_frames_death2, soldier_dead};
980
981 mframe_t soldier_frames_death3 [] =
982 {
983 ai_move, -5, NULL,
984 ai_move, -5, NULL,
985 ai_move, -5, NULL,
986 ai_move, 0, NULL,
987 ai_move, 0, NULL,
988 ai_move, 0, NULL,
989 ai_move, 0, NULL,
990 ai_move, 0, NULL,
991 ai_move, 0, NULL,
992 ai_move, 0, NULL,
993
994 ai_move, 0, NULL,
995 ai_move, 0, NULL,
996 ai_move, 0, NULL,
997 ai_move, 0, NULL,
998 ai_move, 0, NULL,
999 ai_move, 0, NULL,
1000 ai_move, 0, NULL,
1001 ai_move, 0, NULL,
1002 ai_move, 0, NULL,
1003 ai_move, 0, NULL,
1004
1005 ai_move, 0, NULL,
1006 ai_move, 0, NULL,
1007 ai_move, 0, NULL,
1008 ai_move, 0, NULL,
1009 ai_move, 0, NULL,
1010 ai_move, 0, NULL,
1011 ai_move, 0, NULL,
1012 ai_move, 0, NULL,
1013 ai_move, 0, NULL,
1014 ai_move, 0, NULL,
1015
1016 ai_move, 0, NULL,
1017 ai_move, 0, NULL,
1018 ai_move, 0, NULL,
1019 ai_move, 0, NULL,
1020 ai_move, 0, NULL,
1021 ai_move, 0, NULL,
1022 ai_move, 0, NULL,
1023 ai_move, 0, NULL,
1024 ai_move, 0, NULL,
1025 ai_move, 0, NULL,
1026
1027 ai_move, 0, NULL,
1028 ai_move, 0, NULL,
1029 ai_move, 0, NULL,
1030 ai_move, 0, NULL,
1031 ai_move, 0, NULL,
1032 };
1033 mmove_t soldier_move_death3 = {FRAME_death301, FRAME_death345, soldier_frames_death3, soldier_dead};
1034
1035 mframe_t soldier_frames_death4 [] =
1036 {
1037 ai_move, 0, NULL,
1038 ai_move, 0, NULL,
1039 ai_move, 0, NULL,
1040 ai_move, 0, NULL,
1041 ai_move, 0, NULL,
1042 ai_move, 0, NULL,
1043 ai_move, 0, NULL,
1044 ai_move, 0, NULL,
1045 ai_move, 0, NULL,
1046 ai_move, 0, NULL,
1047
1048 ai_move, 0, NULL,
1049 ai_move, 0, NULL,
1050 ai_move, 0, NULL,
1051 ai_move, 0, NULL,
1052 ai_move, 0, NULL,
1053 ai_move, 0, NULL,
1054 ai_move, 0, NULL,
1055 ai_move, 0, NULL,
1056 ai_move, 0, NULL,
1057 ai_move, 0, NULL,
1058
1059 ai_move, 0, NULL,
1060 ai_move, 0, NULL,
1061 ai_move, 0, NULL,
1062 ai_move, 0, NULL,
1063 ai_move, 0, NULL,
1064 ai_move, 0, NULL,
1065 ai_move, 0, NULL,
1066 ai_move, 0, NULL,
1067 ai_move, 0, NULL,
1068 ai_move, 0, NULL,
1069
1070 ai_move, 0, NULL,
1071 ai_move, 0, NULL,
1072 ai_move, 0, NULL,
1073 ai_move, 0, NULL,
1074 ai_move, 0, NULL,
1075 ai_move, 0, NULL,
1076 ai_move, 0, NULL,
1077 ai_move, 0, NULL,
1078 ai_move, 0, NULL,
1079 ai_move, 0, NULL,
1080
1081 ai_move, 0, NULL,
1082 ai_move, 0, NULL,
1083 ai_move, 0, NULL,
1084 ai_move, 0, NULL,
1085 ai_move, 0, NULL,
1086 ai_move, 0, NULL,
1087 ai_move, 0, NULL,
1088 ai_move, 0, NULL,
1089 ai_move, 0, NULL,
1090 ai_move, 0, NULL,
1091
1092 ai_move, 0, NULL,
1093 ai_move, 0, NULL,
1094 ai_move, 0, NULL
1095 };
1096 mmove_t soldier_move_death4 = {FRAME_death401, FRAME_death453, soldier_frames_death4, soldier_dead};
1097
1098 mframe_t soldier_frames_death5 [] =
1099 {
1100 ai_move, -5, NULL,
1101 ai_move, -5, NULL,
1102 ai_move, -5, NULL,
1103 ai_move, 0, NULL,
1104 ai_move, 0, NULL,
1105 ai_move, 0, NULL,
1106 ai_move, 0, NULL,
1107 ai_move, 0, NULL,
1108 ai_move, 0, NULL,
1109 ai_move, 0, NULL,
1110
1111 ai_move, 0, NULL,
1112 ai_move, 0, NULL,
1113 ai_move, 0, NULL,
1114 ai_move, 0, NULL,
1115 ai_move, 0, NULL,
1116 ai_move, 0, NULL,
1117 ai_move, 0, NULL,
1118 ai_move, 0, NULL,
1119 ai_move, 0, NULL,
1120 ai_move, 0, NULL,
1121
1122 ai_move, 0, NULL,
1123 ai_move, 0, NULL,
1124 ai_move, 0, NULL,
1125 ai_move, 0, NULL
1126 };
1127 mmove_t soldier_move_death5 = {FRAME_death501, FRAME_death524, soldier_frames_death5, soldier_dead};
1128
1129 mframe_t soldier_frames_death6 [] =
1130 {
1131 ai_move, 0, NULL,
1132 ai_move, 0, NULL,
1133 ai_move, 0, NULL,
1134 ai_move, 0, NULL,
1135 ai_move, 0, NULL,
1136 ai_move, 0, NULL,
1137 ai_move, 0, NULL,
1138 ai_move, 0, NULL,
1139 ai_move, 0, NULL,
1140 ai_move, 0, NULL
1141 };
1142 mmove_t soldier_move_death6 = {FRAME_death601, FRAME_death610, soldier_frames_death6, soldier_dead};
1143
1144 void soldier_die (edict_t *self, edict_t *inflictor, edict_t *attacker, int damage, vec3_t point)
1145 {
1146 int n;
1147
1148 // check for gib
1149 if (self->health <= self->gib_health)
1150 {
1151 gi.sound (self, CHAN_VOICE, gi.soundindex ("misc/udeath.wav"), 1, ATTN_NORM, 0);
1152 for (n= 0; n < 3; n++)
1153 ThrowGib (self, "models/objects/gibs/sm_meat/tris.md2", damage, GIB_ORGANIC);
1154 ThrowGib (self, "models/objects/gibs/chest/tris.md2", damage, GIB_ORGANIC);
1155 ThrowHead (self, "models/objects/gibs/head2/tris.md2", damage, GIB_ORGANIC);
1156 self->deadflag = DEAD_DEAD;
1157 return;
1158 }
1159
1160 if (self->deadflag == DEAD_DEAD)
1161 return;
1162
1163 // regular death
1164 self->deadflag = DEAD_DEAD;
1165 self->takedamage = DAMAGE_YES;
1166 self->s.skinnum |= 1;
1167
1168 if (self->s.skinnum == 1)
1169 gi.sound (self, CHAN_VOICE, sound_death_light, 1, ATTN_NORM, 0);
1170 else if (self->s.skinnum == 3)
1171 gi.sound (self, CHAN_VOICE, sound_death, 1, ATTN_NORM, 0);
1172 else // (self->s.skinnum == 5)
1173 gi.sound (self, CHAN_VOICE, sound_death_ss, 1, ATTN_NORM, 0);
1174
1175 if (fabs((self->s.origin[2] + self->viewheight) - point[2]) <= 4)
1176 {
1177 // head shot
1178 self->monsterinfo.currentmove = &soldier_move_death3;
1179 return;
1180 }
1181
1182 n = rand() % 5;
1183 if (n == 0)
1184 self->monsterinfo.currentmove = &soldier_move_death1;
1185 else if (n == 1)
1186 self->monsterinfo.currentmove = &soldier_move_death2;
1187 else if (n == 2)
1188 self->monsterinfo.currentmove = &soldier_move_death4;
1189 else if (n == 3)
1190 self->monsterinfo.currentmove = &soldier_move_death5;
1191 else
1192 self->monsterinfo.currentmove = &soldier_move_death6;
1193 }
1194
1195
1196 //
1197 // SPAWN
1198 //
1199
1200 void SP_monster_soldier_x (edict_t *self)
1201 {
1202
1203 self->s.modelindex = gi.modelindex ("models/monsters/soldier/tris.md2");
1204 self->monsterinfo.scale = MODEL_SCALE;
1205 VectorSet (self->mins, -16, -16, -24);
1206 VectorSet (self->maxs, 16, 16, 32);
1207 self->movetype = MOVETYPE_STEP;
1208 self->solid = SOLID_BBOX;
1209
1210 sound_idle = gi.soundindex ("soldier/solidle1.wav");
1211 sound_sight1 = gi.soundindex ("soldier/solsght1.wav");
1212 sound_sight2 = gi.soundindex ("soldier/solsrch1.wav");
1213 sound_cock = gi.soundindex ("infantry/infatck3.wav");
1214
1215 self->mass = 100;
1216
1217 self->pain = soldier_pain;
1218 self->die = soldier_die;
1219
1220 self->monsterinfo.stand = soldier_stand;
1221 self->monsterinfo.walk = soldier_walk;
1222 self->monsterinfo.run = soldier_run;
1223 self->monsterinfo.dodge = soldier_dodge;
1224 self->monsterinfo.attack = soldier_attack;
1225 self->monsterinfo.melee = NULL;
1226 self->monsterinfo.sight = soldier_sight;
1227
1228 gi.linkentity (self);
1229
1230 self->monsterinfo.stand (self);
1231
1232 walkmonster_start (self);
1233 }
1234
1235
1236 /*QUAKED monster_soldier_light (1 .5 0) (-16 -16 -24) (16 16 32) Ambush Trigger_Spawn Sight
1237 */
1238 void SP_monster_soldier_light (edict_t *self)
1239 {
1240 if (deathmatch->value)
1241 {
1242 G_FreeEdict (self);
1243 return;
1244 }
1245
1246 SP_monster_soldier_x (self);
1247
1248 sound_pain_light = gi.soundindex ("soldier/solpain2.wav");
1249 sound_death_light = gi.soundindex ("soldier/soldeth2.wav");
1250 gi.modelindex ("models/objects/laser/tris.md2");
1251 gi.soundindex ("misc/lasfly.wav");
1252 gi.soundindex ("soldier/solatck2.wav");
1253
1254 self->s.skinnum = 0;
1255 self->health = 20;
1256 self->gib_health = -30;
1257 }
1258
1259 /*QUAKED monster_soldier (1 .5 0) (-16 -16 -24) (16 16 32) Ambush Trigger_Spawn Sight
1260 */
1261 void SP_monster_soldier (edict_t *self)
1262 {
1263 if (deathmatch->value)
1264 {
1265 G_FreeEdict (self);
1266 return;
1267 }
1268
1269 SP_monster_soldier_x (self);
1270
1271 sound_pain = gi.soundindex ("soldier/solpain1.wav");
1272 sound_death = gi.soundindex ("soldier/soldeth1.wav");
1273 gi.soundindex ("soldier/solatck1.wav");
1274
1275 self->s.skinnum = 2;
1276 self->health = 30;
1277 self->gib_health = -30;
1278 }
1279
1280 /*QUAKED monster_soldier_ss (1 .5 0) (-16 -16 -24) (16 16 32) Ambush Trigger_Spawn Sight
1281 */
1282 void SP_monster_soldier_ss (edict_t *self)
1283 {
1284 if (deathmatch->value)
1285 {
1286 G_FreeEdict (self);
1287 return;
1288 }
1289
1290 SP_monster_soldier_x (self);
1291
1292 sound_pain_ss = gi.soundindex ("soldier/solpain3.wav");
1293 sound_death_ss = gi.soundindex ("soldier/soldeth3.wav");
1294 gi.soundindex ("soldier/solatck3.wav");
1295
1296 self->s.skinnum = 4;
1297 self->health = 40;
1298 self->gib_health = -30;
1299 }
1300