m_supertank.cpp 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731
  1. // Copyright (c) ZeniMax Media Inc.
  2. // Licensed under the GNU General Public License 2.0.
  3. /*
  4. ==============================================================================
  5. SUPERTANK
  6. ==============================================================================
  7. */
  8. #include "g_local.h"
  9. #include "m_supertank.h"
  10. #include "m_flash.h"
  11. constexpr spawnflags_t SPAWNFLAG_SUPERTANK_POWERSHIELD = 8_spawnflag;
  12. // n64
  13. constexpr spawnflags_t SPAWNFLAG_SUPERTANK_LONG_DEATH = 16_spawnflag;
  14. static cached_soundindex sound_pain1;
  15. static cached_soundindex sound_pain2;
  16. static cached_soundindex sound_pain3;
  17. static cached_soundindex sound_death;
  18. static cached_soundindex sound_search1;
  19. static cached_soundindex sound_search2;
  20. static cached_soundindex tread_sound;
  21. void TreadSound(edict_t *self)
  22. {
  23. gi.sound(self, CHAN_BODY, tread_sound, 1, ATTN_NORM, 0);
  24. }
  25. MONSTERINFO_SEARCH(supertank_search) (edict_t *self) -> void
  26. {
  27. if (frandom() < 0.5f)
  28. gi.sound(self, CHAN_VOICE, sound_search1, 1, ATTN_NORM, 0);
  29. else
  30. gi.sound(self, CHAN_VOICE, sound_search2, 1, ATTN_NORM, 0);
  31. }
  32. void supertank_dead(edict_t *self);
  33. void supertankRocket(edict_t *self);
  34. void supertankMachineGun(edict_t *self);
  35. void supertank_reattack1(edict_t *self);
  36. //
  37. // stand
  38. //
  39. mframe_t supertank_frames_stand[] = {
  40. { ai_stand },
  41. { ai_stand },
  42. { ai_stand },
  43. { ai_stand },
  44. { ai_stand },
  45. { ai_stand },
  46. { ai_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 },
  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 },
  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 },
  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 },
  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 },
  97. { ai_stand },
  98. { ai_stand },
  99. { ai_stand }
  100. };
  101. MMOVE_T(supertank_move_stand) = { FRAME_stand_1, FRAME_stand_60, supertank_frames_stand, nullptr };
  102. MONSTERINFO_STAND(supertank_stand) (edict_t *self) -> void
  103. {
  104. M_SetAnimation(self, &supertank_move_stand);
  105. }
  106. mframe_t supertank_frames_run[] = {
  107. { ai_run, 12, TreadSound },
  108. { ai_run, 12 },
  109. { ai_run, 12 },
  110. { ai_run, 12 },
  111. { ai_run, 12 },
  112. { ai_run, 12 },
  113. { ai_run, 12 },
  114. { ai_run, 12 },
  115. { ai_run, 12 },
  116. { ai_run, 12 },
  117. { ai_run, 12 },
  118. { ai_run, 12 },
  119. { ai_run, 12 },
  120. { ai_run, 12 },
  121. { ai_run, 12 },
  122. { ai_run, 12 },
  123. { ai_run, 12 },
  124. { ai_run, 12 }
  125. };
  126. MMOVE_T(supertank_move_run) = { FRAME_forwrd_1, FRAME_forwrd_18, supertank_frames_run, nullptr };
  127. //
  128. // walk
  129. //
  130. mframe_t supertank_frames_forward[] = {
  131. { ai_walk, 4, TreadSound },
  132. { ai_walk, 4 },
  133. { ai_walk, 4 },
  134. { ai_walk, 4 },
  135. { ai_walk, 4 },
  136. { ai_walk, 4 },
  137. { ai_walk, 4 },
  138. { ai_walk, 4 },
  139. { ai_walk, 4 },
  140. { ai_walk, 4 },
  141. { ai_walk, 4 },
  142. { ai_walk, 4 },
  143. { ai_walk, 4 },
  144. { ai_walk, 4 },
  145. { ai_walk, 4 },
  146. { ai_walk, 4 },
  147. { ai_walk, 4 },
  148. { ai_walk, 4 }
  149. };
  150. MMOVE_T(supertank_move_forward) = { FRAME_forwrd_1, FRAME_forwrd_18, supertank_frames_forward, nullptr };
  151. void supertank_forward(edict_t *self)
  152. {
  153. M_SetAnimation(self, &supertank_move_forward);
  154. }
  155. MONSTERINFO_WALK(supertank_walk) (edict_t *self) -> void
  156. {
  157. M_SetAnimation(self, &supertank_move_forward);
  158. }
  159. MONSTERINFO_RUN(supertank_run) (edict_t *self) -> void
  160. {
  161. if (self->monsterinfo.aiflags & AI_STAND_GROUND)
  162. M_SetAnimation(self, &supertank_move_stand);
  163. else
  164. M_SetAnimation(self, &supertank_move_run);
  165. }
  166. #if 0
  167. mframe_t supertank_frames_turn_right[] = {
  168. { ai_move, 0, TreadSound },
  169. { ai_move },
  170. { ai_move },
  171. { ai_move },
  172. { ai_move },
  173. { ai_move },
  174. { ai_move },
  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 },
  185. { ai_move }
  186. };
  187. MMOVE_T(supertank_move_turn_right) = { FRAME_right_1, FRAME_right_18, supertank_frames_turn_right, supertank_run };
  188. mframe_t supertank_frames_turn_left[] = {
  189. { ai_move, 0, TreadSound },
  190. { ai_move },
  191. { ai_move },
  192. { ai_move },
  193. { ai_move },
  194. { ai_move },
  195. { ai_move },
  196. { ai_move },
  197. { ai_move },
  198. { ai_move },
  199. { ai_move },
  200. { ai_move },
  201. { ai_move },
  202. { ai_move },
  203. { ai_move },
  204. { ai_move },
  205. { ai_move },
  206. { ai_move }
  207. };
  208. MMOVE_T(supertank_move_turn_left) = { FRAME_left_1, FRAME_left_18, supertank_frames_turn_left, supertank_run };
  209. #endif
  210. mframe_t supertank_frames_pain3[] = {
  211. { ai_move },
  212. { ai_move },
  213. { ai_move },
  214. { ai_move }
  215. };
  216. MMOVE_T(supertank_move_pain3) = { FRAME_pain3_9, FRAME_pain3_12, supertank_frames_pain3, supertank_run };
  217. mframe_t supertank_frames_pain2[] = {
  218. { ai_move },
  219. { ai_move },
  220. { ai_move },
  221. { ai_move }
  222. };
  223. MMOVE_T(supertank_move_pain2) = { FRAME_pain2_5, FRAME_pain2_8, supertank_frames_pain2, supertank_run };
  224. mframe_t supertank_frames_pain1[] = {
  225. { ai_move },
  226. { ai_move },
  227. { ai_move },
  228. { ai_move }
  229. };
  230. MMOVE_T(supertank_move_pain1) = { FRAME_pain1_1, FRAME_pain1_4, supertank_frames_pain1, supertank_run };
  231. static void BossLoop(edict_t *self)
  232. {
  233. if (!(self->spawnflags & SPAWNFLAG_SUPERTANK_LONG_DEATH))
  234. return;
  235. if (self->count)
  236. self->count--;
  237. else
  238. self->spawnflags &= ~SPAWNFLAG_SUPERTANK_LONG_DEATH;
  239. self->monsterinfo.nextframe = FRAME_death_19;
  240. }
  241. static void supertankGrenade(edict_t *self)
  242. {
  243. vec3_t forward, right;
  244. vec3_t start;
  245. monster_muzzleflash_id_t flash_number;
  246. if (!self->enemy || !self->enemy->inuse) // PGM
  247. return; // PGM
  248. if (self->s.frame == FRAME_attak4_1)
  249. flash_number = MZ2_SUPERTANK_GRENADE_1;
  250. else
  251. flash_number = MZ2_SUPERTANK_GRENADE_2;
  252. AngleVectors(self->s.angles, forward, right, nullptr);
  253. start = M_ProjectFlashSource(self, monster_flash_offset[flash_number], forward, right);
  254. vec3_t aim_point;
  255. PredictAim(self, self->enemy, start, 0, false, crandom_open() * 0.1f, &forward, &aim_point);
  256. for (float speed = 500.f; speed < 1000.f; speed += 100.f)
  257. {
  258. if (!M_CalculatePitchToFire(self, aim_point, start, forward, speed, 2.5f, true))
  259. continue;
  260. monster_fire_grenade(self, start, forward, 50, speed, flash_number, 0.f, 0.f);
  261. break;
  262. }
  263. }
  264. mframe_t supertank_frames_death1[] = {
  265. { ai_move, 0, BossExplode },
  266. { ai_move },
  267. { ai_move },
  268. { ai_move },
  269. { ai_move },
  270. { ai_move },
  271. { ai_move },
  272. { ai_move },
  273. { ai_move },
  274. { ai_move },
  275. { ai_move },
  276. { ai_move },
  277. { ai_move },
  278. { ai_move },
  279. { ai_move },
  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, 0, BossLoop }
  289. };
  290. MMOVE_T(supertank_move_death) = { FRAME_death_1, FRAME_death_24, supertank_frames_death1, supertank_dead };
  291. mframe_t supertank_frames_attack4[] = {
  292. { ai_move, 0, supertankGrenade },
  293. { ai_move },
  294. { ai_move },
  295. { ai_move, 0, supertankGrenade },
  296. { ai_move },
  297. { ai_move }
  298. };
  299. MMOVE_T(supertank_move_attack4) = { FRAME_attak4_1, FRAME_attak4_6, supertank_frames_attack4, supertank_run };
  300. mframe_t supertank_frames_attack2[] = {
  301. { ai_charge },
  302. { ai_charge },
  303. { ai_charge },
  304. { ai_charge },
  305. { ai_charge },
  306. { ai_charge },
  307. { ai_charge },
  308. { ai_charge, 0, supertankRocket },
  309. { ai_charge },
  310. { ai_charge },
  311. { ai_charge, 0, supertankRocket },
  312. { ai_charge },
  313. { ai_charge },
  314. { ai_charge, 0, supertankRocket },
  315. { ai_charge },
  316. { ai_charge },
  317. { ai_charge },
  318. { ai_charge },
  319. { ai_charge },
  320. { ai_charge },
  321. { ai_charge },
  322. { ai_move },
  323. { ai_move },
  324. { ai_move },
  325. { ai_move },
  326. { ai_move },
  327. { ai_move }
  328. };
  329. MMOVE_T(supertank_move_attack2) = { FRAME_attak2_1, FRAME_attak2_27, supertank_frames_attack2, supertank_run };
  330. mframe_t supertank_frames_attack1[] = {
  331. { ai_charge, 0, supertankMachineGun },
  332. { ai_charge, 0, supertankMachineGun },
  333. { ai_charge, 0, supertankMachineGun },
  334. { ai_charge, 0, supertankMachineGun },
  335. { ai_charge, 0, supertankMachineGun },
  336. { ai_charge, 0, supertankMachineGun },
  337. };
  338. MMOVE_T(supertank_move_attack1) = { FRAME_attak1_1, FRAME_attak1_6, supertank_frames_attack1, supertank_reattack1 };
  339. mframe_t supertank_frames_end_attack1[] = {
  340. { ai_move },
  341. { ai_move },
  342. { ai_move },
  343. { ai_move },
  344. { ai_move },
  345. { ai_move },
  346. { ai_move },
  347. { ai_move },
  348. { ai_move },
  349. { ai_move },
  350. { ai_move },
  351. { ai_move },
  352. { ai_move },
  353. { ai_move }
  354. };
  355. MMOVE_T(supertank_move_end_attack1) = { FRAME_attak1_7, FRAME_attak1_20, supertank_frames_end_attack1, supertank_run };
  356. void supertank_reattack1(edict_t *self)
  357. {
  358. if (visible(self, self->enemy))
  359. {
  360. if (self->timestamp >= level.time || frandom() < 0.3f)
  361. M_SetAnimation(self, &supertank_move_attack1);
  362. else
  363. M_SetAnimation(self, &supertank_move_end_attack1);
  364. }
  365. else
  366. M_SetAnimation(self, &supertank_move_end_attack1);
  367. }
  368. PAIN(supertank_pain) (edict_t *self, edict_t *other, float kick, int damage, const mod_t &mod) -> void
  369. {
  370. if (level.time < self->pain_debounce_time)
  371. return;
  372. // Lessen the chance of him going into his pain frames
  373. if (mod.id != MOD_CHAINFIST)
  374. {
  375. if (damage <= 25)
  376. if (frandom() < 0.2f)
  377. return;
  378. // Don't go into pain if he's firing his rockets
  379. if ((self->s.frame >= FRAME_attak2_1) && (self->s.frame <= FRAME_attak2_14))
  380. return;
  381. }
  382. if (damage <= 10)
  383. gi.sound(self, CHAN_VOICE, sound_pain1, 1, ATTN_NORM, 0);
  384. else if (damage <= 25)
  385. gi.sound(self, CHAN_VOICE, sound_pain3, 1, ATTN_NORM, 0);
  386. else
  387. gi.sound(self, CHAN_VOICE, sound_pain2, 1, ATTN_NORM, 0);
  388. self->pain_debounce_time = level.time + 3_sec;
  389. if (!M_ShouldReactToPain(self, mod))
  390. return; // no pain anims in nightmare
  391. if (damage <= 10)
  392. M_SetAnimation(self, &supertank_move_pain1);
  393. else if (damage <= 25)
  394. M_SetAnimation(self, &supertank_move_pain2);
  395. else
  396. M_SetAnimation(self, &supertank_move_pain3);
  397. }
  398. MONSTERINFO_SETSKIN(supertank_setskin) (edict_t *self) -> void
  399. {
  400. if (self->health < (self->max_health / 2))
  401. self->s.skinnum |= 1;
  402. else
  403. self->s.skinnum &= ~1;
  404. }
  405. void supertankRocket(edict_t *self)
  406. {
  407. vec3_t forward, right;
  408. vec3_t start;
  409. vec3_t dir;
  410. vec3_t vec;
  411. monster_muzzleflash_id_t flash_number;
  412. if (!self->enemy || !self->enemy->inuse) // PGM
  413. return; // PGM
  414. if (self->s.frame == FRAME_attak2_8)
  415. flash_number = MZ2_SUPERTANK_ROCKET_1;
  416. else if (self->s.frame == FRAME_attak2_11)
  417. flash_number = MZ2_SUPERTANK_ROCKET_2;
  418. else // (self->s.frame == FRAME_attak2_14)
  419. flash_number = MZ2_SUPERTANK_ROCKET_3;
  420. AngleVectors(self->s.angles, forward, right, nullptr);
  421. start = M_ProjectFlashSource(self, monster_flash_offset[flash_number], forward, right);
  422. if (self->spawnflags.has(SPAWNFLAG_SUPERTANK_POWERSHIELD))
  423. {
  424. vec = self->enemy->s.origin;
  425. vec[2] += self->enemy->viewheight;
  426. dir = vec - start;
  427. dir.normalize();
  428. monster_fire_heat(self, start, dir, 40, 500, flash_number, 0.075f);
  429. }
  430. else
  431. {
  432. PredictAim(self, self->enemy, start, 750, false, 0.f, &forward, nullptr);
  433. monster_fire_rocket(self, start, forward, 50, 750, flash_number);
  434. }
  435. }
  436. void supertankMachineGun(edict_t *self)
  437. {
  438. vec3_t dir;
  439. vec3_t start;
  440. vec3_t forward, right;
  441. monster_muzzleflash_id_t flash_number;
  442. if (!self->enemy || !self->enemy->inuse) // PGM
  443. return; // PGM
  444. flash_number = static_cast<monster_muzzleflash_id_t>(MZ2_SUPERTANK_MACHINEGUN_1 + (self->s.frame - FRAME_attak1_1));
  445. dir[0] = 0;
  446. dir[1] = self->s.angles[1];
  447. dir[2] = 0;
  448. AngleVectors(dir, forward, right, nullptr);
  449. start = M_ProjectFlashSource(self, monster_flash_offset[flash_number], forward, right);
  450. PredictAim(self, self->enemy, start, 0, true, -0.1f, &forward, nullptr);
  451. monster_fire_bullet(self, start, forward, 6, 4, DEFAULT_BULLET_HSPREAD * 3, DEFAULT_BULLET_VSPREAD * 3, flash_number);
  452. }
  453. MONSTERINFO_ATTACK(supertank_attack) (edict_t *self) -> void
  454. {
  455. vec3_t vec;
  456. float range;
  457. vec = self->enemy->s.origin - self->s.origin;
  458. range = range_to(self, self->enemy);
  459. // Attack 1 == Chaingun
  460. // Attack 2 == Rocket Launcher
  461. // Attack 3 == Grenade Launcher
  462. bool chaingun_good = M_CheckClearShot(self, monster_flash_offset[MZ2_SUPERTANK_MACHINEGUN_1]);
  463. bool rocket_good = M_CheckClearShot(self, monster_flash_offset[MZ2_SUPERTANK_ROCKET_1]);
  464. bool grenade_good = M_CheckClearShot(self, monster_flash_offset[MZ2_SUPERTANK_GRENADE_1]);
  465. // fire rockets more often at distance
  466. if (chaingun_good && (!rocket_good || range <= 540 || frandom() < 0.3f))
  467. {
  468. // prefer grenade if the enemy is above us
  469. if (grenade_good && (range >= 350 || vec.z > 120.f || frandom() < 0.2f))
  470. M_SetAnimation(self, &supertank_move_attack4);
  471. else
  472. {
  473. M_SetAnimation(self, &supertank_move_attack1);
  474. self->timestamp = level.time + random_time(1500_ms, 2700_ms);
  475. }
  476. }
  477. else if (rocket_good)
  478. {
  479. // prefer grenade if the enemy is above us
  480. if (grenade_good && (vec.z > 120.f || frandom() < 0.2f))
  481. M_SetAnimation(self, &supertank_move_attack4);
  482. else
  483. M_SetAnimation(self, &supertank_move_attack2);
  484. }
  485. else if (grenade_good)
  486. M_SetAnimation(self, &supertank_move_attack4);
  487. }
  488. //
  489. // death
  490. //
  491. static void supertank_gib(edict_t *self)
  492. {
  493. gi.WriteByte(svc_temp_entity);
  494. gi.WriteByte(TE_EXPLOSION1_BIG);
  495. gi.WritePosition(self->s.origin);
  496. gi.multicast(self->s.origin, MULTICAST_PHS, false);
  497. self->s.sound = 0;
  498. self->s.skinnum /= 2;
  499. ThrowGibs(self, 500, {
  500. { 2, "models/objects/gibs/sm_meat/tris.md2" },
  501. { 2, "models/objects/gibs/sm_metal/tris.md2", GIB_METALLIC },
  502. { "models/monsters/boss1/gibs/cgun.md2", GIB_SKINNED | GIB_METALLIC },
  503. { "models/monsters/boss1/gibs/chest.md2", GIB_SKINNED },
  504. { "models/monsters/boss1/gibs/core.md2", GIB_SKINNED },
  505. { "models/monsters/boss1/gibs/ltread.md2", GIB_SKINNED | GIB_UPRIGHT },
  506. { "models/monsters/boss1/gibs/rgun.md2", GIB_SKINNED | GIB_UPRIGHT },
  507. { "models/monsters/boss1/gibs/rtread.md2", GIB_SKINNED | GIB_UPRIGHT },
  508. { "models/monsters/boss1/gibs/tube.md2", GIB_SKINNED | GIB_UPRIGHT },
  509. { "models/monsters/boss1/gibs/head.md2", GIB_SKINNED | GIB_METALLIC | GIB_HEAD }
  510. });
  511. }
  512. void supertank_dead(edict_t *self)
  513. {
  514. // no blowy on deady
  515. if (self->spawnflags.has(SPAWNFLAG_MONSTER_DEAD))
  516. {
  517. self->deadflag = false;
  518. self->takedamage = true;
  519. return;
  520. }
  521. supertank_gib(self);
  522. }
  523. DIE(supertank_die) (edict_t *self, edict_t *inflictor, edict_t *attacker, int damage, const vec3_t &point, const mod_t &mod) -> void
  524. {
  525. if (self->spawnflags.has(SPAWNFLAG_MONSTER_DEAD))
  526. {
  527. // check for gib
  528. if (M_CheckGib(self, mod))
  529. {
  530. supertank_gib(self);
  531. self->deadflag = true;
  532. return;
  533. }
  534. if (self->deadflag)
  535. return;
  536. }
  537. else
  538. {
  539. gi.sound(self, CHAN_VOICE, sound_death, 1, ATTN_NORM, 0);
  540. self->deadflag = true;
  541. self->takedamage = false;
  542. }
  543. M_SetAnimation(self, &supertank_move_death);
  544. }
  545. //===========
  546. // PGM
  547. MONSTERINFO_BLOCKED(supertank_blocked) (edict_t *self, float dist) -> bool
  548. {
  549. if (blocked_checkplat(self, dist))
  550. return true;
  551. return false;
  552. }
  553. // PGM
  554. //===========
  555. //
  556. // monster_supertank
  557. //
  558. // RAFAEL (Powershield)
  559. /*QUAKED monster_supertank (1 .5 0) (-64 -64 0) (64 64 72) Ambush Trigger_Spawn Sight Powershield LongDeath
  560. */
  561. void SP_monster_supertank(edict_t *self)
  562. {
  563. if ( !M_AllowSpawn( self ) ) {
  564. G_FreeEdict( self );
  565. return;
  566. }
  567. sound_pain1.assign("bosstank/btkpain1.wav");
  568. sound_pain2.assign("bosstank/btkpain2.wav");
  569. sound_pain3.assign("bosstank/btkpain3.wav");
  570. sound_death.assign("bosstank/btkdeth1.wav");
  571. sound_search1.assign("bosstank/btkunqv1.wav");
  572. sound_search2.assign("bosstank/btkunqv2.wav");
  573. tread_sound.assign("bosstank/btkengn1.wav");
  574. gi.soundindex("gunner/gunatck3.wav");
  575. gi.soundindex("infantry/infatck1.wav");
  576. gi.soundindex("tank/rocket.wav");
  577. self->movetype = MOVETYPE_STEP;
  578. self->solid = SOLID_BBOX;
  579. self->s.modelindex = gi.modelindex("models/monsters/boss1/tris.md2");
  580. gi.modelindex("models/monsters/boss1/gibs/cgun.md2");
  581. gi.modelindex("models/monsters/boss1/gibs/chest.md2");
  582. gi.modelindex("models/monsters/boss1/gibs/core.md2");
  583. gi.modelindex("models/monsters/boss1/gibs/head.md2");
  584. gi.modelindex("models/monsters/boss1/gibs/ltread.md2");
  585. gi.modelindex("models/monsters/boss1/gibs/rgun.md2");
  586. gi.modelindex("models/monsters/boss1/gibs/rtread.md2");
  587. gi.modelindex("models/monsters/boss1/gibs/tube.md2");
  588. self->mins = { -64, -64, 0 };
  589. self->maxs = { 64, 64, 112 };
  590. self->health = 1500 * st.health_multiplier;
  591. self->gib_health = -500;
  592. self->mass = 800;
  593. self->pain = supertank_pain;
  594. self->die = supertank_die;
  595. self->monsterinfo.stand = supertank_stand;
  596. self->monsterinfo.walk = supertank_walk;
  597. self->monsterinfo.run = supertank_run;
  598. self->monsterinfo.dodge = nullptr;
  599. self->monsterinfo.attack = supertank_attack;
  600. self->monsterinfo.search = supertank_search;
  601. self->monsterinfo.melee = nullptr;
  602. self->monsterinfo.sight = nullptr;
  603. self->monsterinfo.blocked = supertank_blocked; // PGM
  604. self->monsterinfo.setskin = supertank_setskin;
  605. gi.linkentity(self);
  606. M_SetAnimation(self, &supertank_move_stand);
  607. self->monsterinfo.scale = MODEL_SCALE;
  608. // RAFAEL
  609. if (self->spawnflags.has(SPAWNFLAG_SUPERTANK_POWERSHIELD))
  610. {
  611. if (!st.was_key_specified("power_armor_type"))
  612. self->monsterinfo.power_armor_type = IT_ITEM_POWER_SHIELD;
  613. if (!st.was_key_specified("power_armor_power"))
  614. self->monsterinfo.power_armor_power = 400;
  615. }
  616. // RAFAEL
  617. walkmonster_start(self);
  618. // PMM
  619. self->monsterinfo.aiflags |= AI_IGNORE_SHOTS;
  620. // pmm
  621. // TODO
  622. if (level.is_n64)
  623. {
  624. self->spawnflags |= SPAWNFLAG_SUPERTANK_LONG_DEATH;
  625. self->count = 10;
  626. }
  627. }
  628. //
  629. // monster_boss5
  630. // RAFAEL
  631. //
  632. /*QUAKED monster_boss5 (1 .5 0) (-64 -64 0) (64 64 72) Ambush Trigger_Spawn Sight
  633. */
  634. void SP_monster_boss5(edict_t *self)
  635. {
  636. self->spawnflags |= SPAWNFLAG_SUPERTANK_POWERSHIELD;
  637. SP_monster_supertank(self);
  638. gi.soundindex("weapons/railgr1a.wav");
  639. self->s.skinnum = 2;
  640. }