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 mutant
24
25 ==============================================================================
26 */
27
28 #include "g_local.h"
29 #include "m_mutant.h"
30
31
32 static int sound_swing;
33 static int sound_hit;
34 static int sound_hit2;
35 static int sound_death;
36 static int sound_idle;
37 static int sound_pain1;
38 static int sound_pain2;
39 static int sound_sight;
40 static int sound_search;
41 static int sound_step1;
42 static int sound_step2;
43 static int sound_step3;
44 static int sound_thud;
45
46 //
47 // SOUNDS
48 //
49
mutant_step(edict_t * self)50 void mutant_step (edict_t *self)
51 {
52 int n;
53 n = (rand() + 1) % 3;
54 if (n == 0)
55 gi.sound (self, CHAN_VOICE, sound_step1, 1, ATTN_NORM, 0);
56 else if (n == 1)
57 gi.sound (self, CHAN_VOICE, sound_step2, 1, ATTN_NORM, 0);
58 else
59 gi.sound (self, CHAN_VOICE, sound_step3, 1, ATTN_NORM, 0);
60 }
61
mutant_sight(edict_t * self,edict_t * other)62 void mutant_sight (edict_t *self, edict_t *other)
63 {
64 gi.sound (self, CHAN_VOICE, sound_sight, 1, ATTN_NORM, 0);
65 }
66
mutant_search(edict_t * self)67 void mutant_search (edict_t *self)
68 {
69 gi.sound (self, CHAN_VOICE, sound_search, 1, ATTN_NORM, 0);
70 }
71
mutant_swing(edict_t * self)72 void mutant_swing (edict_t *self)
73 {
74 gi.sound (self, CHAN_VOICE, sound_swing, 1, ATTN_NORM, 0);
75 }
76
77
78 //
79 // STAND
80 //
81
82 mframe_t mutant_frames_stand [] =
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}, // 10
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}, // 20
105
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 {ai_stand, 0, NULL},
113 {ai_stand, 0, NULL},
114 {ai_stand, 0, NULL},
115 {ai_stand, 0, NULL}, // 30
116
117 {ai_stand, 0, NULL},
118 {ai_stand, 0, NULL},
119 {ai_stand, 0, NULL},
120 {ai_stand, 0, NULL},
121 {ai_stand, 0, NULL},
122 {ai_stand, 0, NULL},
123 {ai_stand, 0, NULL},
124 {ai_stand, 0, NULL},
125 {ai_stand, 0, NULL},
126 {ai_stand, 0, NULL}, // 40
127
128 {ai_stand, 0, NULL},
129 {ai_stand, 0, NULL},
130 {ai_stand, 0, NULL},
131 {ai_stand, 0, NULL},
132 {ai_stand, 0, NULL},
133 {ai_stand, 0, NULL},
134 {ai_stand, 0, NULL},
135 {ai_stand, 0, NULL},
136 {ai_stand, 0, NULL},
137 {ai_stand, 0, NULL}, // 50
138
139 {ai_stand, 0, NULL}
140 };
141 mmove_t mutant_move_stand = {FRAME_stand101, FRAME_stand151, mutant_frames_stand, NULL};
142
mutant_stand(edict_t * self)143 void mutant_stand (edict_t *self)
144 {
145 self->monsterinfo.currentmove = &mutant_move_stand;
146 }
147
148
149 //
150 // IDLE
151 //
152
mutant_idle_loop(edict_t * self)153 void mutant_idle_loop (edict_t *self)
154 {
155 if (random() < 0.75)
156 self->monsterinfo.nextframe = FRAME_stand155;
157 }
158
159 mframe_t mutant_frames_idle [] =
160 {
161 {ai_stand, 0, NULL},
162 {ai_stand, 0, NULL},
163 {ai_stand, 0, NULL},
164 {ai_stand, 0, NULL}, // scratch loop start
165 {ai_stand, 0, NULL},
166 {ai_stand, 0, NULL},
167 {ai_stand, 0, mutant_idle_loop}, // scratch loop end
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 };
175 mmove_t mutant_move_idle = {FRAME_stand152, FRAME_stand164, mutant_frames_idle, mutant_stand};
176
mutant_idle(edict_t * self)177 void mutant_idle (edict_t *self)
178 {
179 self->monsterinfo.currentmove = &mutant_move_idle;
180 gi.sound (self, CHAN_VOICE, sound_idle, 1, ATTN_IDLE, 0);
181 }
182
183
184 //
185 // WALK
186 //
187
188 void mutant_walk (edict_t *self);
189
190 mframe_t mutant_frames_walk [] =
191 {
192 {ai_walk, 3, NULL},
193 {ai_walk, 1, NULL},
194 {ai_walk, 5, NULL},
195 {ai_walk, 10, NULL},
196 {ai_walk, 13, NULL},
197 {ai_walk, 10, NULL},
198 {ai_walk, 0, NULL},
199 {ai_walk, 5, NULL},
200 {ai_walk, 6, NULL},
201 {ai_walk, 16, NULL},
202 {ai_walk, 15, NULL},
203 {ai_walk, 6, NULL}
204 };
205 mmove_t mutant_move_walk = {FRAME_walk05, FRAME_walk16, mutant_frames_walk, NULL};
206
mutant_walk_loop(edict_t * self)207 void mutant_walk_loop (edict_t *self)
208 {
209 self->monsterinfo.currentmove = &mutant_move_walk;
210 }
211
212 mframe_t mutant_frames_start_walk [] =
213 {
214 {ai_walk, 5, NULL},
215 {ai_walk, 5, NULL},
216 {ai_walk, -2, NULL},
217 {ai_walk, 1, NULL}
218 };
219 mmove_t mutant_move_start_walk = {FRAME_walk01, FRAME_walk04, mutant_frames_start_walk, mutant_walk_loop};
220
mutant_walk(edict_t * self)221 void mutant_walk (edict_t *self)
222 {
223 self->monsterinfo.currentmove = &mutant_move_start_walk;
224 }
225
226
227 //
228 // RUN
229 //
230
231 mframe_t mutant_frames_run [] =
232 {
233 {ai_run, 40, NULL},
234 {ai_run, 40, mutant_step},
235 {ai_run, 24, NULL},
236 {ai_run, 5, mutant_step},
237 {ai_run, 17, NULL},
238 {ai_run, 10, NULL}
239 };
240 mmove_t mutant_move_run = {FRAME_run03, FRAME_run08, mutant_frames_run, NULL};
241
mutant_run(edict_t * self)242 void mutant_run (edict_t *self)
243 {
244 if (self->monsterinfo.aiflags & AI_STAND_GROUND)
245 self->monsterinfo.currentmove = &mutant_move_stand;
246 else
247 self->monsterinfo.currentmove = &mutant_move_run;
248 }
249
250
251 //
252 // MELEE
253 //
254
mutant_hit_left(edict_t * self)255 void mutant_hit_left (edict_t *self)
256 {
257 vec3_t aim;
258
259 VectorSet (aim, MELEE_DISTANCE, self->mins[0], 8);
260 if (fire_hit (self, aim, (10 + (rand() %5)), 100))
261 gi.sound (self, CHAN_WEAPON, sound_hit, 1, ATTN_NORM, 0);
262 else
263 gi.sound (self, CHAN_WEAPON, sound_swing, 1, ATTN_NORM, 0);
264 }
265
mutant_hit_right(edict_t * self)266 void mutant_hit_right (edict_t *self)
267 {
268 vec3_t aim;
269
270 VectorSet (aim, MELEE_DISTANCE, self->maxs[0], 8);
271 if (fire_hit (self, aim, (10 + (rand() %5)), 100))
272 gi.sound (self, CHAN_WEAPON, sound_hit2, 1, ATTN_NORM, 0);
273 else
274 gi.sound (self, CHAN_WEAPON, sound_swing, 1, ATTN_NORM, 0);
275 }
276
mutant_check_refire(edict_t * self)277 void mutant_check_refire (edict_t *self)
278 {
279 if (!self->enemy || !self->enemy->inuse || self->enemy->health <= 0)
280 return;
281
282 if ( ((skill->value == 3) && (random() < 0.5)) || (range(self, self->enemy) == RANGE_MELEE) )
283 self->monsterinfo.nextframe = FRAME_attack09;
284 }
285
286 mframe_t mutant_frames_attack [] =
287 {
288 {ai_charge, 0, NULL},
289 {ai_charge, 0, NULL},
290 {ai_charge, 0, mutant_hit_left},
291 {ai_charge, 0, NULL},
292 {ai_charge, 0, NULL},
293 {ai_charge, 0, mutant_hit_right},
294 {ai_charge, 0, mutant_check_refire}
295 };
296 mmove_t mutant_move_attack = {FRAME_attack09, FRAME_attack15, mutant_frames_attack, mutant_run};
297
mutant_melee(edict_t * self)298 void mutant_melee (edict_t *self)
299 {
300 self->monsterinfo.currentmove = &mutant_move_attack;
301 }
302
303
304 //
305 // ATTACK
306 //
307
mutant_jump_touch(edict_t * self,edict_t * other,cplane_t * plane,csurface_t * surf)308 void mutant_jump_touch (edict_t *self, edict_t *other, cplane_t *plane, csurface_t *surf)
309 {
310 if (self->health <= 0)
311 {
312 self->touch = NULL;
313 return;
314 }
315
316 if (other->takedamage)
317 {
318 if (VectorLength(self->velocity) > 400)
319 {
320 vec3_t point;
321 vec3_t normal;
322 int damage;
323
324 VectorCopy (self->velocity, normal);
325 VectorNormalize(normal);
326 VectorMA (self->s.origin, self->maxs[0], normal, point);
327 damage = 40 + 10 * random();
328 T_Damage (other, self, self, self->velocity, point, normal, damage, damage, 0, MOD_UNKNOWN);
329 }
330 }
331
332 if (!M_CheckBottom (self))
333 {
334 if (self->groundentity)
335 {
336 self->monsterinfo.nextframe = FRAME_attack02;
337 self->touch = NULL;
338 }
339 return;
340 }
341
342 self->touch = NULL;
343 }
344
mutant_jump_takeoff(edict_t * self)345 void mutant_jump_takeoff (edict_t *self)
346 {
347 vec3_t forward;
348
349 gi.sound (self, CHAN_VOICE, sound_sight, 1, ATTN_NORM, 0);
350 AngleVectors (self->s.angles, forward, NULL, NULL);
351 self->s.origin[2] += 1;
352 VectorScale (forward, 600, self->velocity);
353 self->velocity[2] = 250;
354 self->groundentity = NULL;
355 self->monsterinfo.aiflags |= AI_DUCKED;
356 self->monsterinfo.attack_finished = level.time + 3;
357 self->touch = mutant_jump_touch;
358 }
359
mutant_check_landing(edict_t * self)360 void mutant_check_landing (edict_t *self)
361 {
362 if (self->groundentity)
363 {
364 gi.sound (self, CHAN_WEAPON, sound_thud, 1, ATTN_NORM, 0);
365 self->monsterinfo.attack_finished = 0;
366 self->monsterinfo.aiflags &= ~AI_DUCKED;
367 return;
368 }
369
370 if (level.time > self->monsterinfo.attack_finished)
371 self->monsterinfo.nextframe = FRAME_attack02;
372 else
373 self->monsterinfo.nextframe = FRAME_attack05;
374 }
375
376 mframe_t mutant_frames_jump [] =
377 {
378 {ai_charge, 0, NULL},
379 {ai_charge, 17, NULL},
380 {ai_charge, 15, mutant_jump_takeoff},
381 {ai_charge, 15, NULL},
382 {ai_charge, 15, mutant_check_landing},
383 {ai_charge, 0, NULL},
384 {ai_charge, 3, NULL},
385 {ai_charge, 0, NULL}
386 };
387 mmove_t mutant_move_jump = {FRAME_attack01, FRAME_attack08, mutant_frames_jump, mutant_run};
388
mutant_jump(edict_t * self)389 void mutant_jump (edict_t *self)
390 {
391 self->monsterinfo.currentmove = &mutant_move_jump;
392 }
393
394
395 //
396 // CHECKATTACK
397 //
398
mutant_check_melee(edict_t * self)399 qboolean mutant_check_melee (edict_t *self)
400 {
401 if (range (self, self->enemy) == RANGE_MELEE)
402 return true;
403 return false;
404 }
405
mutant_check_jump(edict_t * self)406 qboolean mutant_check_jump (edict_t *self)
407 {
408 vec3_t v;
409 float distance;
410
411 if (self->absmin[2] > (self->enemy->absmin[2] + 0.75 * self->enemy->size[2]))
412 return false;
413
414 if (self->absmax[2] < (self->enemy->absmin[2] + 0.25 * self->enemy->size[2]))
415 return false;
416
417 v[0] = self->s.origin[0] - self->enemy->s.origin[0];
418 v[1] = self->s.origin[1] - self->enemy->s.origin[1];
419 v[2] = 0;
420 distance = VectorLength(v);
421
422 if (distance < 100)
423 return false;
424 if (distance > 100)
425 {
426 if (random() < 0.9)
427 return false;
428 }
429
430 return true;
431 }
432
mutant_checkattack(edict_t * self)433 qboolean mutant_checkattack (edict_t *self)
434 {
435 if (!self->enemy || self->enemy->health <= 0)
436 return false;
437
438 if (mutant_check_melee(self))
439 {
440 self->monsterinfo.attack_state = AS_MELEE;
441 return true;
442 }
443
444 if (mutant_check_jump(self))
445 {
446 self->monsterinfo.attack_state = AS_MISSILE;
447 // FIXME play a jump sound here
448 return true;
449 }
450
451 return false;
452 }
453
454
455 //
456 // PAIN
457 //
458
459 mframe_t mutant_frames_pain1 [] =
460 {
461 {ai_move, 4, NULL},
462 {ai_move, -3, NULL},
463 {ai_move, -8, NULL},
464 {ai_move, 2, NULL},
465 {ai_move, 5, NULL}
466 };
467 mmove_t mutant_move_pain1 = {FRAME_pain101, FRAME_pain105, mutant_frames_pain1, mutant_run};
468
469 mframe_t mutant_frames_pain2 [] =
470 {
471 {ai_move, -24,NULL},
472 {ai_move, 11, NULL},
473 {ai_move, 5, NULL},
474 {ai_move, -2, NULL},
475 {ai_move, 6, NULL},
476 {ai_move, 4, NULL}
477 };
478 mmove_t mutant_move_pain2 = {FRAME_pain201, FRAME_pain206, mutant_frames_pain2, mutant_run};
479
480 mframe_t mutant_frames_pain3 [] =
481 {
482 {ai_move, -22,NULL},
483 {ai_move, 3, NULL},
484 {ai_move, 3, NULL},
485 {ai_move, 2, NULL},
486 {ai_move, 1, NULL},
487 {ai_move, 1, NULL},
488 {ai_move, 6, NULL},
489 {ai_move, 3, NULL},
490 {ai_move, 2, NULL},
491 {ai_move, 0, NULL},
492 {ai_move, 1, NULL}
493 };
494 mmove_t mutant_move_pain3 = {FRAME_pain301, FRAME_pain311, mutant_frames_pain3, mutant_run};
495
mutant_pain(edict_t * self,edict_t * other,float kick,int damage)496 void mutant_pain (edict_t *self, edict_t *other, float kick, int damage)
497 {
498 float r;
499
500 if (self->health < (self->max_health / 2))
501 self->s.skinnum = 1;
502
503 if (level.time < self->pain_debounce_time)
504 return;
505
506 self->pain_debounce_time = level.time + 3;
507
508 if (skill->value == 3)
509 return; // no pain anims in nightmare
510
511 r = random();
512 if (r < 0.33)
513 {
514 gi.sound (self, CHAN_VOICE, sound_pain1, 1, ATTN_NORM, 0);
515 self->monsterinfo.currentmove = &mutant_move_pain1;
516 }
517 else if (r < 0.66)
518 {
519 gi.sound (self, CHAN_VOICE, sound_pain2, 1, ATTN_NORM, 0);
520 self->monsterinfo.currentmove = &mutant_move_pain2;
521 }
522 else
523 {
524 gi.sound (self, CHAN_VOICE, sound_pain1, 1, ATTN_NORM, 0);
525 self->monsterinfo.currentmove = &mutant_move_pain3;
526 }
527 }
528
529
530 //
531 // DEATH
532 //
533
mutant_dead(edict_t * self)534 void mutant_dead (edict_t *self)
535 {
536 VectorSet (self->mins, -16, -16, -24);
537 VectorSet (self->maxs, 16, 16, -8);
538 self->movetype = MOVETYPE_TOSS;
539 self->svflags |= SVF_DEADMONSTER;
540 gi.linkentity (self);
541
542 M_FlyCheck (self);
543 }
544
545 mframe_t mutant_frames_death1 [] =
546 {
547 {ai_move, 0, NULL},
548 {ai_move, 0, NULL},
549 {ai_move, 0, NULL},
550 {ai_move, 0, NULL},
551 {ai_move, 0, NULL},
552 {ai_move, 0, NULL},
553 {ai_move, 0, NULL},
554 {ai_move, 0, NULL},
555 {ai_move, 0, NULL}
556 };
557 mmove_t mutant_move_death1 = {FRAME_death101, FRAME_death109, mutant_frames_death1, mutant_dead};
558
559 mframe_t mutant_frames_death2 [] =
560 {
561 {ai_move, 0, NULL},
562 {ai_move, 0, NULL},
563 {ai_move, 0, NULL},
564 {ai_move, 0, NULL},
565 {ai_move, 0, NULL},
566 {ai_move, 0, NULL},
567 {ai_move, 0, NULL},
568 {ai_move, 0, NULL},
569 {ai_move, 0, NULL},
570 {ai_move, 0, NULL}
571 };
572 mmove_t mutant_move_death2 = {FRAME_death201, FRAME_death210, mutant_frames_death2, mutant_dead};
573
mutant_die(edict_t * self,edict_t * inflictor,edict_t * attacker,int damage,vec3_t point)574 void mutant_die (edict_t *self, edict_t *inflictor, edict_t *attacker, int damage, vec3_t point)
575 {
576 int n;
577
578 if (self->health <= self->gib_health)
579 {
580 gi.sound (self, CHAN_VOICE, gi.soundindex ("misc/udeath.wav"), 1, ATTN_NORM, 0);
581 for (n= 0; n < 2; n++)
582 ThrowGib (self, "models/objects/gibs/bone/tris.md2", damage, GIB_ORGANIC);
583 for (n= 0; n < 4; n++)
584 ThrowGib (self, "models/objects/gibs/sm_meat/tris.md2", damage, GIB_ORGANIC);
585 ThrowHead (self, "models/objects/gibs/head2/tris.md2", damage, GIB_ORGANIC);
586 self->deadflag = DEAD_DEAD;
587 return;
588 }
589
590 if (self->deadflag == DEAD_DEAD)
591 return;
592
593 gi.sound (self, CHAN_VOICE, sound_death, 1, ATTN_NORM, 0);
594 self->deadflag = DEAD_DEAD;
595 self->takedamage = DAMAGE_YES;
596 self->s.skinnum = 1;
597
598 if (random() < 0.5)
599 self->monsterinfo.currentmove = &mutant_move_death1;
600 else
601 self->monsterinfo.currentmove = &mutant_move_death2;
602 }
603
604
605 //
606 // SPAWN
607 //
608
609 /*QUAKED monster_mutant (1 .5 0) (-32 -32 -24) (32 32 32) Ambush Trigger_Spawn Sight
610 */
SP_monster_mutant(edict_t * self)611 void SP_monster_mutant (edict_t *self)
612 {
613 if (deathmatch->value)
614 {
615 G_FreeEdict (self);
616 return;
617 }
618
619 sound_swing = gi.soundindex ("mutant/mutatck1.wav");
620 sound_hit = gi.soundindex ("mutant/mutatck2.wav");
621 sound_hit2 = gi.soundindex ("mutant/mutatck3.wav");
622 sound_death = gi.soundindex ("mutant/mutdeth1.wav");
623 sound_idle = gi.soundindex ("mutant/mutidle1.wav");
624 sound_pain1 = gi.soundindex ("mutant/mutpain1.wav");
625 sound_pain2 = gi.soundindex ("mutant/mutpain2.wav");
626 sound_sight = gi.soundindex ("mutant/mutsght1.wav");
627 sound_search = gi.soundindex ("mutant/mutsrch1.wav");
628 sound_step1 = gi.soundindex ("mutant/step1.wav");
629 sound_step2 = gi.soundindex ("mutant/step2.wav");
630 sound_step3 = gi.soundindex ("mutant/step3.wav");
631 sound_thud = gi.soundindex ("mutant/thud1.wav");
632
633 self->movetype = MOVETYPE_STEP;
634 self->solid = SOLID_BBOX;
635 self->s.modelindex = gi.modelindex ("models/monsters/mutant/tris.md2");
636 VectorSet (self->mins, -32, -32, -24);
637 VectorSet (self->maxs, 32, 32, 48);
638
639 self->health = 300;
640 self->gib_health = -120;
641 self->mass = 300;
642
643 self->pain = mutant_pain;
644 self->die = mutant_die;
645
646 self->monsterinfo.stand = mutant_stand;
647 self->monsterinfo.walk = mutant_walk;
648 self->monsterinfo.run = mutant_run;
649 self->monsterinfo.dodge = NULL;
650 self->monsterinfo.attack = mutant_jump;
651 self->monsterinfo.melee = mutant_melee;
652 self->monsterinfo.sight = mutant_sight;
653 self->monsterinfo.search = mutant_search;
654 self->monsterinfo.idle = mutant_idle;
655 self->monsterinfo.checkattack = mutant_checkattack;
656
657 gi.linkentity (self);
658
659 self->monsterinfo.currentmove = &mutant_move_stand;
660
661 self->monsterinfo.scale = MODEL_SCALE;
662 walkmonster_start (self);
663 }
664