m_chick.c 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949
  1. // Copyright (c) ZeniMax Media Inc.
  2. // Licensed under the GNU General Public License 2.0.
  3. /*
  4. ==============================================================================
  5. chick
  6. ==============================================================================
  7. */
  8. #include "g_local.h"
  9. #include "m_chick.h"
  10. // ROGUE
  11. #define LEAD_TARGET 1
  12. // ROGUE
  13. qboolean visible (edict_t *self, edict_t *other);
  14. void chick_stand (edict_t *self);
  15. void chick_run (edict_t *self);
  16. void chick_reslash(edict_t *self);
  17. void chick_rerocket(edict_t *self);
  18. void chick_attack1(edict_t *self);
  19. static int sound_missile_prelaunch;
  20. static int sound_missile_launch;
  21. static int sound_melee_swing;
  22. static int sound_melee_hit;
  23. static int sound_missile_reload;
  24. static int sound_death1;
  25. static int sound_death2;
  26. static int sound_fall_down;
  27. static int sound_idle1;
  28. static int sound_idle2;
  29. static int sound_pain1;
  30. static int sound_pain2;
  31. static int sound_pain3;
  32. static int sound_sight;
  33. static int sound_search;
  34. void ChickMoan (edict_t *self)
  35. {
  36. if (random() < 0.5)
  37. gi.sound (self, CHAN_VOICE, sound_idle1, 1, ATTN_IDLE, 0);
  38. else
  39. gi.sound (self, CHAN_VOICE, sound_idle2, 1, ATTN_IDLE, 0);
  40. }
  41. mframe_t chick_frames_fidget [] =
  42. {
  43. ai_stand, 0, NULL,
  44. ai_stand, 0, NULL,
  45. ai_stand, 0, NULL,
  46. ai_stand, 0, NULL,
  47. ai_stand, 0, NULL,
  48. ai_stand, 0, NULL,
  49. ai_stand, 0, NULL,
  50. ai_stand, 0, NULL,
  51. ai_stand, 0, ChickMoan,
  52. ai_stand, 0, NULL,
  53. ai_stand, 0, NULL,
  54. ai_stand, 0, NULL,
  55. ai_stand, 0, NULL,
  56. ai_stand, 0, NULL,
  57. ai_stand, 0, NULL,
  58. ai_stand, 0, NULL,
  59. ai_stand, 0, NULL,
  60. ai_stand, 0, NULL,
  61. ai_stand, 0, NULL,
  62. ai_stand, 0, NULL,
  63. ai_stand, 0, NULL,
  64. ai_stand, 0, NULL,
  65. ai_stand, 0, NULL,
  66. ai_stand, 0, NULL,
  67. ai_stand, 0, NULL,
  68. ai_stand, 0, NULL,
  69. ai_stand, 0, NULL,
  70. ai_stand, 0, NULL,
  71. ai_stand, 0, NULL,
  72. ai_stand, 0, NULL
  73. };
  74. mmove_t chick_move_fidget = {FRAME_stand201, FRAME_stand230, chick_frames_fidget, chick_stand};
  75. void chick_fidget (edict_t *self)
  76. {
  77. if (self->monsterinfo.aiflags & AI_STAND_GROUND)
  78. return;
  79. if (random() <= 0.3)
  80. self->monsterinfo.currentmove = &chick_move_fidget;
  81. }
  82. mframe_t chick_frames_stand [] =
  83. {
  84. ai_stand, 0, NULL,
  85. ai_stand, 0, NULL,
  86. ai_stand, 0, NULL,
  87. ai_stand, 0, NULL,
  88. ai_stand, 0, NULL,
  89. ai_stand, 0, NULL,
  90. ai_stand, 0, NULL,
  91. ai_stand, 0, NULL,
  92. ai_stand, 0, NULL,
  93. ai_stand, 0, NULL,
  94. ai_stand, 0, NULL,
  95. ai_stand, 0, NULL,
  96. ai_stand, 0, NULL,
  97. ai_stand, 0, NULL,
  98. ai_stand, 0, NULL,
  99. ai_stand, 0, NULL,
  100. ai_stand, 0, NULL,
  101. ai_stand, 0, NULL,
  102. ai_stand, 0, NULL,
  103. ai_stand, 0, NULL,
  104. ai_stand, 0, NULL,
  105. ai_stand, 0, NULL,
  106. ai_stand, 0, NULL,
  107. ai_stand, 0, NULL,
  108. ai_stand, 0, NULL,
  109. ai_stand, 0, NULL,
  110. ai_stand, 0, NULL,
  111. ai_stand, 0, NULL,
  112. ai_stand, 0, NULL,
  113. ai_stand, 0, chick_fidget,
  114. };
  115. mmove_t chick_move_stand = {FRAME_stand101, FRAME_stand130, chick_frames_stand, NULL};
  116. void chick_stand (edict_t *self)
  117. {
  118. self->monsterinfo.currentmove = &chick_move_stand;
  119. }
  120. mframe_t chick_frames_start_run [] =
  121. {
  122. ai_run, 1, NULL,
  123. ai_run, 0, NULL,
  124. ai_run, 0, NULL,
  125. ai_run, -1, NULL,
  126. ai_run, -1, NULL,
  127. ai_run, 0, NULL,
  128. ai_run, 1, NULL,
  129. ai_run, 3, NULL,
  130. ai_run, 6, NULL,
  131. ai_run, 3, NULL
  132. };
  133. mmove_t chick_move_start_run = {FRAME_walk01, FRAME_walk10, chick_frames_start_run, chick_run};
  134. mframe_t chick_frames_run [] =
  135. {
  136. ai_run, 6, NULL,
  137. ai_run, 8, NULL,
  138. ai_run, 13, NULL,
  139. ai_run, 5, monster_done_dodge, // make sure to clear dodge bit
  140. ai_run, 7, NULL,
  141. ai_run, 4, NULL,
  142. ai_run, 11, NULL,
  143. ai_run, 5, NULL,
  144. ai_run, 9, NULL,
  145. ai_run, 7, NULL
  146. };
  147. mmove_t chick_move_run = {FRAME_walk11, FRAME_walk20, chick_frames_run, NULL};
  148. mframe_t chick_frames_walk [] =
  149. {
  150. ai_walk, 6, NULL,
  151. ai_walk, 8, NULL,
  152. ai_walk, 13, NULL,
  153. ai_walk, 5, NULL,
  154. ai_walk, 7, NULL,
  155. ai_walk, 4, NULL,
  156. ai_walk, 11, NULL,
  157. ai_walk, 5, NULL,
  158. ai_walk, 9, NULL,
  159. ai_walk, 7, NULL
  160. };
  161. mmove_t chick_move_walk = {FRAME_walk11, FRAME_walk20, chick_frames_walk, NULL};
  162. void chick_walk (edict_t *self)
  163. {
  164. self->monsterinfo.currentmove = &chick_move_walk;
  165. }
  166. void chick_run (edict_t *self)
  167. {
  168. monster_done_dodge (self);
  169. if (self->monsterinfo.aiflags & AI_STAND_GROUND)
  170. {
  171. self->monsterinfo.currentmove = &chick_move_stand;
  172. return;
  173. }
  174. if (self->monsterinfo.currentmove == &chick_move_walk ||
  175. self->monsterinfo.currentmove == &chick_move_start_run)
  176. {
  177. self->monsterinfo.currentmove = &chick_move_run;
  178. }
  179. else
  180. {
  181. self->monsterinfo.currentmove = &chick_move_start_run;
  182. }
  183. }
  184. mframe_t chick_frames_pain1 [] =
  185. {
  186. ai_move, 0, NULL,
  187. ai_move, 0, NULL,
  188. ai_move, 0, NULL,
  189. ai_move, 0, NULL,
  190. ai_move, 0, NULL
  191. };
  192. mmove_t chick_move_pain1 = {FRAME_pain101, FRAME_pain105, chick_frames_pain1, chick_run};
  193. mframe_t chick_frames_pain2 [] =
  194. {
  195. ai_move, 0, NULL,
  196. ai_move, 0, NULL,
  197. ai_move, 0, NULL,
  198. ai_move, 0, NULL,
  199. ai_move, 0, NULL
  200. };
  201. mmove_t chick_move_pain2 = {FRAME_pain201, FRAME_pain205, chick_frames_pain2, chick_run};
  202. mframe_t chick_frames_pain3 [] =
  203. {
  204. ai_move, 0, NULL,
  205. ai_move, 0, NULL,
  206. ai_move, -6, NULL,
  207. ai_move, 3, NULL,
  208. ai_move, 11, NULL,
  209. ai_move, 3, NULL,
  210. ai_move, 0, NULL,
  211. ai_move, 0, NULL,
  212. ai_move, 4, NULL,
  213. ai_move, 1, NULL,
  214. ai_move, 0, NULL,
  215. ai_move, -3, NULL,
  216. ai_move, -4, NULL,
  217. ai_move, 5, NULL,
  218. ai_move, 7, NULL,
  219. ai_move, -2, NULL,
  220. ai_move, 3, NULL,
  221. ai_move, -5, NULL,
  222. ai_move, -2, NULL,
  223. ai_move, -8, NULL,
  224. ai_move, 2, NULL
  225. };
  226. mmove_t chick_move_pain3 = {FRAME_pain301, FRAME_pain321, chick_frames_pain3, chick_run};
  227. void chick_pain (edict_t *self, edict_t *other, float kick, int damage)
  228. {
  229. float r;
  230. monster_done_dodge(self);
  231. if (self->health < (self->max_health / 2))
  232. self->s.skinnum = 1;
  233. if (level.time < self->pain_debounce_time)
  234. return;
  235. self->pain_debounce_time = level.time + 3;
  236. r = random();
  237. if (r < 0.33)
  238. gi.sound (self, CHAN_VOICE, sound_pain1, 1, ATTN_NORM, 0);
  239. else if (r < 0.66)
  240. gi.sound (self, CHAN_VOICE, sound_pain2, 1, ATTN_NORM, 0);
  241. else
  242. gi.sound (self, CHAN_VOICE, sound_pain3, 1, ATTN_NORM, 0);
  243. if (skill->value == 3)
  244. return; // no pain anims in nightmare
  245. // PMM - clear this from blindfire
  246. self->monsterinfo.aiflags &= ~AI_MANUAL_STEERING;
  247. if (damage <= 10)
  248. self->monsterinfo.currentmove = &chick_move_pain1;
  249. else if (damage <= 25)
  250. self->monsterinfo.currentmove = &chick_move_pain2;
  251. else
  252. self->monsterinfo.currentmove = &chick_move_pain3;
  253. // PMM - clear duck flag
  254. if (self->monsterinfo.aiflags & AI_DUCKED)
  255. monster_duck_up(self);
  256. }
  257. void chick_dead (edict_t *self)
  258. {
  259. VectorSet (self->mins, -16, -16, 0);
  260. VectorSet (self->maxs, 16, 16, 16);
  261. self->movetype = MOVETYPE_TOSS;
  262. self->svflags |= SVF_DEADMONSTER;
  263. self->nextthink = 0;
  264. gi.linkentity (self);
  265. }
  266. mframe_t chick_frames_death2 [] =
  267. {
  268. ai_move, -6, NULL,
  269. ai_move, 0, NULL,
  270. ai_move, -1, NULL,
  271. ai_move, -5, NULL,
  272. ai_move, 0, NULL,
  273. ai_move, -1, NULL,
  274. ai_move, -2, NULL,
  275. ai_move, 1, NULL,
  276. ai_move, 10, NULL,
  277. ai_move, 2, NULL,
  278. ai_move, 3, NULL,
  279. ai_move, 1, NULL,
  280. ai_move, 2, NULL,
  281. ai_move, 0, NULL,
  282. ai_move, 3, NULL,
  283. ai_move, 3, NULL,
  284. ai_move, 1, NULL,
  285. ai_move, -3, NULL,
  286. ai_move, -5, NULL,
  287. ai_move, 4, NULL,
  288. ai_move, 15, NULL,
  289. ai_move, 14, NULL,
  290. ai_move, 1, NULL
  291. };
  292. mmove_t chick_move_death2 = {FRAME_death201, FRAME_death223, chick_frames_death2, chick_dead};
  293. mframe_t chick_frames_death1 [] =
  294. {
  295. ai_move, 0, NULL,
  296. ai_move, 0, NULL,
  297. ai_move, -7, NULL,
  298. ai_move, 4, NULL,
  299. ai_move, 11, NULL,
  300. ai_move, 0, NULL,
  301. ai_move, 0, NULL,
  302. ai_move, 0, NULL,
  303. ai_move, 0, NULL,
  304. ai_move, 0, NULL,
  305. ai_move, 0, NULL,
  306. ai_move, 0, NULL
  307. };
  308. mmove_t chick_move_death1 = {FRAME_death101, FRAME_death112, chick_frames_death1, chick_dead};
  309. void chick_die (edict_t *self, edict_t *inflictor, edict_t *attacker, int damage, vec3_t point)
  310. {
  311. int n;
  312. // check for gib
  313. if (self->health <= self->gib_health)
  314. {
  315. gi.sound (self, CHAN_VOICE, gi.soundindex ("misc/udeath.wav"), 1, ATTN_NORM, 0);
  316. for (n= 0; n < 2; n++)
  317. ThrowGib (self, "models/objects/gibs/bone/tris.md2", damage, GIB_ORGANIC);
  318. for (n= 0; n < 4; n++)
  319. ThrowGib (self, "models/objects/gibs/sm_meat/tris.md2", damage, GIB_ORGANIC);
  320. ThrowHead (self, "models/objects/gibs/head2/tris.md2", damage, GIB_ORGANIC);
  321. self->deadflag = DEAD_DEAD;
  322. return;
  323. }
  324. if (self->deadflag == DEAD_DEAD)
  325. return;
  326. // regular death
  327. self->deadflag = DEAD_DEAD;
  328. self->takedamage = DAMAGE_YES;
  329. n = rand() % 2;
  330. if (n == 0)
  331. {
  332. self->monsterinfo.currentmove = &chick_move_death1;
  333. gi.sound (self, CHAN_VOICE, sound_death1, 1, ATTN_NORM, 0);
  334. }
  335. else
  336. {
  337. self->monsterinfo.currentmove = &chick_move_death2;
  338. gi.sound (self, CHAN_VOICE, sound_death2, 1, ATTN_NORM, 0);
  339. }
  340. }
  341. // PMM - changes to duck code for new dodge
  342. mframe_t chick_frames_duck [] =
  343. {
  344. ai_move, 0, monster_duck_down,
  345. ai_move, 1, NULL,
  346. ai_move, 4, monster_duck_hold,
  347. ai_move, -4, NULL,
  348. ai_move, -5, monster_duck_up,
  349. ai_move, 3, NULL,
  350. ai_move, 1, NULL
  351. };
  352. mmove_t chick_move_duck = {FRAME_duck01, FRAME_duck07, chick_frames_duck, chick_run};
  353. /*
  354. void chick_dodge (edict_t *self, edict_t *attacker, float eta, trace_t *tr)
  355. {
  356. // begin orig code
  357. if (random() > 0.25)
  358. return;
  359. if (!self->enemy)
  360. self->enemy = attacker;
  361. self->monsterinfo.currentmove = &chick_move_duck;
  362. // end
  363. float r;
  364. float height;
  365. int shooting = 0;
  366. if (!self->enemy)
  367. {
  368. self->enemy = attacker;
  369. FoundTarget (self);
  370. }
  371. // PMM - don't bother if it's going to hit anyway; fix for weird in-your-face etas (I was
  372. // seeing numbers like 13 and 14)
  373. if ((eta < 0.1) || (eta > 5))
  374. return;
  375. r = random();
  376. if (r > (0.25*((skill->value)+1)))
  377. return;
  378. if ((self->monsterinfo.currentmove == &chick_move_start_attack1) ||
  379. (self->monsterinfo.currentmove == &chick_move_attack1))
  380. {
  381. shooting = 1;
  382. }
  383. if (self->monsterinfo.aiflags & AI_DODGING)
  384. {
  385. height = self->absmax[2];
  386. }
  387. else
  388. {
  389. height = self->absmax[2]-32-1; // the -1 is because the absmax is s.origin + maxs + 1
  390. }
  391. // check to see if it makes sense to duck
  392. if (tr->endpos[2] <= height)
  393. {
  394. vec3_t right, diff;
  395. if (shooting)
  396. {
  397. self->monsterinfo.attack_state = AS_SLIDING;
  398. return;
  399. }
  400. AngleVectors (self->s.angles, NULL, right, NULL);
  401. VectorSubtract (tr->endpos, self->s.origin, diff);
  402. if (DotProduct (right, diff) < 0)
  403. {
  404. self->monsterinfo.lefty = 1;
  405. }
  406. // if it doesn't sense to duck, try to strafe away
  407. monster_done_dodge (self);
  408. self->monsterinfo.currentmove = &chick_move_run;
  409. self->monsterinfo.attack_state = AS_SLIDING;
  410. return;
  411. }
  412. if (skill->value == 0)
  413. {
  414. self->monsterinfo.currentmove = &chick_move_duck;
  415. // PMM - stupid dodge
  416. self->monsterinfo.duck_wait_time = level.time + eta + 1;
  417. self->monsterinfo.aiflags |= AI_DODGING;
  418. return;
  419. }
  420. if (!shooting)
  421. {
  422. self->monsterinfo.currentmove = &chick_move_duck;
  423. self->monsterinfo.duck_wait_time = level.time + eta + (0.1 * (3 - skill->value));
  424. self->monsterinfo.aiflags |= AI_DODGING;
  425. }
  426. return;
  427. }
  428. */
  429. void ChickSlash (edict_t *self)
  430. {
  431. vec3_t aim;
  432. VectorSet (aim, MELEE_DISTANCE, self->mins[0], 10);
  433. gi.sound (self, CHAN_WEAPON, sound_melee_swing, 1, ATTN_NORM, 0);
  434. fire_hit (self, aim, (10 + (rand() %6)), 100);
  435. }
  436. void ChickRocket (edict_t *self)
  437. {
  438. vec3_t forward, right;
  439. vec3_t start;
  440. vec3_t dir;
  441. vec3_t vec;
  442. trace_t trace; // PMM - check target
  443. int rocketSpeed;
  444. float dist;
  445. // pmm - blindfire
  446. vec3_t target;
  447. qboolean blindfire = false;
  448. if (self->monsterinfo.aiflags & AI_MANUAL_STEERING)
  449. blindfire = true;
  450. else
  451. blindfire = false;
  452. if(!self->enemy || !self->enemy->inuse) //PGM
  453. return; //PGM
  454. AngleVectors (self->s.angles, forward, right, NULL);
  455. G_ProjectSource (self->s.origin, monster_flash_offset[MZ2_CHICK_ROCKET_1], forward, right, start);
  456. rocketSpeed = 500 + (100 * skill->value); // PGM rock & roll.... :)
  457. // put a debug trail from start to endpoint, confirm that the start point is
  458. // correct for the trace
  459. // PMM
  460. if (blindfire)
  461. VectorCopy (self->monsterinfo.blind_fire_target, target);
  462. else
  463. VectorCopy (self->enemy->s.origin, target);
  464. // pmm
  465. //PGM
  466. // PMM - blindfire shooting
  467. if (blindfire)
  468. {
  469. VectorCopy (target, vec);
  470. VectorSubtract (vec, start, dir);
  471. }
  472. // pmm
  473. // don't shoot at feet if they're above where i'm shooting from.
  474. else if(random() < 0.33 || (start[2] < self->enemy->absmin[2]))
  475. {
  476. // gi.dprintf("normal shot\n");
  477. VectorCopy (target, vec);
  478. vec[2] += self->enemy->viewheight;
  479. VectorSubtract (vec, start, dir);
  480. }
  481. else
  482. {
  483. // gi.dprintf("shooting at feet!\n");
  484. VectorCopy (target, vec);
  485. vec[2] = self->enemy->absmin[2];
  486. VectorSubtract (vec, start, dir);
  487. }
  488. //PGM
  489. //======
  490. //PMM - lead target (not when blindfiring)
  491. // 20, 35, 50, 65 chance of leading
  492. if((!blindfire) && ((random() < (0.2 + ((3 - skill->value) * 0.15)))))
  493. {
  494. float time;
  495. // gi.dprintf ("leading target\n");
  496. dist = VectorLength (dir);
  497. time = dist/rocketSpeed;
  498. VectorMA(vec, time, self->enemy->velocity, vec);
  499. VectorSubtract(vec, start, dir);
  500. }
  501. //PMM - lead target
  502. //======
  503. VectorNormalize (dir);
  504. // pmm blindfire doesn't check target (done in checkattack)
  505. // paranoia, make sure we're not shooting a target right next to us
  506. trace = gi.trace(start, vec3_origin, vec3_origin, vec, self, MASK_SHOT);
  507. if (blindfire)
  508. {
  509. // blindfire has different fail criteria for the trace
  510. if (!(trace.startsolid || trace.allsolid || (trace.fraction < 0.5)))
  511. monster_fire_rocket (self, start, dir, 50, rocketSpeed, MZ2_CHICK_ROCKET_1);
  512. else
  513. {
  514. // geez, this is bad. she's avoiding about 80% of her blindfires due to hitting things.
  515. // hunt around for a good shot
  516. // try shifting the target to the left a little (to help counter her large offset)
  517. VectorCopy (target, vec);
  518. VectorMA (vec, -10, right, vec);
  519. VectorSubtract(vec, start, dir);
  520. VectorNormalize (dir);
  521. trace = gi.trace(start, vec3_origin, vec3_origin, vec, self, MASK_SHOT);
  522. if (!(trace.startsolid || trace.allsolid || (trace.fraction < 0.5)))
  523. monster_fire_rocket (self, start, dir, 50, rocketSpeed, MZ2_CHICK_ROCKET_1);
  524. else
  525. {
  526. // ok, that failed. try to the right
  527. VectorCopy (target, vec);
  528. VectorMA (vec, 10, right, vec);
  529. VectorSubtract(vec, start, dir);
  530. VectorNormalize (dir);
  531. trace = gi.trace(start, vec3_origin, vec3_origin, vec, self, MASK_SHOT);
  532. if (!(trace.startsolid || trace.allsolid || (trace.fraction < 0.5)))
  533. monster_fire_rocket (self, start, dir, 50, rocketSpeed, MZ2_CHICK_ROCKET_1);
  534. // else if ((g_showlogic) && (g_showlogic->value))
  535. // // ok, I give up
  536. // gi.dprintf ("chick avoiding blindfire shot\n");
  537. }
  538. }
  539. }
  540. else
  541. {
  542. trace = gi.trace(start, vec3_origin, vec3_origin, vec, self, MASK_SHOT);
  543. if(trace.ent == self->enemy || trace.ent == world)
  544. {
  545. if(trace.fraction > 0.5 || (trace.ent && trace.ent->client))
  546. monster_fire_rocket (self, start, dir, 50, rocketSpeed, MZ2_CHICK_ROCKET_1);
  547. // else
  548. // gi.dprintf("didn't make it halfway to target...aborting\n");
  549. }
  550. }
  551. }
  552. void Chick_PreAttack1 (edict_t *self)
  553. {
  554. gi.sound (self, CHAN_VOICE, sound_missile_prelaunch, 1, ATTN_NORM, 0);
  555. }
  556. void ChickReload (edict_t *self)
  557. {
  558. gi.sound (self, CHAN_VOICE, sound_missile_reload, 1, ATTN_NORM, 0);
  559. }
  560. mframe_t chick_frames_start_attack1 [] =
  561. {
  562. ai_charge, 0, Chick_PreAttack1,
  563. ai_charge, 0, NULL,
  564. ai_charge, 0, NULL,
  565. ai_charge, 4, NULL,
  566. ai_charge, 0, NULL,
  567. ai_charge, -3, NULL,
  568. ai_charge, 3, NULL,
  569. ai_charge, 5, NULL,
  570. ai_charge, 7, NULL,
  571. ai_charge, 0, NULL,
  572. ai_charge, 0, NULL,
  573. ai_charge, 0, NULL,
  574. ai_charge, 0, chick_attack1
  575. };
  576. mmove_t chick_move_start_attack1 = {FRAME_attak101, FRAME_attak113, chick_frames_start_attack1, NULL};
  577. mframe_t chick_frames_attack1 [] =
  578. {
  579. ai_charge, 19, ChickRocket,
  580. ai_charge, -6, NULL,
  581. ai_charge, -5, NULL,
  582. ai_charge, -2, NULL,
  583. ai_charge, -7, NULL,
  584. ai_charge, 0, NULL,
  585. ai_charge, 1, NULL,
  586. ai_charge, 10, ChickReload,
  587. ai_charge, 4, NULL,
  588. ai_charge, 5, NULL,
  589. ai_charge, 6, NULL,
  590. ai_charge, 6, NULL,
  591. ai_charge, 4, NULL,
  592. ai_charge, 3, chick_rerocket
  593. };
  594. mmove_t chick_move_attack1 = {FRAME_attak114, FRAME_attak127, chick_frames_attack1, NULL};
  595. mframe_t chick_frames_end_attack1 [] =
  596. {
  597. ai_charge, -3, NULL,
  598. ai_charge, 0, NULL,
  599. ai_charge, -6, NULL,
  600. ai_charge, -4, NULL,
  601. ai_charge, -2, NULL
  602. };
  603. mmove_t chick_move_end_attack1 = {FRAME_attak128, FRAME_attak132, chick_frames_end_attack1, chick_run};
  604. void chick_rerocket(edict_t *self)
  605. {
  606. if (self->monsterinfo.aiflags & AI_MANUAL_STEERING)
  607. {
  608. self->monsterinfo.aiflags &= ~AI_MANUAL_STEERING;
  609. self->monsterinfo.currentmove = &chick_move_end_attack1;
  610. return;
  611. }
  612. if (self->enemy->health > 0)
  613. {
  614. if (range (self, self->enemy) > RANGE_MELEE)
  615. if ( visible (self, self->enemy) )
  616. if (random() <= (0.6 + (0.05*((float)skill->value))))
  617. {
  618. self->monsterinfo.currentmove = &chick_move_attack1;
  619. return;
  620. }
  621. }
  622. self->monsterinfo.currentmove = &chick_move_end_attack1;
  623. }
  624. void chick_attack1(edict_t *self)
  625. {
  626. self->monsterinfo.currentmove = &chick_move_attack1;
  627. }
  628. mframe_t chick_frames_slash [] =
  629. {
  630. ai_charge, 1, NULL,
  631. ai_charge, 7, ChickSlash,
  632. ai_charge, -7, NULL,
  633. ai_charge, 1, NULL,
  634. ai_charge, -1, NULL,
  635. ai_charge, 1, NULL,
  636. ai_charge, 0, NULL,
  637. ai_charge, 1, NULL,
  638. ai_charge, -2, chick_reslash
  639. };
  640. mmove_t chick_move_slash = {FRAME_attak204, FRAME_attak212, chick_frames_slash, NULL};
  641. mframe_t chick_frames_end_slash [] =
  642. {
  643. ai_charge, -6, NULL,
  644. ai_charge, -1, NULL,
  645. ai_charge, -6, NULL,
  646. ai_charge, 0, NULL
  647. };
  648. mmove_t chick_move_end_slash = {FRAME_attak213, FRAME_attak216, chick_frames_end_slash, chick_run};
  649. void chick_reslash(edict_t *self)
  650. {
  651. if (self->enemy->health > 0)
  652. {
  653. if (range (self, self->enemy) == RANGE_MELEE)
  654. if (random() <= 0.9)
  655. {
  656. self->monsterinfo.currentmove = &chick_move_slash;
  657. return;
  658. }
  659. else
  660. {
  661. self->monsterinfo.currentmove = &chick_move_end_slash;
  662. return;
  663. }
  664. }
  665. self->monsterinfo.currentmove = &chick_move_end_slash;
  666. }
  667. void chick_slash(edict_t *self)
  668. {
  669. self->monsterinfo.currentmove = &chick_move_slash;
  670. }
  671. mframe_t chick_frames_start_slash [] =
  672. {
  673. ai_charge, 1, NULL,
  674. ai_charge, 8, NULL,
  675. ai_charge, 3, NULL
  676. };
  677. mmove_t chick_move_start_slash = {FRAME_attak201, FRAME_attak203, chick_frames_start_slash, chick_slash};
  678. void chick_melee(edict_t *self)
  679. {
  680. self->monsterinfo.currentmove = &chick_move_start_slash;
  681. }
  682. void chick_attack(edict_t *self)
  683. {
  684. float r, chance;
  685. monster_done_dodge (self);
  686. // PMM
  687. if (self->monsterinfo.attack_state == AS_BLIND)
  688. {
  689. // setup shot probabilities
  690. if (self->monsterinfo.blind_fire_delay < 1.0)
  691. chance = 1.0;
  692. else if (self->monsterinfo.blind_fire_delay < 7.5)
  693. chance = 0.4;
  694. else
  695. chance = 0.1;
  696. r = random();
  697. // minimum of 2 seconds, plus 0-3, after the shots are done
  698. self->monsterinfo.blind_fire_delay += 4.0 + 1.5 + random();
  699. // don't shoot at the origin
  700. if (VectorCompare (self->monsterinfo.blind_fire_target, vec3_origin))
  701. return;
  702. // don't shoot if the dice say not to
  703. if (r > chance)
  704. {
  705. // if ((g_showlogic) && (g_showlogic->value))
  706. // gi.dprintf ("blindfire - NO SHOT\n");
  707. return;
  708. }
  709. // turn on manual steering to signal both manual steering and blindfire
  710. self->monsterinfo.aiflags |= AI_MANUAL_STEERING;
  711. self->monsterinfo.currentmove = &chick_move_start_attack1;
  712. self->monsterinfo.attack_finished = level.time + 2*random();
  713. return;
  714. }
  715. // pmm
  716. self->monsterinfo.currentmove = &chick_move_start_attack1;
  717. }
  718. void chick_sight(edict_t *self, edict_t *other)
  719. {
  720. gi.sound (self, CHAN_VOICE, sound_sight, 1, ATTN_NORM, 0);
  721. }
  722. //===========
  723. //PGM
  724. qboolean chick_blocked (edict_t *self, float dist)
  725. {
  726. if(blocked_checkshot (self, 0.25 + (0.05 * skill->value) ))
  727. return true;
  728. if(blocked_checkplat (self, dist))
  729. return true;
  730. return false;
  731. }
  732. //PGM
  733. //===========
  734. void chick_duck (edict_t *self, float eta)
  735. {
  736. if ((self->monsterinfo.currentmove == &chick_move_start_attack1) ||
  737. (self->monsterinfo.currentmove == &chick_move_attack1))
  738. {
  739. // if we're shooting, and not on easy, don't dodge
  740. if (skill->value)
  741. {
  742. self->monsterinfo.aiflags &= ~AI_DUCKED;
  743. return;
  744. }
  745. }
  746. if (skill->value == 0)
  747. // PMM - stupid dodge
  748. self->monsterinfo.duck_wait_time = level.time + eta + 1;
  749. else
  750. self->monsterinfo.duck_wait_time = level.time + eta + (0.1 * (3 - skill->value));
  751. // has to be done immediately otherwise she can get stuck
  752. monster_duck_down(self);
  753. self->monsterinfo.nextframe = FRAME_duck01;
  754. self->monsterinfo.currentmove = &chick_move_duck;
  755. return;
  756. }
  757. void chick_sidestep (edict_t *self)
  758. {
  759. if ((self->monsterinfo.currentmove == &chick_move_start_attack1) ||
  760. (self->monsterinfo.currentmove == &chick_move_attack1))
  761. {
  762. // if we're shooting, and not on easy, don't dodge
  763. if (skill->value)
  764. {
  765. self->monsterinfo.aiflags &= ~AI_DODGING;
  766. return;
  767. }
  768. }
  769. if (self->monsterinfo.currentmove != &chick_move_run)
  770. self->monsterinfo.currentmove = &chick_move_run;
  771. }
  772. /*QUAKED monster_chick (1 .5 0) (-16 -16 -24) (16 16 32) Ambush Trigger_Spawn Sight
  773. */
  774. void SP_monster_chick (edict_t *self)
  775. {
  776. if (deathmatch->value)
  777. {
  778. G_FreeEdict (self);
  779. return;
  780. }
  781. sound_missile_prelaunch = gi.soundindex ("chick/chkatck1.wav");
  782. sound_missile_launch = gi.soundindex ("chick/chkatck2.wav");
  783. sound_melee_swing = gi.soundindex ("chick/chkatck3.wav");
  784. sound_melee_hit = gi.soundindex ("chick/chkatck4.wav");
  785. sound_missile_reload = gi.soundindex ("chick/chkatck5.wav");
  786. sound_death1 = gi.soundindex ("chick/chkdeth1.wav");
  787. sound_death2 = gi.soundindex ("chick/chkdeth2.wav");
  788. sound_fall_down = gi.soundindex ("chick/chkfall1.wav");
  789. sound_idle1 = gi.soundindex ("chick/chkidle1.wav");
  790. sound_idle2 = gi.soundindex ("chick/chkidle2.wav");
  791. sound_pain1 = gi.soundindex ("chick/chkpain1.wav");
  792. sound_pain2 = gi.soundindex ("chick/chkpain2.wav");
  793. sound_pain3 = gi.soundindex ("chick/chkpain3.wav");
  794. sound_sight = gi.soundindex ("chick/chksght1.wav");
  795. sound_search = gi.soundindex ("chick/chksrch1.wav");
  796. self->movetype = MOVETYPE_STEP;
  797. self->solid = SOLID_BBOX;
  798. self->s.modelindex = gi.modelindex ("models/monsters/bitch2/tris.md2");
  799. VectorSet (self->mins, -16, -16, 0);
  800. VectorSet (self->maxs, 16, 16, 56);
  801. self->health = 175;
  802. self->gib_health = -70;
  803. self->mass = 200;
  804. self->pain = chick_pain;
  805. self->die = chick_die;
  806. self->monsterinfo.stand = chick_stand;
  807. self->monsterinfo.walk = chick_walk;
  808. self->monsterinfo.run = chick_run;
  809. // pmm
  810. self->monsterinfo.dodge = M_MonsterDodge;
  811. self->monsterinfo.duck = chick_duck;
  812. self->monsterinfo.unduck = monster_duck_up;
  813. self->monsterinfo.sidestep = chick_sidestep;
  814. // self->monsterinfo.dodge = chick_dodge;
  815. // pmm
  816. self->monsterinfo.attack = chick_attack;
  817. self->monsterinfo.melee = chick_melee;
  818. self->monsterinfo.sight = chick_sight;
  819. self->monsterinfo.blocked = chick_blocked; // PGM
  820. gi.linkentity (self);
  821. self->monsterinfo.currentmove = &chick_move_stand;
  822. self->monsterinfo.scale = MODEL_SCALE;
  823. // PMM
  824. self->monsterinfo.blindfire = true;
  825. // pmm
  826. walkmonster_start (self);
  827. }