m_boss32.cpp 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828
  1. // Copyright (c) ZeniMax Media Inc.
  2. // Licensed under the GNU General Public License 2.0.
  3. /*
  4. ==============================================================================
  5. Makron -- Final Boss
  6. ==============================================================================
  7. */
  8. #include "g_local.h"
  9. #include "m_boss32.h"
  10. #include "m_flash.h"
  11. void MakronRailgun(edict_t *self);
  12. void MakronSaveloc(edict_t *self);
  13. void MakronHyperblaster(edict_t *self);
  14. void makron_step_left(edict_t *self);
  15. void makron_step_right(edict_t *self);
  16. void makronBFG(edict_t *self);
  17. void makron_dead(edict_t *self);
  18. static cached_soundindex sound_pain4;
  19. static cached_soundindex sound_pain5;
  20. static cached_soundindex sound_pain6;
  21. static cached_soundindex sound_death;
  22. static cached_soundindex sound_step_left;
  23. static cached_soundindex sound_step_right;
  24. static cached_soundindex sound_attack_bfg;
  25. static cached_soundindex sound_brainsplorch;
  26. static cached_soundindex sound_prerailgun;
  27. static cached_soundindex sound_popup;
  28. static cached_soundindex sound_taunt1;
  29. static cached_soundindex sound_taunt2;
  30. static cached_soundindex sound_taunt3;
  31. static cached_soundindex sound_hit;
  32. void makron_taunt(edict_t *self)
  33. {
  34. float r;
  35. r = frandom();
  36. if (r <= 0.3f)
  37. gi.sound(self, CHAN_AUTO, sound_taunt1, 1, ATTN_NONE, 0);
  38. else if (r <= 0.6f)
  39. gi.sound(self, CHAN_AUTO, sound_taunt2, 1, ATTN_NONE, 0);
  40. else
  41. gi.sound(self, CHAN_AUTO, sound_taunt3, 1, ATTN_NONE, 0);
  42. }
  43. //
  44. // stand
  45. //
  46. mframe_t makron_frames_stand[] = {
  47. { ai_stand },
  48. { ai_stand },
  49. { ai_stand },
  50. { ai_stand },
  51. { ai_stand },
  52. { ai_stand },
  53. { ai_stand },
  54. { ai_stand },
  55. { ai_stand },
  56. { ai_stand }, // 10
  57. { ai_stand },
  58. { ai_stand },
  59. { ai_stand },
  60. { ai_stand },
  61. { ai_stand },
  62. { ai_stand },
  63. { ai_stand },
  64. { ai_stand },
  65. { ai_stand },
  66. { ai_stand }, // 20
  67. { ai_stand },
  68. { ai_stand },
  69. { ai_stand },
  70. { ai_stand },
  71. { ai_stand },
  72. { ai_stand },
  73. { ai_stand },
  74. { ai_stand },
  75. { ai_stand },
  76. { ai_stand }, // 30
  77. { ai_stand },
  78. { ai_stand },
  79. { ai_stand },
  80. { ai_stand },
  81. { ai_stand },
  82. { ai_stand },
  83. { ai_stand },
  84. { ai_stand },
  85. { ai_stand },
  86. { ai_stand }, // 40
  87. { ai_stand },
  88. { ai_stand },
  89. { ai_stand },
  90. { ai_stand },
  91. { ai_stand },
  92. { ai_stand },
  93. { ai_stand },
  94. { ai_stand },
  95. { ai_stand },
  96. { ai_stand }, // 50
  97. { ai_stand },
  98. { ai_stand },
  99. { ai_stand },
  100. { ai_stand },
  101. { ai_stand },
  102. { ai_stand },
  103. { ai_stand },
  104. { ai_stand },
  105. { ai_stand },
  106. { ai_stand } // 60
  107. };
  108. MMOVE_T(makron_move_stand) = { FRAME_stand201, FRAME_stand260, makron_frames_stand, nullptr };
  109. MONSTERINFO_STAND(makron_stand) (edict_t *self) -> void
  110. {
  111. M_SetAnimation(self, &makron_move_stand);
  112. }
  113. mframe_t makron_frames_run[] = {
  114. { ai_run, 3, makron_step_left },
  115. { ai_run, 12 },
  116. { ai_run, 8 },
  117. { ai_run, 8 },
  118. { ai_run, 8, makron_step_right },
  119. { ai_run, 6 },
  120. { ai_run, 12 },
  121. { ai_run, 9 },
  122. { ai_run, 6 },
  123. { ai_run, 12 }
  124. };
  125. MMOVE_T(makron_move_run) = { FRAME_walk204, FRAME_walk213, makron_frames_run, nullptr };
  126. void makron_hit(edict_t *self)
  127. {
  128. gi.sound(self, CHAN_AUTO, sound_hit, 1, ATTN_NONE, 0);
  129. }
  130. void makron_popup(edict_t *self)
  131. {
  132. gi.sound(self, CHAN_BODY, sound_popup, 1, ATTN_NONE, 0);
  133. }
  134. void makron_step_left(edict_t *self)
  135. {
  136. gi.sound(self, CHAN_BODY, sound_step_left, 1, ATTN_NORM, 0);
  137. }
  138. void makron_step_right(edict_t *self)
  139. {
  140. gi.sound(self, CHAN_BODY, sound_step_right, 1, ATTN_NORM, 0);
  141. }
  142. void makron_brainsplorch(edict_t *self)
  143. {
  144. gi.sound(self, CHAN_VOICE, sound_brainsplorch, 1, ATTN_NORM, 0);
  145. }
  146. void makron_prerailgun(edict_t *self)
  147. {
  148. gi.sound(self, CHAN_WEAPON, sound_prerailgun, 1, ATTN_NORM, 0);
  149. }
  150. mframe_t makron_frames_walk[] = {
  151. { ai_walk, 3, makron_step_left },
  152. { ai_walk, 12 },
  153. { ai_walk, 8 },
  154. { ai_walk, 8 },
  155. { ai_walk, 8, makron_step_right },
  156. { ai_walk, 6 },
  157. { ai_walk, 12 },
  158. { ai_walk, 9 },
  159. { ai_walk, 6 },
  160. { ai_walk, 12 }
  161. };
  162. MMOVE_T(makron_move_walk) = { FRAME_walk204, FRAME_walk213, makron_frames_run, nullptr };
  163. MONSTERINFO_WALK(makron_walk) (edict_t *self) -> void
  164. {
  165. M_SetAnimation(self, &makron_move_walk);
  166. }
  167. MONSTERINFO_RUN(makron_run) (edict_t *self) -> void
  168. {
  169. if (self->monsterinfo.aiflags & AI_STAND_GROUND)
  170. M_SetAnimation(self, &makron_move_stand);
  171. else
  172. M_SetAnimation(self, &makron_move_run);
  173. }
  174. mframe_t makron_frames_pain6[] = {
  175. { ai_move },
  176. { ai_move },
  177. { ai_move },
  178. { ai_move },
  179. { ai_move },
  180. { ai_move },
  181. { ai_move },
  182. { ai_move },
  183. { ai_move },
  184. { ai_move }, // 10
  185. { ai_move },
  186. { ai_move },
  187. { ai_move },
  188. { ai_move },
  189. { ai_move },
  190. { ai_move, 0, makron_popup },
  191. { ai_move },
  192. { ai_move },
  193. { ai_move },
  194. { ai_move }, // 20
  195. { ai_move },
  196. { ai_move },
  197. { ai_move },
  198. { ai_move, 0, makron_taunt },
  199. { ai_move },
  200. { ai_move },
  201. { ai_move }
  202. };
  203. MMOVE_T(makron_move_pain6) = { FRAME_pain601, FRAME_pain627, makron_frames_pain6, makron_run };
  204. mframe_t makron_frames_pain5[] = {
  205. { ai_move },
  206. { ai_move },
  207. { ai_move },
  208. { ai_move }
  209. };
  210. MMOVE_T(makron_move_pain5) = { FRAME_pain501, FRAME_pain504, makron_frames_pain5, makron_run };
  211. mframe_t makron_frames_pain4[] = {
  212. { ai_move },
  213. { ai_move },
  214. { ai_move },
  215. { ai_move }
  216. };
  217. MMOVE_T(makron_move_pain4) = { FRAME_pain401, FRAME_pain404, makron_frames_pain4, makron_run };
  218. /*
  219. ---
  220. Makron Torso. This needs to be spawned in
  221. ---
  222. */
  223. THINK(makron_torso_think) (edict_t *self) -> void
  224. {
  225. if (++self->s.frame >= 365)
  226. self->s.frame = 346;
  227. self->nextthink = level.time + 10_hz;
  228. if (self->s.angles[0] > 0)
  229. self->s.angles[0] = max(0.f, self->s.angles[0] - 15);
  230. }
  231. void makron_torso(edict_t *ent)
  232. {
  233. ent->s.frame = 346;
  234. ent->s.modelindex = gi.modelindex("models/monsters/boss3/rider/tris.md2");
  235. ent->s.skinnum = 1;
  236. ent->think = makron_torso_think;
  237. ent->nextthink = level.time + 10_hz;
  238. ent->s.sound = gi.soundindex("makron/spine.wav");
  239. ent->movetype = MOVETYPE_TOSS;
  240. ent->s.effects = EF_GIB;
  241. vec3_t forward, up;
  242. AngleVectors(ent->s.angles, forward, nullptr, up);
  243. ent->velocity += (up * 120);
  244. ent->velocity += (forward * -120);
  245. ent->s.origin += (forward * -10);
  246. ent->s.angles[0] = 90;
  247. ent->avelocity = {};
  248. gi.linkentity(ent);
  249. }
  250. void makron_spawn_torso(edict_t *self)
  251. {
  252. edict_t *tempent = ThrowGib(self, "models/monsters/boss3/rider/tris.md2", 0, GIB_NONE, self->s.scale);
  253. tempent->s.origin = self->s.origin;
  254. tempent->s.angles = self->s.angles;
  255. self->maxs[2] -= tempent->maxs[2];
  256. tempent->s.origin[2] += self->maxs[2] - 15;
  257. makron_torso(tempent);
  258. }
  259. mframe_t makron_frames_death2[] = {
  260. { ai_move, -15 },
  261. { ai_move, 3 },
  262. { ai_move, -12 },
  263. { ai_move, 0, makron_step_left },
  264. { ai_move },
  265. { ai_move },
  266. { ai_move },
  267. { ai_move },
  268. { ai_move },
  269. { ai_move }, // 10
  270. { ai_move },
  271. { ai_move },
  272. { ai_move },
  273. { ai_move },
  274. { ai_move },
  275. { ai_move, 11 },
  276. { ai_move, 12 },
  277. { ai_move, 11, makron_step_right },
  278. { ai_move },
  279. { ai_move }, // 20
  280. { ai_move },
  281. { ai_move },
  282. { ai_move },
  283. { ai_move },
  284. { ai_move },
  285. { ai_move },
  286. { ai_move },
  287. { ai_move },
  288. { ai_move },
  289. { ai_move }, // 30
  290. { ai_move },
  291. { ai_move },
  292. { ai_move },
  293. { ai_move, 5 },
  294. { ai_move, 7 },
  295. { ai_move, 6, makron_step_left },
  296. { ai_move },
  297. { ai_move },
  298. { ai_move, -1 },
  299. { ai_move, 2 }, // 40
  300. { ai_move },
  301. { ai_move },
  302. { ai_move },
  303. { ai_move },
  304. { ai_move },
  305. { ai_move },
  306. { ai_move },
  307. { ai_move },
  308. { ai_move },
  309. { ai_move }, // 50
  310. { ai_move },
  311. { ai_move },
  312. { ai_move },
  313. { ai_move, -6 },
  314. { ai_move, -4 },
  315. { ai_move, -6, makron_step_right },
  316. { ai_move, -4 },
  317. { ai_move, -4, makron_step_left },
  318. { ai_move },
  319. { ai_move }, // 60
  320. { ai_move },
  321. { ai_move },
  322. { ai_move, -2 },
  323. { ai_move, -5 },
  324. { ai_move, -3, makron_step_right },
  325. { ai_move, -8 },
  326. { ai_move, -3, makron_step_left },
  327. { ai_move, -7 },
  328. { ai_move, -4 },
  329. { ai_move, -4, makron_step_right }, // 70
  330. { ai_move, -6 },
  331. { ai_move, -7 },
  332. { ai_move, 0, makron_step_left },
  333. { ai_move },
  334. { ai_move },
  335. { ai_move },
  336. { ai_move },
  337. { ai_move },
  338. { ai_move },
  339. { ai_move }, // 80
  340. { ai_move },
  341. { ai_move },
  342. { ai_move },
  343. { ai_move },
  344. { ai_move },
  345. { ai_move, -2 },
  346. { ai_move },
  347. { ai_move },
  348. { ai_move, 2 },
  349. { ai_move }, // 90
  350. { ai_move, 27, makron_hit },
  351. { ai_move, 26 },
  352. { ai_move, 0, makron_brainsplorch },
  353. { ai_move },
  354. { ai_move } // 95
  355. };
  356. MMOVE_T(makron_move_death2) = { FRAME_death201, FRAME_death295, makron_frames_death2, makron_dead };
  357. #if 0
  358. mframe_t makron_frames_death3[] = {
  359. { ai_move },
  360. { ai_move },
  361. { ai_move },
  362. { ai_move },
  363. { ai_move },
  364. { ai_move },
  365. { ai_move },
  366. { ai_move },
  367. { ai_move },
  368. { ai_move },
  369. { ai_move },
  370. { ai_move },
  371. { ai_move },
  372. { ai_move },
  373. { ai_move },
  374. { ai_move },
  375. { ai_move },
  376. { ai_move },
  377. { ai_move },
  378. { ai_move }
  379. };
  380. MMOVE_T(makron_move_death3) = { FRAME_death301, FRAME_death320, makron_frames_death3, nullptr };
  381. #endif
  382. mframe_t makron_frames_sight[] = {
  383. { ai_move },
  384. { ai_move },
  385. { ai_move },
  386. { ai_move },
  387. { ai_move },
  388. { ai_move },
  389. { ai_move },
  390. { ai_move },
  391. { ai_move },
  392. { ai_move },
  393. { ai_move },
  394. { ai_move },
  395. { ai_move }
  396. };
  397. MMOVE_T(makron_move_sight) = { FRAME_active01, FRAME_active13, makron_frames_sight, makron_run };
  398. void makronBFG(edict_t *self)
  399. {
  400. vec3_t forward, right;
  401. vec3_t start;
  402. vec3_t dir;
  403. vec3_t vec;
  404. AngleVectors(self->s.angles, forward, right, nullptr);
  405. start = M_ProjectFlashSource(self, monster_flash_offset[MZ2_MAKRON_BFG], forward, right);
  406. vec = self->enemy->s.origin;
  407. vec[2] += self->enemy->viewheight;
  408. dir = vec - start;
  409. dir.normalize();
  410. gi.sound(self, CHAN_VOICE, sound_attack_bfg, 1, ATTN_NORM, 0);
  411. monster_fire_bfg(self, start, dir, 50, 300, 100, 300, MZ2_MAKRON_BFG);
  412. }
  413. mframe_t makron_frames_attack3[] = {
  414. { ai_charge },
  415. { ai_charge },
  416. { ai_charge },
  417. { ai_charge, 0, makronBFG },
  418. { ai_move },
  419. { ai_move },
  420. { ai_move },
  421. { ai_move }
  422. };
  423. MMOVE_T(makron_move_attack3) = { FRAME_attak301, FRAME_attak308, makron_frames_attack3, makron_run };
  424. mframe_t makron_frames_attack4[] = {
  425. { ai_charge },
  426. { ai_charge },
  427. { ai_charge },
  428. { ai_charge },
  429. { ai_move, 0, MakronHyperblaster }, // fire
  430. { ai_move, 0, MakronHyperblaster }, // fire
  431. { ai_move, 0, MakronHyperblaster }, // fire
  432. { ai_move, 0, MakronHyperblaster }, // fire
  433. { ai_move, 0, MakronHyperblaster }, // fire
  434. { ai_move, 0, MakronHyperblaster }, // fire
  435. { ai_move, 0, MakronHyperblaster }, // fire
  436. { ai_move, 0, MakronHyperblaster }, // fire
  437. { ai_move, 0, MakronHyperblaster }, // fire
  438. { ai_move, 0, MakronHyperblaster }, // fire
  439. { ai_move, 0, MakronHyperblaster }, // fire
  440. { ai_move, 0, MakronHyperblaster }, // fire
  441. { ai_move, 0, MakronHyperblaster }, // fire
  442. { ai_move, 0, MakronHyperblaster }, // fire
  443. { ai_move, 0, MakronHyperblaster }, // fire
  444. { ai_move, 0, MakronHyperblaster }, // fire
  445. { ai_move, 0, MakronHyperblaster }, // fire
  446. { ai_move },
  447. { ai_move },
  448. { ai_move },
  449. { ai_move },
  450. { ai_move }
  451. };
  452. MMOVE_T(makron_move_attack4) = { FRAME_attak401, FRAME_attak426, makron_frames_attack4, makron_run };
  453. mframe_t makron_frames_attack5[] = {
  454. { ai_charge, 0, makron_prerailgun },
  455. { ai_charge },
  456. { ai_charge },
  457. { ai_charge },
  458. { ai_charge },
  459. { ai_charge },
  460. { ai_charge },
  461. { ai_charge, 0, MakronSaveloc },
  462. { ai_move, 0, MakronRailgun }, // Fire railgun
  463. { ai_move },
  464. { ai_move },
  465. { ai_move },
  466. { ai_move },
  467. { ai_move },
  468. { ai_move },
  469. { ai_move }
  470. };
  471. MMOVE_T(makron_move_attack5) = { FRAME_attak501, FRAME_attak516, makron_frames_attack5, makron_run };
  472. void MakronSaveloc(edict_t *self)
  473. {
  474. self->pos1 = self->enemy->s.origin; // save for aiming the shot
  475. self->pos1[2] += self->enemy->viewheight;
  476. };
  477. void MakronRailgun(edict_t *self)
  478. {
  479. vec3_t start;
  480. vec3_t dir;
  481. vec3_t forward, right;
  482. AngleVectors(self->s.angles, forward, right, nullptr);
  483. start = M_ProjectFlashSource(self, monster_flash_offset[MZ2_MAKRON_RAILGUN_1], forward, right);
  484. // calc direction to where we targted
  485. dir = self->pos1 - start;
  486. dir.normalize();
  487. monster_fire_railgun(self, start, dir, 50, 100, MZ2_MAKRON_RAILGUN_1);
  488. }
  489. void MakronHyperblaster(edict_t *self)
  490. {
  491. vec3_t dir;
  492. vec3_t vec;
  493. vec3_t start;
  494. vec3_t forward, right;
  495. monster_muzzleflash_id_t flash_number = (monster_muzzleflash_id_t) (MZ2_MAKRON_BLASTER_1 + (self->s.frame - FRAME_attak405));
  496. AngleVectors(self->s.angles, forward, right, nullptr);
  497. start = M_ProjectFlashSource(self, monster_flash_offset[flash_number], forward, right);
  498. if (self->enemy)
  499. {
  500. vec = self->enemy->s.origin;
  501. vec[2] += self->enemy->viewheight;
  502. vec -= start;
  503. vec = vectoangles(vec);
  504. dir[0] = vec[0];
  505. }
  506. else
  507. {
  508. dir[0] = 0;
  509. }
  510. if (self->s.frame <= FRAME_attak413)
  511. dir[1] = self->s.angles[1] - 10 * (self->s.frame - FRAME_attak413);
  512. else
  513. dir[1] = self->s.angles[1] + 10 * (self->s.frame - FRAME_attak421);
  514. dir[2] = 0;
  515. AngleVectors(dir, forward, nullptr, nullptr);
  516. monster_fire_blaster(self, start, forward, 15, 1000, flash_number, EF_BLASTER);
  517. }
  518. PAIN(makron_pain) (edict_t *self, edict_t *other, float kick, int damage, const mod_t &mod) -> void
  519. {
  520. if (self->monsterinfo.active_move == &makron_move_sight)
  521. return;
  522. if (level.time < self->pain_debounce_time)
  523. return;
  524. // Lessen the chance of him going into his pain frames
  525. if (mod.id != MOD_CHAINFIST && damage <= 25)
  526. if (frandom() < 0.2f)
  527. return;
  528. self->pain_debounce_time = level.time + 3_sec;
  529. bool do_pain6 = false;
  530. if (damage <= 40)
  531. gi.sound(self, CHAN_VOICE, sound_pain4, 1, ATTN_NONE, 0);
  532. else if (damage <= 110)
  533. gi.sound(self, CHAN_VOICE, sound_pain5, 1, ATTN_NONE, 0);
  534. else
  535. {
  536. if (damage <= 150)
  537. {
  538. if (frandom() <= 0.45f)
  539. {
  540. do_pain6 = true;
  541. gi.sound(self, CHAN_VOICE, sound_pain6, 1, ATTN_NONE, 0);
  542. }
  543. }
  544. else
  545. {
  546. if (frandom() <= 0.35f)
  547. {
  548. do_pain6 = true;
  549. gi.sound(self, CHAN_VOICE, sound_pain6, 1, ATTN_NONE, 0);
  550. }
  551. }
  552. }
  553. if (!M_ShouldReactToPain(self, mod))
  554. return; // no pain anims in nightmare
  555. if (damage <= 40)
  556. M_SetAnimation(self, &makron_move_pain4);
  557. else if (damage <= 110)
  558. M_SetAnimation(self, &makron_move_pain5);
  559. else if (do_pain6)
  560. M_SetAnimation(self, &makron_move_pain6);
  561. }
  562. MONSTERINFO_SETSKIN(makron_setskin) (edict_t *self) -> void
  563. {
  564. if (self->health < (self->max_health / 2))
  565. self->s.skinnum = 1;
  566. else
  567. self->s.skinnum = 0;
  568. }
  569. MONSTERINFO_SIGHT(makron_sight) (edict_t *self, edict_t *other) -> void
  570. {
  571. M_SetAnimation(self, &makron_move_sight);
  572. }
  573. MONSTERINFO_ATTACK(makron_attack) (edict_t *self) -> void
  574. {
  575. float r;
  576. r = frandom();
  577. if (r <= 0.3f)
  578. M_SetAnimation(self, &makron_move_attack3);
  579. else if (r <= 0.6f)
  580. M_SetAnimation(self, &makron_move_attack4);
  581. else
  582. M_SetAnimation(self, &makron_move_attack5);
  583. }
  584. //
  585. // death
  586. //
  587. void makron_dead(edict_t *self)
  588. {
  589. self->mins = { -60, -60, 0 };
  590. self->maxs = { 60, 60, 24 };
  591. self->movetype = MOVETYPE_TOSS;
  592. self->svflags |= SVF_DEADMONSTER;
  593. gi.linkentity(self);
  594. monster_dead(self);
  595. }
  596. DIE(makron_die) (edict_t *self, edict_t *inflictor, edict_t *attacker, int damage, const vec3_t &point, const mod_t &mod) -> void
  597. {
  598. self->s.sound = 0;
  599. // check for gib
  600. if (M_CheckGib(self, mod))
  601. {
  602. gi.sound(self, CHAN_VOICE, gi.soundindex("misc/udeath.wav"), 1, ATTN_NORM, 0);
  603. ThrowGibs(self, damage, {
  604. { "models/objects/gibs/sm_meat/tris.md2" },
  605. { 4, "models/objects/gibs/sm_metal/tris.md2", GIB_METALLIC },
  606. { "models/objects/gibs/gear/tris.md2", GIB_METALLIC | GIB_HEAD }
  607. });
  608. self->deadflag = true;
  609. return;
  610. }
  611. if (self->deadflag)
  612. return;
  613. // regular death
  614. gi.sound(self, CHAN_VOICE, sound_death, 1, ATTN_NONE, 0);
  615. self->deadflag = true;
  616. self->takedamage = true;
  617. self->svflags |= SVF_DEADMONSTER;
  618. M_SetAnimation(self, &makron_move_death2);
  619. makron_spawn_torso(self);
  620. self->mins = { -60, -60, 0 };
  621. self->maxs = { 60, 60, 48 };
  622. }
  623. // [Paril-KEX] use generic function
  624. MONSTERINFO_CHECKATTACK(Makron_CheckAttack) (edict_t *self) -> bool
  625. {
  626. return M_CheckAttack_Base(self, 0.4f, 0.8f, 0.4f, 0.2f, 0.0f, 0.f);
  627. }
  628. //
  629. // monster_makron
  630. //
  631. void MakronPrecache()
  632. {
  633. sound_pain4.assign("makron/pain3.wav");
  634. sound_pain5.assign("makron/pain2.wav");
  635. sound_pain6.assign("makron/pain1.wav");
  636. sound_death.assign("makron/death.wav");
  637. sound_step_left.assign("makron/step1.wav");
  638. sound_step_right.assign("makron/step2.wav");
  639. sound_attack_bfg.assign("makron/bfg_fire.wav");
  640. sound_brainsplorch.assign("makron/brain1.wav");
  641. sound_prerailgun.assign("makron/rail_up.wav");
  642. sound_popup.assign("makron/popup.wav");
  643. sound_taunt1.assign("makron/voice4.wav");
  644. sound_taunt2.assign("makron/voice3.wav");
  645. sound_taunt3.assign("makron/voice.wav");
  646. sound_hit.assign("makron/bhit.wav");
  647. gi.modelindex("models/monsters/boss3/rider/tris.md2");
  648. }
  649. /*QUAKED monster_makron (1 .5 0) (-30 -30 0) (30 30 90) Ambush Trigger_Spawn Sight
  650. */
  651. void SP_monster_makron(edict_t *self)
  652. {
  653. if ( !M_AllowSpawn( self ) ) {
  654. G_FreeEdict( self );
  655. return;
  656. }
  657. MakronPrecache();
  658. self->movetype = MOVETYPE_STEP;
  659. self->solid = SOLID_BBOX;
  660. self->s.modelindex = gi.modelindex("models/monsters/boss3/rider/tris.md2");
  661. self->mins = { -30, -30, 0 };
  662. self->maxs = { 30, 30, 90 };
  663. self->health = 3000 * st.health_multiplier;
  664. self->gib_health = -2000;
  665. self->mass = 500;
  666. self->pain = makron_pain;
  667. self->die = makron_die;
  668. self->monsterinfo.stand = makron_stand;
  669. self->monsterinfo.walk = makron_walk;
  670. self->monsterinfo.run = makron_run;
  671. self->monsterinfo.dodge = nullptr;
  672. self->monsterinfo.attack = makron_attack;
  673. self->monsterinfo.melee = nullptr;
  674. self->monsterinfo.sight = makron_sight;
  675. self->monsterinfo.checkattack = Makron_CheckAttack;
  676. self->monsterinfo.setskin = makron_setskin;
  677. gi.linkentity(self);
  678. // M_SetAnimation(self, &makron_move_stand);
  679. M_SetAnimation(self, &makron_move_sight);
  680. self->monsterinfo.scale = MODEL_SCALE;
  681. walkmonster_start(self);
  682. // PMM
  683. self->monsterinfo.aiflags |= AI_IGNORE_SHOTS;
  684. // pmm
  685. }
  686. /*
  687. =================
  688. MakronSpawn
  689. =================
  690. */
  691. THINK(MakronSpawn) (edict_t *self) -> void
  692. {
  693. vec3_t vec;
  694. edict_t *player;
  695. SP_monster_makron(self);
  696. self->think(self);
  697. // jump at player
  698. if (self->enemy && self->enemy->inuse && self->enemy->health > 0)
  699. player = self->enemy;
  700. else
  701. player = AI_GetSightClient(self);
  702. if (!player)
  703. return;
  704. vec = player->s.origin - self->s.origin;
  705. self->s.angles[YAW] = vectoyaw(vec);
  706. vec.normalize();
  707. self->velocity = vec * 400;
  708. self->velocity[2] = 200;
  709. self->groundentity = nullptr;
  710. self->enemy = player;
  711. FoundTarget(self);
  712. self->monsterinfo.sight(self, self->enemy);
  713. self->s.frame = self->monsterinfo.nextframe = FRAME_active01; // FIXME: why????
  714. }
  715. /*
  716. =================
  717. MakronToss
  718. Jorg is just about dead, so set up to launch Makron out
  719. =================
  720. */
  721. void MakronToss(edict_t *self)
  722. {
  723. edict_t *ent = G_Spawn();
  724. ent->classname = "monster_makron";
  725. ent->target = self->target;
  726. ent->s.origin = self->s.origin;
  727. ent->enemy = self->enemy;
  728. MakronSpawn(ent);
  729. // [Paril-KEX] set health bar over to Makron when we throw him out
  730. for (size_t i = 0; i < 2; i++)
  731. if (level.health_bar_entities[i] && level.health_bar_entities[i]->enemy == self)
  732. level.health_bar_entities[i]->enemy = ent;
  733. }