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