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 Vec3Set (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 Vec3Set (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->floatVal == 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,cBspPlane_t * plane,cBspSurface_t * surf)308 void mutant_jump_touch (edict_t *self, edict_t *other, cBspPlane_t *plane, cBspSurface_t *surf)
309 {
310 if (self->health <= 0)
311 {
312 self->touch = NULL;
313 return;
314 }
315
316 if (other->takedamage)
317 {
318 if (Vec3Length(self->velocity) > 400)
319 {
320 vec3_t point;
321 vec3_t normal;
322 int damage;
323
324 Vec3Copy (self->velocity, normal);
325 VectorNormalizef (normal, normal);
326 Vec3MA (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 Angles_Vectors (self->s.angles, forward, NULL, NULL);
351 self->s.origin[2] += 1;
352 Vec3Scale (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 qBool mutant_check_melee (edict_t *self)
400 {
401 if (range (self, self->enemy) == RANGE_MELEE)
402 return qTrue;
403 return qFalse;
404 }
405
mutant_check_jump(edict_t * self)406 qBool 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 qFalse;
413
414 if (self->absMax[2] < (self->enemy->absMin[2] + 0.25 * self->enemy->size[2]))
415 return qFalse;
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 = Vec3Length(v);
421
422 if (distance < 100)
423 return qFalse;
424 if (distance > 100)
425 {
426 if (random() < 0.9)
427 return qFalse;
428 }
429
430 return qTrue;
431 }
432
mutant_checkattack(edict_t * self)433 qBool mutant_checkattack (edict_t *self)
434 {
435 if (!self->enemy || self->enemy->health <= 0)
436 return qFalse;
437
438 if (mutant_check_melee(self))
439 {
440 self->monsterinfo.attack_state = AS_MELEE;
441 return qTrue;
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 qTrue;
449 }
450
451 return qFalse;
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->floatVal == 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 Vec3Set (self->mins, -16, -16, -24);
537 Vec3Set (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->floatVal)
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 Vec3Set (self->mins, -32, -32, -24);
637 Vec3Set (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