m_boss2.c 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663
  1. // Copyright (c) ZeniMax Media Inc.
  2. // Licensed under the GNU General Public License 2.0.
  3. /*
  4. ==============================================================================
  5. boss2
  6. ==============================================================================
  7. */
  8. #include "g_local.h"
  9. #include "m_boss2.h"
  10. void BossExplode (edict_t *self);
  11. qboolean infront (edict_t *self, edict_t *other);
  12. static int sound_pain1;
  13. static int sound_pain2;
  14. static int sound_pain3;
  15. static int sound_death;
  16. static int sound_search1;
  17. void boss2_search (edict_t *self)
  18. {
  19. if (random() < 0.5)
  20. gi.sound (self, CHAN_VOICE, sound_search1, 1, ATTN_NONE, 0);
  21. }
  22. void boss2_run (edict_t *self);
  23. void boss2_stand (edict_t *self);
  24. void boss2_dead (edict_t *self);
  25. void boss2_attack (edict_t *self);
  26. void boss2_attack_mg (edict_t *self);
  27. void boss2_reattack_mg (edict_t *self);
  28. void boss2_die (edict_t *self, edict_t *inflictor, edict_t *attacker, int damage, vec3_t point);
  29. void Boss2Rocket (edict_t *self)
  30. {
  31. vec3_t forward, right;
  32. vec3_t start;
  33. vec3_t dir;
  34. vec3_t vec;
  35. AngleVectors (self->s.angles, forward, right, NULL);
  36. //1
  37. G_ProjectSource (self->s.origin, monster_flash_offset[MZ2_BOSS2_ROCKET_1], forward, right, start);
  38. VectorCopy (self->enemy->s.origin, vec);
  39. vec[2] += self->enemy->viewheight;
  40. VectorSubtract (vec, start, dir);
  41. VectorNormalize (dir);
  42. monster_fire_rocket (self, start, dir, 50, 500, MZ2_BOSS2_ROCKET_1);
  43. //2
  44. G_ProjectSource (self->s.origin, monster_flash_offset[MZ2_BOSS2_ROCKET_2], forward, right, start);
  45. VectorCopy (self->enemy->s.origin, vec);
  46. vec[2] += self->enemy->viewheight;
  47. VectorSubtract (vec, start, dir);
  48. VectorNormalize (dir);
  49. monster_fire_rocket (self, start, dir, 50, 500, MZ2_BOSS2_ROCKET_2);
  50. //3
  51. G_ProjectSource (self->s.origin, monster_flash_offset[MZ2_BOSS2_ROCKET_3], forward, right, start);
  52. VectorCopy (self->enemy->s.origin, vec);
  53. vec[2] += self->enemy->viewheight;
  54. VectorSubtract (vec, start, dir);
  55. VectorNormalize (dir);
  56. monster_fire_rocket (self, start, dir, 50, 500, MZ2_BOSS2_ROCKET_3);
  57. //4
  58. G_ProjectSource (self->s.origin, monster_flash_offset[MZ2_BOSS2_ROCKET_4], forward, right, start);
  59. VectorCopy (self->enemy->s.origin, vec);
  60. vec[2] += self->enemy->viewheight;
  61. VectorSubtract (vec, start, dir);
  62. VectorNormalize (dir);
  63. monster_fire_rocket (self, start, dir, 50, 500, MZ2_BOSS2_ROCKET_4);
  64. }
  65. void boss2_firebullet_right (edict_t *self)
  66. {
  67. vec3_t forward, right, target;
  68. vec3_t start;
  69. AngleVectors (self->s.angles, forward, right, NULL);
  70. G_ProjectSource (self->s.origin, monster_flash_offset[MZ2_BOSS2_MACHINEGUN_R1], forward, right, start);
  71. VectorMA (self->enemy->s.origin, -0.2, self->enemy->velocity, target);
  72. target[2] += self->enemy->viewheight;
  73. VectorSubtract (target, start, forward);
  74. VectorNormalize (forward);
  75. monster_fire_bullet (self, start, forward, 6, 4, DEFAULT_BULLET_HSPREAD, DEFAULT_BULLET_VSPREAD, MZ2_BOSS2_MACHINEGUN_R1);
  76. }
  77. void boss2_firebullet_left (edict_t *self)
  78. {
  79. vec3_t forward, right, target;
  80. vec3_t start;
  81. AngleVectors (self->s.angles, forward, right, NULL);
  82. G_ProjectSource (self->s.origin, monster_flash_offset[MZ2_BOSS2_MACHINEGUN_L1], forward, right, start);
  83. VectorMA (self->enemy->s.origin, -0.2, self->enemy->velocity, target);
  84. target[2] += self->enemy->viewheight;
  85. VectorSubtract (target, start, forward);
  86. VectorNormalize (forward);
  87. monster_fire_bullet (self, start, forward, 6, 4, DEFAULT_BULLET_HSPREAD, DEFAULT_BULLET_VSPREAD, MZ2_BOSS2_MACHINEGUN_L1);
  88. }
  89. void Boss2MachineGun (edict_t *self)
  90. {
  91. /* vec3_t forward, right;
  92. vec3_t start;
  93. vec3_t dir;
  94. vec3_t vec;
  95. int flash_number;
  96. AngleVectors (self->s.angles, forward, right, NULL);
  97. flash_number = MZ2_BOSS2_MACHINEGUN_1 + (self->s.frame - FRAME_attack10);
  98. G_ProjectSource (self->s.origin, monster_flash_offset[flash_number], forward, right, start);
  99. VectorCopy (self->enemy->s.origin, vec);
  100. vec[2] += self->enemy->viewheight;
  101. VectorSubtract (vec, start, dir);
  102. VectorNormalize (dir);
  103. monster_fire_bullet (self, start, dir, 3, 4, DEFAULT_BULLET_HSPREAD, DEFAULT_BULLET_VSPREAD, flash_number);
  104. */
  105. boss2_firebullet_left(self);
  106. boss2_firebullet_right(self);
  107. }
  108. mframe_t boss2_frames_stand [] =
  109. {
  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. };
  132. mmove_t boss2_move_stand = {FRAME_stand30, FRAME_stand50, boss2_frames_stand, NULL};
  133. mframe_t boss2_frames_fidget [] =
  134. {
  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. };
  166. mmove_t boss2_move_fidget = {FRAME_stand1, FRAME_stand30, boss2_frames_fidget, NULL};
  167. mframe_t boss2_frames_walk [] =
  168. {
  169. ai_walk, 8, NULL,
  170. ai_walk, 8, NULL,
  171. ai_walk, 8, NULL,
  172. ai_walk, 8, NULL,
  173. ai_walk, 8, NULL,
  174. ai_walk, 8, NULL,
  175. ai_walk, 8, NULL,
  176. ai_walk, 8, NULL,
  177. ai_walk, 8, NULL,
  178. ai_walk, 8, NULL,
  179. ai_walk, 8, NULL,
  180. ai_walk, 8, NULL,
  181. ai_walk, 8, NULL,
  182. ai_walk, 8, NULL,
  183. ai_walk, 8, NULL,
  184. ai_walk, 8, NULL,
  185. ai_walk, 8, NULL,
  186. ai_walk, 8, NULL,
  187. ai_walk, 8, NULL,
  188. ai_walk, 8, NULL
  189. };
  190. mmove_t boss2_move_walk = {FRAME_walk1, FRAME_walk20, boss2_frames_walk, NULL};
  191. mframe_t boss2_frames_run [] =
  192. {
  193. ai_run, 8, NULL,
  194. ai_run, 8, NULL,
  195. ai_run, 8, NULL,
  196. ai_run, 8, NULL,
  197. ai_run, 8, NULL,
  198. ai_run, 8, NULL,
  199. ai_run, 8, NULL,
  200. ai_run, 8, NULL,
  201. ai_run, 8, NULL,
  202. ai_run, 8, NULL,
  203. ai_run, 8, NULL,
  204. ai_run, 8, NULL,
  205. ai_run, 8, NULL,
  206. ai_run, 8, NULL,
  207. ai_run, 8, NULL,
  208. ai_run, 8, NULL,
  209. ai_run, 8, NULL,
  210. ai_run, 8, NULL,
  211. ai_run, 8, NULL,
  212. ai_run, 8, NULL
  213. };
  214. mmove_t boss2_move_run = {FRAME_walk1, FRAME_walk20, boss2_frames_run, NULL};
  215. mframe_t boss2_frames_attack_pre_mg [] =
  216. {
  217. ai_charge, 1, NULL,
  218. ai_charge, 1, NULL,
  219. ai_charge, 1, NULL,
  220. ai_charge, 1, NULL,
  221. ai_charge, 1, NULL,
  222. ai_charge, 1, NULL,
  223. ai_charge, 1, NULL,
  224. ai_charge, 1, NULL,
  225. ai_charge, 1, boss2_attack_mg
  226. };
  227. mmove_t boss2_move_attack_pre_mg = {FRAME_attack1, FRAME_attack9, boss2_frames_attack_pre_mg, NULL};
  228. // Loop this
  229. mframe_t boss2_frames_attack_mg [] =
  230. {
  231. ai_charge, 1, Boss2MachineGun,
  232. ai_charge, 1, Boss2MachineGun,
  233. ai_charge, 1, Boss2MachineGun,
  234. ai_charge, 1, Boss2MachineGun,
  235. ai_charge, 1, Boss2MachineGun,
  236. ai_charge, 1, boss2_reattack_mg
  237. };
  238. mmove_t boss2_move_attack_mg = {FRAME_attack10, FRAME_attack15, boss2_frames_attack_mg, NULL};
  239. mframe_t boss2_frames_attack_post_mg [] =
  240. {
  241. ai_charge, 1, NULL,
  242. ai_charge, 1, NULL,
  243. ai_charge, 1, NULL,
  244. ai_charge, 1, NULL
  245. };
  246. mmove_t boss2_move_attack_post_mg = {FRAME_attack16, FRAME_attack19, boss2_frames_attack_post_mg, boss2_run};
  247. mframe_t boss2_frames_attack_rocket [] =
  248. {
  249. ai_charge, 1, NULL,
  250. ai_charge, 1, NULL,
  251. ai_charge, 1, NULL,
  252. ai_charge, 1, NULL,
  253. ai_charge, 1, NULL,
  254. ai_charge, 1, NULL,
  255. ai_charge, 1, NULL,
  256. ai_charge, 1, NULL,
  257. ai_charge, 1, NULL,
  258. ai_charge, 1, NULL,
  259. ai_charge, 1, NULL,
  260. ai_charge, 1, NULL,
  261. ai_move, -20, Boss2Rocket,
  262. ai_charge, 1, NULL,
  263. ai_charge, 1, NULL,
  264. ai_charge, 1, NULL,
  265. ai_charge, 1, NULL,
  266. ai_charge, 1, NULL,
  267. ai_charge, 1, NULL,
  268. ai_charge, 1, NULL,
  269. ai_charge, 1, NULL
  270. };
  271. mmove_t boss2_move_attack_rocket = {FRAME_attack20, FRAME_attack40, boss2_frames_attack_rocket, boss2_run};
  272. mframe_t boss2_frames_pain_heavy [] =
  273. {
  274. ai_move, 0, NULL,
  275. ai_move, 0, NULL,
  276. ai_move, 0, NULL,
  277. ai_move, 0, NULL,
  278. ai_move, 0, NULL,
  279. ai_move, 0, NULL,
  280. ai_move, 0, NULL,
  281. ai_move, 0, NULL,
  282. ai_move, 0, NULL,
  283. ai_move, 0, NULL,
  284. ai_move, 0, NULL,
  285. ai_move, 0, NULL,
  286. ai_move, 0, NULL,
  287. ai_move, 0, NULL,
  288. ai_move, 0, NULL,
  289. ai_move, 0, NULL,
  290. ai_move, 0, NULL,
  291. ai_move, 0, NULL
  292. };
  293. mmove_t boss2_move_pain_heavy = {FRAME_pain2, FRAME_pain19, boss2_frames_pain_heavy, boss2_run};
  294. mframe_t boss2_frames_pain_light [] =
  295. {
  296. ai_move, 0, NULL,
  297. ai_move, 0, NULL,
  298. ai_move, 0, NULL,
  299. ai_move, 0, NULL
  300. };
  301. mmove_t boss2_move_pain_light = {FRAME_pain20, FRAME_pain23, boss2_frames_pain_light, boss2_run};
  302. mframe_t boss2_frames_death [] =
  303. {
  304. ai_move, 0, NULL,
  305. ai_move, 0, NULL,
  306. ai_move, 0, NULL,
  307. ai_move, 0, NULL,
  308. ai_move, 0, NULL,
  309. ai_move, 0, NULL,
  310. ai_move, 0, NULL,
  311. ai_move, 0, NULL,
  312. ai_move, 0, NULL,
  313. ai_move, 0, NULL,
  314. ai_move, 0, NULL,
  315. ai_move, 0, NULL,
  316. ai_move, 0, NULL,
  317. ai_move, 0, NULL,
  318. ai_move, 0, NULL,
  319. ai_move, 0, NULL,
  320. ai_move, 0, NULL,
  321. ai_move, 0, NULL,
  322. ai_move, 0, NULL,
  323. ai_move, 0, NULL,
  324. ai_move, 0, NULL,
  325. ai_move, 0, NULL,
  326. ai_move, 0, NULL,
  327. ai_move, 0, NULL,
  328. ai_move, 0, NULL,
  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, BossExplode
  353. };
  354. mmove_t boss2_move_death = {FRAME_death2, FRAME_death50, boss2_frames_death, boss2_dead};
  355. void boss2_stand (edict_t *self)
  356. {
  357. self->monsterinfo.currentmove = &boss2_move_stand;
  358. }
  359. void boss2_run (edict_t *self)
  360. {
  361. if (self->monsterinfo.aiflags & AI_STAND_GROUND)
  362. self->monsterinfo.currentmove = &boss2_move_stand;
  363. else
  364. self->monsterinfo.currentmove = &boss2_move_run;
  365. }
  366. void boss2_walk (edict_t *self)
  367. {
  368. self->monsterinfo.currentmove = &boss2_move_walk;
  369. }
  370. void boss2_attack (edict_t *self)
  371. {
  372. vec3_t vec;
  373. float range;
  374. VectorSubtract (self->enemy->s.origin, self->s.origin, vec);
  375. range = VectorLength (vec);
  376. if (range <= 125)
  377. {
  378. self->monsterinfo.currentmove = &boss2_move_attack_pre_mg;
  379. }
  380. else
  381. {
  382. if (random() <= 0.6)
  383. self->monsterinfo.currentmove = &boss2_move_attack_pre_mg;
  384. else
  385. self->monsterinfo.currentmove = &boss2_move_attack_rocket;
  386. }
  387. }
  388. void boss2_attack_mg (edict_t *self)
  389. {
  390. self->monsterinfo.currentmove = &boss2_move_attack_mg;
  391. }
  392. void boss2_reattack_mg (edict_t *self)
  393. {
  394. if ( infront(self, self->enemy) )
  395. if (random() <= 0.7)
  396. self->monsterinfo.currentmove = &boss2_move_attack_mg;
  397. else
  398. self->monsterinfo.currentmove = &boss2_move_attack_post_mg;
  399. else
  400. self->monsterinfo.currentmove = &boss2_move_attack_post_mg;
  401. }
  402. void boss2_pain (edict_t *self, edict_t *other, float kick, int damage)
  403. {
  404. if (self->health < (self->max_health / 2))
  405. self->s.skinnum = 1;
  406. if (level.time < self->pain_debounce_time)
  407. return;
  408. self->pain_debounce_time = level.time + 3;
  409. // American wanted these at no attenuation
  410. if (damage < 10)
  411. {
  412. gi.sound (self, CHAN_VOICE, sound_pain3, 1, ATTN_NONE, 0);
  413. self->monsterinfo.currentmove = &boss2_move_pain_light;
  414. }
  415. else if (damage < 30)
  416. {
  417. gi.sound (self, CHAN_VOICE, sound_pain1, 1, ATTN_NONE, 0);
  418. self->monsterinfo.currentmove = &boss2_move_pain_light;
  419. }
  420. else
  421. {
  422. gi.sound (self, CHAN_VOICE, sound_pain2, 1, ATTN_NONE, 0);
  423. self->monsterinfo.currentmove = &boss2_move_pain_heavy;
  424. }
  425. }
  426. void boss2_dead (edict_t *self)
  427. {
  428. VectorSet (self->mins, -56, -56, 0);
  429. VectorSet (self->maxs, 56, 56, 80);
  430. self->movetype = MOVETYPE_TOSS;
  431. self->svflags |= SVF_DEADMONSTER;
  432. self->nextthink = 0;
  433. gi.linkentity (self);
  434. }
  435. void boss2_die (edict_t *self, edict_t *inflictor, edict_t *attacker, int damage, vec3_t point)
  436. {
  437. gi.sound (self, CHAN_VOICE, sound_death, 1, ATTN_NONE, 0);
  438. self->deadflag = DEAD_DEAD;
  439. self->takedamage = DAMAGE_NO;
  440. self->count = 0;
  441. self->monsterinfo.currentmove = &boss2_move_death;
  442. #if 0
  443. int n;
  444. self->s.sound = 0;
  445. // check for gib
  446. if (self->health <= self->gib_health)
  447. {
  448. gi.sound (self, CHAN_VOICE, gi.soundindex ("misc/udeath.wav"), 1, ATTN_NORM, 0);
  449. for (n= 0; n < 2; n++)
  450. ThrowGib (self, "models/objects/gibs/bone/tris.md2", damage, GIB_ORGANIC);
  451. for (n= 0; n < 4; n++)
  452. ThrowGib (self, "models/objects/gibs/sm_meat/tris.md2", damage, GIB_ORGANIC);
  453. ThrowHead (self, "models/objects/gibs/head2/tris.md2", damage, GIB_ORGANIC);
  454. self->deadflag = DEAD_DEAD;
  455. return;
  456. }
  457. if (self->deadflag == DEAD_DEAD)
  458. return;
  459. self->deadflag = DEAD_DEAD;
  460. self->takedamage = DAMAGE_YES;
  461. self->monsterinfo.currentmove = &boss2_move_death;
  462. #endif
  463. }
  464. qboolean Boss2_CheckAttack (edict_t *self)
  465. {
  466. vec3_t spot1, spot2;
  467. vec3_t temp;
  468. float chance;
  469. trace_t tr;
  470. qboolean enemy_infront;
  471. int enemy_range;
  472. float enemy_yaw;
  473. if (self->enemy->health > 0)
  474. {
  475. // see if any entities are in the way of the shot
  476. VectorCopy (self->s.origin, spot1);
  477. spot1[2] += self->viewheight;
  478. VectorCopy (self->enemy->s.origin, spot2);
  479. spot2[2] += self->enemy->viewheight;
  480. tr = gi.trace (spot1, NULL, NULL, spot2, self, CONTENTS_SOLID|CONTENTS_MONSTER|CONTENTS_SLIME|CONTENTS_LAVA);
  481. // do we have a clear shot?
  482. if (tr.ent != self->enemy)
  483. return false;
  484. }
  485. enemy_infront = infront(self, self->enemy);
  486. enemy_range = range(self, self->enemy);
  487. VectorSubtract (self->enemy->s.origin, self->s.origin, temp);
  488. enemy_yaw = vectoyaw(temp);
  489. self->ideal_yaw = enemy_yaw;
  490. // melee attack
  491. if (enemy_range == RANGE_MELEE)
  492. {
  493. if (self->monsterinfo.melee)
  494. self->monsterinfo.attack_state = AS_MELEE;
  495. else
  496. self->monsterinfo.attack_state = AS_MISSILE;
  497. return true;
  498. }
  499. // missile attack
  500. if (!self->monsterinfo.attack)
  501. return false;
  502. if (level.time < self->monsterinfo.attack_finished)
  503. return false;
  504. if (enemy_range == RANGE_FAR)
  505. return false;
  506. if (self->monsterinfo.aiflags & AI_STAND_GROUND)
  507. {
  508. chance = 0.4;
  509. }
  510. else if (enemy_range == RANGE_MELEE)
  511. {
  512. chance = 0.8;
  513. }
  514. else if (enemy_range == RANGE_NEAR)
  515. {
  516. chance = 0.8;
  517. }
  518. else if (enemy_range == RANGE_MID)
  519. {
  520. chance = 0.8;
  521. }
  522. else
  523. {
  524. return false;
  525. }
  526. if (random () < chance)
  527. {
  528. self->monsterinfo.attack_state = AS_MISSILE;
  529. self->monsterinfo.attack_finished = level.time + 2*random();
  530. return true;
  531. }
  532. if (self->flags & FL_FLY)
  533. {
  534. if (random() < 0.3)
  535. self->monsterinfo.attack_state = AS_SLIDING;
  536. else
  537. self->monsterinfo.attack_state = AS_STRAIGHT;
  538. }
  539. return false;
  540. }
  541. /*QUAKED monster_boss2 (1 .5 0) (-56 -56 0) (56 56 80) Ambush Trigger_Spawn Sight
  542. */
  543. void SP_monster_boss2 (edict_t *self)
  544. {
  545. if (deathmatch->value)
  546. {
  547. G_FreeEdict (self);
  548. return;
  549. }
  550. sound_pain1 = gi.soundindex ("bosshovr/bhvpain1.wav");
  551. sound_pain2 = gi.soundindex ("bosshovr/bhvpain2.wav");
  552. sound_pain3 = gi.soundindex ("bosshovr/bhvpain3.wav");
  553. sound_death = gi.soundindex ("bosshovr/bhvdeth1.wav");
  554. sound_search1 = gi.soundindex ("bosshovr/bhvunqv1.wav");
  555. self->s.sound = gi.soundindex ("bosshovr/bhvengn1.wav");
  556. self->movetype = MOVETYPE_STEP;
  557. self->solid = SOLID_BBOX;
  558. self->s.modelindex = gi.modelindex ("models/monsters/boss2/tris.md2");
  559. VectorSet (self->mins, -56, -56, 0);
  560. VectorSet (self->maxs, 56, 56, 80);
  561. self->health = 2000;
  562. self->gib_health = -200;
  563. self->mass = 1000;
  564. self->flags |= FL_IMMUNE_LASER;
  565. self->pain = boss2_pain;
  566. self->die = boss2_die;
  567. self->monsterinfo.stand = boss2_stand;
  568. self->monsterinfo.walk = boss2_walk;
  569. self->monsterinfo.run = boss2_run;
  570. self->monsterinfo.attack = boss2_attack;
  571. self->monsterinfo.search = boss2_search;
  572. self->monsterinfo.checkattack = Boss2_CheckAttack;
  573. gi.linkentity (self);
  574. self->monsterinfo.currentmove = &boss2_move_stand;
  575. self->monsterinfo.scale = MODEL_SCALE;
  576. flymonster_start (self);
  577. }