1 /*
2 ==============================================================================
3
4 SOLDIER
5
6 ==============================================================================
7 */
8
9 #include "g_local.h"
10 #include "m_soldier.h"
11
12
13 static int sound_idle;
14 static int sound_sight1;
15 static int sound_sight2;
16 static int sound_pain_light;
17 static int sound_pain;
18 static int sound_pain_ss;
19 static int sound_death_light;
20 static int sound_death;
21 static int sound_death_ss;
22 static int sound_cock;
23
24 #define BLASTER_DISTANCE 300
25
soldier_idle(edict_t * self)26 void soldier_idle (edict_t *self)
27 {
28 if (random() > 0.8)
29 gi.sound (self, CHAN_VOICE, sound_idle, 1, ATTN_IDLE, 0);
30 }
31
soldier_cock(edict_t * self)32 void soldier_cock (edict_t *self)
33 {
34 if (self->s.frame == FRAME_stand322)
35 gi.sound (self, CHAN_WEAPON, sound_cock, 1, ATTN_IDLE, 0);
36 else
37 gi.sound (self, CHAN_WEAPON, sound_cock, 1, ATTN_NORM, 0);
38 }
39
40
41 // STAND
42
43 void soldier_stand (edict_t *self);
44
45 mframe_t soldier_frames_stand1 [] =
46 {
47 ai_stand, 0, soldier_idle,
48 ai_stand, 0, NULL,
49 ai_stand, 0, NULL,
50 ai_stand, 0, NULL,
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
58 ai_stand, 0, NULL,
59 ai_stand, 0, NULL,
60 ai_stand, 0, NULL,
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
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 ai_stand, 0, NULL,
76 ai_stand, 0, NULL,
77 ai_stand, 0, NULL,
78 ai_stand, 0, NULL
79 };
80 mmove_t soldier_move_stand1 = {FRAME_stand101, FRAME_stand130, soldier_frames_stand1, soldier_stand};
81
82 mframe_t soldier_frames_stand3 [] =
83 {
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 ai_stand, 0, NULL,
94
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 ai_stand, 0, NULL,
105
106 ai_stand, 0, NULL,
107 ai_stand, 0, soldier_cock,
108 ai_stand, 0, NULL,
109 ai_stand, 0, NULL,
110 ai_stand, 0, NULL,
111 ai_stand, 0, NULL,
112 ai_stand, 0, NULL,
113 ai_stand, 0, NULL,
114 ai_stand, 0, NULL,
115 ai_stand, 0, NULL,
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 };
127 mmove_t soldier_move_stand3 = {FRAME_stand301, FRAME_stand339, soldier_frames_stand3, soldier_stand};
128
129 #if 0
130 mframe_t soldier_frames_stand4 [] =
131 {
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, NULL,
138 ai_stand, 0, NULL,
139 ai_stand, 0, NULL,
140 ai_stand, 0, NULL,
141 ai_stand, 0, NULL,
142
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, NULL,
149 ai_stand, 0, NULL,
150 ai_stand, 0, NULL,
151 ai_stand, 0, NULL,
152 ai_stand, 0, NULL,
153
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 ai_stand, 0, NULL,
161 ai_stand, 0, NULL,
162 ai_stand, 0, NULL,
163 ai_stand, 0, NULL,
164
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 ai_stand, 0, NULL,
172 ai_stand, 0, NULL,
173 ai_stand, 0, NULL,
174 ai_stand, 0, NULL,
175
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 ai_stand, 4, NULL,
183 ai_stand, 1, NULL,
184 ai_stand, -1, NULL,
185 ai_stand, -2, NULL,
186
187 ai_stand, 0, NULL,
188 ai_stand, 0, NULL
189 };
190 mmove_t soldier_move_stand4 = {FRAME_stand401, FRAME_stand452, soldier_frames_stand4, NULL};
191 #endif
192
soldier_stand(edict_t * self)193 void soldier_stand (edict_t *self)
194 {
195 if ((self->monsterinfo.currentmove == &soldier_move_stand3) || (random() < 0.8))
196 self->monsterinfo.currentmove = &soldier_move_stand1;
197 else
198 self->monsterinfo.currentmove = &soldier_move_stand3;
199 }
200
201
202 //
203 // WALK
204 //
205
soldier_walk1_random(edict_t * self)206 void soldier_walk1_random (edict_t *self)
207 {
208 if (random() > 0.1)
209 self->monsterinfo.nextframe = FRAME_walk101;
210 }
211
212 mframe_t soldier_frames_walk1 [] =
213 {
214 ai_walk, 3, NULL,
215 ai_walk, 6, NULL,
216 ai_walk, 2, NULL,
217 ai_walk, 2, NULL,
218 ai_walk, 2, NULL,
219 ai_walk, 1, NULL,
220 ai_walk, 6, NULL,
221 ai_walk, 5, NULL,
222 ai_walk, 3, NULL,
223 ai_walk, -1, soldier_walk1_random,
224 ai_walk, 0, NULL,
225 ai_walk, 0, NULL,
226 ai_walk, 0, NULL,
227 ai_walk, 0, NULL,
228 ai_walk, 0, NULL,
229 ai_walk, 0, NULL,
230 ai_walk, 0, NULL,
231 ai_walk, 0, NULL,
232 ai_walk, 0, NULL,
233 ai_walk, 0, NULL,
234 ai_walk, 0, NULL,
235 ai_walk, 0, NULL,
236 ai_walk, 0, NULL,
237 ai_walk, 0, NULL,
238 ai_walk, 0, NULL,
239 ai_walk, 0, NULL,
240 ai_walk, 0, NULL,
241 ai_walk, 0, NULL,
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 };
248 mmove_t soldier_move_walk1 = {FRAME_walk101, FRAME_walk133, soldier_frames_walk1, NULL};
249
250 mframe_t soldier_frames_walk2 [] =
251 {
252 ai_walk, 4, NULL,
253 ai_walk, 4, NULL,
254 ai_walk, 9, NULL,
255 ai_walk, 8, NULL,
256 ai_walk, 5, NULL,
257 ai_walk, 1, NULL,
258 ai_walk, 3, NULL,
259 ai_walk, 7, NULL,
260 ai_walk, 6, NULL,
261 ai_walk, 7, NULL
262 };
263 mmove_t soldier_move_walk2 = {FRAME_walk209, FRAME_walk218, soldier_frames_walk2, NULL};
264
soldier_walk(edict_t * self)265 void soldier_walk (edict_t *self)
266 {
267 if (random() < 0.5)
268 self->monsterinfo.currentmove = &soldier_move_walk1;
269 else
270 self->monsterinfo.currentmove = &soldier_move_walk2;
271 }
272
273
274 //
275 // RUN
276 //
277
278 void soldier_run (edict_t *self);
279
280 mframe_t soldier_frames_start_run [] =
281 {
282 ai_run, 7, NULL,
283 ai_run, 5, NULL
284 };
285 mmove_t soldier_move_start_run = {FRAME_run01, FRAME_run02, soldier_frames_start_run, soldier_run};
286
287 mframe_t soldier_frames_run [] =
288 {
289 ai_run, 10, NULL,
290 ai_run, 11, NULL,
291 ai_run, 11, NULL,
292 ai_run, 16, NULL,
293 ai_run, 10, NULL,
294 ai_run, 15, NULL
295 };
296 mmove_t soldier_move_run = {FRAME_run03, FRAME_run08, soldier_frames_run, NULL};
297
soldier_run(edict_t * self)298 void soldier_run (edict_t *self)
299 {
300 if (self->monsterinfo.aiflags & AI_STAND_GROUND)
301 {
302 self->monsterinfo.currentmove = &soldier_move_stand1;
303 return;
304 }
305
306 if (self->monsterinfo.currentmove == &soldier_move_walk1 ||
307 self->monsterinfo.currentmove == &soldier_move_walk2 ||
308 self->monsterinfo.currentmove == &soldier_move_start_run)
309 {
310 self->monsterinfo.currentmove = &soldier_move_run;
311 }
312 else
313 {
314 self->monsterinfo.currentmove = &soldier_move_start_run;
315 }
316 }
317
318
319 //
320 // PAIN
321 //
322
323 mframe_t soldier_frames_pain1 [] =
324 {
325 ai_move, -3, NULL,
326 ai_move, 4, NULL,
327 ai_move, 1, NULL,
328 ai_move, 1, NULL,
329 ai_move, 0, NULL
330 };
331 mmove_t soldier_move_pain1 = {FRAME_pain101, FRAME_pain105, soldier_frames_pain1, soldier_run};
332
333 mframe_t soldier_frames_pain2 [] =
334 {
335 ai_move, -13, NULL,
336 ai_move, -1, NULL,
337 ai_move, 2, NULL,
338 ai_move, 4, NULL,
339 ai_move, 2, NULL,
340 ai_move, 3, NULL,
341 ai_move, 2, NULL
342 };
343 mmove_t soldier_move_pain2 = {FRAME_pain201, FRAME_pain207, soldier_frames_pain2, soldier_run};
344
345 mframe_t soldier_frames_pain3 [] =
346 {
347 ai_move, -8, NULL,
348 ai_move, 10, NULL,
349 ai_move, -4, NULL,
350 ai_move, -1, NULL,
351 ai_move, -3, NULL,
352 ai_move, 0, NULL,
353 ai_move, 3, NULL,
354 ai_move, 0, NULL,
355 ai_move, 0, NULL,
356 ai_move, 0, NULL,
357 ai_move, 0, NULL,
358 ai_move, 1, NULL,
359 ai_move, 0, NULL,
360 ai_move, 1, NULL,
361 ai_move, 2, NULL,
362 ai_move, 4, NULL,
363 ai_move, 3, NULL,
364 ai_move, 2, NULL
365 };
366 mmove_t soldier_move_pain3 = {FRAME_pain301, FRAME_pain318, soldier_frames_pain3, soldier_run};
367
368 mframe_t soldier_frames_pain4 [] =
369 {
370 ai_move, 0, NULL,
371 ai_move, 0, NULL,
372 ai_move, 0, NULL,
373 ai_move, -10, NULL,
374 ai_move, -6, NULL,
375 ai_move, 8, NULL,
376 ai_move, 4, NULL,
377 ai_move, 1, NULL,
378 ai_move, 0, NULL,
379 ai_move, 2, NULL,
380 ai_move, 5, NULL,
381 ai_move, 2, NULL,
382 ai_move, -1, NULL,
383 ai_move, -1, NULL,
384 ai_move, 3, NULL,
385 ai_move, 2, NULL,
386 ai_move, 0, NULL
387 };
388 mmove_t soldier_move_pain4 = {FRAME_pain401, FRAME_pain417, soldier_frames_pain4, soldier_run};
389
390
soldier_pain(edict_t * self,edict_t * other,float kick,int damage)391 void soldier_pain (edict_t *self, edict_t *other, float kick, int damage)
392 {
393 float r;
394 int n;
395
396 if (self->health < (self->max_health / 2))
397 self->s.skinnum |= 1;
398
399 if (level.time < self->pain_debounce_time)
400 {
401 if ((self->velocity[2] > 100) && ( (self->monsterinfo.currentmove == &soldier_move_pain1) || (self->monsterinfo.currentmove == &soldier_move_pain2) || (self->monsterinfo.currentmove == &soldier_move_pain3)))
402 self->monsterinfo.currentmove = &soldier_move_pain4;
403 return;
404 }
405
406 self->pain_debounce_time = level.time + 3;
407
408 n = self->s.skinnum | 1;
409 if (n == 1)
410 gi.sound (self, CHAN_VOICE, sound_pain_light, 1, ATTN_NORM, 0);
411 else if (n == 3)
412 gi.sound (self, CHAN_VOICE, sound_pain, 1, ATTN_NORM, 0);
413 else
414 gi.sound (self, CHAN_VOICE, sound_pain_ss, 1, ATTN_NORM, 0);
415
416 if (self->velocity[2] > 100)
417 {
418 self->monsterinfo.currentmove = &soldier_move_pain4;
419 return;
420 }
421
422 if (skill->value == 3)
423 return; // no pain anims in nightmare
424
425 r = random();
426
427 if (r < 0.33)
428 self->monsterinfo.currentmove = &soldier_move_pain1;
429 else if (r < 0.66)
430 self->monsterinfo.currentmove = &soldier_move_pain2;
431 else
432 self->monsterinfo.currentmove = &soldier_move_pain3;
433 }
434
435
436 //
437 // ATTACK
438 //
439
440 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};
441 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};
442 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};
443
soldier_fire(edict_t * self,int flash_number)444 void soldier_fire (edict_t *self, int flash_number)
445 {
446 vec3_t start;
447 vec3_t forward, right, up;
448 vec3_t aim;
449 vec3_t dir;
450 vec3_t end;
451 float r, u;
452 int flash_index, distance;
453
454 if (self->s.skinnum < 2)
455 flash_index = blaster_flash[flash_number];
456 else if (self->s.skinnum < 4)
457 flash_index = shotgun_flash[flash_number];
458 else
459 flash_index = machinegun_flash[flash_number];
460
461 AngleVectors (self->s.angles, forward, right, NULL);
462 G_ProjectSource (self->s.origin, monster_flash_offset[flash_index], forward, right, start);
463
464 VectorSubtract(self->s.origin, self->enemy->s.origin, aim);
465 distance = VectorLength(aim);
466
467 if (flash_number == 5 || flash_number == 6)
468 {
469 VectorCopy (forward, aim);
470 }
471 else
472 {
473 VectorCopy (self->enemy->s.origin, end);
474 end[2] += self->enemy->viewheight;
475 VectorSubtract (end, start, aim);
476 vectoangles (aim, dir);
477 AngleVectors (dir, forward, right, up);
478
479 r = crandom()*1000;
480 u = crandom()*500;
481 VectorMA (start, 8192, forward, end);
482 VectorMA (end, r, right, end);
483 VectorMA (end, u, up, end);
484
485 VectorSubtract (end, start, aim);
486 VectorNormalize (aim);
487 }
488
489 if (self->s.skinnum <= 1)
490 {
491 if (distance>BLASTER_DISTANCE || true)
492 {
493 monster_fire_blaster (self, start, aim, 75, 600, flash_index, (sv_serversideonly->value)?EF_BLASTER:0);
494 }
495 else
496 {
497 aim[2]+=.1;
498 monster_fire_plasma (self, start, aim, 1, 800, EF_BLASTER);
499 }
500
501 }
502 else if (self->s.skinnum <= 3)
503 {
504 monster_fire_shotgun (self, start, aim, 9, 1, DEFAULT_SHOTGUN_HSPREAD, DEFAULT_SHOTGUN_VSPREAD, DEFAULT_SHOTGUN_COUNT, flash_index);
505 }
506 else
507 {
508 if (!(self->monsterinfo.aiflags & AI_HOLD_FRAME))
509 self->monsterinfo.pausetime = level.time + (3 + rand() % 8) * FRAMETIME;
510
511 monster_fire_bullet (self, start, aim, 20, 4, DEFAULT_BULLET_HSPREAD, DEFAULT_BULLET_VSPREAD, flash_index);
512
513 if (level.time >= self->monsterinfo.pausetime)
514 self->monsterinfo.aiflags &= ~AI_HOLD_FRAME;
515 else
516 self->monsterinfo.aiflags |= AI_HOLD_FRAME;
517 }
518 }
519
520 // ATTACK1 (blaster/shotgun)
521
soldier_fire1(edict_t * self)522 void soldier_fire1 (edict_t *self)
523 {
524 soldier_fire (self, 0);
525 }
526
soldier_attack1_refire1(edict_t * self)527 void soldier_attack1_refire1 (edict_t *self)
528 {
529 if (self->s.skinnum > 1)
530 return;
531
532 if (self->enemy->health <= 0)
533 return;
534
535 if ( ((skill->value == 3) && (random() < 0.5)) || (range(self, self->enemy) == RANGE_MELEE) )
536 self->monsterinfo.nextframe = FRAME_attak102;
537 else
538 self->monsterinfo.nextframe = FRAME_attak110;
539 }
540
soldier_attack1_refire2(edict_t * self)541 void soldier_attack1_refire2 (edict_t *self)
542 {
543 if (self->s.skinnum < 2)
544 return;
545
546 if (self->enemy->health <= 0)
547 return;
548
549 if ( ((skill->value == 3) && (random() < 0.5)) || (range(self, self->enemy) == RANGE_MELEE) )
550 self->monsterinfo.nextframe = FRAME_attak102;
551 }
552
553 mframe_t soldier_frames_attack1 [] =
554 {
555 ai_charge, 0, NULL,
556 ai_charge, 0, NULL,
557 ai_charge, 0, soldier_fire1,
558 ai_charge, 0, NULL,
559 ai_charge, 0, NULL,
560 ai_charge, 0, soldier_attack1_refire1,
561 ai_charge, 0, NULL,
562 ai_charge, 0, soldier_cock,
563 ai_charge, 0, soldier_attack1_refire2,
564 ai_charge, 0, NULL,
565 ai_charge, 0, NULL,
566 ai_charge, 0, NULL
567 };
568 mmove_t soldier_move_attack1 = {FRAME_attak101, FRAME_attak112, soldier_frames_attack1, soldier_run};
569
570 // ATTACK2 (blaster/shotgun)
571
soldier_fire2(edict_t * self)572 void soldier_fire2 (edict_t *self)
573 {
574 soldier_fire (self, 1);
575 }
576
soldier_attack2_refire1(edict_t * self)577 void soldier_attack2_refire1 (edict_t *self)
578 {
579 if (self->s.skinnum > 1)
580 return;
581
582 if (self->enemy->health <= 0)
583 return;
584
585 if ( ((skill->value == 3) && (random() < 0.5)) || (range(self, self->enemy) == RANGE_MELEE) )
586 self->monsterinfo.nextframe = FRAME_attak204;
587 else
588 self->monsterinfo.nextframe = FRAME_attak216;
589 }
590
soldier_attack2_refire2(edict_t * self)591 void soldier_attack2_refire2 (edict_t *self)
592 {
593 if (self->s.skinnum < 2)
594 return;
595
596 if (self->enemy->health <= 0)
597 return;
598
599 if ( ((skill->value == 3) && (random() < 0.5)) || (range(self, self->enemy) == RANGE_MELEE) )
600 self->monsterinfo.nextframe = FRAME_attak204;
601 }
602
603 mframe_t soldier_frames_attack2 [] =
604 {
605 ai_charge, 0, NULL,
606 ai_charge, 0, NULL,
607 ai_charge, 0, NULL,
608 ai_charge, 0, NULL,
609 ai_charge, 0, soldier_fire2,
610 ai_charge, 0, NULL,
611 ai_charge, 0, NULL,
612 ai_charge, 0, soldier_attack2_refire1,
613 ai_charge, 0, NULL,
614 ai_charge, 0, NULL,
615 ai_charge, 0, NULL,
616 ai_charge, 0, NULL,
617 ai_charge, 0, soldier_cock,
618 ai_charge, 0, NULL,
619 ai_charge, 0, soldier_attack2_refire2,
620 ai_charge, 0, NULL,
621 ai_charge, 0, NULL,
622 ai_charge, 0, NULL
623 };
624 mmove_t soldier_move_attack2 = {FRAME_attak201, FRAME_attak218, soldier_frames_attack2, soldier_run};
625
626 // ATTACK3 (duck and shoot)
627
soldier_duck_down(edict_t * self)628 void soldier_duck_down (edict_t *self)
629 {
630 if (self->monsterinfo.aiflags & AI_DUCKED)
631 return;
632 self->monsterinfo.aiflags |= AI_DUCKED;
633 self->maxs[2] -= 32;
634 self->takedamage = DAMAGE_YES;
635 self->monsterinfo.pausetime = level.time + 1;
636 gi.linkentity (self);
637 }
638
soldier_duck_up(edict_t * self)639 void soldier_duck_up (edict_t *self)
640 {
641 self->monsterinfo.aiflags &= ~AI_DUCKED;
642 self->maxs[2] += 32;
643 self->takedamage = DAMAGE_AIM;
644 gi.linkentity (self);
645 }
646
soldier_fire3(edict_t * self)647 void soldier_fire3 (edict_t *self)
648 {
649 soldier_duck_down (self);
650 soldier_fire (self, 2);
651 }
652
soldier_attack3_refire(edict_t * self)653 void soldier_attack3_refire (edict_t *self)
654 {
655 if ((level.time + 0.4) < self->monsterinfo.pausetime)
656 self->monsterinfo.nextframe = FRAME_attak303;
657 }
658
659 mframe_t soldier_frames_attack3 [] =
660 {
661 ai_charge, 0, NULL,
662 ai_charge, 0, NULL,
663 ai_charge, 0, soldier_fire3,
664 ai_charge, 0, NULL,
665 ai_charge, 0, NULL,
666 ai_charge, 0, soldier_attack3_refire,
667 ai_charge, 0, soldier_duck_up,
668 ai_charge, 0, NULL,
669 ai_charge, 0, NULL
670 };
671 mmove_t soldier_move_attack3 = {FRAME_attak301, FRAME_attak309, soldier_frames_attack3, soldier_run};
672
673 // ATTACK4 (machinegun)
674
soldier_fire4(edict_t * self)675 void soldier_fire4 (edict_t *self)
676 {
677 soldier_fire (self, 3);
678 //
679 // if (self->enemy->health <= 0)
680 // return;
681 //
682 // if ( ((skill->value == 3) && (random() < 0.5)) || (range(self, self->enemy) == RANGE_MELEE) )
683 // self->monsterinfo.nextframe = FRAME_attak402;
684 }
685
686 mframe_t soldier_frames_attack4 [] =
687 {
688 ai_charge, 0, NULL,
689 ai_charge, 0, NULL,
690 ai_charge, 0, soldier_fire4,
691 ai_charge, 0, NULL,
692 ai_charge, 0, NULL,
693 ai_charge, 0, NULL
694 };
695 mmove_t soldier_move_attack4 = {FRAME_attak401, FRAME_attak406, soldier_frames_attack4, soldier_run};
696
697 #if 0
698 // ATTACK5 (prone)
699
700 void soldier_fire5 (edict_t *self)
701 {
702 soldier_fire (self, 4);
703 }
704
705 void soldier_attack5_refire (edict_t *self)
706 {
707 if (self->enemy->health <= 0)
708 return;
709
710 if ( ((skill->value == 3) && (random() < 0.5)) || (range(self, self->enemy) == RANGE_MELEE) )
711 self->monsterinfo.nextframe = FRAME_attak505;
712 }
713
714 mframe_t soldier_frames_attack5 [] =
715 {
716 ai_charge, 8, NULL,
717 ai_charge, 8, NULL,
718 ai_charge, 0, NULL,
719 ai_charge, 0, NULL,
720 ai_charge, 0, soldier_fire5,
721 ai_charge, 0, NULL,
722 ai_charge, 0, NULL,
723 ai_charge, 0, soldier_attack5_refire
724 };
725 mmove_t soldier_move_attack5 = {FRAME_attak501, FRAME_attak508, soldier_frames_attack5, soldier_run};
726 #endif
727
728 // ATTACK6 (run & shoot)
729
soldier_fire8(edict_t * self)730 void soldier_fire8 (edict_t *self)
731 {
732 soldier_fire (self, 7);
733 }
734
soldier_attack6_refire(edict_t * self)735 void soldier_attack6_refire (edict_t *self)
736 {
737 if (self->enemy->health <= 0)
738 return;
739
740 if (range(self, self->enemy) < RANGE_MID)
741 return;
742
743 if (skill->value == 3)
744 self->monsterinfo.nextframe = FRAME_runs03;
745 }
746
747 mframe_t soldier_frames_attack6 [] =
748 {
749 ai_charge, 10, NULL,
750 ai_charge, 4, NULL,
751 ai_charge, 12, NULL,
752 ai_charge, 11, soldier_fire8,
753 ai_charge, 13, NULL,
754 ai_charge, 18, NULL,
755 ai_charge, 15, NULL,
756 ai_charge, 14, NULL,
757 ai_charge, 11, NULL,
758 ai_charge, 8, NULL,
759 ai_charge, 11, NULL,
760 ai_charge, 12, NULL,
761 ai_charge, 12, NULL,
762 ai_charge, 17, soldier_attack6_refire
763 };
764 mmove_t soldier_move_attack6 = {FRAME_runs01, FRAME_runs14, soldier_frames_attack6, soldier_run};
765
soldier_attack(edict_t * self)766 void soldier_attack(edict_t *self)
767 {
768 if (self->s.skinnum < 4)
769 {
770 if (random() < 0.5)
771 self->monsterinfo.currentmove = &soldier_move_attack1;
772 else
773 self->monsterinfo.currentmove = &soldier_move_attack2;
774 }
775 else
776 {
777 self->monsterinfo.currentmove = &soldier_move_attack4;
778 }
779 }
780
781
782 //
783 // SIGHT
784 //
785
soldier_sight(edict_t * self,edict_t * other)786 void soldier_sight(edict_t *self, edict_t *other)
787 {
788 if (random() < 0.5)
789 gi.sound (self, CHAN_VOICE, sound_sight1, 1, ATTN_NORM, 0);
790 else
791 gi.sound (self, CHAN_VOICE, sound_sight2, 1, ATTN_NORM, 0);
792
793 if ((skill->value > 0) && (range(self, self->enemy) >= RANGE_MID))
794 {
795 if (random() > 0.5)
796 self->monsterinfo.currentmove = &soldier_move_attack6;
797 }
798 }
799
800 //
801 // DUCK
802 //
803
soldier_duck_hold(edict_t * self)804 void soldier_duck_hold (edict_t *self)
805 {
806 if (level.time >= self->monsterinfo.pausetime)
807 self->monsterinfo.aiflags &= ~AI_HOLD_FRAME;
808 else
809 self->monsterinfo.aiflags |= AI_HOLD_FRAME;
810 }
811
812 mframe_t soldier_frames_duck [] =
813 {
814 ai_move, 5, soldier_duck_down,
815 ai_move, -1, soldier_duck_hold,
816 ai_move, 1, NULL,
817 ai_move, 0, soldier_duck_up,
818 ai_move, 5, NULL
819 };
820 mmove_t soldier_move_duck = {FRAME_duck01, FRAME_duck05, soldier_frames_duck, soldier_run};
821
soldier_dodge(edict_t * self,edict_t * attacker,float eta)822 void soldier_dodge (edict_t *self, edict_t *attacker, float eta)
823 {
824 float r;
825
826 r = random();
827 if (r > 0.25)
828 return;
829
830 if (!self->enemy)
831 self->enemy = attacker;
832
833 if (skill->value == 0)
834 {
835 self->monsterinfo.currentmove = &soldier_move_duck;
836 return;
837 }
838
839 self->monsterinfo.pausetime = level.time + eta + 0.3;
840 r = random();
841
842 if (skill->value == 1)
843 {
844 if (r > 0.33)
845 self->monsterinfo.currentmove = &soldier_move_duck;
846 else
847 self->monsterinfo.currentmove = &soldier_move_attack3;
848 return;
849 }
850
851 if (skill->value >= 2)
852 {
853 if (r > 0.66)
854 self->monsterinfo.currentmove = &soldier_move_duck;
855 else
856 self->monsterinfo.currentmove = &soldier_move_attack3;
857 return;
858 }
859
860 self->monsterinfo.currentmove = &soldier_move_attack3;
861 }
862
863
864 //
865 // DEATH
866 //
867
soldier_fire6(edict_t * self)868 void soldier_fire6 (edict_t *self)
869 {
870 soldier_fire (self, 5);
871 }
872
soldier_fire7(edict_t * self)873 void soldier_fire7 (edict_t *self)
874 {
875 soldier_fire (self, 6);
876 }
877
soldier_dead(edict_t * self)878 void soldier_dead (edict_t *self)
879 {
880 VectorSet (self->mins, -16, -16, -24);
881 VectorSet (self->maxs, 16, 16, -8);
882 self->movetype = MOVETYPE_TOSS;
883 self->svflags |= SVF_DEADMONSTER;
884 self->nextthink = 0;
885
886 self->think=FadeDieSink;
887 self->nextthink=level.time+FADETIME+random()*5;
888 self->floater=1;
889
890 gi.linkentity (self);
891 }
892
893 mframe_t soldier_frames_death1 [] =
894 {
895 ai_move, 0, NULL,
896 ai_move, -10, NULL,
897 ai_move, -10, NULL,
898 ai_move, -10, NULL,
899 ai_move, -5, NULL,
900 ai_move, 0, NULL,
901 ai_move, 0, NULL,
902 ai_move, 0, NULL,
903 ai_move, 0, NULL,
904 ai_move, 0, NULL,
905
906 ai_move, 0, NULL,
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
917 ai_move, 0, NULL,
918 ai_move, 0, soldier_fire6,
919 ai_move, 0, NULL,
920 ai_move, 0, NULL,
921 ai_move, 0, soldier_fire7,
922 ai_move, 0, NULL,
923 ai_move, 0, NULL,
924 ai_move, 0, NULL,
925 ai_move, 0, NULL,
926 ai_move, 0, NULL,
927
928 ai_move, 0, NULL,
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 };
935 mmove_t soldier_move_death1 = {FRAME_death101, FRAME_death136, soldier_frames_death1, soldier_dead};
936
937 mframe_t soldier_frames_death2 [] =
938 {
939 ai_move, -5, NULL,
940 ai_move, -5, NULL,
941 ai_move, -5, NULL,
942 ai_move, 0, 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
950 ai_move, 0, NULL,
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
961 ai_move, 0, NULL,
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
972 ai_move, 0, NULL,
973 ai_move, 0, NULL,
974 ai_move, 0, NULL,
975 ai_move, 0, NULL,
976 ai_move, 0, NULL
977 };
978 mmove_t soldier_move_death2 = {FRAME_death201, FRAME_death235, soldier_frames_death2, soldier_dead};
979
980 mframe_t soldier_frames_death3 [] =
981 {
982 ai_move, -5, NULL,
983 ai_move, -5, NULL,
984 ai_move, -5, NULL,
985 ai_move, 0, 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
993 ai_move, 0, NULL,
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
1004 ai_move, 0, NULL,
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
1015 ai_move, 0, NULL,
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
1026 ai_move, 0, NULL,
1027 ai_move, 0, NULL,
1028 ai_move, 0, NULL,
1029 ai_move, 0, NULL,
1030 ai_move, 0, NULL,
1031 };
1032 mmove_t soldier_move_death3 = {FRAME_death301, FRAME_death345, soldier_frames_death3, soldier_dead};
1033
1034 mframe_t soldier_frames_death4 [] =
1035 {
1036 ai_move, 0, NULL,
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
1047 ai_move, 0, NULL,
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
1058 ai_move, 0, NULL,
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
1069 ai_move, 0, NULL,
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
1080 ai_move, 0, NULL,
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
1091 ai_move, 0, NULL,
1092 ai_move, 0, NULL,
1093 ai_move, 0, NULL
1094 };
1095 mmove_t soldier_move_death4 = {FRAME_death401, FRAME_death453, soldier_frames_death4, soldier_dead};
1096
1097 mframe_t soldier_frames_death5 [] =
1098 {
1099 ai_move, -5, NULL,
1100 ai_move, -5, NULL,
1101 ai_move, -5, NULL,
1102 ai_move, 0, 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
1110 ai_move, 0, NULL,
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
1121 ai_move, 0, NULL,
1122 ai_move, 0, NULL,
1123 ai_move, 0, NULL,
1124 ai_move, 0, NULL
1125 };
1126 mmove_t soldier_move_death5 = {FRAME_death501, FRAME_death524, soldier_frames_death5, soldier_dead};
1127
1128 mframe_t soldier_frames_death6 [] =
1129 {
1130 ai_move, 0, NULL,
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 };
1141 mmove_t soldier_move_death6 = {FRAME_death601, FRAME_death610, soldier_frames_death6, soldier_dead};
1142
soldier_die(edict_t * self,edict_t * inflictor,edict_t * attacker,int damage,vec3_t point)1143 void soldier_die (edict_t *self, edict_t *inflictor, edict_t *attacker, int damage, vec3_t point)
1144 {
1145 int n;
1146
1147 switch (meansOfDeath & ~MOD_FRIENDLY_FIRE)
1148 {
1149 case MOD_ROCKET:
1150 case MOD_BFG_LASER:
1151 case MOD_BFG_BLAST:
1152 case MOD_HANDGRENADE:
1153 case MOD_HELD_GRENADE:
1154 case MOD_BOMB:
1155 case MOD_C4:
1156 case MOD_GAS_BOOM:
1157 self->health = self->gib_health;
1158 break;
1159 case MOD_FLAME:
1160 case MOD_DISCHARGE:
1161 case MOD_LAVA:
1162 self->health -= damage * 2;
1163 break;
1164 case MOD_HG_SPLASH:
1165 case MOD_R_SPLASH:
1166 case MOD_G_SPLASH:
1167 self->health -= damage * 5;
1168 break;
1169 case MOD_R_BFG_SPLASH:
1170 self->health -= damage * 10;
1171 break;
1172 }
1173
1174 // check for gib
1175 if (self->health <= self->gib_health)
1176 {
1177 gi.sound (self, CHAN_VOICE, gi.soundindex ("misc/udeath.wav"), 1, ATTN_NORM, 0);
1178 for (n= 0; n < 3; n++)
1179 ThrowGib (self, "models/objects/gibs/sm_meat/tris.md2", damage, GIB_ORGANIC);
1180 ThrowGib (self, "models/objects/gibs/chest/tris.md2", damage, GIB_ORGANIC);
1181 ThrowHead (self, "models/objects/gibs/head2/tris.md2", damage, GIB_ORGANIC);
1182 self->deadflag = DEAD_DEAD;
1183 return;
1184 }
1185
1186 if (self->deadflag == DEAD_DEAD)
1187 return;
1188
1189 // regular death
1190 self->deadflag = DEAD_DEAD;
1191 self->takedamage = DAMAGE_YES;
1192 self->s.skinnum |= 1;
1193
1194 if (self->s.skinnum == 1)
1195 gi.sound (self, CHAN_VOICE, sound_death_light, 1, ATTN_NORM, 0);
1196 else if (self->s.skinnum == 3)
1197 gi.sound (self, CHAN_VOICE, sound_death, 1, ATTN_NORM, 0);
1198 else // (self->s.skinnum == 5)
1199 gi.sound (self, CHAN_VOICE, sound_death_ss, 1, ATTN_NORM, 0);
1200
1201 if (headShot) //(fabs((self->s.origin[2] + self->viewheight) - point[2]) <= 4)
1202 {
1203 // head shot
1204 self->monsterinfo.currentmove = &soldier_move_death3;
1205 return;
1206 }
1207
1208 n = rand() % 5;
1209 if (n == 0)
1210 self->monsterinfo.currentmove = &soldier_move_death1;
1211 else if (n == 1)
1212 self->monsterinfo.currentmove = &soldier_move_death2;
1213 else if (n == 2)
1214 self->monsterinfo.currentmove = &soldier_move_death4;
1215 else if (n == 3)
1216 self->monsterinfo.currentmove = &soldier_move_death5;
1217 else
1218 self->monsterinfo.currentmove = &soldier_move_death6;
1219
1220 }
1221
1222
1223 //
1224 // SPAWN
1225 //
1226
SP_monster_soldier_x(edict_t * self)1227 void SP_monster_soldier_x (edict_t *self)
1228 {
1229
1230 self->s.modelindex = gi.modelindex ("models/monsters/soldier/tris.md2");
1231 self->monsterinfo.scale = MODEL_SCALE;
1232 VectorSet (self->mins, -16, -16, -24);
1233 VectorSet (self->maxs, 16, 16, 32);
1234 self->movetype = MOVETYPE_STEP;
1235 self->solid = SOLID_BBOX;
1236
1237 sound_idle = gi.soundindex ("soldier/solidle1.wav");
1238 sound_sight1 = gi.soundindex ("soldier/solsght1.wav");
1239 sound_sight2 = gi.soundindex ("soldier/solsrch1.wav");
1240 sound_cock = gi.soundindex ("infantry/infatck3.wav");
1241
1242 self->mass = 100;
1243
1244 self->pain = soldier_pain;
1245 self->die = soldier_die;
1246
1247 self->monsterinfo.stand = soldier_stand;
1248 self->monsterinfo.walk = soldier_walk;
1249 self->monsterinfo.run = soldier_run;
1250 self->monsterinfo.dodge = soldier_dodge;
1251 self->monsterinfo.attack = soldier_attack;
1252 self->monsterinfo.melee = NULL;
1253 self->monsterinfo.sight = soldier_sight;
1254
1255 gi.linkentity (self);
1256
1257 self->monsterinfo.stand (self);
1258
1259 walkmonster_start (self);
1260 }
1261
1262
1263 /*QUAKED monster_soldier_light (1 .5 0) (-16 -16 -24) (16 16 32) Ambush Trigger_Spawn Sight
1264 */
SP_monster_soldier_light(edict_t * self)1265 void SP_monster_soldier_light (edict_t *self)
1266 {
1267 if (deathmatch->value)
1268 {
1269 G_FreeEdict (self);
1270 return;
1271 }
1272
1273 SP_monster_soldier_x (self);
1274
1275 sound_pain_light = gi.soundindex ("soldier/solpain2.wav");
1276 sound_death_light = gi.soundindex ("soldier/soldeth2.wav");
1277 gi.modelindex ("models/objects/laser/tris.md2");
1278 gi.soundindex ("misc/lasfly.wav");
1279 gi.soundindex ("soldier/solatck2.wav");
1280
1281 self->s.skinnum = 0;
1282 self->health = 90;
1283 self->gib_health = -500;
1284
1285 self->max_health = self->health;
1286 }
1287
1288 /*QUAKED monster_soldier (1 .5 0) (-16 -16 -24) (16 16 32) Ambush Trigger_Spawn Sight
1289 */
soldier_enemycheck(edict_t * ent,edict_t * other)1290 qboolean soldier_enemycheck (edict_t *ent, edict_t *other)
1291 {
1292
1293 if (!Q_stricmp (other->classname, "monster_soldier_light"))
1294 return true;
1295
1296 return false;
1297 }
SP_monster_soldier(edict_t * self)1298 void SP_monster_soldier (edict_t *self)
1299 {
1300 if (deathmatch->value)
1301 {
1302 G_FreeEdict (self);
1303 return;
1304 }
1305
1306 SP_monster_soldier_x (self);
1307
1308
1309 self->monsterinfo.enemycheck = soldier_enemycheck;
1310
1311 sound_pain = gi.soundindex ("soldier/solpain1.wav");
1312 sound_death = gi.soundindex ("soldier/soldeth1.wav");
1313 gi.soundindex ("soldier/solatck1.wav");
1314
1315 self->s.skinnum = 2;
1316 self->health = 90;
1317 self->gib_health = -500;
1318
1319 self->max_health = self->health;
1320 }
1321
1322 /*QUAKED monster_soldier_ss (1 .5 0) (-16 -16 -24) (16 16 32) Ambush Trigger_Spawn Sight
1323 */
SP_monster_soldier_ss(edict_t * self)1324 void SP_monster_soldier_ss (edict_t *self)
1325 {
1326 if (deathmatch->value)
1327 {
1328 G_FreeEdict (self);
1329 return;
1330 }
1331
1332 SP_monster_soldier_x (self);
1333
1334 sound_pain_ss = gi.soundindex ("soldier/solpain3.wav");
1335 sound_death_ss = gi.soundindex ("soldier/soldeth3.wav");
1336 gi.soundindex ("soldier/solatck3.wav");
1337
1338 self->s.skinnum = 4;
1339 self->health = 90;
1340 self->gib_health = -500;
1341
1342 self->max_health = self->health;
1343 }
1344