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 mframe_t infantry_frames_stand [] =
29 {
30 	ai_stand, 0, NULL,
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 };
53 mmove_t infantry_move_stand = {FRAME_stand50, FRAME_stand71, infantry_frames_stand, NULL};
54 
infantry_stand(edict_t * self)55 void infantry_stand (edict_t *self)
56 {
57 	self->monsterinfo.currentmove = &infantry_move_stand;
58 }
59 
60 
61 mframe_t infantry_frames_fidget [] =
62 {
63 	ai_stand, 1,  NULL,
64 	ai_stand, 0,  NULL,
65 	ai_stand, 1,  NULL,
66 	ai_stand, 3,  NULL,
67 	ai_stand, 6,  NULL,
68 	ai_stand, 3,  NULL,
69 	ai_stand, 0,  NULL,
70 	ai_stand, 0,  NULL,
71 	ai_stand, 0,  NULL,
72 	ai_stand, 0,  NULL,
73 	ai_stand, 1,  NULL,
74 	ai_stand, 0,  NULL,
75 	ai_stand, 0,  NULL,
76 	ai_stand, 0,  NULL,
77 	ai_stand, 0,  NULL,
78 	ai_stand, 1,  NULL,
79 	ai_stand, 0,  NULL,
80 	ai_stand, -1, NULL,
81 	ai_stand, 0,  NULL,
82 	ai_stand, 0,  NULL,
83 	ai_stand, 1,  NULL,
84 	ai_stand, 0,  NULL,
85 	ai_stand, -2, NULL,
86 	ai_stand, 1,  NULL,
87 	ai_stand, 1,  NULL,
88 	ai_stand, 1,  NULL,
89 	ai_stand, -1, NULL,
90 	ai_stand, 0,  NULL,
91 	ai_stand, 0,  NULL,
92 	ai_stand, -1, NULL,
93 	ai_stand, 0,  NULL,
94 	ai_stand, 0,  NULL,
95 	ai_stand, 0,  NULL,
96 	ai_stand, 0,  NULL,
97 	ai_stand, 0,  NULL,
98 	ai_stand, -1, NULL,
99 	ai_stand, 0,  NULL,
100 	ai_stand, 0,  NULL,
101 	ai_stand, 1,  NULL,
102 	ai_stand, 0,  NULL,
103 	ai_stand, 0,  NULL,
104 	ai_stand, -1, NULL,
105 	ai_stand, -1, NULL,
106 	ai_stand, 0,  NULL,
107 	ai_stand, -3, NULL,
108 	ai_stand, -2, NULL,
109 	ai_stand, -3, NULL,
110 	ai_stand, -3, NULL,
111 	ai_stand, -2, NULL
112 };
113 mmove_t infantry_move_fidget = {FRAME_stand01, FRAME_stand49, infantry_frames_fidget, infantry_stand};
114 
infantry_fidget(edict_t * self)115 void infantry_fidget (edict_t *self)
116 {
117 	self->monsterinfo.currentmove = &infantry_move_fidget;
118 	gi.sound (self, CHAN_VOICE, sound_idle, 1, ATTN_IDLE, 0);
119 }
120 
121 mframe_t infantry_frames_walk [] =
122 {
123 	ai_walk, 5,  NULL,
124 	ai_walk, 4,  NULL,
125 	ai_walk, 4,  NULL,
126 	ai_walk, 5,  NULL,
127 	ai_walk, 4,  NULL,
128 	ai_walk, 5,  NULL,
129 	ai_walk, 6,  NULL,
130 	ai_walk, 4,  NULL,
131 	ai_walk, 4,  NULL,
132 	ai_walk, 4,  NULL,
133 	ai_walk, 4,  NULL,
134 	ai_walk, 5,  NULL
135 };
136 mmove_t infantry_move_walk = {FRAME_walk03, FRAME_walk14, infantry_frames_walk, NULL};
137 
infantry_walk(edict_t * self)138 void infantry_walk (edict_t *self)
139 {
140 	self->monsterinfo.currentmove = &infantry_move_walk;
141 }
142 
143 mframe_t infantry_frames_run [] =
144 {
145 	ai_run, 10, NULL,
146 	ai_run, 20, NULL,
147 	ai_run, 5,  NULL,
148 	ai_run, 7,  monster_done_dodge,
149 	ai_run, 30, NULL,
150 	ai_run, 35, NULL,
151 	ai_run, 2,  NULL,
152 	ai_run, 6,  NULL
153 };
154 mmove_t infantry_move_run = {FRAME_run01, FRAME_run08, infantry_frames_run, NULL};
155 
infantry_run(edict_t * self)156 void infantry_run (edict_t *self)
157 {
158 	monster_done_dodge (self);
159 
160 	if (self->monsterinfo.aiflags & AI_STAND_GROUND)
161 		self->monsterinfo.currentmove = &infantry_move_stand;
162 	else
163 		self->monsterinfo.currentmove = &infantry_move_run;
164 }
165 
166 
167 mframe_t infantry_frames_pain1 [] =
168 {
169 	ai_move, -3, NULL,
170 	ai_move, -2, NULL,
171 	ai_move, -1, NULL,
172 	ai_move, -2, NULL,
173 	ai_move, -1, NULL,
174 	ai_move, 1,  NULL,
175 	ai_move, -1, NULL,
176 	ai_move, 1,  NULL,
177 	ai_move, 6,  NULL,
178 	ai_move, 2,  NULL
179 };
180 mmove_t infantry_move_pain1 = {FRAME_pain101, FRAME_pain110, infantry_frames_pain1, infantry_run};
181 
182 mframe_t infantry_frames_pain2 [] =
183 {
184 	ai_move, -3, NULL,
185 	ai_move, -3, NULL,
186 	ai_move, 0,  NULL,
187 	ai_move, -1, NULL,
188 	ai_move, -2, NULL,
189 	ai_move, 0,  NULL,
190 	ai_move, 0,  NULL,
191 	ai_move, 2,  NULL,
192 	ai_move, 5,  NULL,
193 	ai_move, 2,  NULL
194 };
195 mmove_t infantry_move_pain2 = {FRAME_pain201, FRAME_pain210, infantry_frames_pain2, infantry_run};
196 
infantry_pain(edict_t * self,edict_t * other,float kick,int damage)197 void infantry_pain (edict_t *self, edict_t *other, float kick, int damage)
198 {
199 	int		n;
200 
201 	if (self->health < (self->max_health / 2))
202 		self->s.skinnum = 1;
203 
204 	if (!self->groundentity)
205 	{
206 //		if ((g_showlogic) && (g_showlogic->value))
207 //			gi.dprintf ("infantry: pain avoided due to no ground\n");
208 		return;
209 	}
210 
211 	monster_done_dodge (self);
212 
213 	if (level.time < self->pain_debounce_time)
214 		return;
215 
216 	self->pain_debounce_time = level.time + 3;
217 
218 	if (skill->value == 3)
219 		return;		// no pain anims in nightmare
220 
221 	n = rand() % 2;
222 	if (n == 0)
223 	{
224 		self->monsterinfo.currentmove = &infantry_move_pain1;
225 		gi.sound (self, CHAN_VOICE, sound_pain1, 1, ATTN_NORM, 0);
226 	}
227 	else
228 	{
229 		self->monsterinfo.currentmove = &infantry_move_pain2;
230 		gi.sound (self, CHAN_VOICE, sound_pain2, 1, ATTN_NORM, 0);
231 	}
232 
233 	// PMM - clear duck flag
234 	if (self->monsterinfo.aiflags & AI_DUCKED)
235 		monster_duck_up(self);
236 }
237 
238 
239 vec3_t	aimangles[] =
240 {
241 	0.0, 5.0, 0.0,
242 	10.0, 15.0, 0.0,
243 	20.0, 25.0, 0.0,
244 	25.0, 35.0, 0.0,
245 	30.0, 40.0, 0.0,
246 	30.0, 45.0, 0.0,
247 	25.0, 50.0, 0.0,
248 	20.0, 40.0, 0.0,
249 	15.0, 35.0, 0.0,
250 	40.0, 35.0, 0.0,
251 	70.0, 35.0, 0.0,
252 	90.0, 35.0, 0.0
253 };
254 
InfantryMachineGun(edict_t * self)255 void InfantryMachineGun (edict_t *self)
256 {
257 	vec3_t	start, target;
258 	vec3_t	forward, right;
259 	vec3_t	vec;
260 	int		flash_number;
261 
262 	if(!self->enemy || !self->enemy->inuse)		//PGM
263 		return;									//PGM
264 
265 	// pmm - new attack start frame
266 	if (self->s.frame == FRAME_attak104)
267 	{
268 		flash_number = MZ2_INFANTRY_MACHINEGUN_1;
269 		AngleVectors (self->s.angles, forward, right, NULL);
270 		G_ProjectSource (self->s.origin, monster_flash_offset[flash_number], forward, right, start);
271 
272 		if (self->enemy)
273 		{
274 			VectorMA (self->enemy->s.origin, -0.2, self->enemy->velocity, target);
275 			target[2] += self->enemy->viewheight;
276 			VectorSubtract (target, start, forward);
277 			VectorNormalize (forward);
278 		}
279 		else
280 		{
281 			AngleVectors (self->s.angles, forward, right, NULL);
282 		}
283 	}
284 	else
285 	{
286 		flash_number = MZ2_INFANTRY_MACHINEGUN_2 + (self->s.frame - FRAME_death211);
287 
288 		AngleVectors (self->s.angles, forward, right, NULL);
289 		G_ProjectSource (self->s.origin, monster_flash_offset[flash_number], forward, right, start);
290 
291 		VectorSubtract (self->s.angles, aimangles[flash_number-MZ2_INFANTRY_MACHINEGUN_2], vec);
292 		AngleVectors (vec, forward, NULL, NULL);
293 	}
294 
295 	monster_fire_bullet (self, start, forward, 3, 4, DEFAULT_BULLET_HSPREAD, DEFAULT_BULLET_VSPREAD, flash_number);
296 }
297 
infantry_sight(edict_t * self,edict_t * other)298 void infantry_sight (edict_t *self, edict_t *other)
299 {
300 	gi.sound (self, CHAN_BODY, sound_sight, 1, ATTN_NORM, 0);
301 }
302 
infantry_dead(edict_t * self)303 void infantry_dead (edict_t *self)
304 {
305 	VectorSet (self->mins, -16, -16, -24);
306 	VectorSet (self->maxs, 16, 16, -8);
307 	self->movetype = MOVETYPE_TOSS;
308 	self->svflags |= SVF_DEADMONSTER;
309 	gi.linkentity (self);
310 
311 	M_FlyCheck (self);
312 }
313 
314 mframe_t infantry_frames_death1 [] =
315 {
316 	ai_move, -4, NULL,
317 	ai_move, 0,  NULL,
318 	ai_move, 0,  NULL,
319 	ai_move, -1, NULL,
320 	ai_move, -4, NULL,
321 	ai_move, 0,  NULL,
322 	ai_move, 0,  NULL,
323 	ai_move, 0,  NULL,
324 	ai_move, -1, NULL,
325 	ai_move, 3,  NULL,
326 	ai_move, 1,  NULL,
327 	ai_move, 1,  NULL,
328 	ai_move, -2, NULL,
329 	ai_move, 2,  NULL,
330 	ai_move, 2,  NULL,
331 	ai_move, 9,  NULL,
332 	ai_move, 9,  NULL,
333 	ai_move, 5,  NULL,
334 	ai_move, -3, NULL,
335 	ai_move, -3, NULL
336 };
337 mmove_t infantry_move_death1 = {FRAME_death101, FRAME_death120, infantry_frames_death1, infantry_dead};
338 
339 // Off with his head
340 mframe_t infantry_frames_death2 [] =
341 {
342 	ai_move, 0,   NULL,
343 	ai_move, 1,   NULL,
344 	ai_move, 5,   NULL,
345 	ai_move, -1,  NULL,
346 	ai_move, 0,   NULL,
347 	ai_move, 1,   NULL,
348 	ai_move, 1,   NULL,
349 	ai_move, 4,   NULL,
350 	ai_move, 3,   NULL,
351 	ai_move, 0,   NULL,
352 	ai_move, -2,  InfantryMachineGun,
353 	ai_move, -2,  InfantryMachineGun,
354 	ai_move, -3,  InfantryMachineGun,
355 	ai_move, -1,  InfantryMachineGun,
356 	ai_move, -2,  InfantryMachineGun,
357 	ai_move, 0,   InfantryMachineGun,
358 	ai_move, 2,   InfantryMachineGun,
359 	ai_move, 2,   InfantryMachineGun,
360 	ai_move, 3,   InfantryMachineGun,
361 	ai_move, -10, InfantryMachineGun,
362 	ai_move, -7,  InfantryMachineGun,
363 	ai_move, -8,  InfantryMachineGun,
364 	ai_move, -6,  NULL,
365 	ai_move, 4,   NULL,
366 	ai_move, 0,   NULL
367 };
368 mmove_t infantry_move_death2 = {FRAME_death201, FRAME_death225, infantry_frames_death2, infantry_dead};
369 
370 mframe_t infantry_frames_death3 [] =
371 {
372 	ai_move, 0,   NULL,
373 	ai_move, 0,   NULL,
374 	ai_move, 0,   NULL,
375 	ai_move, -6,  NULL,
376 	ai_move, -11, NULL,
377 	ai_move, -3,  NULL,
378 	ai_move, -11, NULL,
379 	ai_move, 0,   NULL,
380 	ai_move, 0,   NULL
381 };
382 mmove_t infantry_move_death3 = {FRAME_death301, FRAME_death309, infantry_frames_death3, infantry_dead};
383 
384 
infantry_die(edict_t * self,edict_t * inflictor,edict_t * attacker,int damage,vec3_t point)385 void infantry_die (edict_t *self, edict_t *inflictor, edict_t *attacker, int damage, vec3_t point)
386 {
387 	int		n;
388 
389 // check for gib
390 	if (self->health <= self->gib_health)
391 	{
392 		gi.sound (self, CHAN_VOICE, gi.soundindex ("misc/udeath.wav"), 1, ATTN_NORM, 0);
393 		for (n= 0; n < 2; n++)
394 			ThrowGib (self, "models/objects/gibs/bone/tris.md2", damage, GIB_ORGANIC);
395 		for (n= 0; n < 4; n++)
396 			ThrowGib (self, "models/objects/gibs/sm_meat/tris.md2", damage, GIB_ORGANIC);
397 		ThrowHead (self, "models/objects/gibs/head2/tris.md2", damage, GIB_ORGANIC);
398 		self->deadflag = DEAD_DEAD;
399 		return;
400 	}
401 
402 	if (self->deadflag == DEAD_DEAD)
403 		return;
404 
405 // regular death
406 	self->deadflag = DEAD_DEAD;
407 	self->takedamage = DAMAGE_YES;
408 
409 	n = rand() % 3;
410 	if (n == 0)
411 	{
412 		self->monsterinfo.currentmove = &infantry_move_death1;
413 		gi.sound (self, CHAN_VOICE, sound_die2, 1, ATTN_NORM, 0);
414 	}
415 	else if (n == 1)
416 	{
417 		self->monsterinfo.currentmove = &infantry_move_death2;
418 		gi.sound (self, CHAN_VOICE, sound_die1, 1, ATTN_NORM, 0);
419 	}
420 	else
421 	{
422 		self->monsterinfo.currentmove = &infantry_move_death3;
423 		gi.sound (self, CHAN_VOICE, sound_die2, 1, ATTN_NORM, 0);
424 	}
425 }
426 
427 mframe_t infantry_frames_duck [] =
428 {
429 	ai_move, -2, monster_duck_down,
430 	ai_move, -5, monster_duck_hold,
431 	ai_move, 3,  NULL,
432 	ai_move, 4,  monster_duck_up,
433 	ai_move, 0,  NULL
434 };
435 mmove_t infantry_move_duck = {FRAME_duck01, FRAME_duck05, infantry_frames_duck, infantry_run};
436 
437 // PMM - dodge code moved below so I can see the attack frames
438 
439 
infantry_cock_gun(edict_t * self)440 void infantry_cock_gun (edict_t *self)
441 {
442 	// pmm .. code that was here no longer needed
443 	gi.sound (self, CHAN_WEAPON, sound_weapon_cock, 1, ATTN_NORM, 0);
444 }
445 
infantry_fire(edict_t * self)446 void infantry_fire (edict_t *self)
447 {
448 	InfantryMachineGun (self);
449 	if (level.time >= self->monsterinfo.pausetime)
450 		self->monsterinfo.aiflags &= ~AI_HOLD_FRAME;
451 	else
452 		self->monsterinfo.aiflags |= AI_HOLD_FRAME;
453 }
454 
455 // this is here instead of cock_gun
456 
infantry_fire_prep(edict_t * self)457 void infantry_fire_prep (edict_t *self)
458 {
459 	int n;
460 	n = (rand() & 15) + 3 + 1;
461 	self->monsterinfo.pausetime = level.time + n*FRAMETIME;
462 }
463 
464 // pmm
465 // frames reordered, tweaked for new frames
466 
467 mframe_t infantry_frames_attack1 [] =
468 {
469 	ai_charge, -3, NULL,					//101
470 	ai_charge, -2, NULL,					//102
471 	ai_charge, -1, infantry_fire_prep,		//103
472 	ai_charge, 5,  infantry_fire,			//104
473 	ai_charge, 1,  NULL,					//105
474 	ai_charge, -3, NULL,					//106
475 	ai_charge, -2, NULL,					//107
476 	ai_charge, 2,  infantry_cock_gun,		//108
477 	ai_charge, 1,  NULL,					//109
478 	ai_charge, 1,  NULL,					//110
479 	ai_charge, -1, NULL,					//111
480 	ai_charge, 0,  NULL,					//112
481 	ai_charge, -1, NULL,					//113
482 	ai_charge, -1, NULL,					//114
483 	ai_charge, 4,  NULL						//115
484 };
485 mmove_t infantry_move_attack1 = {FRAME_attak101, FRAME_attak115, infantry_frames_attack1, infantry_run};
486 
487 
infantry_swing(edict_t * self)488 void infantry_swing (edict_t *self)
489 {
490 	gi.sound (self, CHAN_WEAPON, sound_punch_swing, 1, ATTN_NORM, 0);
491 }
492 
infantry_smack(edict_t * self)493 void infantry_smack (edict_t *self)
494 {
495 	vec3_t	aim;
496 
497 	VectorSet (aim, MELEE_DISTANCE, 0, 0);
498 	if (fire_hit (self, aim, (5 + (rand() % 5)), 50))
499 		gi.sound (self, CHAN_WEAPON, sound_punch_hit, 1, ATTN_NORM, 0);
500 }
501 
502 mframe_t infantry_frames_attack2 [] =
503 {
504 	ai_charge, 3, NULL,
505 	ai_charge, 6, NULL,
506 	ai_charge, 0, infantry_swing,
507 	ai_charge, 8, NULL,
508 	ai_charge, 5, NULL,
509 	ai_charge, 8, infantry_smack,
510 	ai_charge, 6, NULL,
511 	ai_charge, 3, NULL,
512 };
513 mmove_t infantry_move_attack2 = {FRAME_attak201, FRAME_attak208, infantry_frames_attack2, infantry_run};
514 
infantry_attack(edict_t * self)515 void infantry_attack(edict_t *self)
516 {
517 	monster_done_dodge (self);
518 
519 	if (range (self, self->enemy) == RANGE_MELEE)
520 		self->monsterinfo.currentmove = &infantry_move_attack2;
521 	else
522 		self->monsterinfo.currentmove = &infantry_move_attack1;
523 }
524 
525 //===========
526 //PGM
infantry_jump_now(edict_t * self)527 void infantry_jump_now (edict_t *self)
528 {
529 	vec3_t	forward,up;
530 
531 	monster_jump_start (self);
532 
533 	AngleVectors (self->s.angles, forward, NULL, up);
534 	VectorMA(self->velocity, 100, forward, self->velocity);
535 	VectorMA(self->velocity, 300, up, self->velocity);
536 }
537 
infantry_jump2_now(edict_t * self)538 void infantry_jump2_now (edict_t *self)
539 {
540 	vec3_t	forward,up;
541 
542 	monster_jump_start (self);
543 
544 	AngleVectors (self->s.angles, forward, NULL, up);
545 	VectorMA(self->velocity, 150, forward, self->velocity);
546 	VectorMA(self->velocity, 400, up, self->velocity);
547 }
548 
infantry_jump_wait_land(edict_t * self)549 void infantry_jump_wait_land (edict_t *self)
550 {
551 	if(self->groundentity == NULL)
552 	{
553 		self->monsterinfo.nextframe = self->s.frame;
554 
555 		if(monster_jump_finished (self))
556 			self->monsterinfo.nextframe = self->s.frame + 1;
557 	}
558 	else
559 		self->monsterinfo.nextframe = self->s.frame + 1;
560 }
561 
562 mframe_t infantry_frames_jump [] =
563 {
564 	ai_move, 0, NULL,
565 	ai_move, 0, NULL,
566 	ai_move, 0, NULL,
567 	ai_move, 0, infantry_jump_now,
568 	ai_move, 0, NULL,
569 	ai_move, 0, NULL,
570 	ai_move, 0, NULL,
571 	ai_move, 0, infantry_jump_wait_land,
572 	ai_move, 0, NULL,
573 	ai_move, 0, NULL
574 };
575 mmove_t infantry_move_jump = { FRAME_jump01, FRAME_jump10, infantry_frames_jump, infantry_run };
576 
577 mframe_t infantry_frames_jump2 [] =
578 {
579 	ai_move, -8, NULL,
580 	ai_move, -4, NULL,
581 	ai_move, -4, NULL,
582 	ai_move, 0, infantry_jump_now,
583 	ai_move, 0, NULL,
584 	ai_move, 0, NULL,
585 	ai_move, 0, NULL,
586 	ai_move, 0, infantry_jump_wait_land,
587 	ai_move, 0, NULL,
588 	ai_move, 0, NULL
589 };
590 mmove_t infantry_move_jump2 = { FRAME_jump01, FRAME_jump10, infantry_frames_jump2, infantry_run };
591 
infantry_jump(edict_t * self)592 void infantry_jump (edict_t *self)
593 {
594 	if(!self->enemy)
595 		return;
596 
597 	monster_done_dodge(self);
598 
599 	if(self->enemy->s.origin[2] > self->s.origin[2])
600 		self->monsterinfo.currentmove = &infantry_move_jump2;
601 	else
602 		self->monsterinfo.currentmove = &infantry_move_jump;
603 }
604 
infantry_blocked(edict_t * self,float dist)605 qboolean infantry_blocked (edict_t *self, float dist)
606 {
607 	if(blocked_checkshot (self, 0.25 + (0.05 * skill->value) ))
608 		return true;
609 
610 	if(blocked_checkjump (self, dist, 192, 40))
611 	{
612 		infantry_jump(self);
613 		return true;
614 	}
615 
616 	if(blocked_checkplat (self, dist))
617 		return true;
618 
619 	return false;
620 }
621 //PGM
622 //===========
623 /*
624 void infantry_dodge (edict_t *self, edict_t *attacker, float eta, trace_t *tr)
625 {
626 //===========
627 //PMM - rogue rewrite of gunner dodge code.
628 	float	r;
629 	float	height;
630 	int		shooting = 0;
631 
632 	if (!self->enemy)
633 	{
634 		self->enemy = attacker;
635 		FoundTarget (self);
636 	}
637 
638 	// PMM - don't bother if it's going to hit anyway; fix for weird in-your-face etas (I was
639 	// seeing numbers like 13 and 14)
640 	if ((eta < 0.1) || (eta > 5))
641 		return;
642 
643 	r = random();
644 	if (r > (0.25*((skill->value)+1)))
645 		return;
646 
647 	if ((self->monsterinfo.currentmove == &infantry_move_attack1) ||
648 		(self->monsterinfo.currentmove == &infantry_move_attack2))
649 	{
650 		shooting = 1;
651 	}
652 	if (self->monsterinfo.aiflags & AI_DODGING)
653 	{
654 		height = self->absmax[2];
655 	}
656 	else
657 	{
658 		height = self->absmax[2]-32-1;  // the -1 is because the absmax is s.origin + maxs + 1
659 	}
660 
661 	// check to see if it makes sense to duck
662 	if (tr->endpos[2] <= height)
663 	{
664 		vec3_t right,diff;
665 
666 		if (shooting)
667 		{
668 			self->monsterinfo.attack_state = AS_SLIDING;
669 			return;
670 		}
671 		AngleVectors (self->s.angles, NULL, right, NULL);
672 		VectorSubtract (tr->endpos, self->s.origin, diff);
673 		if (DotProduct (right, diff) < 0)
674 		{
675 			self->monsterinfo.lefty = 1;
676 		}
677 		// if it doesn't sense to duck, try to strafe away
678 		monster_done_dodge (self);
679 		self->monsterinfo.currentmove = &infantry_move_run;
680 		self->monsterinfo.attack_state = AS_SLIDING;
681 		return;
682 	}
683 
684 	if (skill->value == 0)
685 	{
686 		self->monsterinfo.currentmove = &infantry_move_duck;
687 		// PMM - stupid dodge
688 		self->monsterinfo.duck_wait_time = level.time + eta + 1;
689 		self->monsterinfo.aiflags |= AI_DODGING;
690 		return;
691 	}
692 
693 	if (!shooting)
694 	{
695 		self->monsterinfo.currentmove = &infantry_move_duck;
696 		self->monsterinfo.duck_wait_time = level.time + eta + (0.1 * (3 - skill->value));
697 		self->monsterinfo.aiflags |= AI_DODGING;
698 	}
699 	return;
700 //PMM
701 //===========
702 */
703 
infantry_duck(edict_t * self,float eta)704 void infantry_duck (edict_t *self, float eta)
705 {
706 	// if we're jumping, don't dodge
707 	if ((self->monsterinfo.currentmove == &infantry_move_jump) ||
708 		(self->monsterinfo.currentmove == &infantry_move_jump2))
709 	{
710 		return;
711 	}
712 
713 	if ((self->monsterinfo.currentmove == &infantry_move_attack1) ||
714 		(self->monsterinfo.currentmove == &infantry_move_attack2))
715 	{
716 		// if we're shooting, and not on easy, don't dodge
717 		if (skill->value)
718 		{
719 			self->monsterinfo.aiflags &= ~AI_DUCKED;
720 			return;
721 		}
722 	}
723 
724 	if (skill->value == 0)
725 		// PMM - stupid dodge
726 		self->monsterinfo.duck_wait_time = level.time + eta + 1;
727 	else
728 		self->monsterinfo.duck_wait_time = level.time + eta + (0.1 * (3 - skill->value));
729 
730 	// has to be done immediately otherwise he can get stuck
731 	monster_duck_down(self);
732 
733 	self->monsterinfo.nextframe = FRAME_duck01;
734 	self->monsterinfo.currentmove = &infantry_move_duck;
735 	return;
736 }
737 
infantry_sidestep(edict_t * self)738 void infantry_sidestep (edict_t *self)
739 {
740 	// if we're jumping, don't dodge
741 	if ((self->monsterinfo.currentmove == &infantry_move_jump) ||
742 		(self->monsterinfo.currentmove == &infantry_move_jump2))
743 	{
744 		return;
745 	}
746 
747 	if ((self->monsterinfo.currentmove == &infantry_move_attack1) ||
748 		(self->monsterinfo.currentmove == &infantry_move_attack2))
749 	{
750 		// if we're shooting, and not on easy, don't dodge
751 		if (skill->value)
752 		{
753 			self->monsterinfo.aiflags &= ~AI_DODGING;
754 			return;
755 		}
756 	}
757 
758 	if (self->monsterinfo.currentmove != &infantry_move_run)
759 		self->monsterinfo.currentmove = &infantry_move_run;
760 }
761 
762 /*QUAKED monster_infantry (1 .5 0) (-16 -16 -24) (16 16 32) Ambush Trigger_Spawn Sight
763 */
SP_monster_infantry(edict_t * self)764 void SP_monster_infantry (edict_t *self)
765 {
766 	if (deathmatch->value)
767 	{
768 		G_FreeEdict (self);
769 		return;
770 	}
771 
772 	sound_pain1 = gi.soundindex ("infantry/infpain1.wav");
773 	sound_pain2 = gi.soundindex ("infantry/infpain2.wav");
774 	sound_die1 = gi.soundindex ("infantry/infdeth1.wav");
775 	sound_die2 = gi.soundindex ("infantry/infdeth2.wav");
776 
777 	sound_gunshot = gi.soundindex ("infantry/infatck1.wav");
778 	sound_weapon_cock = gi.soundindex ("infantry/infatck3.wav");
779 	sound_punch_swing = gi.soundindex ("infantry/infatck2.wav");
780 	sound_punch_hit = gi.soundindex ("infantry/melee2.wav");
781 
782 	sound_sight = gi.soundindex ("infantry/infsght1.wav");
783 	sound_search = gi.soundindex ("infantry/infsrch1.wav");
784 	sound_idle = gi.soundindex ("infantry/infidle1.wav");
785 
786 
787 	self->movetype = MOVETYPE_STEP;
788 	self->solid = SOLID_BBOX;
789 	self->s.modelindex = gi.modelindex("models/monsters/infantry/tris.md2");
790 	VectorSet (self->mins, -16, -16, -24);
791 	VectorSet (self->maxs, 16, 16, 32);
792 
793 	self->health = 100;
794 	self->gib_health = -40;
795 	self->mass = 200;
796 
797 	self->pain = infantry_pain;
798 	self->die = infantry_die;
799 
800 	self->monsterinfo.stand = infantry_stand;
801 	self->monsterinfo.walk = infantry_walk;
802 	self->monsterinfo.run = infantry_run;
803 	// pmm
804 	self->monsterinfo.dodge = M_MonsterDodge;
805 	self->monsterinfo.duck = infantry_duck;
806 	self->monsterinfo.unduck = monster_duck_up;
807 	self->monsterinfo.sidestep = infantry_sidestep;
808 //	self->monsterinfo.dodge = infantry_dodge;
809 	// pmm
810 	self->monsterinfo.attack = infantry_attack;
811 	self->monsterinfo.melee = NULL;
812 	self->monsterinfo.sight = infantry_sight;
813 	self->monsterinfo.idle = infantry_fidget;
814 	self->monsterinfo.blocked = infantry_blocked;
815 
816 	gi.linkentity (self);
817 
818 	self->monsterinfo.currentmove = &infantry_move_stand;
819 	self->monsterinfo.scale = MODEL_SCALE;
820 
821 	walkmonster_start (self);
822 }
823