1 /*
2 ==============================================================================
3
4 MEDIC
5
6 ==============================================================================
7 */
8
9 #include "g_local.h"
10 #include "m_medic.h"
11
12 qboolean visible (edict_t *self, edict_t *other);
13
14
15 static int sound_idle1;
16 static int sound_pain1;
17 static int sound_pain2;
18 static int sound_die;
19 static int sound_sight;
20 static int sound_search;
21 static int sound_hook_launch;
22 static int sound_hook_hit;
23 static int sound_hook_heal;
24 static int sound_hook_retract;
25
26
medic_FindDeadMonster(edict_t * self)27 edict_t *medic_FindDeadMonster (edict_t *self)
28 {
29 edict_t *ent = NULL;
30 edict_t *best = NULL;
31
32 while ((ent = findradius(ent, self->s.origin, 1024)) != NULL)
33 {
34 if (ent == self)
35 continue;
36 if (!(ent->svflags & SVF_MONSTER))
37 continue;
38 if (ent->monsterinfo.aiflags & AI_GOOD_GUY)
39 continue;
40 if (ent->owner)
41 continue;
42 if (ent->health > 0)
43 continue;
44 if (ent->nextthink)
45 continue;
46 if (!visible(self, ent))
47 continue;
48 if (!best)
49 {
50 best = ent;
51 continue;
52 }
53 if (ent->max_health <= best->max_health)
54 continue;
55 best = ent;
56 }
57
58 return best;
59 }
60
medic_idle(edict_t * self)61 void medic_idle (edict_t *self)
62 {
63 edict_t *ent;
64
65 gi.sound (self, CHAN_VOICE, sound_idle1, 1, ATTN_IDLE, 0);
66
67 ent = medic_FindDeadMonster(self);
68 if (ent)
69 {
70 self->enemy = ent;
71 self->enemy->owner = self;
72 self->monsterinfo.aiflags |= AI_MEDIC;
73 FoundTarget (self);
74 }
75 }
76
medic_search(edict_t * self)77 void medic_search (edict_t *self)
78 {
79 edict_t *ent;
80
81 gi.sound (self, CHAN_VOICE, sound_search, 1, ATTN_IDLE, 0);
82
83 if (!self->oldenemy)
84 {
85 ent = medic_FindDeadMonster(self);
86 if (ent)
87 {
88 self->oldenemy = self->enemy;
89 self->enemy = ent;
90 self->enemy->owner = self;
91 self->monsterinfo.aiflags |= AI_MEDIC;
92 FoundTarget (self);
93 }
94 }
95 }
96
medic_sight(edict_t * self,edict_t * other)97 void medic_sight (edict_t *self, edict_t *other)
98 {
99 gi.sound (self, CHAN_VOICE, sound_sight, 1, ATTN_NORM, 0);
100 }
101
102
103 mframe_t medic_frames_stand [] =
104 {
105 ai_stand, 0, medic_idle,
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,
116 ai_stand, 0, NULL,
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,
127 ai_stand, 0, NULL,
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,
138 ai_stand, 0, NULL,
139 ai_stand, 0, NULL,
140 ai_stand, 0, NULL,
141 ai_stand, 0, NULL,
142 ai_stand, 0, NULL,
143 ai_stand, 0, NULL,
144 ai_stand, 0, NULL,
145 ai_stand, 0, NULL,
146 ai_stand, 0, NULL,
147 ai_stand, 0, NULL,
148 ai_stand, 0, NULL,
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 ai_stand, 0, NULL,
156 ai_stand, 0, NULL,
157 ai_stand, 0, NULL,
158 ai_stand, 0, NULL,
159 ai_stand, 0, NULL,
160 ai_stand, 0, NULL,
161 ai_stand, 0, NULL,
162 ai_stand, 0, NULL,
163 ai_stand, 0, NULL,
164 ai_stand, 0, NULL,
165 ai_stand, 0, NULL,
166 ai_stand, 0, NULL,
167 ai_stand, 0, NULL,
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 ai_stand, 0, NULL,
175 ai_stand, 0, NULL,
176 ai_stand, 0, NULL,
177 ai_stand, 0, NULL,
178 ai_stand, 0, NULL,
179 ai_stand, 0, NULL,
180 ai_stand, 0, NULL,
181 ai_stand, 0, NULL,
182 ai_stand, 0, NULL,
183 ai_stand, 0, NULL,
184 ai_stand, 0, NULL,
185 ai_stand, 0, NULL,
186 ai_stand, 0, NULL,
187 ai_stand, 0, NULL,
188 ai_stand, 0, NULL,
189 ai_stand, 0, NULL,
190 ai_stand, 0, NULL,
191 ai_stand, 0, NULL,
192 ai_stand, 0, NULL,
193 ai_stand, 0, NULL,
194 ai_stand, 0, NULL,
195
196 };
197 mmove_t medic_move_stand = {FRAME_wait1, FRAME_wait90, medic_frames_stand, NULL};
198
medic_stand(edict_t * self)199 void medic_stand (edict_t *self)
200 {
201 self->monsterinfo.currentmove = &medic_move_stand;
202 }
203
204
205 mframe_t medic_frames_walk [] =
206 {
207 ai_walk, 6.2, NULL,
208 ai_walk, 18.1, NULL,
209 ai_walk, 1, NULL,
210 ai_walk, 9, NULL,
211 ai_walk, 10, NULL,
212 ai_walk, 9, NULL,
213 ai_walk, 11, NULL,
214 ai_walk, 11.6, NULL,
215 ai_walk, 2, NULL,
216 ai_walk, 9.9, NULL,
217 ai_walk, 14, NULL,
218 ai_walk, 9.3, NULL
219 };
220 mmove_t medic_move_walk = {FRAME_walk1, FRAME_walk12, medic_frames_walk, NULL};
221
medic_walk(edict_t * self)222 void medic_walk (edict_t *self)
223 {
224 self->monsterinfo.currentmove = &medic_move_walk;
225 }
226
227
228 mframe_t medic_frames_run [] =
229 {
230 ai_run, 18, NULL,
231 ai_run, 22.5, NULL,
232 ai_run, 25.4, NULL,
233 ai_run, 23.4, NULL,
234 ai_run, 24, NULL,
235 ai_run, 35.6, NULL
236
237 };
238 mmove_t medic_move_run = {FRAME_run1, FRAME_run6, medic_frames_run, NULL};
239
medic_run(edict_t * self)240 void medic_run (edict_t *self)
241 {
242 if (!(self->monsterinfo.aiflags & AI_MEDIC))
243 {
244 edict_t *ent;
245
246 ent = medic_FindDeadMonster(self);
247 if (ent)
248 {
249 self->oldenemy = self->enemy;
250 self->enemy = ent;
251 self->enemy->owner = self;
252 self->monsterinfo.aiflags |= AI_MEDIC;
253 FoundTarget (self);
254 return;
255 }
256 }
257
258 if (self->monsterinfo.aiflags & AI_STAND_GROUND)
259 self->monsterinfo.currentmove = &medic_move_stand;
260 else
261 self->monsterinfo.currentmove = &medic_move_run;
262 }
263
264
265 mframe_t medic_frames_pain1 [] =
266 {
267 ai_move, 0, NULL,
268 ai_move, 0, NULL,
269 ai_move, 0, NULL,
270 ai_move, 0, NULL,
271 ai_move, 0, NULL,
272 ai_move, 0, NULL,
273 ai_move, 0, NULL,
274 ai_move, 0, NULL
275 };
276 mmove_t medic_move_pain1 = {FRAME_paina1, FRAME_paina8, medic_frames_pain1, medic_run};
277
278 mframe_t medic_frames_pain2 [] =
279 {
280 ai_move, 0, NULL,
281 ai_move, 0, NULL,
282 ai_move, 0, NULL,
283 ai_move, 0, NULL,
284 ai_move, 0, NULL,
285 ai_move, 0, NULL,
286 ai_move, 0, NULL,
287 ai_move, 0, NULL,
288 ai_move, 0, NULL,
289 ai_move, 0, NULL,
290 ai_move, 0, NULL,
291 ai_move, 0, NULL,
292 ai_move, 0, NULL,
293 ai_move, 0, NULL,
294 ai_move, 0, NULL
295 };
296 mmove_t medic_move_pain2 = {FRAME_painb1, FRAME_painb15, medic_frames_pain2, medic_run};
297
medic_pain(edict_t * self,edict_t * other,float kick,int damage)298 void medic_pain (edict_t *self, edict_t *other, float kick, int damage)
299 {
300 if (self->health < (self->max_health / 2))
301 self->s.skinnum = 1;
302
303 if (level.time < self->pain_debounce_time)
304 return;
305
306 self->pain_debounce_time = level.time + 3;
307
308 if (skill->value == 3)
309 return; // no pain anims in nightmare
310
311 if (random() < 0.5)
312 {
313 self->monsterinfo.currentmove = &medic_move_pain1;
314 gi.sound (self, CHAN_VOICE, sound_pain1, 1, ATTN_NORM, 0);
315 }
316 else
317 {
318 self->monsterinfo.currentmove = &medic_move_pain2;
319 gi.sound (self, CHAN_VOICE, sound_pain2, 1, ATTN_NORM, 0);
320 }
321 }
322
medic_fire_blaster(edict_t * self)323 void medic_fire_blaster (edict_t *self)
324 {
325 vec3_t start;
326 vec3_t forward, right;
327 vec3_t end;
328 vec3_t dir;
329 int effect;
330
331 if ((self->s.frame == FRAME_attack9) || (self->s.frame == FRAME_attack12))
332 effect = EF_BLASTER;
333 else if ((self->s.frame == FRAME_attack19) || (self->s.frame == FRAME_attack22) || (self->s.frame == FRAME_attack25) || (self->s.frame == FRAME_attack28))
334 effect = EF_HYPERBLASTER;
335 else
336 effect = 0;
337
338 AngleVectors (self->s.angles, forward, right, NULL);
339 G_ProjectSource (self->s.origin, monster_flash_offset[MZ2_MEDIC_BLASTER_1], forward, right, start);
340
341 VectorCopy (self->enemy->s.origin, end);
342 end[2] += self->enemy->viewheight;
343 VectorSubtract (end, start, dir);
344
345 monster_fire_blaster (self, start, dir, 2, 1000, MZ2_MEDIC_BLASTER_1, effect);
346 }
347
348
medic_dead(edict_t * self)349 void medic_dead (edict_t *self)
350 {
351 VectorSet (self->mins, -16, -16, -24);
352 VectorSet (self->maxs, 16, 16, -8);
353 self->movetype = MOVETYPE_TOSS;
354 self->svflags |= SVF_DEADMONSTER;
355 self->nextthink = 0;
356 gi.linkentity (self);
357 }
358
359 mframe_t medic_frames_death [] =
360 {
361 ai_move, 0, NULL,
362 ai_move, 0, NULL,
363 ai_move, 0, NULL,
364 ai_move, 0, NULL,
365 ai_move, 0, NULL,
366 ai_move, 0, NULL,
367 ai_move, 0, NULL,
368 ai_move, 0, NULL,
369 ai_move, 0, NULL,
370 ai_move, 0, NULL,
371 ai_move, 0, NULL,
372 ai_move, 0, NULL,
373 ai_move, 0, NULL,
374 ai_move, 0, NULL,
375 ai_move, 0, NULL,
376 ai_move, 0, NULL,
377 ai_move, 0, NULL,
378 ai_move, 0, NULL,
379 ai_move, 0, NULL,
380 ai_move, 0, NULL,
381 ai_move, 0, NULL,
382 ai_move, 0, NULL,
383 ai_move, 0, NULL,
384 ai_move, 0, NULL,
385 ai_move, 0, NULL,
386 ai_move, 0, NULL,
387 ai_move, 0, NULL,
388 ai_move, 0, NULL,
389 ai_move, 0, NULL,
390 ai_move, 0, NULL
391 };
392 mmove_t medic_move_death = {FRAME_death1, FRAME_death30, medic_frames_death, medic_dead};
393
medic_die(edict_t * self,edict_t * inflictor,edict_t * attacker,int damage,vec3_t point)394 void medic_die (edict_t *self, edict_t *inflictor, edict_t *attacker, int damage, vec3_t point)
395 {
396 int n;
397
398 // if we had a pending patient, free him up for another medic
399 if ((self->enemy) && (self->enemy->owner == self))
400 self->enemy->owner = NULL;
401
402 // check for gib
403 if (self->health <= self->gib_health)
404 {
405 gi.sound (self, CHAN_VOICE, gi.soundindex ("misc/udeath.wav"), 1, ATTN_NORM, 0);
406 for (n= 0; n < 2; n++)
407 ThrowGib (self, "models/objects/gibs/bone/tris.md2", damage, GIB_ORGANIC);
408 for (n= 0; n < 4; n++)
409 ThrowGib (self, "models/objects/gibs/sm_meat/tris.md2", damage, GIB_ORGANIC);
410 ThrowHead (self, "models/objects/gibs/head2/tris.md2", damage, GIB_ORGANIC);
411 self->deadflag = DEAD_DEAD;
412 return;
413 }
414
415 if (self->deadflag == DEAD_DEAD)
416 return;
417
418 // regular death
419 gi.sound (self, CHAN_VOICE, sound_die, 1, ATTN_NORM, 0);
420 self->deadflag = DEAD_DEAD;
421 self->takedamage = DAMAGE_YES;
422
423 self->monsterinfo.currentmove = &medic_move_death;
424 }
425
426
medic_duck_down(edict_t * self)427 void medic_duck_down (edict_t *self)
428 {
429 if (self->monsterinfo.aiflags & AI_DUCKED)
430 return;
431 self->monsterinfo.aiflags |= AI_DUCKED;
432 self->maxs[2] -= 32;
433 self->takedamage = DAMAGE_YES;
434 self->monsterinfo.pausetime = level.time + 1;
435 gi.linkentity (self);
436 }
437
medic_duck_hold(edict_t * self)438 void medic_duck_hold (edict_t *self)
439 {
440 if (level.time >= self->monsterinfo.pausetime)
441 self->monsterinfo.aiflags &= ~AI_HOLD_FRAME;
442 else
443 self->monsterinfo.aiflags |= AI_HOLD_FRAME;
444 }
445
medic_duck_up(edict_t * self)446 void medic_duck_up (edict_t *self)
447 {
448 self->monsterinfo.aiflags &= ~AI_DUCKED;
449 self->maxs[2] += 32;
450 self->takedamage = DAMAGE_AIM;
451 gi.linkentity (self);
452 }
453
454 mframe_t medic_frames_duck [] =
455 {
456 ai_move, -1, NULL,
457 ai_move, -1, NULL,
458 ai_move, -1, medic_duck_down,
459 ai_move, -1, medic_duck_hold,
460 ai_move, -1, NULL,
461 ai_move, -1, NULL,
462 ai_move, -1, medic_duck_up,
463 ai_move, -1, NULL,
464 ai_move, -1, NULL,
465 ai_move, -1, NULL,
466 ai_move, -1, NULL,
467 ai_move, -1, NULL,
468 ai_move, -1, NULL,
469 ai_move, -1, NULL,
470 ai_move, -1, NULL,
471 ai_move, -1, NULL
472 };
473 mmove_t medic_move_duck = {FRAME_duck1, FRAME_duck16, medic_frames_duck, medic_run};
474
medic_dodge(edict_t * self,edict_t * attacker,float eta)475 void medic_dodge (edict_t *self, edict_t *attacker, float eta)
476 {
477 if (random() > 0.25)
478 return;
479
480 if (!self->enemy)
481 self->enemy = attacker;
482
483 self->monsterinfo.currentmove = &medic_move_duck;
484 }
485
486 mframe_t medic_frames_attackHyperBlaster [] =
487 {
488 ai_charge, 0, NULL,
489 ai_charge, 0, NULL,
490 ai_charge, 0, NULL,
491 ai_charge, 0, NULL,
492 ai_charge, 0, medic_fire_blaster,
493 ai_charge, 0, medic_fire_blaster,
494 ai_charge, 0, medic_fire_blaster,
495 ai_charge, 0, medic_fire_blaster,
496 ai_charge, 0, medic_fire_blaster,
497 ai_charge, 0, medic_fire_blaster,
498 ai_charge, 0, medic_fire_blaster,
499 ai_charge, 0, medic_fire_blaster,
500 ai_charge, 0, medic_fire_blaster,
501 ai_charge, 0, medic_fire_blaster,
502 ai_charge, 0, medic_fire_blaster,
503 ai_charge, 0, medic_fire_blaster
504 };
505 mmove_t medic_move_attackHyperBlaster = {FRAME_attack15, FRAME_attack30, medic_frames_attackHyperBlaster, medic_run};
506
507
medic_continue(edict_t * self)508 void medic_continue (edict_t *self)
509 {
510 if (visible (self, self->enemy) )
511 if (random() <= 0.95)
512 self->monsterinfo.currentmove = &medic_move_attackHyperBlaster;
513 }
514
515
516 mframe_t medic_frames_attackBlaster [] =
517 {
518 ai_charge, 0, NULL,
519 ai_charge, 5, NULL,
520 ai_charge, 5, NULL,
521 ai_charge, 3, NULL,
522 ai_charge, 2, NULL,
523 ai_charge, 0, NULL,
524 ai_charge, 0, NULL,
525 ai_charge, 0, NULL,
526 ai_charge, 0, medic_fire_blaster,
527 ai_charge, 0, NULL,
528 ai_charge, 0, NULL,
529 ai_charge, 0, medic_fire_blaster,
530 ai_charge, 0, NULL,
531 ai_charge, 0, medic_continue // Change to medic_continue... Else, go to frame 32
532 };
533 mmove_t medic_move_attackBlaster = {FRAME_attack1, FRAME_attack14, medic_frames_attackBlaster, medic_run};
534
535
medic_hook_launch(edict_t * self)536 void medic_hook_launch (edict_t *self)
537 {
538 gi.sound (self, CHAN_WEAPON, sound_hook_launch, 1, ATTN_NORM, 0);
539 }
540
541 void ED_CallSpawn (edict_t *ent);
542
543 static vec3_t medic_cable_offsets[] =
544 {
545 45.0, -9.2, 15.5,
546 48.4, -9.7, 15.2,
547 47.8, -9.8, 15.8,
548 47.3, -9.3, 14.3,
549 45.4, -10.1, 13.1,
550 41.9, -12.7, 12.0,
551 37.8, -15.8, 11.2,
552 34.3, -18.4, 10.7,
553 32.7, -19.7, 10.4,
554 32.7, -19.7, 10.4
555 };
556
medic_cable_attack(edict_t * self)557 void medic_cable_attack (edict_t *self)
558 {
559 vec3_t offset, start, end, f, r;
560 trace_t tr;
561 vec3_t dir, angles;
562 float distance;
563
564 if (!self->enemy->inuse)
565 return;
566
567 AngleVectors (self->s.angles, f, r, NULL);
568 VectorCopy (medic_cable_offsets[self->s.frame - FRAME_attack42], offset);
569 G_ProjectSource (self->s.origin, offset, f, r, start);
570
571 // check for max distance
572 VectorSubtract (start, self->enemy->s.origin, dir);
573 distance = VectorLength(dir);
574 if (distance > 256)
575 return;
576
577 // check for min/max pitch
578 vectoangles (dir, angles);
579 if (angles[0] < -180)
580 angles[0] += 360;
581 if (fabs(angles[0]) > 45)
582 return;
583
584 tr = gi.trace (start, NULL, NULL, self->enemy->s.origin, self, MASK_SHOT);
585 if (tr.fraction != 1.0 && tr.ent != self->enemy)
586 return;
587
588 if (self->s.frame == FRAME_attack43)
589 {
590 gi.sound (self->enemy, CHAN_AUTO, sound_hook_hit, 1, ATTN_NORM, 0);
591 self->enemy->monsterinfo.aiflags |= AI_RESURRECTING;
592 }
593 else if (self->s.frame == FRAME_attack50)
594 {
595 self->enemy->spawnflags = 0;
596 self->enemy->monsterinfo.aiflags = 0;
597 self->enemy->target = NULL;
598 self->enemy->targetname = NULL;
599 self->enemy->combattarget = NULL;
600 self->enemy->deathtarget = NULL;
601 self->enemy->owner = self;
602 ED_CallSpawn (self->enemy);
603 self->enemy->owner = NULL;
604 if (self->enemy->think)
605 {
606 self->enemy->nextthink = level.time;
607 self->enemy->think (self->enemy);
608 }
609 self->enemy->monsterinfo.aiflags |= AI_RESURRECTING;
610 if (self->oldenemy && self->oldenemy->client)
611 {
612 self->enemy->enemy = self->oldenemy;
613 FoundTarget (self->enemy);
614 }
615 }
616 else
617 {
618 if (self->s.frame == FRAME_attack44)
619 gi.sound (self, CHAN_WEAPON, sound_hook_heal, 1, ATTN_NORM, 0);
620 }
621
622 // adjust start for beam origin being in middle of a segment
623 VectorMA (start, 8, f, start);
624
625 // adjust end z for end spot since the monster is currently dead
626 VectorCopy (self->enemy->s.origin, end);
627 end[2] = self->enemy->absmin[2] + self->enemy->size[2] / 2;
628
629 gi.WriteByte (svc_temp_entity);
630 gi.WriteByte (TE_MEDIC_CABLE_ATTACK);
631 gi.WriteShort (self - g_edicts);
632 gi.WritePosition (start);
633 gi.WritePosition (end);
634 gi.multicast (self->s.origin, MULTICAST_PVS);
635 }
636
medic_hook_retract(edict_t * self)637 void medic_hook_retract (edict_t *self)
638 {
639 gi.sound (self, CHAN_WEAPON, sound_hook_retract, 1, ATTN_NORM, 0);
640 self->enemy->monsterinfo.aiflags &= ~AI_RESURRECTING;
641 }
642
643 mframe_t medic_frames_attackCable [] =
644 {
645 ai_move, 2, NULL,
646 ai_move, 3, NULL,
647 ai_move, 5, NULL,
648 ai_move, 4.4, NULL,
649 ai_charge, 4.7, NULL,
650 ai_charge, 5, NULL,
651 ai_charge, 6, NULL,
652 ai_charge, 4, NULL,
653 ai_charge, 0, NULL,
654 ai_move, 0, medic_hook_launch,
655 ai_move, 0, medic_cable_attack,
656 ai_move, 0, medic_cable_attack,
657 ai_move, 0, medic_cable_attack,
658 ai_move, 0, medic_cable_attack,
659 ai_move, 0, medic_cable_attack,
660 ai_move, 0, medic_cable_attack,
661 ai_move, 0, medic_cable_attack,
662 ai_move, 0, medic_cable_attack,
663 ai_move, 0, medic_cable_attack,
664 ai_move, -15, medic_hook_retract,
665 ai_move, -1.5, NULL,
666 ai_move, -1.2, NULL,
667 ai_move, -3, NULL,
668 ai_move, -2, NULL,
669 ai_move, 0.3, NULL,
670 ai_move, 0.7, NULL,
671 ai_move, 1.2, NULL,
672 ai_move, 1.3, NULL
673 };
674 mmove_t medic_move_attackCable = {FRAME_attack33, FRAME_attack60, medic_frames_attackCable, medic_run};
675
676
medic_attack(edict_t * self)677 void medic_attack(edict_t *self)
678 {
679 if (self->monsterinfo.aiflags & AI_MEDIC)
680 self->monsterinfo.currentmove = &medic_move_attackCable;
681 else
682 self->monsterinfo.currentmove = &medic_move_attackBlaster;
683 }
684
medic_checkattack(edict_t * self)685 qboolean medic_checkattack (edict_t *self)
686 {
687 if (self->monsterinfo.aiflags & AI_MEDIC)
688 {
689 medic_attack(self);
690 return true;
691 }
692
693 return M_CheckAttack (self);
694 }
695
696
697 /*QUAKED monster_medic (1 .5 0) (-16 -16 -24) (16 16 32) Ambush Trigger_Spawn Sight
698 */
SP_monster_medic(edict_t * self)699 void SP_monster_medic (edict_t *self)
700 {
701 if (deathmatch->value)
702 {
703 G_FreeEdict (self);
704 return;
705 }
706
707 sound_idle1 = gi.soundindex ("medic/idle.wav");
708 sound_pain1 = gi.soundindex ("medic/medpain1.wav");
709 sound_pain2 = gi.soundindex ("medic/medpain2.wav");
710 sound_die = gi.soundindex ("medic/meddeth1.wav");
711 sound_sight = gi.soundindex ("medic/medsght1.wav");
712 sound_search = gi.soundindex ("medic/medsrch1.wav");
713 sound_hook_launch = gi.soundindex ("medic/medatck2.wav");
714 sound_hook_hit = gi.soundindex ("medic/medatck3.wav");
715 sound_hook_heal = gi.soundindex ("medic/medatck4.wav");
716 sound_hook_retract = gi.soundindex ("medic/medatck5.wav");
717
718 gi.soundindex ("medic/medatck1.wav");
719
720 self->movetype = MOVETYPE_STEP;
721 self->solid = SOLID_BBOX;
722 self->s.modelindex = gi.modelindex ("models/monsters/medic/tris.md2");
723 VectorSet (self->mins, -24, -24, -24);
724 VectorSet (self->maxs, 24, 24, 32);
725
726 self->health = 300;
727 self->gib_health = -130;
728 self->mass = 400;
729
730 self->pain = medic_pain;
731 self->die = medic_die;
732
733 self->monsterinfo.stand = medic_stand;
734 self->monsterinfo.walk = medic_walk;
735 self->monsterinfo.run = medic_run;
736 self->monsterinfo.dodge = medic_dodge;
737 self->monsterinfo.attack = medic_attack;
738 self->monsterinfo.melee = NULL;
739 self->monsterinfo.sight = medic_sight;
740 self->monsterinfo.idle = medic_idle;
741 self->monsterinfo.search = medic_search;
742 self->monsterinfo.checkattack = medic_checkattack;
743
744 gi.linkentity (self);
745
746 self->monsterinfo.currentmove = &medic_move_stand;
747 self->monsterinfo.scale = MODEL_SCALE;
748
749 walkmonster_start (self);
750 }
751