m_float.cpp 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717
  1. // Copyright (c) ZeniMax Media Inc.
  2. // Licensed under the GNU General Public License 2.0.
  3. /*
  4. ==============================================================================
  5. floater
  6. ==============================================================================
  7. */
  8. #include "g_local.h"
  9. #include "m_float.h"
  10. #include "m_flash.h"
  11. static cached_soundindex sound_attack2;
  12. static cached_soundindex sound_attack3;
  13. static cached_soundindex sound_death1;
  14. static cached_soundindex sound_idle;
  15. static cached_soundindex sound_pain1;
  16. static cached_soundindex sound_pain2;
  17. static cached_soundindex sound_sight;
  18. MONSTERINFO_SIGHT(floater_sight) (edict_t *self, edict_t *other) -> void
  19. {
  20. gi.sound(self, CHAN_VOICE, sound_sight, 1, ATTN_NORM, 0);
  21. }
  22. MONSTERINFO_IDLE(floater_idle) (edict_t *self) -> void
  23. {
  24. gi.sound(self, CHAN_VOICE, sound_idle, 1, ATTN_IDLE, 0);
  25. }
  26. void floater_dead(edict_t *self);
  27. void floater_run(edict_t *self);
  28. void floater_wham(edict_t *self);
  29. void floater_zap(edict_t *self);
  30. void floater_fire_blaster(edict_t *self)
  31. {
  32. vec3_t start;
  33. vec3_t forward, right;
  34. vec3_t end;
  35. vec3_t dir;
  36. if (!self->enemy || !self->enemy->inuse) // PGM
  37. return; // PGM
  38. AngleVectors(self->s.angles, forward, right, nullptr);
  39. start = M_ProjectFlashSource(self, monster_flash_offset[MZ2_FLOAT_BLASTER_1], forward, right);
  40. end = self->enemy->s.origin;
  41. end[2] += self->enemy->viewheight;
  42. dir = end - start;
  43. dir.normalize();
  44. monster_fire_blaster(self, start, dir, 1, 1000, MZ2_FLOAT_BLASTER_1, (self->s.frame % 4) ? EF_NONE : EF_HYPERBLASTER);
  45. }
  46. mframe_t floater_frames_stand1[] = {
  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. };
  100. MMOVE_T(floater_move_stand1) = { FRAME_stand101, FRAME_stand152, floater_frames_stand1, nullptr };
  101. mframe_t floater_frames_stand2[] = {
  102. { ai_stand },
  103. { ai_stand },
  104. { ai_stand },
  105. { ai_stand },
  106. { ai_stand },
  107. { ai_stand },
  108. { ai_stand },
  109. { ai_stand },
  110. { ai_stand },
  111. { ai_stand },
  112. { ai_stand },
  113. { ai_stand },
  114. { ai_stand },
  115. { ai_stand },
  116. { ai_stand },
  117. { ai_stand },
  118. { ai_stand },
  119. { ai_stand },
  120. { ai_stand },
  121. { ai_stand },
  122. { ai_stand },
  123. { ai_stand },
  124. { ai_stand },
  125. { ai_stand },
  126. { ai_stand },
  127. { ai_stand },
  128. { ai_stand },
  129. { ai_stand },
  130. { ai_stand },
  131. { ai_stand },
  132. { ai_stand },
  133. { ai_stand },
  134. { ai_stand },
  135. { ai_stand },
  136. { ai_stand },
  137. { ai_stand },
  138. { ai_stand },
  139. { ai_stand },
  140. { ai_stand },
  141. { ai_stand },
  142. { ai_stand },
  143. { ai_stand },
  144. { ai_stand },
  145. { ai_stand },
  146. { ai_stand },
  147. { ai_stand },
  148. { ai_stand },
  149. { ai_stand },
  150. { ai_stand },
  151. { ai_stand },
  152. { ai_stand },
  153. { ai_stand }
  154. };
  155. MMOVE_T(floater_move_stand2) = { FRAME_stand201, FRAME_stand252, floater_frames_stand2, nullptr };
  156. mframe_t floater_frames_pop[] = {
  157. {},
  158. {},
  159. {},
  160. {},
  161. {},
  162. {},
  163. {},
  164. {},
  165. {},
  166. {},
  167. {},
  168. {},
  169. {},
  170. {},
  171. {},
  172. {},
  173. {},
  174. {},
  175. {},
  176. {},
  177. {},
  178. {},
  179. {},
  180. {},
  181. {},
  182. {},
  183. {}
  184. };
  185. MMOVE_T(floater_move_pop) = { FRAME_actvat05, FRAME_actvat31, floater_frames_pop, floater_run };
  186. mframe_t floater_frames_disguise[] = {
  187. { ai_stand }
  188. };
  189. MMOVE_T(floater_move_disguise) = { FRAME_actvat01, FRAME_actvat01, floater_frames_disguise, nullptr };
  190. MONSTERINFO_STAND(floater_stand) (edict_t *self) -> void
  191. {
  192. if (self->monsterinfo.active_move == &floater_move_disguise)
  193. M_SetAnimation(self, &floater_move_disguise);
  194. else if (frandom() <= 0.5f)
  195. M_SetAnimation(self, &floater_move_stand1);
  196. else
  197. M_SetAnimation(self, &floater_move_stand2);
  198. }
  199. mframe_t floater_frames_attack1[] = {
  200. { ai_charge }, // Blaster attack
  201. { ai_charge },
  202. { ai_charge },
  203. { ai_charge, 0, floater_fire_blaster }, // BOOM (0, -25.8, 32.5) -- LOOP Starts
  204. { ai_charge, 0, floater_fire_blaster },
  205. { ai_charge, 0, floater_fire_blaster },
  206. { ai_charge, 0, floater_fire_blaster },
  207. { ai_charge, 0, floater_fire_blaster },
  208. { ai_charge, 0, floater_fire_blaster },
  209. { ai_charge, 0, floater_fire_blaster },
  210. { ai_charge },
  211. { ai_charge },
  212. { ai_charge },
  213. { ai_charge } // -- LOOP Ends
  214. };
  215. MMOVE_T(floater_move_attack1) = { FRAME_attak101, FRAME_attak114, floater_frames_attack1, floater_run };
  216. // PMM - circle strafe frames
  217. mframe_t floater_frames_attack1a[] = {
  218. { ai_charge, 10 }, // Blaster attack
  219. { ai_charge, 10 },
  220. { ai_charge, 10 },
  221. { ai_charge, 10, floater_fire_blaster }, // BOOM (0, -25.8, 32.5) -- LOOP Starts
  222. { ai_charge, 10, floater_fire_blaster },
  223. { ai_charge, 10, floater_fire_blaster },
  224. { ai_charge, 10, floater_fire_blaster },
  225. { ai_charge, 10, floater_fire_blaster },
  226. { ai_charge, 10, floater_fire_blaster },
  227. { ai_charge, 10, floater_fire_blaster },
  228. { ai_charge, 10 },
  229. { ai_charge, 10 },
  230. { ai_charge, 10 },
  231. { ai_charge, 10 } // -- LOOP Ends
  232. };
  233. MMOVE_T(floater_move_attack1a) = { FRAME_attak101, FRAME_attak114, floater_frames_attack1a, floater_run };
  234. // pmm
  235. mframe_t floater_frames_attack2[] = {
  236. { ai_charge }, // Claws
  237. { ai_charge },
  238. { ai_charge },
  239. { ai_charge },
  240. { ai_charge },
  241. { ai_charge },
  242. { ai_charge },
  243. { ai_charge },
  244. { ai_charge },
  245. { ai_charge },
  246. { ai_charge },
  247. { ai_charge, 0, floater_wham }, // WHAM (0, -45, 29.6) -- LOOP Starts
  248. { ai_charge },
  249. { ai_charge },
  250. { ai_charge },
  251. { ai_charge },
  252. { ai_charge },
  253. { ai_charge },
  254. { ai_charge }, // -- LOOP Ends
  255. { ai_charge },
  256. { ai_charge },
  257. { ai_charge },
  258. { ai_charge },
  259. { ai_charge },
  260. { ai_charge }
  261. };
  262. MMOVE_T(floater_move_attack2) = { FRAME_attak201, FRAME_attak225, floater_frames_attack2, floater_run };
  263. mframe_t floater_frames_attack3[] = {
  264. { ai_charge },
  265. { ai_charge },
  266. { ai_charge },
  267. { ai_charge },
  268. { ai_charge },
  269. { ai_charge },
  270. { ai_charge },
  271. { ai_charge },
  272. { ai_charge, 0, floater_zap }, // -- LOOP Starts
  273. { ai_charge },
  274. { ai_charge },
  275. { ai_charge },
  276. { ai_charge },
  277. { ai_charge },
  278. { ai_charge },
  279. { ai_charge },
  280. { ai_charge },
  281. { ai_charge },
  282. { ai_charge },
  283. { ai_charge },
  284. { ai_charge },
  285. { ai_charge },
  286. { ai_charge },
  287. { ai_charge },
  288. { ai_charge },
  289. { ai_charge },
  290. { ai_charge },
  291. { ai_charge },
  292. { ai_charge }, // -- LOOP Ends
  293. { ai_charge },
  294. { ai_charge },
  295. { ai_charge },
  296. { ai_charge },
  297. { ai_charge }
  298. };
  299. MMOVE_T(floater_move_attack3) = { FRAME_attak301, FRAME_attak334, floater_frames_attack3, floater_run };
  300. #if 0
  301. mframe_t floater_frames_death[] = {
  302. { ai_move },
  303. { ai_move },
  304. { ai_move },
  305. { ai_move },
  306. { ai_move },
  307. { ai_move },
  308. { ai_move },
  309. { ai_move },
  310. { ai_move },
  311. { ai_move },
  312. { ai_move },
  313. { ai_move },
  314. { ai_move }
  315. };
  316. MMOVE_T(floater_move_death) = { FRAME_death01, FRAME_death13, floater_frames_death, floater_dead };
  317. #endif
  318. mframe_t floater_frames_pain1[] = {
  319. { ai_move },
  320. { ai_move },
  321. { ai_move },
  322. { ai_move },
  323. { ai_move },
  324. { ai_move },
  325. { ai_move }
  326. };
  327. MMOVE_T(floater_move_pain1) = { FRAME_pain101, FRAME_pain107, floater_frames_pain1, floater_run };
  328. mframe_t floater_frames_pain2[] = {
  329. { ai_move },
  330. { ai_move },
  331. { ai_move },
  332. { ai_move },
  333. { ai_move },
  334. { ai_move },
  335. { ai_move },
  336. { ai_move }
  337. };
  338. MMOVE_T(floater_move_pain2) = { FRAME_pain201, FRAME_pain208, floater_frames_pain2, floater_run };
  339. #if 0
  340. mframe_t floater_frames_pain3[] = {
  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. };
  354. MMOVE_T(floater_move_pain3) = { FRAME_pain301, FRAME_pain312, floater_frames_pain3, floater_run };
  355. #endif
  356. mframe_t floater_frames_walk[] = {
  357. { ai_walk, 5 },
  358. { ai_walk, 5 },
  359. { ai_walk, 5 },
  360. { ai_walk, 5 },
  361. { ai_walk, 5 },
  362. { ai_walk, 5 },
  363. { ai_walk, 5 },
  364. { ai_walk, 5 },
  365. { ai_walk, 5 },
  366. { ai_walk, 5 },
  367. { ai_walk, 5 },
  368. { ai_walk, 5 },
  369. { ai_walk, 5 },
  370. { ai_walk, 5 },
  371. { ai_walk, 5 },
  372. { ai_walk, 5 },
  373. { ai_walk, 5 },
  374. { ai_walk, 5 },
  375. { ai_walk, 5 },
  376. { ai_walk, 5 },
  377. { ai_walk, 5 },
  378. { ai_walk, 5 },
  379. { ai_walk, 5 },
  380. { ai_walk, 5 },
  381. { ai_walk, 5 },
  382. { ai_walk, 5 },
  383. { ai_walk, 5 },
  384. { ai_walk, 5 },
  385. { ai_walk, 5 },
  386. { ai_walk, 5 },
  387. { ai_walk, 5 },
  388. { ai_walk, 5 },
  389. { ai_walk, 5 },
  390. { ai_walk, 5 },
  391. { ai_walk, 5 },
  392. { ai_walk, 5 },
  393. { ai_walk, 5 },
  394. { ai_walk, 5 },
  395. { ai_walk, 5 },
  396. { ai_walk, 5 },
  397. { ai_walk, 5 },
  398. { ai_walk, 5 },
  399. { ai_walk, 5 },
  400. { ai_walk, 5 },
  401. { ai_walk, 5 },
  402. { ai_walk, 5 },
  403. { ai_walk, 5 },
  404. { ai_walk, 5 },
  405. { ai_walk, 5 },
  406. { ai_walk, 5 },
  407. { ai_walk, 5 },
  408. { ai_walk, 5 }
  409. };
  410. MMOVE_T(floater_move_walk) = { FRAME_stand101, FRAME_stand152, floater_frames_walk, nullptr };
  411. mframe_t floater_frames_run[] = {
  412. { ai_run, 13 },
  413. { ai_run, 13 },
  414. { ai_run, 13 },
  415. { ai_run, 13 },
  416. { ai_run, 13 },
  417. { ai_run, 13 },
  418. { ai_run, 13 },
  419. { ai_run, 13 },
  420. { ai_run, 13 },
  421. { ai_run, 13 },
  422. { ai_run, 13 },
  423. { ai_run, 13 },
  424. { ai_run, 13 },
  425. { ai_run, 13 },
  426. { ai_run, 13 },
  427. { ai_run, 13 },
  428. { ai_run, 13 },
  429. { ai_run, 13 },
  430. { ai_run, 13 },
  431. { ai_run, 13 },
  432. { ai_run, 13 },
  433. { ai_run, 13 },
  434. { ai_run, 13 },
  435. { ai_run, 13 },
  436. { ai_run, 13 },
  437. { ai_run, 13 },
  438. { ai_run, 13 },
  439. { ai_run, 13 },
  440. { ai_run, 13 },
  441. { ai_run, 13 },
  442. { ai_run, 13 },
  443. { ai_run, 13 },
  444. { ai_run, 13 },
  445. { ai_run, 13 },
  446. { ai_run, 13 },
  447. { ai_run, 13 },
  448. { ai_run, 13 },
  449. { ai_run, 13 },
  450. { ai_run, 13 },
  451. { ai_run, 13 },
  452. { ai_run, 13 },
  453. { ai_run, 13 },
  454. { ai_run, 13 },
  455. { ai_run, 13 },
  456. { ai_run, 13 },
  457. { ai_run, 13 },
  458. { ai_run, 13 },
  459. { ai_run, 13 },
  460. { ai_run, 13 },
  461. { ai_run, 13 },
  462. { ai_run, 13 },
  463. { ai_run, 13 }
  464. };
  465. MMOVE_T(floater_move_run) = { FRAME_stand101, FRAME_stand152, floater_frames_run, nullptr };
  466. MONSTERINFO_RUN(floater_run) (edict_t *self) -> void
  467. {
  468. if (self->monsterinfo.active_move == &floater_move_disguise)
  469. M_SetAnimation(self, &floater_move_pop);
  470. else if (self->monsterinfo.aiflags & AI_STAND_GROUND)
  471. M_SetAnimation(self, &floater_move_stand1);
  472. else
  473. M_SetAnimation(self, &floater_move_run);
  474. }
  475. MONSTERINFO_WALK(floater_walk) (edict_t *self) -> void
  476. {
  477. M_SetAnimation(self, &floater_move_walk);
  478. }
  479. void floater_wham(edict_t *self)
  480. {
  481. constexpr vec3_t aim = { MELEE_DISTANCE, 0, 0 };
  482. gi.sound(self, CHAN_WEAPON, sound_attack3, 1, ATTN_NORM, 0);
  483. if (!fire_hit(self, aim, irandom(5, 11), -50))
  484. self->monsterinfo.melee_debounce_time = level.time + 3_sec;
  485. }
  486. void floater_zap(edict_t *self)
  487. {
  488. vec3_t forward, right;
  489. vec3_t origin;
  490. vec3_t dir;
  491. vec3_t offset;
  492. dir = self->enemy->s.origin - self->s.origin;
  493. AngleVectors(self->s.angles, forward, right, nullptr);
  494. // FIXME use a flash and replace these two lines with the commented one
  495. offset = { 18.5f, -0.9f, 10 };
  496. origin = M_ProjectFlashSource(self, offset, forward, right);
  497. gi.sound(self, CHAN_WEAPON, sound_attack2, 1, ATTN_NORM, 0);
  498. // FIXME use the flash, Luke
  499. gi.WriteByte(svc_temp_entity);
  500. gi.WriteByte(TE_SPLASH);
  501. gi.WriteByte(32);
  502. gi.WritePosition(origin);
  503. gi.WriteDir(dir);
  504. gi.WriteByte(SPLASH_SPARKS);
  505. gi.multicast(origin, MULTICAST_PVS, false);
  506. T_Damage(self->enemy, self, self, dir, self->enemy->s.origin, vec3_origin, irandom(5, 11), -10, DAMAGE_ENERGY, MOD_UNKNOWN);
  507. }
  508. MONSTERINFO_ATTACK(floater_attack) (edict_t *self) -> void
  509. {
  510. float chance = 0.5f;
  511. if (frandom() > chance)
  512. {
  513. self->monsterinfo.attack_state = AS_STRAIGHT;
  514. M_SetAnimation(self, &floater_move_attack1);
  515. }
  516. else // circle strafe
  517. {
  518. if (frandom() <= 0.5f) // switch directions
  519. self->monsterinfo.lefty = !self->monsterinfo.lefty;
  520. self->monsterinfo.attack_state = AS_SLIDING;
  521. M_SetAnimation(self, &floater_move_attack1a);
  522. }
  523. }
  524. MONSTERINFO_MELEE(floater_melee) (edict_t *self) -> void
  525. {
  526. if (frandom() < 0.5f)
  527. M_SetAnimation(self, &floater_move_attack3);
  528. else
  529. M_SetAnimation(self, &floater_move_attack2);
  530. }
  531. PAIN(floater_pain) (edict_t *self, edict_t *other, float kick, int damage, const mod_t &mod) -> void
  532. {
  533. int n;
  534. if (level.time < self->pain_debounce_time)
  535. return;
  536. // no pain anims if poppin'
  537. if (self->monsterinfo.active_move == &floater_move_disguise ||
  538. self->monsterinfo.active_move == &floater_move_pop)
  539. return;
  540. n = irandom(3);
  541. if (n == 0)
  542. gi.sound(self, CHAN_VOICE, sound_pain1, 1, ATTN_NORM, 0);
  543. else
  544. gi.sound(self, CHAN_VOICE, sound_pain2, 1, ATTN_NORM, 0);
  545. self->pain_debounce_time = level.time + 3_sec;
  546. if (!M_ShouldReactToPain(self, mod))
  547. return; // no pain anims in nightmare
  548. if (n == 0)
  549. M_SetAnimation(self, &floater_move_pain1);
  550. else
  551. M_SetAnimation(self, &floater_move_pain2);
  552. }
  553. MONSTERINFO_SETSKIN(floater_setskin) (edict_t *self) -> void
  554. {
  555. if (self->health < (self->max_health / 2))
  556. self->s.skinnum = 1;
  557. else
  558. self->s.skinnum = 0;
  559. }
  560. void floater_dead(edict_t *self)
  561. {
  562. self->mins = { -16, -16, -24 };
  563. self->maxs = { 16, 16, -8 };
  564. self->movetype = MOVETYPE_TOSS;
  565. self->svflags |= SVF_DEADMONSTER;
  566. self->nextthink = 0_ms;
  567. gi.linkentity(self);
  568. }
  569. DIE(floater_die) (edict_t *self, edict_t *inflictor, edict_t *attacker, int damage, const vec3_t &point, const mod_t &mod) -> void
  570. {
  571. gi.sound(self, CHAN_VOICE, sound_death1, 1, ATTN_NORM, 0);
  572. gi.WriteByte(svc_temp_entity);
  573. gi.WriteByte(TE_EXPLOSION1);
  574. gi.WritePosition(self->s.origin);
  575. gi.multicast(self->s.origin, MULTICAST_PHS, false);
  576. self->s.skinnum /= 2;
  577. ThrowGibs(self, 55, {
  578. { 2, "models/objects/gibs/sm_metal/tris.md2" },
  579. { 3, "models/objects/gibs/sm_meat/tris.md2" },
  580. { "models/monsters/float/gibs/piece.md2", GIB_SKINNED },
  581. { "models/monsters/float/gibs/gun.md2", GIB_SKINNED },
  582. { "models/monsters/float/gibs/base.md2", GIB_SKINNED },
  583. { "models/monsters/float/gibs/jar.md2", GIB_SKINNED | GIB_HEAD }
  584. });
  585. }
  586. static void float_set_fly_parameters(edict_t *self)
  587. {
  588. self->monsterinfo.fly_thrusters = false;
  589. self->monsterinfo.fly_acceleration = 10.f;
  590. self->monsterinfo.fly_speed = 100.f;
  591. // Technician gets in closer because he has two melee attacks
  592. self->monsterinfo.fly_min_distance = 20.f;
  593. self->monsterinfo.fly_max_distance = 200.f;
  594. }
  595. constexpr spawnflags_t SPAWNFLAG_FLOATER_DISGUISE = 8_spawnflag;
  596. /*QUAKED monster_floater (1 .5 0) (-16 -16 -24) (16 16 32) Ambush Trigger_Spawn Sight Disguise
  597. */
  598. void SP_monster_floater(edict_t *self)
  599. {
  600. if ( !M_AllowSpawn( self ) ) {
  601. G_FreeEdict( self );
  602. return;
  603. }
  604. sound_attack2.assign("floater/fltatck2.wav");
  605. sound_attack3.assign("floater/fltatck3.wav");
  606. sound_death1.assign("floater/fltdeth1.wav");
  607. sound_idle.assign("floater/fltidle1.wav");
  608. sound_pain1.assign("floater/fltpain1.wav");
  609. sound_pain2.assign("floater/fltpain2.wav");
  610. sound_sight.assign("floater/fltsght1.wav");
  611. gi.soundindex("floater/fltatck1.wav");
  612. self->monsterinfo.engine_sound = gi.soundindex("floater/fltsrch1.wav");
  613. self->movetype = MOVETYPE_STEP;
  614. self->solid = SOLID_BBOX;
  615. self->s.modelindex = gi.modelindex("models/monsters/float/tris.md2");
  616. gi.modelindex("models/monsters/float/gibs/base.md2");
  617. gi.modelindex("models/monsters/float/gibs/gun.md2");
  618. gi.modelindex("models/monsters/float/gibs/jar.md2");
  619. gi.modelindex("models/monsters/float/gibs/piece.md2");
  620. self->mins = { -24, -24, -24 };
  621. self->maxs = { 24, 24, 48 };
  622. self->health = 200 * st.health_multiplier;
  623. self->gib_health = -80;
  624. self->mass = 300;
  625. self->pain = floater_pain;
  626. self->die = floater_die;
  627. self->monsterinfo.stand = floater_stand;
  628. self->monsterinfo.walk = floater_walk;
  629. self->monsterinfo.run = floater_run;
  630. self->monsterinfo.attack = floater_attack;
  631. self->monsterinfo.melee = floater_melee;
  632. self->monsterinfo.sight = floater_sight;
  633. self->monsterinfo.idle = floater_idle;
  634. self->monsterinfo.setskin = floater_setskin;
  635. gi.linkentity(self);
  636. if (self->spawnflags.has(SPAWNFLAG_FLOATER_DISGUISE))
  637. M_SetAnimation(self, &floater_move_disguise);
  638. else if (frandom() <= 0.5f)
  639. M_SetAnimation(self, &floater_move_stand1);
  640. else
  641. M_SetAnimation(self, &floater_move_stand2);
  642. self->monsterinfo.scale = MODEL_SCALE;
  643. self->monsterinfo.aiflags |= AI_ALTERNATE_FLY;
  644. float_set_fly_parameters(self);
  645. flymonster_start(self);
  646. }