m_medic.c 18 KB

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