1 /*
2 ==============================================================================
3
4 INFANTRY
5
6 ==============================================================================
7 */
8
9 #include "g_local.h"
10 #include "m_infantry.h"
11
12 void InfantryMachineGun (edict_t *self);
13
14
15 static int sound_pain1;
16 static int sound_pain2;
17 static int sound_die1;
18 static int sound_die2;
19
20 static int sound_gunshot;
21 static int sound_weapon_cock;
22 static int sound_punch_swing;
23 static int sound_punch_hit;
24 static int sound_sight;
25 static int sound_search;
26 static int sound_idle;
27
28
29 mframe_t infantry_frames_stand [] =
30 {
31 ai_stand, 0, NULL,
32 ai_stand, 0, NULL,
33 ai_stand, 0, NULL,
34 ai_stand, 0, NULL,
35 ai_stand, 0, NULL,
36 ai_stand, 0, NULL,
37 ai_stand, 0, NULL,
38 ai_stand, 0, NULL,
39 ai_stand, 0, NULL,
40 ai_stand, 0, NULL,
41 ai_stand, 0, NULL,
42 ai_stand, 0, NULL,
43 ai_stand, 0, NULL,
44 ai_stand, 0, NULL,
45 ai_stand, 0, NULL,
46 ai_stand, 0, NULL,
47 ai_stand, 0, NULL,
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 };
54 mmove_t infantry_move_stand = {FRAME_stand50, FRAME_stand71, infantry_frames_stand, NULL};
55
infantry_stand(edict_t * self)56 void infantry_stand (edict_t *self)
57 {
58 self->monsterinfo.currentmove = &infantry_move_stand;
59 }
60
61
62 mframe_t infantry_frames_fidget [] =
63 {
64 ai_stand, 1, NULL,
65 ai_stand, 0, NULL,
66 ai_stand, 1, NULL,
67 ai_stand, 3, NULL,
68 ai_stand, 6, NULL,
69 ai_stand, 3, NULL,
70 ai_stand, 0, NULL,
71 ai_stand, 0, NULL,
72 ai_stand, 0, NULL,
73 ai_stand, 0, NULL,
74 ai_stand, 1, NULL,
75 ai_stand, 0, NULL,
76 ai_stand, 0, NULL,
77 ai_stand, 0, NULL,
78 ai_stand, 0, NULL,
79 ai_stand, 1, NULL,
80 ai_stand, 0, NULL,
81 ai_stand, -1, NULL,
82 ai_stand, 0, NULL,
83 ai_stand, 0, NULL,
84 ai_stand, 1, NULL,
85 ai_stand, 0, NULL,
86 ai_stand, -2, NULL,
87 ai_stand, 1, NULL,
88 ai_stand, 1, NULL,
89 ai_stand, 1, NULL,
90 ai_stand, -1, NULL,
91 ai_stand, 0, NULL,
92 ai_stand, 0, NULL,
93 ai_stand, -1, NULL,
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, -1, NULL,
100 ai_stand, 0, NULL,
101 ai_stand, 0, NULL,
102 ai_stand, 1, NULL,
103 ai_stand, 0, NULL,
104 ai_stand, 0, NULL,
105 ai_stand, -1, NULL,
106 ai_stand, -1, NULL,
107 ai_stand, 0, NULL,
108 ai_stand, -3, NULL,
109 ai_stand, -2, NULL,
110 ai_stand, -3, NULL,
111 ai_stand, -3, NULL,
112 ai_stand, -2, NULL
113 };
114 mmove_t infantry_move_fidget = {FRAME_stand01, FRAME_stand49, infantry_frames_fidget, infantry_stand};
115
infantry_fidget(edict_t * self)116 void infantry_fidget (edict_t *self)
117 {
118 self->monsterinfo.currentmove = &infantry_move_fidget;
119 gi.sound (self, CHAN_VOICE, sound_idle, 1, ATTN_IDLE, 0);
120 }
121
122 mframe_t infantry_frames_walk [] =
123 {
124 ai_walk, 5, NULL,
125 ai_walk, 4, NULL,
126 ai_walk, 4, NULL,
127 ai_walk, 5, NULL,
128 ai_walk, 4, NULL,
129 ai_walk, 5, NULL,
130 ai_walk, 6, NULL,
131 ai_walk, 4, NULL,
132 ai_walk, 4, NULL,
133 ai_walk, 4, NULL,
134 ai_walk, 4, NULL,
135 ai_walk, 5, NULL
136 };
137 mmove_t infantry_move_walk = {FRAME_walk03, FRAME_walk14, infantry_frames_walk, NULL};
138
infantry_walk(edict_t * self)139 void infantry_walk (edict_t *self)
140 {
141 self->monsterinfo.currentmove = &infantry_move_walk;
142 }
143
144 mframe_t infantry_frames_run [] =
145 {
146 ai_run, 10, NULL,
147 ai_run, 20, NULL,
148 ai_run, 5, NULL,
149 ai_run, 7, NULL,
150 ai_run, 30, NULL,
151 ai_run, 35, NULL,
152 ai_run, 2, NULL,
153 ai_run, 6, NULL
154 };
155 mmove_t infantry_move_run = {FRAME_run01, FRAME_run08, infantry_frames_run, NULL};
156
infantry_run(edict_t * self)157 void infantry_run (edict_t *self)
158 {
159 if (self->monsterinfo.aiflags & AI_STAND_GROUND)
160 self->monsterinfo.currentmove = &infantry_move_stand;
161 else
162 self->monsterinfo.currentmove = &infantry_move_run;
163 }
164
165
166 mframe_t infantry_frames_pain1 [] =
167 {
168 ai_move, -3, NULL,
169 ai_move, -2, NULL,
170 ai_move, -1, NULL,
171 ai_move, -2, NULL,
172 ai_move, -1, NULL,
173 ai_move, 1, NULL,
174 ai_move, -1, NULL,
175 ai_move, 1, NULL,
176 ai_move, 6, NULL,
177 ai_move, 2, NULL
178 };
179 mmove_t infantry_move_pain1 = {FRAME_pain101, FRAME_pain110, infantry_frames_pain1, infantry_run};
180
181 mframe_t infantry_frames_pain2 [] =
182 {
183 ai_move, -3, NULL,
184 ai_move, -3, NULL,
185 ai_move, 0, NULL,
186 ai_move, -1, NULL,
187 ai_move, -2, NULL,
188 ai_move, 0, NULL,
189 ai_move, 0, NULL,
190 ai_move, 2, NULL,
191 ai_move, 5, NULL,
192 ai_move, 2, NULL
193 };
194 mmove_t infantry_move_pain2 = {FRAME_pain201, FRAME_pain210, infantry_frames_pain2, infantry_run};
195
infantry_pain(edict_t * self,edict_t * other,float kick,int damage)196 void infantry_pain (edict_t *self, edict_t *other, float kick, int damage)
197 {
198 int n;
199
200 if (self->health < (self->max_health / 2))
201 self->s.skinnum = 1;
202
203 if (level.time < self->pain_debounce_time)
204 return;
205
206 self->pain_debounce_time = level.time + 3;
207
208 if (skill->value == 3)
209 return; // no pain anims in nightmare
210
211 n = rand() % 2;
212 if (n == 0)
213 {
214 self->monsterinfo.currentmove = &infantry_move_pain1;
215 gi.sound (self, CHAN_VOICE, sound_pain1, 1, ATTN_NORM, 0);
216 }
217 else
218 {
219 self->monsterinfo.currentmove = &infantry_move_pain2;
220 gi.sound (self, CHAN_VOICE, sound_pain2, 1, ATTN_NORM, 0);
221 }
222 }
223
224
225 vec3_t aimangles[] =
226 {
227 0.0, 5.0, 0.0,
228 10.0, 15.0, 0.0,
229 20.0, 25.0, 0.0,
230 25.0, 35.0, 0.0,
231 30.0, 40.0, 0.0,
232 30.0, 45.0, 0.0,
233 25.0, 50.0, 0.0,
234 20.0, 40.0, 0.0,
235 15.0, 35.0, 0.0,
236 40.0, 35.0, 0.0,
237 70.0, 35.0, 0.0,
238 90.0, 35.0, 0.0
239 };
240
InfantryMachineGun(edict_t * self)241 void InfantryMachineGun (edict_t *self)
242 {
243 vec3_t start, target;
244 vec3_t forward, right;
245 vec3_t vec;
246 int flash_number;
247
248 if (self->s.frame == FRAME_attak111)
249 {
250 flash_number = MZ2_INFANTRY_MACHINEGUN_1;
251 AngleVectors (self->s.angles, forward, right, NULL);
252 G_ProjectSource (self->s.origin, monster_flash_offset[flash_number], forward, right, start);
253
254 if (self->enemy)
255 {
256 VectorMA (self->enemy->s.origin, -0.2, self->enemy->velocity, target);
257 target[2] += self->enemy->viewheight;
258 VectorSubtract (target, start, forward);
259 VectorNormalize (forward);
260 }
261 else
262 {
263 AngleVectors (self->s.angles, forward, right, NULL);
264 }
265 }
266 else
267 {
268 flash_number = MZ2_INFANTRY_MACHINEGUN_2 + (self->s.frame - FRAME_death211);
269
270 AngleVectors (self->s.angles, forward, right, NULL);
271 G_ProjectSource (self->s.origin, monster_flash_offset[flash_number], forward, right, start);
272
273 VectorSubtract (self->s.angles, aimangles[flash_number-MZ2_INFANTRY_MACHINEGUN_2], vec);
274 AngleVectors (vec, forward, NULL, NULL);
275 }
276
277 monster_fire_bullet (self, start, forward, 3, 4, DEFAULT_BULLET_HSPREAD, DEFAULT_BULLET_VSPREAD, flash_number);
278 }
279
infantry_sight(edict_t * self,edict_t * other)280 void infantry_sight (edict_t *self, edict_t *other)
281 {
282 gi.sound (self, CHAN_BODY, sound_sight, 1, ATTN_NORM, 0);
283 }
284
infantry_dead(edict_t * self)285 void infantry_dead (edict_t *self)
286 {
287 VectorSet (self->mins, -16, -16, -24);
288 VectorSet (self->maxs, 16, 16, -8);
289 self->movetype = MOVETYPE_TOSS;
290 self->svflags |= SVF_DEADMONSTER;
291 gi.linkentity (self);
292
293 M_FlyCheck (self);
294 }
295
296 mframe_t infantry_frames_death1 [] =
297 {
298 ai_move, -4, NULL,
299 ai_move, 0, NULL,
300 ai_move, 0, NULL,
301 ai_move, -1, NULL,
302 ai_move, -4, NULL,
303 ai_move, 0, NULL,
304 ai_move, 0, NULL,
305 ai_move, 0, NULL,
306 ai_move, -1, NULL,
307 ai_move, 3, NULL,
308 ai_move, 1, NULL,
309 ai_move, 1, NULL,
310 ai_move, -2, NULL,
311 ai_move, 2, NULL,
312 ai_move, 2, NULL,
313 ai_move, 9, NULL,
314 ai_move, 9, NULL,
315 ai_move, 5, NULL,
316 ai_move, -3, NULL,
317 ai_move, -3, NULL
318 };
319 mmove_t infantry_move_death1 = {FRAME_death101, FRAME_death120, infantry_frames_death1, infantry_dead};
320
321 // Off with his head
322 mframe_t infantry_frames_death2 [] =
323 {
324 ai_move, 0, NULL,
325 ai_move, 1, NULL,
326 ai_move, 5, NULL,
327 ai_move, -1, NULL,
328 ai_move, 0, NULL,
329 ai_move, 1, NULL,
330 ai_move, 1, NULL,
331 ai_move, 4, NULL,
332 ai_move, 3, NULL,
333 ai_move, 0, NULL,
334 ai_move, -2, InfantryMachineGun,
335 ai_move, -2, InfantryMachineGun,
336 ai_move, -3, InfantryMachineGun,
337 ai_move, -1, InfantryMachineGun,
338 ai_move, -2, InfantryMachineGun,
339 ai_move, 0, InfantryMachineGun,
340 ai_move, 2, InfantryMachineGun,
341 ai_move, 2, InfantryMachineGun,
342 ai_move, 3, InfantryMachineGun,
343 ai_move, -10, InfantryMachineGun,
344 ai_move, -7, InfantryMachineGun,
345 ai_move, -8, InfantryMachineGun,
346 ai_move, -6, NULL,
347 ai_move, 4, NULL,
348 ai_move, 0, NULL
349 };
350 mmove_t infantry_move_death2 = {FRAME_death201, FRAME_death225, infantry_frames_death2, infantry_dead};
351
352 mframe_t infantry_frames_death3 [] =
353 {
354 ai_move, 0, NULL,
355 ai_move, 0, NULL,
356 ai_move, 0, NULL,
357 ai_move, -6, NULL,
358 ai_move, -11, NULL,
359 ai_move, -3, NULL,
360 ai_move, -11, NULL,
361 ai_move, 0, NULL,
362 ai_move, 0, NULL
363 };
364 mmove_t infantry_move_death3 = {FRAME_death301, FRAME_death309, infantry_frames_death3, infantry_dead};
365
366
infantry_die(edict_t * self,edict_t * inflictor,edict_t * attacker,int damage,vec3_t point)367 void infantry_die (edict_t *self, edict_t *inflictor, edict_t *attacker, int damage, vec3_t point)
368 {
369 int n;
370
371 // check for gib
372 if (self->health <= self->gib_health)
373 {
374 gi.sound (self, CHAN_VOICE, gi.soundindex ("misc/udeath.wav"), 1, ATTN_NORM, 0);
375 for (n= 0; n < 2; n++)
376 ThrowGib (self, "models/objects/gibs/bone/tris.md2", damage, GIB_ORGANIC);
377 for (n= 0; n < 4; n++)
378 ThrowGib (self, "models/objects/gibs/sm_meat/tris.md2", damage, GIB_ORGANIC);
379 ThrowHead (self, "models/objects/gibs/head2/tris.md2", damage, GIB_ORGANIC);
380 self->deadflag = DEAD_DEAD;
381 return;
382 }
383
384 if (self->deadflag == DEAD_DEAD)
385 return;
386
387 // regular death
388 self->deadflag = DEAD_DEAD;
389 self->takedamage = DAMAGE_YES;
390
391 n = rand() % 3;
392 if (n == 0)
393 {
394 self->monsterinfo.currentmove = &infantry_move_death1;
395 gi.sound (self, CHAN_VOICE, sound_die2, 1, ATTN_NORM, 0);
396 }
397 else if (n == 1)
398 {
399 self->monsterinfo.currentmove = &infantry_move_death2;
400 gi.sound (self, CHAN_VOICE, sound_die1, 1, ATTN_NORM, 0);
401 }
402 else
403 {
404 self->monsterinfo.currentmove = &infantry_move_death3;
405 gi.sound (self, CHAN_VOICE, sound_die2, 1, ATTN_NORM, 0);
406 }
407 }
408
409
infantry_duck_down(edict_t * self)410 void infantry_duck_down (edict_t *self)
411 {
412 if (self->monsterinfo.aiflags & AI_DUCKED)
413 return;
414 self->monsterinfo.aiflags |= AI_DUCKED;
415 self->maxs[2] -= 32;
416 self->takedamage = DAMAGE_YES;
417 self->monsterinfo.pausetime = level.time + 1;
418 gi.linkentity (self);
419 }
420
infantry_duck_hold(edict_t * self)421 void infantry_duck_hold (edict_t *self)
422 {
423 if (level.time >= self->monsterinfo.pausetime)
424 self->monsterinfo.aiflags &= ~AI_HOLD_FRAME;
425 else
426 self->monsterinfo.aiflags |= AI_HOLD_FRAME;
427 }
428
infantry_duck_up(edict_t * self)429 void infantry_duck_up (edict_t *self)
430 {
431 self->monsterinfo.aiflags &= ~AI_DUCKED;
432 self->maxs[2] += 32;
433 self->takedamage = DAMAGE_AIM;
434 gi.linkentity (self);
435 }
436
437 mframe_t infantry_frames_duck [] =
438 {
439 ai_move, -2, infantry_duck_down,
440 ai_move, -5, infantry_duck_hold,
441 ai_move, 3, NULL,
442 ai_move, 4, infantry_duck_up,
443 ai_move, 0, NULL
444 };
445 mmove_t infantry_move_duck = {FRAME_duck01, FRAME_duck05, infantry_frames_duck, infantry_run};
446
infantry_dodge(edict_t * self,edict_t * attacker,float eta)447 void infantry_dodge (edict_t *self, edict_t *attacker, float eta)
448 {
449 if (random() > 0.25)
450 return;
451
452 if (!self->enemy)
453 self->enemy = attacker;
454
455 self->monsterinfo.currentmove = &infantry_move_duck;
456 }
457
458
infantry_cock_gun(edict_t * self)459 void infantry_cock_gun (edict_t *self)
460 {
461 int n;
462
463 gi.sound (self, CHAN_WEAPON, sound_weapon_cock, 1, ATTN_NORM, 0);
464 n = (rand() & 15) + 3 + 7;
465 self->monsterinfo.pausetime = level.time + n * FRAMETIME;
466 }
467
infantry_fire(edict_t * self)468 void infantry_fire (edict_t *self)
469 {
470 InfantryMachineGun (self);
471
472 if (level.time >= self->monsterinfo.pausetime)
473 self->monsterinfo.aiflags &= ~AI_HOLD_FRAME;
474 else
475 self->monsterinfo.aiflags |= AI_HOLD_FRAME;
476 }
477
478 mframe_t infantry_frames_attack1 [] =
479 {
480 ai_charge, 4, NULL,
481 ai_charge, -1, NULL,
482 ai_charge, -1, NULL,
483 ai_charge, 0, infantry_cock_gun,
484 ai_charge, -1, NULL,
485 ai_charge, 1, NULL,
486 ai_charge, 1, NULL,
487 ai_charge, 2, NULL,
488 ai_charge, -2, NULL,
489 ai_charge, -3, NULL,
490 ai_charge, 1, infantry_fire,
491 ai_charge, 5, NULL,
492 ai_charge, -1, NULL,
493 ai_charge, -2, NULL,
494 ai_charge, -3, NULL
495 };
496 mmove_t infantry_move_attack1 = {FRAME_attak101, FRAME_attak115, infantry_frames_attack1, infantry_run};
497
498
infantry_swing(edict_t * self)499 void infantry_swing (edict_t *self)
500 {
501 gi.sound (self, CHAN_WEAPON, sound_punch_swing, 1, ATTN_NORM, 0);
502 }
503
infantry_smack(edict_t * self)504 void infantry_smack (edict_t *self)
505 {
506 vec3_t aim;
507
508 VectorSet (aim, MELEE_DISTANCE, 0, 0);
509 if (fire_hit (self, aim, (5 + (rand() % 5)), 50))
510 gi.sound (self, CHAN_WEAPON, sound_punch_hit, 1, ATTN_NORM, 0);
511 }
512
513 mframe_t infantry_frames_attack2 [] =
514 {
515 ai_charge, 3, NULL,
516 ai_charge, 6, NULL,
517 ai_charge, 0, infantry_swing,
518 ai_charge, 8, NULL,
519 ai_charge, 5, NULL,
520 ai_charge, 8, infantry_smack,
521 ai_charge, 6, NULL,
522 ai_charge, 3, NULL,
523 };
524 mmove_t infantry_move_attack2 = {FRAME_attak201, FRAME_attak208, infantry_frames_attack2, infantry_run};
525
infantry_attack(edict_t * self)526 void infantry_attack(edict_t *self)
527 {
528 if (range (self, self->enemy) == RANGE_MELEE)
529 self->monsterinfo.currentmove = &infantry_move_attack2;
530 else
531 self->monsterinfo.currentmove = &infantry_move_attack1;
532 }
533
534
535 /*QUAKED monster_infantry (1 .5 0) (-16 -16 -24) (16 16 32) Ambush Trigger_Spawn Sight
536 */
SP_monster_infantry(edict_t * self)537 void SP_monster_infantry (edict_t *self)
538 {
539 if (deathmatch->value)
540 {
541 G_FreeEdict (self);
542 return;
543 }
544
545 sound_pain1 = gi.soundindex ("infantry/infpain1.wav");
546 sound_pain2 = gi.soundindex ("infantry/infpain2.wav");
547 sound_die1 = gi.soundindex ("infantry/infdeth1.wav");
548 sound_die2 = gi.soundindex ("infantry/infdeth2.wav");
549
550 sound_gunshot = gi.soundindex ("infantry/infatck1.wav");
551 sound_weapon_cock = gi.soundindex ("infantry/infatck3.wav");
552 sound_punch_swing = gi.soundindex ("infantry/infatck2.wav");
553 sound_punch_hit = gi.soundindex ("infantry/melee2.wav");
554
555 sound_sight = gi.soundindex ("infantry/infsght1.wav");
556 sound_search = gi.soundindex ("infantry/infsrch1.wav");
557 sound_idle = gi.soundindex ("infantry/infidle1.wav");
558
559
560 self->movetype = MOVETYPE_STEP;
561 self->solid = SOLID_BBOX;
562 self->s.modelindex = gi.modelindex("models/monsters/infantry/tris.md2");
563 VectorSet (self->mins, -16, -16, -24);
564 VectorSet (self->maxs, 16, 16, 32);
565
566 self->health = 100;
567 self->gib_health = -40;
568 self->mass = 200;
569
570 self->pain = infantry_pain;
571 self->die = infantry_die;
572
573 self->monsterinfo.stand = infantry_stand;
574 self->monsterinfo.walk = infantry_walk;
575 self->monsterinfo.run = infantry_run;
576 self->monsterinfo.dodge = infantry_dodge;
577 self->monsterinfo.attack = infantry_attack;
578 self->monsterinfo.melee = NULL;
579 self->monsterinfo.sight = infantry_sight;
580 self->monsterinfo.idle = infantry_fidget;
581
582 gi.linkentity (self);
583
584 self->monsterinfo.currentmove = &infantry_move_stand;
585 self->monsterinfo.scale = MODEL_SCALE;
586
587 walkmonster_start (self);
588 }
589