Quake II RTX doxygen  1.0 dev
m_medic.c
Go to the documentation of this file.
1 /*
2 Copyright (C) 1997-2001 Id Software, Inc.
3 
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (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. See the
12 GNU General Public License for more details.
13 
14 You should have received a copy of the GNU General Public License along
15 with this program; if not, write to the Free Software Foundation, Inc.,
16 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
17 */
18 /*
19 ==============================================================================
20 
21 MEDIC
22 
23 ==============================================================================
24 */
25 
26 #include "g_local.h"
27 #include "m_medic.h"
28 
29 qboolean visible(edict_t *self, edict_t *other);
30 
31 
32 static int sound_idle1;
33 static int sound_pain1;
34 static int sound_pain2;
35 static int sound_die;
36 static int sound_sight;
37 static int sound_search;
38 static int sound_hook_launch;
39 static int sound_hook_hit;
40 static int sound_hook_heal;
41 static int sound_hook_retract;
42 
43 
44 edict_t *medic_FindDeadMonster(edict_t *self)
45 {
46  edict_t *ent = NULL;
47  edict_t *best = NULL;
48 
49  while ((ent = findradius(ent, self->s.origin, 1024)) != NULL) {
50  if (ent == self)
51  continue;
52  if (!(ent->svflags & SVF_MONSTER))
53  continue;
54  if (ent->monsterinfo.aiflags & AI_GOOD_GUY)
55  continue;
56  if (ent->owner)
57  continue;
58  if (ent->health > 0)
59  continue;
60  if (ent->nextthink)
61  continue;
62  if (!visible(self, ent))
63  continue;
64  if (!best) {
65  best = ent;
66  continue;
67  }
68  if (ent->max_health <= best->max_health)
69  continue;
70  best = ent;
71  }
72 
73  return best;
74 }
75 
76 void medic_idle(edict_t *self)
77 {
78  edict_t *ent;
79 
80  gi.sound(self, CHAN_VOICE, sound_idle1, 1, ATTN_IDLE, 0);
81 
82  ent = medic_FindDeadMonster(self);
83  if (ent) {
84  self->enemy = ent;
85  self->enemy->owner = self;
86  self->monsterinfo.aiflags |= AI_MEDIC;
87  FoundTarget(self);
88  }
89 }
90 
91 void medic_search(edict_t *self)
92 {
93  edict_t *ent;
94 
95  gi.sound(self, CHAN_VOICE, sound_search, 1, ATTN_IDLE, 0);
96 
97  if (!self->oldenemy) {
98  ent = medic_FindDeadMonster(self);
99  if (ent) {
100  self->oldenemy = self->enemy;
101  self->enemy = ent;
102  self->enemy->owner = self;
103  self->monsterinfo.aiflags |= AI_MEDIC;
104  FoundTarget(self);
105  }
106  }
107 }
108 
109 void medic_sight(edict_t *self, edict_t *other)
110 {
111  gi.sound(self, CHAN_VOICE, sound_sight, 1, ATTN_NORM, 0);
112 }
113 
114 
116  { ai_stand, 0, medic_idle },
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  { ai_stand, 0, NULL },
196  { ai_stand, 0, NULL },
197  { ai_stand, 0, NULL },
198  { ai_stand, 0, NULL },
199  { ai_stand, 0, NULL },
200  { ai_stand, 0, NULL },
201  { ai_stand, 0, NULL },
202  { ai_stand, 0, NULL },
203  { ai_stand, 0, NULL },
204  { ai_stand, 0, NULL },
205  { ai_stand, 0, NULL },
206 
207 };
209 
210 void medic_stand(edict_t *self)
211 {
212  self->monsterinfo.currentmove = &medic_move_stand;
213 }
214 
215 
217  { ai_walk, 6.2, NULL },
218  { ai_walk, 18.1, NULL },
219  { ai_walk, 1, NULL },
220  { ai_walk, 9, NULL },
221  { ai_walk, 10, NULL },
222  { ai_walk, 9, NULL },
223  { ai_walk, 11, NULL },
224  { ai_walk, 11.6, NULL },
225  { ai_walk, 2, NULL },
226  { ai_walk, 9.9, NULL },
227  { ai_walk, 14, NULL },
228  { ai_walk, 9.3, NULL }
229 };
231 
232 void medic_walk(edict_t *self)
233 {
234  self->monsterinfo.currentmove = &medic_move_walk;
235 }
236 
237 
239  { ai_run, 18, NULL },
240  { ai_run, 22.5, NULL },
241  { ai_run, 25.4, NULL },
242  { ai_run, 23.4, NULL },
243  { ai_run, 24, NULL },
244  { ai_run, 35.6, NULL }
245 
246 };
248 
249 void medic_run(edict_t *self)
250 {
251  if (!(self->monsterinfo.aiflags & AI_MEDIC)) {
252  edict_t *ent;
253 
254  ent = medic_FindDeadMonster(self);
255  if (ent) {
256  self->oldenemy = self->enemy;
257  self->enemy = ent;
258  self->enemy->owner = self;
259  self->monsterinfo.aiflags |= AI_MEDIC;
260  FoundTarget(self);
261  return;
262  }
263  }
264 
265  if (self->monsterinfo.aiflags & AI_STAND_GROUND)
266  self->monsterinfo.currentmove = &medic_move_stand;
267  else
268  self->monsterinfo.currentmove = &medic_move_run;
269 }
270 
271 
273  { ai_move, 0, NULL },
274  { ai_move, 0, NULL },
275  { ai_move, 0, NULL },
276  { ai_move, 0, NULL },
277  { ai_move, 0, NULL },
278  { ai_move, 0, NULL },
279  { ai_move, 0, NULL },
280  { ai_move, 0, NULL }
281 };
283 
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  { ai_move, 0, NULL },
296  { ai_move, 0, NULL },
297  { ai_move, 0, NULL },
298  { ai_move, 0, NULL },
299  { ai_move, 0, NULL }
300 };
302 
303 void medic_pain(edict_t *self, edict_t *other, float kick, int damage)
304 {
305  if (self->health < (self->max_health / 2))
306  self->s.skinnum = 1;
307 
308  if (level.time < self->pain_debounce_time)
309  return;
310 
311  self->pain_debounce_time = level.time + 3;
312 
313  if (skill->value == 3)
314  return; // no pain anims in nightmare
315 
316  if (random() < 0.5) {
317  self->monsterinfo.currentmove = &medic_move_pain1;
318  gi.sound(self, CHAN_VOICE, sound_pain1, 1, ATTN_NORM, 0);
319  } else {
320  self->monsterinfo.currentmove = &medic_move_pain2;
321  gi.sound(self, CHAN_VOICE, sound_pain2, 1, ATTN_NORM, 0);
322  }
323 }
324 
325 void medic_fire_blaster(edict_t *self)
326 {
327  vec3_t start;
328  vec3_t forward, right;
329  vec3_t end;
330  vec3_t dir;
331  int effect;
332 
333  if ((self->s.frame == FRAME_attack9) || (self->s.frame == FRAME_attack12))
334  effect = EF_BLASTER;
335  else if ((self->s.frame == FRAME_attack19) || (self->s.frame == FRAME_attack22) || (self->s.frame == FRAME_attack25) || (self->s.frame == FRAME_attack28))
336  effect = EF_HYPERBLASTER;
337  else
338  effect = 0;
339 
340  AngleVectors(self->s.angles, forward, right, NULL);
341  G_ProjectSource(self->s.origin, monster_flash_offset[MZ2_MEDIC_BLASTER_1], forward, right, start);
342 
343  VectorCopy(self->enemy->s.origin, end);
344  end[2] += self->enemy->viewheight;
345  VectorSubtract(end, start, dir);
346 
347  monster_fire_blaster(self, start, dir, 2, 1000, MZ2_MEDIC_BLASTER_1, effect);
348 }
349 
350 
351 void medic_dead(edict_t *self)
352 {
353  VectorSet(self->mins, -16, -16, -24);
354  VectorSet(self->maxs, 16, 16, -8);
355  self->movetype = MOVETYPE_TOSS;
356  self->svflags |= SVF_DEADMONSTER;
357  self->nextthink = 0;
358  gi.linkentity(self);
359 }
360 
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  { ai_move, 0, NULL }
392 };
394 
395 void medic_die(edict_t *self, edict_t *inflictor, edict_t *attacker, int damage, vec3_t point)
396 {
397  int n;
398 
399  // if we had a pending patient, free him up for another medic
400  if ((self->enemy) && (self->enemy->owner == self))
401  self->enemy->owner = NULL;
402 
403 // check for gib
404  if (self->health <= self->gib_health) {
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 
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 
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 
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 
455  { ai_move, -1, NULL },
456  { ai_move, -1, NULL },
457  { ai_move, -1, medic_duck_down },
458  { ai_move, -1, medic_duck_hold },
459  { ai_move, -1, NULL },
460  { ai_move, -1, NULL },
461  { ai_move, -1, medic_duck_up },
462  { ai_move, -1, NULL },
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 };
473 
474 void medic_dodge(edict_t *self, edict_t *attacker, float eta)
475 {
476  if (random() > 0.25)
477  return;
478 
479  if (!self->enemy)
480  self->enemy = attacker;
481 
482  self->monsterinfo.currentmove = &medic_move_duck;
483 }
484 
486  { ai_charge, 0, NULL },
487  { ai_charge, 0, NULL },
488  { ai_charge, 0, NULL },
489  { ai_charge, 0, NULL },
502 };
504 
505 
506 void medic_continue(edict_t *self)
507 {
508  if (visible(self, self->enemy))
509  if (random() <= 0.95)
510  self->monsterinfo.currentmove = &medic_move_attackHyperBlaster;
511 }
512 
513 
515  { ai_charge, 0, NULL },
516  { ai_charge, 5, NULL },
517  { ai_charge, 5, NULL },
518  { ai_charge, 3, NULL },
519  { ai_charge, 2, NULL },
520  { ai_charge, 0, NULL },
521  { ai_charge, 0, NULL },
522  { ai_charge, 0, NULL },
524  { ai_charge, 0, NULL },
525  { ai_charge, 0, NULL },
527  { ai_charge, 0, NULL },
528  { ai_charge, 0, medic_continue } // Change to medic_continue... Else, go to frame 32
529 };
531 
532 
533 void medic_hook_launch(edict_t *self)
534 {
535  gi.sound(self, CHAN_WEAPON, sound_hook_launch, 1, ATTN_NORM, 0);
536 }
537 
538 void ED_CallSpawn(edict_t *ent);
539 
540 static vec3_t medic_cable_offsets[] = {
541  { 45.0, -9.2, 15.5 },
542  { 48.4, -9.7, 15.2 },
543  { 47.8, -9.8, 15.8 },
544  { 47.3, -9.3, 14.3 },
545  { 45.4, -10.1, 13.1 },
546  { 41.9, -12.7, 12.0 },
547  { 37.8, -15.8, 11.2 },
548  { 34.3, -18.4, 10.7 },
549  { 32.7, -19.7, 10.4 },
550  { 32.7, -19.7, 10.4 }
551 };
552 
553 void medic_cable_attack(edict_t *self)
554 {
555  vec3_t offset, start, end, f, r;
556  trace_t tr;
557  vec3_t dir, angles;
558  float distance;
559 
560  if (!self->enemy->inuse)
561  return;
562 
563  AngleVectors(self->s.angles, f, r, NULL);
564  VectorCopy(medic_cable_offsets[self->s.frame - FRAME_attack42], offset);
565  G_ProjectSource(self->s.origin, offset, f, r, start);
566 
567  // check for max distance
568  VectorSubtract(start, self->enemy->s.origin, dir);
569  distance = VectorLength(dir);
570  if (distance > 256)
571  return;
572 
573  // check for min/max pitch
574  vectoangles(dir, angles);
575  if (angles[0] < -180)
576  angles[0] += 360;
577  if (fabs(angles[0]) > 45)
578  return;
579 
580  tr = gi.trace(start, NULL, NULL, self->enemy->s.origin, self, MASK_SHOT);
581  if (tr.fraction != 1.0 && tr.ent != self->enemy)
582  return;
583 
584  if (self->s.frame == FRAME_attack43) {
585  gi.sound(self->enemy, CHAN_AUTO, sound_hook_hit, 1, ATTN_NORM, 0);
586  self->enemy->monsterinfo.aiflags |= AI_RESURRECTING;
587  } else if (self->s.frame == FRAME_attack50) {
588  self->enemy->spawnflags = 0;
589  self->enemy->monsterinfo.aiflags = 0;
590  self->enemy->target = NULL;
591  self->enemy->targetname = NULL;
592  self->enemy->combattarget = NULL;
593  self->enemy->deathtarget = NULL;
594  self->enemy->owner = self;
595  ED_CallSpawn(self->enemy);
596  self->enemy->owner = NULL;
597  if (self->enemy->think) {
598  self->enemy->nextthink = level.time;
599  self->enemy->think(self->enemy);
600  }
601  self->enemy->monsterinfo.aiflags |= AI_RESURRECTING;
602  if (self->oldenemy && self->oldenemy->client) {
603  self->enemy->enemy = self->oldenemy;
604  FoundTarget(self->enemy);
605  }
606  } else {
607  if (self->s.frame == FRAME_attack44)
608  gi.sound(self, CHAN_WEAPON, sound_hook_heal, 1, ATTN_NORM, 0);
609  }
610 
611  // adjust start for beam origin being in middle of a segment
612  VectorMA(start, 8, f, start);
613 
614  // adjust end z for end spot since the monster is currently dead
615  VectorCopy(self->enemy->s.origin, end);
616  end[2] = self->enemy->absmin[2] + self->enemy->size[2] / 2;
617 
618  gi.WriteByte(svc_temp_entity);
619  gi.WriteByte(TE_MEDIC_CABLE_ATTACK);
620  gi.WriteShort(self - g_edicts);
621  gi.WritePosition(start);
622  gi.WritePosition(end);
623  gi.multicast(self->s.origin, MULTICAST_PVS);
624 }
625 
626 void medic_hook_retract(edict_t *self)
627 {
628  gi.sound(self, CHAN_WEAPON, sound_hook_retract, 1, ATTN_NORM, 0);
629  self->enemy->monsterinfo.aiflags &= ~AI_RESURRECTING;
630 }
631 
633  { ai_move, 2, NULL },
634  { ai_move, 3, NULL },
635  { ai_move, 5, NULL },
636  { ai_move, 4.4, NULL },
637  { ai_charge, 4.7, NULL },
638  { ai_charge, 5, NULL },
639  { ai_charge, 6, NULL },
640  { ai_charge, 4, NULL },
641  { ai_charge, 0, NULL },
642  { ai_move, 0, medic_hook_launch },
643  { ai_move, 0, medic_cable_attack },
644  { ai_move, 0, medic_cable_attack },
645  { ai_move, 0, medic_cable_attack },
646  { ai_move, 0, medic_cable_attack },
647  { ai_move, 0, medic_cable_attack },
648  { ai_move, 0, medic_cable_attack },
649  { ai_move, 0, medic_cable_attack },
650  { ai_move, 0, medic_cable_attack },
651  { ai_move, 0, medic_cable_attack },
652  { ai_move, -15, medic_hook_retract },
653  { ai_move, -1.5, NULL },
654  { ai_move, -1.2, NULL },
655  { ai_move, -3, NULL },
656  { ai_move, -2, NULL },
657  { ai_move, 0.3, NULL },
658  { ai_move, 0.7, NULL },
659  { ai_move, 1.2, NULL },
660  { ai_move, 1.3, NULL }
661 };
663 
664 
665 void medic_attack(edict_t *self)
666 {
667  if (self->monsterinfo.aiflags & AI_MEDIC)
668  self->monsterinfo.currentmove = &medic_move_attackCable;
669  else
670  self->monsterinfo.currentmove = &medic_move_attackBlaster;
671 }
672 
673 qboolean medic_checkattack(edict_t *self)
674 {
675  if (self->monsterinfo.aiflags & AI_MEDIC) {
676  medic_attack(self);
677  return qtrue;
678  }
679 
680  return M_CheckAttack(self);
681 }
682 
683 
684 /*QUAKED monster_medic (1 .5 0) (-16 -16 -24) (16 16 32) Ambush Trigger_Spawn Sight
685 */
686 void SP_monster_medic(edict_t *self)
687 {
688  if (deathmatch->value) {
689  G_FreeEdict(self);
690  return;
691  }
692 
693  sound_idle1 = gi.soundindex("medic/idle.wav");
694  sound_pain1 = gi.soundindex("medic/medpain1.wav");
695  sound_pain2 = gi.soundindex("medic/medpain2.wav");
696  sound_die = gi.soundindex("medic/meddeth1.wav");
697  sound_sight = gi.soundindex("medic/medsght1.wav");
698  sound_search = gi.soundindex("medic/medsrch1.wav");
699  sound_hook_launch = gi.soundindex("medic/medatck2.wav");
700  sound_hook_hit = gi.soundindex("medic/medatck3.wav");
701  sound_hook_heal = gi.soundindex("medic/medatck4.wav");
702  sound_hook_retract = gi.soundindex("medic/medatck5.wav");
703 
704  gi.soundindex("medic/medatck1.wav");
705 
706  self->movetype = MOVETYPE_STEP;
707  self->solid = SOLID_BBOX;
708  self->s.modelindex = gi.modelindex("models/monsters/medic/tris.md2");
709  VectorSet(self->mins, -24, -24, -24);
710  VectorSet(self->maxs, 24, 24, 32);
711 
712  self->health = 300;
713  self->gib_health = -130;
714  self->mass = 400;
715 
716  self->pain = medic_pain;
717  self->die = medic_die;
718 
719  self->monsterinfo.stand = medic_stand;
720  self->monsterinfo.walk = medic_walk;
721  self->monsterinfo.run = medic_run;
722  self->monsterinfo.dodge = medic_dodge;
723  self->monsterinfo.attack = medic_attack;
724  self->monsterinfo.melee = NULL;
725  self->monsterinfo.sight = medic_sight;
726  self->monsterinfo.idle = medic_idle;
727  self->monsterinfo.search = medic_search;
728  self->monsterinfo.checkattack = medic_checkattack;
729 
730  gi.linkentity(self);
731 
732  self->monsterinfo.currentmove = &medic_move_stand;
733  self->monsterinfo.scale = MODEL_SCALE;
734 
735  walkmonster_start(self);
736 }
gi
game_import_t gi
Definition: g_main.c:23
AI_RESURRECTING
#define AI_RESURRECTING
Definition: g_local.h:140
deathmatch
cvar_t * deathmatch
Definition: g_main.c:33
medic_attack
void medic_attack(edict_t *self)
Definition: m_medic.c:665
G_ProjectSource
void G_ProjectSource(const vec3_t point, const vec3_t distance, const vec3_t forward, const vec3_t right, vec3_t result)
Definition: g_utils.c:23
AI_MEDIC
#define AI_MEDIC
Definition: g_local.h:139
DEAD_DEAD
#define DEAD_DEAD
Definition: g_local.h:112
sound_die
static int sound_die
Definition: m_medic.c:35
ThrowGib
void ThrowGib(edict_t *self, char *gibname, int damage, int type)
Definition: g_misc.c:130
medic_checkattack
qboolean medic_checkattack(edict_t *self)
Definition: m_medic.c:673
FRAME_paina1
#define FRAME_paina1
Definition: m_medic.h:130
ED_CallSpawn
void ED_CallSpawn(edict_t *ent)
Definition: g_spawn.c:340
FRAME_attack1
#define FRAME_attack1
Definition: m_boss2.h:92
ai_charge
void ai_charge(edict_t *self, float dist)
Definition: g_ai.c:175
AI_GOOD_GUY
#define AI_GOOD_GUY
Definition: g_local.h:134
FRAME_attack15
#define FRAME_attack15
Definition: m_boss2.h:106
sound_hook_heal
static int sound_hook_heal
Definition: m_medic.c:40
m_medic.h
FRAME_run6
#define FRAME_run6
Definition: m_berserk.h:63
sound_search
static int sound_search
Definition: m_medic.c:37
medic_sight
void medic_sight(edict_t *self, edict_t *other)
Definition: m_medic.c:109
FRAME_attack28
#define FRAME_attack28
Definition: m_boss2.h:119
medic_frames_duck
mframe_t medic_frames_duck[]
Definition: m_medic.c:454
FRAME_attack43
#define FRAME_attack43
Definition: m_medic.h:241
sound_hook_hit
static int sound_hook_hit
Definition: m_medic.c:39
AI_STAND_GROUND
#define AI_STAND_GROUND
Definition: g_local.h:126
MODEL_SCALE
#define MODEL_SCALE
Definition: m_actor.h:504
medic_frames_attackBlaster
mframe_t medic_frames_attackBlaster[]
Definition: m_medic.c:514
medic_hook_retract
void medic_hook_retract(edict_t *self)
Definition: m_medic.c:626
medic_run
void medic_run(edict_t *self)
Definition: m_medic.c:249
DAMAGE_YES
@ DAMAGE_YES
Definition: g_local.h:88
FRAME_attack14
#define FRAME_attack14
Definition: m_boss2.h:105
medic_duck_hold
void medic_duck_hold(edict_t *self)
Definition: m_medic.c:438
M_CheckAttack
qboolean M_CheckAttack(edict_t *self)
Definition: g_ai.c:553
FRAME_attack30
#define FRAME_attack30
Definition: m_boss2.h:121
g_edicts
edict_t * g_edicts
Definition: g_main.c:31
other
@ other
Definition: ogg.c:63
medic_frames_attackCable
mframe_t medic_frames_attackCable[]
Definition: m_medic.c:632
walkmonster_start
void walkmonster_start(edict_t *self)
Definition: g_monster.c:630
MOVETYPE_STEP
@ MOVETYPE_STEP
Definition: g_local.h:192
FRAME_walk12
#define FRAME_walk12
Definition: m_boss2.h:83
medic_move_pain2
mmove_t medic_move_pain2
Definition: m_medic.c:301
visible
qboolean visible(edict_t *self, edict_t *other)
Definition: g_ai.c:268
medic_cable_offsets
static vec3_t medic_cable_offsets[]
Definition: m_medic.c:540
sound_pain2
static int sound_pain2
Definition: m_medic.c:34
vectoangles
void vectoangles(vec3_t vec, vec3_t angles)
Definition: g_utils.c:330
FRAME_duck16
#define FRAME_duck16
Definition: m_medic.h:168
FRAME_death1
#define FRAME_death1
Definition: m_berserk.h:245
medic_walk
void medic_walk(edict_t *self)
Definition: m_medic.c:232
medic_frames_pain1
mframe_t medic_frames_pain1[]
Definition: m_medic.c:272
findradius
edict_t * findradius(edict_t *from, vec3_t org, float rad)
Definition: g_utils.c:75
G_FreeEdict
void G_FreeEdict(edict_t *e)
Definition: g_utils.c:421
medic_frames_walk
mframe_t medic_frames_walk[]
Definition: m_medic.c:216
medic_duck_up
void medic_duck_up(edict_t *self)
Definition: m_medic.c:446
medic_pain
void medic_pain(edict_t *self, edict_t *other, float kick, int damage)
Definition: m_medic.c:303
sound_idle1
static int sound_idle1
Definition: m_medic.c:32
FRAME_attack12
#define FRAME_attack12
Definition: m_boss2.h:103
forward
static vec3_t forward
Definition: p_view.c:27
FRAME_painb15
#define FRAME_painb15
Definition: m_berserk.h:239
svc_temp_entity
#define svc_temp_entity
Definition: g_local.h:38
medic_move_stand
mmove_t medic_move_stand
Definition: m_medic.c:208
AI_HOLD_FRAME
#define AI_HOLD_FRAME
Definition: g_local.h:133
medic_move_attackHyperBlaster
mmove_t medic_move_attackHyperBlaster
Definition: m_medic.c:503
mframe_t
Definition: g_local.h:394
FRAME_attack19
#define FRAME_attack19
Definition: m_boss2.h:110
mmove_t
Definition: g_local.h:400
medic_move_walk
mmove_t medic_move_walk
Definition: m_medic.c:230
FRAME_wait90
#define FRAME_wait90
Definition: m_medic.h:123
ai_walk
void ai_walk(edict_t *self, float dist)
Definition: g_ai.c:148
FRAME_attack9
#define FRAME_attack9
Definition: m_boss2.h:100
random
#define random()
Definition: g_local.h:504
FRAME_attack25
#define FRAME_attack25
Definition: m_boss2.h:116
medic_move_duck
mmove_t medic_move_duck
Definition: m_medic.c:472
AngleVectors
void AngleVectors(vec3_t angles, vec3_t forward, vec3_t right, vec3_t up)
Definition: shared.c:23
FRAME_attack22
#define FRAME_attack22
Definition: m_boss2.h:113
SP_monster_medic
void SP_monster_medic(edict_t *self)
Definition: m_medic.c:686
medic_dead
void medic_dead(edict_t *self)
Definition: m_medic.c:351
FRAME_wait1
#define FRAME_wait1
Definition: m_medic.h:34
FoundTarget
void FoundTarget(edict_t *self)
Definition: g_ai.c:328
medic_idle
void medic_idle(edict_t *self)
Definition: m_medic.c:76
sound_hook_launch
static int sound_hook_launch
Definition: m_medic.c:38
FRAME_painb1
#define FRAME_painb1
Definition: m_berserk.h:225
sound_sight
static int sound_sight
Definition: m_medic.c:36
skill
cvar_t * skill
Definition: g_main.c:36
medic_frames_run
mframe_t medic_frames_run[]
Definition: m_medic.c:238
medic_move_pain1
mmove_t medic_move_pain1
Definition: m_medic.c:282
medic_move_run
mmove_t medic_move_run
Definition: m_medic.c:247
ai_move
void ai_move(edict_t *self, float dist)
Definition: g_ai.c:86
medic_fire_blaster
void medic_fire_blaster(edict_t *self)
Definition: m_medic.c:325
level_locals_t::time
float time
Definition: g_local.h:299
monster_fire_blaster
void monster_fire_blaster(edict_t *self, vec3_t start, vec3_t dir, int damage, int speed, int flashtype, int effect)
Definition: g_monster.c:49
FRAME_walk1
#define FRAME_walk1
Definition: m_boss2.h:72
medic_move_attackBlaster
mmove_t medic_move_attackBlaster
Definition: m_medic.c:530
medic_search
void medic_search(edict_t *self)
Definition: m_medic.c:91
DAMAGE_AIM
@ DAMAGE_AIM
Definition: g_local.h:89
medic_frames_attackHyperBlaster
mframe_t medic_frames_attackHyperBlaster[]
Definition: m_medic.c:485
medic_hook_launch
void medic_hook_launch(edict_t *self)
Definition: m_medic.c:533
medic_move_attackCable
mmove_t medic_move_attackCable
Definition: m_medic.c:662
right
static vec3_t right
Definition: p_view.c:27
ai_run
void ai_run(edict_t *self, float dist)
Definition: g_ai.c:821
GIB_ORGANIC
#define GIB_ORGANIC
Definition: g_local.h:122
FRAME_run1
#define FRAME_run1
Definition: m_berserk.h:58
level
level_locals_t level
Definition: g_main.c:22
medic_dodge
void medic_dodge(edict_t *self, edict_t *attacker, float eta)
Definition: m_medic.c:474
FRAME_attack42
#define FRAME_attack42
Definition: m_medic.h:240
medic_frames_death
mframe_t medic_frames_death[]
Definition: m_medic.c:361
medic_duck_down
void medic_duck_down(edict_t *self)
Definition: m_medic.c:427
FRAME_paina8
#define FRAME_paina8
Definition: m_medic.h:137
monster_flash_offset
const vec3_t monster_flash_offset[256]
Definition: m_flash.c:25
sound_hook_retract
static int sound_hook_retract
Definition: m_medic.c:41
ThrowHead
void ThrowHead(edict_t *self, char *gibname, int damage, int type)
Definition: g_misc.c:175
medic_stand
void medic_stand(edict_t *self)
Definition: m_medic.c:210
sound_pain1
static int sound_pain1
Definition: m_medic.c:33
medic_move_death
mmove_t medic_move_death
Definition: m_medic.c:393
medic_continue
void medic_continue(edict_t *self)
Definition: m_medic.c:506
MOVETYPE_TOSS
@ MOVETYPE_TOSS
Definition: g_local.h:194
medic_die
void medic_die(edict_t *self, edict_t *inflictor, edict_t *attacker, int damage, vec3_t point)
Definition: m_medic.c:395
FRAME_death30
#define FRAME_death30
Definition: m_boss2.h:182
AI_DUCKED
#define AI_DUCKED
Definition: g_local.h:137
medic_frames_pain2
mframe_t medic_frames_pain2[]
Definition: m_medic.c:284
FRAME_attack33
#define FRAME_attack33
Definition: m_boss2.h:124
medic_cable_attack
void medic_cable_attack(edict_t *self)
Definition: m_medic.c:553
FRAME_duck1
#define FRAME_duck1
Definition: m_berserk.h:191
medic_frames_stand
mframe_t medic_frames_stand[]
Definition: m_medic.c:115
FRAME_attack44
#define FRAME_attack44
Definition: m_medic.h:242
ai_stand
void ai_stand(edict_t *self, float dist)
Definition: g_ai.c:100
medic_FindDeadMonster
edict_t * medic_FindDeadMonster(edict_t *self)
Definition: m_medic.c:44
FRAME_attack50
#define FRAME_attack50
Definition: m_medic.h:248
g_local.h
FRAME_attack60
#define FRAME_attack60
Definition: m_medic.h:258