m_carrier.c 35 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308
  1. // Copyright (c) ZeniMax Media Inc.
  2. // Licensed under the GNU General Public License 2.0.
  3. /*
  4. ==============================================================================
  5. carrier
  6. ==============================================================================
  7. */
  8. // self->timestamp used for frame calculations in grenade & spawn code
  9. // self->wait used to prevent rapid refire of rocket launcher
  10. #include "g_local.h"
  11. #include "m_carrier.h"
  12. #define CARRIER_ROCKET_TIME 2 // number of seconds between rocket shots
  13. #define CARRIER_ROCKET_SPEED 750
  14. #define NUM_FLYERS_SPAWNED 6 // max # of flyers he can spawn
  15. #define RAIL_FIRE_TIME 3
  16. void BossExplode (edict_t *self);
  17. void Grenade_Explode (edict_t *ent);
  18. qboolean infront (edict_t *self, edict_t *other);
  19. qboolean inback (edict_t *self, edict_t *other);
  20. qboolean below (edict_t *self, edict_t *other);
  21. void drawbbox (edict_t *self);
  22. //char *ED_NewString (char *string);
  23. void ED_CallSpawn (edict_t *ent);
  24. static int sound_pain1;
  25. static int sound_pain2;
  26. static int sound_pain3;
  27. static int sound_death;
  28. //static int sound_search1;
  29. static int sound_sight;
  30. static int sound_rail;
  31. static int sound_spawn;
  32. float orig_yaw_speed;
  33. vec3_t flyer_mins = {-16, -16, -24};
  34. vec3_t flyer_maxs = {16, 16, 16};
  35. extern mmove_t flyer_move_attack2, flyer_move_attack3, flyer_move_kamikaze;
  36. void carrier_run (edict_t *self);
  37. void carrier_stand (edict_t *self);
  38. void carrier_dead (edict_t *self);
  39. void carrier_attack (edict_t *self);
  40. void carrier_attack_mg (edict_t *self);
  41. void carrier_reattack_mg (edict_t *self);
  42. void carrier_die (edict_t *self, edict_t *inflictor, edict_t *attacker, int damage, vec3_t point);
  43. void carrier_attack_gren (edict_t *self);
  44. void carrier_reattack_gren (edict_t *self);
  45. void carrier_start_spawn (edict_t *self);
  46. void carrier_spawn_check (edict_t *self);
  47. void carrier_prep_spawn (edict_t *self);
  48. void CarrierMachineGunHold (edict_t *self);
  49. void CarrierRocket (edict_t *self);
  50. void carrier_sight (edict_t *self, edict_t *other)
  51. {
  52. gi.sound (self, CHAN_VOICE, sound_sight, 1, ATTN_NORM, 0);
  53. }
  54. // code starts here
  55. //void carrier_search (edict_t *self)
  56. //{
  57. // if (random() < 0.5)
  58. // gi.sound (self, CHAN_VOICE, sound_search1, 1, ATTN_NONE, 0);
  59. //}
  60. //
  61. // this is the smarts for the rocket launcher in coop
  62. //
  63. // if there is a player behind/below the carrier, and we can shoot, and we can trace a LOS to them ..
  64. // pick one of the group, and let it rip
  65. void CarrierCoopCheck (edict_t *self)
  66. {
  67. // no more than 4 players in coop, so..
  68. edict_t *targets[4];
  69. int num_targets = 0, target, player;
  70. edict_t *ent;
  71. trace_t tr;
  72. // if we're not in coop, this is a noop
  73. if (!coop || !coop->value)
  74. return;
  75. // if we are, and we have recently fired, bail
  76. if (self->wait > level.time)
  77. return;
  78. memset (targets, 0, 4*sizeof(edict_t *));
  79. // cycle through players
  80. for (player = 1; player <= game.maxclients; player++)
  81. {
  82. ent = &g_edicts[player];
  83. if (!ent->inuse)
  84. continue;
  85. if (!ent->client)
  86. continue;
  87. if (inback(self, ent) || below(self, ent))
  88. {
  89. tr = gi.trace (self->s.origin, NULL, NULL, ent->s.origin, self, MASK_SOLID);
  90. if (tr.fraction == 1.0)
  91. {
  92. // if ((g_showlogic) && (g_showlogic->value))
  93. // gi.dprintf ("Carrier: found a player who I can shoot\n");
  94. targets[num_targets++] = ent;
  95. }
  96. }
  97. }
  98. if (!num_targets)
  99. return;
  100. // get a number from 0 to (num_targets-1)
  101. target = random() * num_targets;
  102. // just in case we got a 1.0 from random
  103. if (target == num_targets)
  104. target--;
  105. // make sure to prevent rapid fire rockets
  106. self->wait = level.time + CARRIER_ROCKET_TIME;
  107. // save off the real enemy
  108. ent = self->enemy;
  109. // set the new guy as temporary enemy
  110. self->enemy = targets[target];
  111. CarrierRocket (self);
  112. // put the real enemy back
  113. self->enemy = ent;
  114. // we're done
  115. return;
  116. }
  117. void CarrierGrenade (edict_t *self)
  118. {
  119. vec3_t start;
  120. vec3_t forward, right, up;
  121. vec3_t aim;
  122. int flash_number;
  123. float direction; // from lower left to upper right, or lower right to upper left
  124. float spreadR, spreadU;
  125. int mytime;
  126. CarrierCoopCheck(self);
  127. if (!self->enemy)
  128. return;
  129. if (random() < 0.5)
  130. direction = -1.0;
  131. else
  132. direction = 1.0;
  133. mytime = (int)((level.time - self->timestamp)/0.4);
  134. if (mytime == 0)
  135. {
  136. spreadR = 0.15 * direction;
  137. // spreadU = 0.1 * direction;
  138. spreadU = 0.1 - 0.1 * direction;
  139. }
  140. else if (mytime == 1)
  141. {
  142. spreadR = 0;
  143. // spreadU = 0;
  144. spreadU = 0.1;
  145. }
  146. else if (mytime == 2)
  147. {
  148. spreadR = -0.15 * direction;
  149. // spreadU = -0.1 * direction;
  150. spreadU = 0.1 - -0.1 * direction;
  151. }
  152. else if (mytime == 3)
  153. {
  154. spreadR = 0;
  155. // spreadU = 0;
  156. spreadU = 0.1;
  157. }
  158. else
  159. {
  160. // error, shoot straight
  161. // if ((g_showlogic) && (g_showlogic->value))
  162. // gi.dprintf ("CarrierGrenade: bad time %2.2f %2.2f\n", level.time, self->timestamp);
  163. spreadR = 0;
  164. spreadU = 0;
  165. }
  166. AngleVectors (self->s.angles, forward, right, up);
  167. G_ProjectSource (self->s.origin, monster_flash_offset[MZ2_CARRIER_GRENADE], forward, right, start);
  168. VectorSubtract (self->enemy->s.origin, start, aim);
  169. VectorNormalize (aim);
  170. VectorMA (aim, spreadR, right, aim);
  171. VectorMA (aim, spreadU, up, aim);
  172. if(aim[2] > 0.15)
  173. aim[2] = 0.15;
  174. else if(aim[2] < -0.5)
  175. aim[2] = -0.5;
  176. flash_number = MZ2_GUNNER_GRENADE_1;
  177. monster_fire_grenade (self, start, aim, 50, 600, flash_number);
  178. }
  179. void CarrierPredictiveRocket (edict_t *self)
  180. {
  181. vec3_t forward, right;
  182. vec3_t start;
  183. vec3_t dir;
  184. // if ((g_showlogic) && (g_showlogic->value))
  185. // gi.dprintf("predictive fire\n");
  186. AngleVectors (self->s.angles, forward, right, NULL);
  187. //1
  188. G_ProjectSource (self->s.origin, monster_flash_offset[MZ2_CARRIER_ROCKET_1], forward, right, start);
  189. PredictAim (self->enemy, start, CARRIER_ROCKET_SPEED, false, -0.3, dir, NULL);
  190. monster_fire_rocket (self, start, dir, 50, CARRIER_ROCKET_SPEED, MZ2_CARRIER_ROCKET_1);
  191. //2
  192. G_ProjectSource (self->s.origin, monster_flash_offset[MZ2_CARRIER_ROCKET_2], forward, right, start);
  193. PredictAim (self->enemy, start, CARRIER_ROCKET_SPEED, false, -0.15, dir, NULL);
  194. monster_fire_rocket (self, start, dir, 50, CARRIER_ROCKET_SPEED, MZ2_CARRIER_ROCKET_2);
  195. //3
  196. G_ProjectSource (self->s.origin, monster_flash_offset[MZ2_CARRIER_ROCKET_3], forward, right, start);
  197. PredictAim (self->enemy, start, CARRIER_ROCKET_SPEED, false, 0, dir, NULL);
  198. monster_fire_rocket (self, start, dir, 50, CARRIER_ROCKET_SPEED, MZ2_CARRIER_ROCKET_3);
  199. //4
  200. G_ProjectSource (self->s.origin, monster_flash_offset[MZ2_CARRIER_ROCKET_4], forward, right, start);
  201. PredictAim (self->enemy, start, CARRIER_ROCKET_SPEED, false, 0.15, dir, NULL);
  202. monster_fire_rocket (self, start, dir, 50, CARRIER_ROCKET_SPEED, MZ2_CARRIER_ROCKET_4);
  203. }
  204. void CarrierRocket (edict_t *self)
  205. {
  206. vec3_t forward, right;
  207. vec3_t start;
  208. vec3_t dir;
  209. vec3_t vec;
  210. if(self->enemy)
  211. {
  212. if(self->enemy->client && random() < 0.5)
  213. {
  214. CarrierPredictiveRocket(self);
  215. return;
  216. }
  217. }
  218. else
  219. return;
  220. AngleVectors (self->s.angles, forward, right, NULL);
  221. //1
  222. G_ProjectSource (self->s.origin, monster_flash_offset[MZ2_CARRIER_ROCKET_1], forward, right, start);
  223. VectorCopy (self->enemy->s.origin, vec);
  224. // vec[2] += self->enemy->viewheight;
  225. vec[2] -= 15;
  226. VectorSubtract (vec, start, dir);
  227. VectorNormalize (dir);
  228. VectorMA (dir, 0.4, right, dir);
  229. VectorNormalize (dir);
  230. monster_fire_rocket (self, start, dir, 50, 500, MZ2_CARRIER_ROCKET_1);
  231. //2
  232. G_ProjectSource (self->s.origin, monster_flash_offset[MZ2_CARRIER_ROCKET_2], forward, right, start);
  233. VectorCopy (self->enemy->s.origin, vec);
  234. // vec[2] += self->enemy->viewheight;
  235. VectorSubtract (vec, start, dir);
  236. VectorNormalize (dir);
  237. VectorMA (dir, 0.025, right, dir);
  238. VectorNormalize (dir);
  239. monster_fire_rocket (self, start, dir, 50, 500, MZ2_CARRIER_ROCKET_2);
  240. //3
  241. G_ProjectSource (self->s.origin, monster_flash_offset[MZ2_CARRIER_ROCKET_3], forward, right, start);
  242. VectorCopy (self->enemy->s.origin, vec);
  243. // vec[2] += self->enemy->viewheight;
  244. VectorSubtract (vec, start, dir);
  245. VectorNormalize (dir);
  246. VectorMA (dir, -0.025, right, dir);
  247. VectorNormalize (dir);
  248. monster_fire_rocket (self, start, dir, 50, 500, MZ2_CARRIER_ROCKET_3);
  249. //4
  250. G_ProjectSource (self->s.origin, monster_flash_offset[MZ2_CARRIER_ROCKET_4], forward, right, start);
  251. VectorCopy (self->enemy->s.origin, vec);
  252. // vec[2] += self->enemy->viewheight;
  253. vec[2] -= 15;
  254. VectorSubtract (vec, start, dir);
  255. VectorNormalize (dir);
  256. VectorMA (dir, -0.4, right, dir);
  257. VectorNormalize (dir);
  258. monster_fire_rocket (self, start, dir, 50, 500, MZ2_CARRIER_ROCKET_4);
  259. //5
  260. // G_ProjectSource (self->s.origin, monster_flash_offset[MZ2_BOSS2_ROCKET_4], forward, right, start);
  261. // VectorCopy (self->enemy->s.origin, vec);
  262. // vec[2] += self->enemy->viewheight;
  263. // VectorSubtract (vec, start, dir);
  264. // VectorNormalize (dir);
  265. // monster_fire_rocket (self, start, dir, 50, 500, MZ2_BOSS2_ROCKET_2);
  266. }
  267. void carrier_firebullet_right (edict_t *self)
  268. {
  269. vec3_t forward, right, target;
  270. vec3_t start;
  271. int flashnum;
  272. // if we're in manual steering mode, it means we're leaning down .. use the lower shot
  273. if (self->monsterinfo.aiflags & AI_MANUAL_STEERING)
  274. flashnum = MZ2_CARRIER_MACHINEGUN_R2;
  275. else
  276. flashnum = MZ2_CARRIER_MACHINEGUN_R1;
  277. AngleVectors (self->s.angles, forward, right, NULL);
  278. G_ProjectSource (self->s.origin, monster_flash_offset[flashnum], forward, right, start);
  279. // VectorMA (self->enemy->s.origin, -0.2, self->enemy->velocity, target);
  280. VectorMA (self->enemy->s.origin, 0.2, self->enemy->velocity, target);
  281. target[2] += self->enemy->viewheight;
  282. /*
  283. gi.WriteByte (svc_temp_entity);
  284. gi.WriteByte (TE_DEBUGTRAIL);
  285. gi.WritePosition (start);
  286. gi.WritePosition (target);
  287. gi.multicast (start, MULTICAST_ALL);
  288. */
  289. VectorSubtract (target, start, forward);
  290. VectorNormalize (forward);
  291. monster_fire_bullet (self, start, forward, 6, 4, DEFAULT_BULLET_HSPREAD*3, DEFAULT_BULLET_VSPREAD, flashnum);
  292. }
  293. void carrier_firebullet_left (edict_t *self)
  294. {
  295. vec3_t forward, right, target;
  296. vec3_t start;
  297. int flashnum;
  298. // if we're in manual steering mode, it means we're leaning down .. use the lower shot
  299. if (self->monsterinfo.aiflags & AI_MANUAL_STEERING)
  300. flashnum = MZ2_CARRIER_MACHINEGUN_L2;
  301. else
  302. flashnum = MZ2_CARRIER_MACHINEGUN_L1;
  303. AngleVectors (self->s.angles, forward, right, NULL);
  304. G_ProjectSource (self->s.origin, monster_flash_offset[flashnum], forward, right, start);
  305. // VectorMA (self->enemy->s.origin, 0.2, self->enemy->velocity, target);
  306. VectorMA (self->enemy->s.origin, -0.2, self->enemy->velocity, target);
  307. target[2] += self->enemy->viewheight;
  308. VectorSubtract (target, start, forward);
  309. /*
  310. gi.WriteByte (svc_temp_entity);
  311. gi.WriteByte (TE_DEBUGTRAIL);
  312. gi.WritePosition (start);
  313. gi.WritePosition (target);
  314. gi.multicast (start, MULTICAST_ALL);
  315. */
  316. VectorNormalize (forward);
  317. monster_fire_bullet (self, start, forward, 6, 4, DEFAULT_BULLET_HSPREAD*3, DEFAULT_BULLET_VSPREAD, flashnum);
  318. }
  319. void CarrierMachineGun (edict_t *self)
  320. {
  321. CarrierCoopCheck(self);
  322. if (self->enemy)
  323. carrier_firebullet_left(self);
  324. if (self->enemy)
  325. carrier_firebullet_right(self);
  326. }
  327. void CarrierSpawn (edict_t *self)
  328. {
  329. vec3_t f, r, offset, startpoint, spawnpoint;
  330. edict_t *ent;
  331. int mytime;
  332. // VectorSet (offset, 105, 0, -30); // real distance needed is (sqrt (56*56*2) + sqrt(16*16*2)) or 101.8
  333. VectorSet (offset, 105, 0, -58); // real distance needed is (sqrt (56*56*2) + sqrt(16*16*2)) or 101.8
  334. AngleVectors (self->s.angles, f, r, NULL);
  335. G_ProjectSource (self->s.origin, offset, f, r, startpoint);
  336. // the +0.1 is because level.time is sometimes a little low
  337. mytime = (int)((level.time + 0.1 - self->timestamp)/0.5);
  338. // if ((g_showlogic) && (g_showlogic->value))
  339. // gi.dprintf ("mytime = %d, (%2.2f)\n", mytime, level.time - self->timestamp);
  340. if (FindSpawnPoint (startpoint, flyer_mins, flyer_maxs, spawnpoint, 32))
  341. {
  342. // the second flier should be a kamikaze flyer
  343. if (mytime != 2)
  344. ent = CreateMonster (spawnpoint, self->s.angles, "monster_flyer");
  345. else
  346. ent = CreateMonster (spawnpoint, self->s.angles, "monster_kamikaze");
  347. if (!ent)
  348. return;
  349. gi.sound (self, CHAN_BODY, sound_spawn, 1, ATTN_NONE, 0);
  350. self->monsterinfo.monster_slots--;
  351. // if ((g_showlogic) && (g_showlogic->value))
  352. // gi.dprintf ("carrier: post-spawn : %d slots left\n", self->monsterinfo.monster_slots);
  353. ent->nextthink = level.time;
  354. ent->think (ent);
  355. ent->monsterinfo.aiflags |= AI_SPAWNED_CARRIER|AI_DO_NOT_COUNT|AI_IGNORE_SHOTS;
  356. ent->monsterinfo.commander = self;
  357. if ((self->enemy->inuse) && (self->enemy->health > 0))
  358. {
  359. ent->enemy = self->enemy;
  360. FoundTarget (ent);
  361. if (mytime == 1)
  362. {
  363. ent->monsterinfo.lefty = 0;
  364. ent->monsterinfo.attack_state = AS_SLIDING;
  365. ent->monsterinfo.currentmove = &flyer_move_attack3;
  366. }
  367. else if (mytime == 2)
  368. {
  369. ent->monsterinfo.lefty = 0;
  370. ent->monsterinfo.attack_state = AS_STRAIGHT;
  371. ent->monsterinfo.currentmove = &flyer_move_kamikaze;
  372. ent->mass = 100;
  373. ent->monsterinfo.aiflags |= AI_CHARGING;
  374. }
  375. else if (mytime == 3)
  376. {
  377. ent->monsterinfo.lefty = 1;
  378. ent->monsterinfo.attack_state = AS_SLIDING;
  379. ent->monsterinfo.currentmove = &flyer_move_attack3;
  380. }
  381. // else if ((g_showlogic) && (g_showlogic->value))
  382. // gi.dprintf ("carrier: unexpected time %d!\n", mytime);
  383. }
  384. }
  385. }
  386. void carrier_prep_spawn (edict_t *self)
  387. {
  388. CarrierCoopCheck(self);
  389. self->monsterinfo.aiflags |= AI_MANUAL_STEERING;
  390. self->timestamp = level.time;
  391. self->yaw_speed = 10;
  392. CarrierMachineGun(self);
  393. }
  394. void carrier_spawn_check (edict_t *self)
  395. {
  396. // gi.dprintf ("times - %2.2f %2.2f\n", level.time, self->timestamp);
  397. CarrierCoopCheck(self);
  398. CarrierMachineGun(self);
  399. CarrierSpawn (self);
  400. if (level.time > (self->timestamp + 1.1)) // 0.5 seconds per flyer. this gets three
  401. {
  402. self->monsterinfo.aiflags &= ~AI_MANUAL_STEERING;
  403. self->yaw_speed = orig_yaw_speed;
  404. return;
  405. }
  406. else
  407. self->monsterinfo.nextframe = FRAME_spawn08;
  408. }
  409. void carrier_ready_spawn (edict_t *self)
  410. {
  411. float current_yaw;
  412. vec3_t offset, f, r, startpoint, spawnpoint;
  413. CarrierCoopCheck(self);
  414. CarrierMachineGun(self);
  415. current_yaw = anglemod(self->s.angles[YAW]);
  416. // gi.dprintf ("yaws = %2.2f %2.2f\n", current_yaw, self->ideal_yaw);
  417. if (fabs(current_yaw - self->ideal_yaw) > 0.1)
  418. {
  419. self->monsterinfo.aiflags |= AI_HOLD_FRAME;
  420. self->timestamp += FRAMETIME;
  421. return;
  422. }
  423. self->monsterinfo.aiflags &= ~AI_HOLD_FRAME;
  424. VectorSet (offset, 105,0,-58);
  425. AngleVectors (self->s.angles, f, r, NULL);
  426. G_ProjectSource (self->s.origin, offset, f, r, startpoint);
  427. if (FindSpawnPoint (startpoint, flyer_mins, flyer_maxs, spawnpoint, 32))
  428. {
  429. SpawnGrow_Spawn (spawnpoint, 0);
  430. }
  431. }
  432. void carrier_start_spawn (edict_t *self)
  433. {
  434. int mytime;
  435. float enemy_yaw;
  436. vec3_t temp;
  437. // vec3_t offset, f, r, startpoint;
  438. CarrierCoopCheck(self);
  439. if (!orig_yaw_speed)
  440. orig_yaw_speed = self->yaw_speed;
  441. if (!self->enemy)
  442. return;
  443. mytime = (int)((level.time - self->timestamp)/0.5);
  444. VectorSubtract (self->enemy->s.origin, self->s.origin, temp);
  445. enemy_yaw = vectoyaw2(temp);
  446. // note that the offsets are based on a forward of 105 from the end angle
  447. if (mytime == 0)
  448. {
  449. self->ideal_yaw = anglemod(enemy_yaw - 30);
  450. // VectorSet (offset, 90.9, 52.5, 0);
  451. }
  452. else if (mytime == 1)
  453. {
  454. self->ideal_yaw = anglemod(enemy_yaw);
  455. // VectorSet (offset, 90.9, -52.5, 0);
  456. }
  457. else if (mytime == 2)
  458. {
  459. self->ideal_yaw = anglemod(enemy_yaw + 30);
  460. // VectorSet (offset, 90.9, -52.5, 0);
  461. }
  462. // else if ((g_showlogic) && (g_showlogic->value))
  463. // gi.dprintf ("carrier: bad spawntime\n");
  464. CarrierMachineGun (self);
  465. }
  466. mframe_t carrier_frames_stand [] =
  467. {
  468. // ai_stand, 0, drawbbox,
  469. ai_stand, 0, NULL,
  470. ai_stand, 0, NULL,
  471. ai_stand, 0, NULL,
  472. ai_stand, 0, NULL,
  473. ai_stand, 0, NULL,
  474. ai_stand, 0, NULL,
  475. ai_stand, 0, NULL,
  476. ai_stand, 0, NULL,
  477. ai_stand, 0, NULL,
  478. ai_stand, 0, NULL,
  479. ai_stand, 0, NULL,
  480. ai_stand, 0, NULL,
  481. ai_stand, 0, NULL
  482. };
  483. mmove_t carrier_move_stand = {FRAME_search01, FRAME_search13, carrier_frames_stand, NULL};
  484. mframe_t carrier_frames_walk [] =
  485. {
  486. // ai_walk, 12, drawbbox,
  487. ai_walk, 4, NULL,
  488. ai_walk, 4, NULL,
  489. ai_walk, 4, NULL,
  490. ai_walk, 4, NULL,
  491. ai_walk, 4, NULL,
  492. ai_walk, 4, NULL,
  493. ai_walk, 4, NULL,
  494. ai_walk, 4, NULL,
  495. ai_walk, 4, NULL,
  496. ai_walk, 4, NULL,
  497. ai_walk, 4, NULL,
  498. ai_walk, 4, NULL,
  499. ai_walk, 4, NULL
  500. };
  501. mmove_t carrier_move_walk = {FRAME_search01, FRAME_search13, carrier_frames_walk, NULL};
  502. mframe_t carrier_frames_run [] =
  503. {
  504. // ai_run, 12, drawbbox,
  505. ai_run, 6, CarrierCoopCheck,
  506. ai_run, 6, CarrierCoopCheck,
  507. ai_run, 6, CarrierCoopCheck,
  508. ai_run, 6, CarrierCoopCheck,
  509. ai_run, 6, CarrierCoopCheck,
  510. ai_run, 6, CarrierCoopCheck,
  511. ai_run, 6, CarrierCoopCheck,
  512. ai_run, 6, CarrierCoopCheck,
  513. ai_run, 6, CarrierCoopCheck,
  514. ai_run, 6, CarrierCoopCheck,
  515. ai_run, 6, CarrierCoopCheck,
  516. ai_run, 6, CarrierCoopCheck,
  517. ai_run, 6, CarrierCoopCheck
  518. };
  519. mmove_t carrier_move_run = {FRAME_search01, FRAME_search13, carrier_frames_run, NULL};
  520. mframe_t carrier_frames_attack_pre_mg [] =
  521. {
  522. ai_charge, 4, CarrierCoopCheck,
  523. ai_charge, 4, CarrierCoopCheck,
  524. ai_charge, 4, CarrierCoopCheck,
  525. ai_charge, 4, CarrierCoopCheck,
  526. ai_charge, 4, CarrierCoopCheck,
  527. ai_charge, 4, CarrierCoopCheck,
  528. ai_charge, 4, CarrierCoopCheck,
  529. ai_charge, 4, carrier_attack_mg
  530. };
  531. mmove_t carrier_move_attack_pre_mg = {FRAME_firea01, FRAME_firea08, carrier_frames_attack_pre_mg, NULL};
  532. // Loop this
  533. mframe_t carrier_frames_attack_mg [] =
  534. {
  535. ai_charge, -2, CarrierMachineGun,
  536. ai_charge, -2, CarrierMachineGun,
  537. ai_charge, -2, carrier_reattack_mg
  538. /*
  539. ai_charge, 0, CarrierMachineGunHold,
  540. // ai_charge, 0, CarrierMachineGun,
  541. ai_charge, 0, CarrierMachineGun,
  542. ai_charge, 0, carrier_reattack_mg
  543. */
  544. };
  545. mmove_t carrier_move_attack_mg = {FRAME_firea09, FRAME_firea11, carrier_frames_attack_mg, NULL};
  546. mframe_t carrier_frames_attack_post_mg [] =
  547. {
  548. ai_charge, 4, CarrierCoopCheck,
  549. ai_charge, 4, CarrierCoopCheck,
  550. ai_charge, 4, CarrierCoopCheck,
  551. ai_charge, 4, CarrierCoopCheck
  552. };
  553. mmove_t carrier_move_attack_post_mg = {FRAME_firea12, FRAME_firea15, carrier_frames_attack_post_mg, carrier_run};
  554. mframe_t carrier_frames_attack_pre_gren [] =
  555. {
  556. ai_charge, 4, CarrierCoopCheck,
  557. ai_charge, 4, CarrierCoopCheck,
  558. ai_charge, 4, CarrierCoopCheck,
  559. ai_charge, 4, CarrierCoopCheck,
  560. ai_charge, 4, CarrierCoopCheck,
  561. ai_charge, 4, carrier_attack_gren
  562. };
  563. mmove_t carrier_move_attack_pre_gren = {FRAME_fireb01, FRAME_fireb06, carrier_frames_attack_pre_gren, NULL};
  564. mframe_t carrier_frames_attack_gren [] =
  565. {
  566. ai_charge, -15, CarrierGrenade,
  567. ai_charge, 4, CarrierCoopCheck,
  568. ai_charge, 4, CarrierCoopCheck,
  569. ai_charge, 4, carrier_reattack_gren
  570. };
  571. mmove_t carrier_move_attack_gren = {FRAME_fireb07, FRAME_fireb10, carrier_frames_attack_gren, NULL};
  572. mframe_t carrier_frames_attack_post_gren [] =
  573. {
  574. ai_charge, 4, CarrierCoopCheck,
  575. ai_charge, 4, CarrierCoopCheck,
  576. ai_charge, 4, CarrierCoopCheck,
  577. ai_charge, 4, CarrierCoopCheck,
  578. ai_charge, 4, CarrierCoopCheck,
  579. ai_charge, 4, CarrierCoopCheck
  580. };
  581. mmove_t carrier_move_attack_post_gren = {FRAME_fireb11, FRAME_fireb16, carrier_frames_attack_post_gren, carrier_run};
  582. mframe_t carrier_frames_attack_rocket [] =
  583. {
  584. ai_charge, 15, CarrierRocket
  585. };
  586. mmove_t carrier_move_attack_rocket = {FRAME_fireb01, FRAME_fireb01, carrier_frames_attack_rocket, carrier_run};
  587. void CarrierRail (edict_t *self)
  588. {
  589. vec3_t start;
  590. vec3_t dir;
  591. vec3_t forward, right;
  592. CarrierCoopCheck(self);
  593. AngleVectors (self->s.angles, forward, right, NULL);
  594. G_ProjectSource (self->s.origin, monster_flash_offset[MZ2_CARRIER_RAILGUN], forward, right, start);
  595. // calc direction to where we targeted
  596. VectorSubtract (self->pos1, start, dir);
  597. VectorNormalize (dir);
  598. monster_fire_railgun (self, start, dir, 50, 100, MZ2_CARRIER_RAILGUN);
  599. self->monsterinfo.attack_finished = level.time + RAIL_FIRE_TIME;
  600. }
  601. void CarrierSaveLoc (edict_t *self)
  602. {
  603. CarrierCoopCheck(self);
  604. VectorCopy (self->enemy->s.origin, self->pos1); //save for aiming the shot
  605. self->pos1[2] += self->enemy->viewheight;
  606. };
  607. mframe_t carrier_frames_attack_rail [] =
  608. {
  609. ai_charge, 2, CarrierCoopCheck,
  610. ai_charge, 2, CarrierSaveLoc,
  611. ai_charge, 2, CarrierCoopCheck,
  612. ai_charge, -20, CarrierRail,
  613. ai_charge, 2, CarrierCoopCheck,
  614. ai_charge, 2, CarrierCoopCheck,
  615. ai_charge, 2, CarrierCoopCheck,
  616. ai_charge, 2, CarrierCoopCheck,
  617. ai_charge, 2, CarrierCoopCheck
  618. };
  619. mmove_t carrier_move_attack_rail = {FRAME_search01, FRAME_search09, carrier_frames_attack_rail, carrier_run};
  620. mframe_t carrier_frames_spawn [] =
  621. {
  622. ai_charge, -2, CarrierMachineGun,
  623. ai_charge, -2, CarrierMachineGun,
  624. ai_charge, -2, CarrierMachineGun,
  625. ai_charge, -2, CarrierMachineGun,
  626. ai_charge, -2, CarrierMachineGun,
  627. ai_charge, -2, CarrierMachineGun,
  628. ai_charge, -2, carrier_prep_spawn, // 7 - end of wind down
  629. ai_charge, -2, carrier_start_spawn, // 8 - start of spawn
  630. ai_charge, -2, carrier_ready_spawn,
  631. ai_charge, -2, CarrierMachineGun,
  632. ai_charge, -2, CarrierMachineGun,
  633. ai_charge, -10, carrier_spawn_check, //12 - actual spawn
  634. ai_charge, -2, CarrierMachineGun, //13 - begin of wind down
  635. ai_charge, -2, CarrierMachineGun,
  636. ai_charge, -2, CarrierMachineGun,
  637. ai_charge, -2, CarrierMachineGun,
  638. ai_charge, -2, CarrierMachineGun,
  639. ai_charge, -2, carrier_reattack_mg //18 - end of wind down
  640. };
  641. mmove_t carrier_move_spawn = {FRAME_spawn01, FRAME_spawn18, carrier_frames_spawn, NULL};
  642. mframe_t carrier_frames_pain_heavy [] =
  643. {
  644. ai_move, 0, NULL,
  645. ai_move, 0, NULL,
  646. ai_move, 0, NULL,
  647. ai_move, 0, NULL,
  648. ai_move, 0, NULL,
  649. ai_move, 0, NULL,
  650. ai_move, 0, NULL,
  651. ai_move, 0, NULL,
  652. ai_move, 0, NULL,
  653. ai_move, 0, NULL
  654. };
  655. mmove_t carrier_move_pain_heavy = {FRAME_death01, FRAME_death10, carrier_frames_pain_heavy, carrier_run};
  656. mframe_t carrier_frames_pain_light [] =
  657. {
  658. ai_move, 0, NULL,
  659. ai_move, 0, NULL,
  660. ai_move, 0, NULL,
  661. ai_move, 0, NULL
  662. };
  663. mmove_t carrier_move_pain_light = {FRAME_spawn01, FRAME_spawn04, carrier_frames_pain_light, carrier_run};
  664. mframe_t carrier_frames_death [] =
  665. {
  666. ai_move, 0, NULL,
  667. ai_move, 0, NULL,
  668. ai_move, 0, NULL,
  669. ai_move, 0, NULL,
  670. ai_move, 0, NULL,
  671. ai_move, 0, NULL,
  672. ai_move, 0, NULL,
  673. ai_move, 0, NULL,
  674. ai_move, 0, NULL,
  675. ai_move, 0, NULL,
  676. ai_move, 0, NULL,
  677. ai_move, 0, NULL,
  678. ai_move, 0, NULL,
  679. ai_move, 0, NULL,
  680. ai_move, 0, NULL,
  681. ai_move, 0, BossExplode
  682. };
  683. mmove_t carrier_move_death = {FRAME_death01, FRAME_death16, carrier_frames_death, carrier_dead};
  684. void carrier_stand (edict_t *self)
  685. {
  686. // gi.dprintf ("carrier stand\n");
  687. self->monsterinfo.currentmove = &carrier_move_stand;
  688. }
  689. void carrier_run (edict_t *self)
  690. {
  691. // gi.dprintf ("carrier run - %2.2f - %s \n", level.time, self->enemy->classname);
  692. self->monsterinfo.aiflags &= ~AI_HOLD_FRAME;
  693. if (self->monsterinfo.aiflags & AI_STAND_GROUND)
  694. self->monsterinfo.currentmove = &carrier_move_stand;
  695. else
  696. self->monsterinfo.currentmove = &carrier_move_run;
  697. }
  698. void carrier_walk (edict_t *self)
  699. {
  700. self->monsterinfo.currentmove = &carrier_move_walk;
  701. }
  702. void CarrierMachineGunHold (edict_t *self)
  703. {
  704. // self->monsterinfo.aiflags |= AI_HOLD_FRAME;
  705. // self->yaw_speed = 0;
  706. // self->monsterinfo.currentmove = &carrier_move_attack_mg;
  707. CarrierMachineGun (self);
  708. }
  709. void carrier_attack (edict_t *self)
  710. {
  711. vec3_t vec;
  712. float range, luck;
  713. qboolean enemy_inback, enemy_infront, enemy_below;
  714. // gi.dprintf ("carrier attack\n");
  715. self->monsterinfo.aiflags &= ~AI_HOLD_FRAME;
  716. if ((!self->enemy) || (!self->enemy->inuse))
  717. return;
  718. enemy_inback = inback(self, self->enemy);
  719. enemy_infront = infront (self, self->enemy);
  720. enemy_below = below (self, self->enemy);
  721. if (self->bad_area)
  722. {
  723. if ((enemy_inback) || (enemy_below))
  724. self->monsterinfo.currentmove = &carrier_move_attack_rocket;
  725. else if ((random() < 0.1) || (level.time < self->monsterinfo.attack_finished))
  726. self->monsterinfo.currentmove = &carrier_move_attack_pre_mg;
  727. else
  728. {
  729. gi.sound (self, CHAN_WEAPON, sound_rail, 1, ATTN_NORM, 0);
  730. self->monsterinfo.currentmove = &carrier_move_attack_rail;
  731. }
  732. return;
  733. }
  734. if (self->monsterinfo.attack_state == AS_BLIND)
  735. {
  736. self->monsterinfo.currentmove = &carrier_move_spawn;
  737. return;
  738. }
  739. if (!enemy_inback && !enemy_infront && !enemy_below) // to side and not under
  740. {
  741. if ((random() < 0.1) || (level.time < self->monsterinfo.attack_finished))
  742. self->monsterinfo.currentmove = &carrier_move_attack_pre_mg;
  743. else
  744. {
  745. gi.sound (self, CHAN_WEAPON, sound_rail, 1, ATTN_NORM, 0);
  746. self->monsterinfo.currentmove = &carrier_move_attack_rail;
  747. }
  748. return;
  749. }
  750. /* if ((g_showlogic) && (g_showlogic->value))
  751. {
  752. gi.dprintf ("checking enemy ..");
  753. if (enemy_inback)
  754. gi.dprintf (" in back\n");
  755. else if (enemy_infront)
  756. gi.dprintf (" in front\n");
  757. else
  758. gi.dprintf (" inaccessible\n");
  759. }
  760. */
  761. if (enemy_infront)
  762. {
  763. VectorSubtract (self->enemy->s.origin, self->s.origin, vec);
  764. range = VectorLength (vec);
  765. if (range <= 125)
  766. {
  767. if ((random() < 0.8) || (level.time < self->monsterinfo.attack_finished))
  768. self->monsterinfo.currentmove = &carrier_move_attack_pre_mg;
  769. else
  770. {
  771. gi.sound (self, CHAN_WEAPON, sound_rail, 1, ATTN_NORM, 0);
  772. self->monsterinfo.currentmove = &carrier_move_attack_rail;
  773. }
  774. }
  775. else if (range < 600)
  776. {
  777. luck = random();
  778. if (self->monsterinfo.monster_slots > 2)
  779. {
  780. if (luck <= 0.20)
  781. self->monsterinfo.currentmove = &carrier_move_attack_pre_mg;
  782. else if (luck <= 0.40)
  783. self->monsterinfo.currentmove = &carrier_move_attack_pre_gren;
  784. else if ((luck <= 0.7) && !(level.time < self->monsterinfo.attack_finished))
  785. {
  786. gi.sound (self, CHAN_WEAPON, sound_rail, 1, ATTN_NORM, 0);
  787. self->monsterinfo.currentmove = &carrier_move_attack_rail;
  788. }
  789. else
  790. self->monsterinfo.currentmove = &carrier_move_spawn;
  791. }
  792. else
  793. {
  794. if (luck <= 0.30)
  795. self->monsterinfo.currentmove = &carrier_move_attack_pre_mg;
  796. else if (luck <= 0.65)
  797. self->monsterinfo.currentmove = &carrier_move_attack_pre_gren;
  798. else if (level.time >= self->monsterinfo.attack_finished)
  799. {
  800. gi.sound (self, CHAN_WEAPON, sound_rail, 1, ATTN_NORM, 0);
  801. self->monsterinfo.currentmove = &carrier_move_attack_rail;
  802. }
  803. else
  804. self->monsterinfo.currentmove = &carrier_move_attack_pre_mg;
  805. }
  806. }
  807. else // won't use grenades at this range
  808. {
  809. luck = random();
  810. if (self->monsterinfo.monster_slots > 2)
  811. {
  812. if (luck < 0.3)
  813. self->monsterinfo.currentmove = &carrier_move_attack_pre_mg;
  814. else if ((luck < 0.65) && !(level.time < self->monsterinfo.attack_finished))
  815. {
  816. gi.sound (self, CHAN_WEAPON, sound_rail, 1, ATTN_NORM, 0);
  817. VectorCopy (self->enemy->s.origin, self->pos1); //save for aiming the shot
  818. self->pos1[2] += self->enemy->viewheight;
  819. self->monsterinfo.currentmove = &carrier_move_attack_rail;
  820. }
  821. else
  822. self->monsterinfo.currentmove = &carrier_move_spawn;
  823. }
  824. else
  825. {
  826. if ((luck < 0.45) || (level.time < self->monsterinfo.attack_finished))
  827. self->monsterinfo.currentmove = &carrier_move_attack_pre_mg;
  828. else
  829. {
  830. gi.sound (self, CHAN_WEAPON, sound_rail, 1, ATTN_NORM, 0);
  831. self->monsterinfo.currentmove = &carrier_move_attack_rail;
  832. }
  833. }
  834. }
  835. }
  836. else if ((enemy_below) || (enemy_inback))
  837. {
  838. self->monsterinfo.currentmove = &carrier_move_attack_rocket;
  839. }
  840. }
  841. void carrier_attack_mg (edict_t *self)
  842. {
  843. CarrierCoopCheck(self);
  844. self->monsterinfo.currentmove = &carrier_move_attack_mg;
  845. }
  846. void carrier_reattack_mg (edict_t *self)
  847. {
  848. CarrierCoopCheck(self);
  849. if ( infront(self, self->enemy) )
  850. if (random() <= 0.5)
  851. if ((random() < 0.7) || (self->monsterinfo.monster_slots <= 2))
  852. self->monsterinfo.currentmove = &carrier_move_attack_mg;
  853. else
  854. self->monsterinfo.currentmove = &carrier_move_spawn;
  855. else
  856. self->monsterinfo.currentmove = &carrier_move_attack_post_mg;
  857. else
  858. self->monsterinfo.currentmove = &carrier_move_attack_post_mg;
  859. }
  860. void carrier_attack_gren (edict_t *self)
  861. {
  862. // gi.dprintf ("carrier_attack_gren - %2.2f\n",level.time);
  863. CarrierCoopCheck(self);
  864. self->timestamp = level.time;
  865. self->monsterinfo.currentmove = &carrier_move_attack_gren;
  866. }
  867. void carrier_reattack_gren (edict_t *self)
  868. {
  869. CarrierCoopCheck(self);
  870. // gi.dprintf ("carrier_reattack - %2.2f", level.time);
  871. if ( infront(self, self->enemy) )
  872. if (self->timestamp + 1.3 > level.time ) // four grenades
  873. {
  874. // gi.dprintf (" attacking\n");
  875. self->monsterinfo.currentmove = &carrier_move_attack_gren;
  876. return;
  877. }
  878. // gi.dprintf ("not attacking\n");
  879. self->monsterinfo.currentmove = &carrier_move_attack_post_gren;
  880. }
  881. void carrier_pain (edict_t *self, edict_t *other, float kick, int damage)
  882. {
  883. qboolean changed = false;
  884. if (self->health < (self->max_health / 2))
  885. self->s.skinnum = 1;
  886. if (skill->value == 3)
  887. return; // no pain anims in nightmare
  888. // gi.dprintf ("carrier pain\n");
  889. if (level.time < self->pain_debounce_time)
  890. return;
  891. self->pain_debounce_time = level.time + 5;
  892. if (damage < 10)
  893. {
  894. gi.sound (self, CHAN_VOICE, sound_pain3, 1, ATTN_NONE, 0);
  895. }
  896. else if (damage < 30)
  897. {
  898. gi.sound (self, CHAN_VOICE, sound_pain1, 1, ATTN_NONE, 0);
  899. if (random() < 0.5)
  900. {
  901. changed = true;
  902. self->monsterinfo.currentmove = &carrier_move_pain_light;
  903. }
  904. }
  905. else
  906. {
  907. gi.sound (self, CHAN_VOICE, sound_pain2, 1, ATTN_NONE, 0);
  908. self->monsterinfo.currentmove = &carrier_move_pain_heavy;
  909. changed = true;
  910. }
  911. // if we changed frames, clean up our little messes
  912. if (changed)
  913. {
  914. self->monsterinfo.aiflags &= ~AI_HOLD_FRAME;
  915. self->monsterinfo.aiflags &= ~AI_MANUAL_STEERING;
  916. self->yaw_speed = orig_yaw_speed;
  917. }
  918. }
  919. void carrier_dead (edict_t *self)
  920. {
  921. VectorSet (self->mins, -56, -56, 0);
  922. VectorSet (self->maxs, 56, 56, 80);
  923. self->movetype = MOVETYPE_TOSS;
  924. self->svflags |= SVF_DEADMONSTER;
  925. self->nextthink = 0;
  926. gi.linkentity (self);
  927. }
  928. void carrier_die (edict_t *self, edict_t *inflictor, edict_t *attacker, int damage, vec3_t point)
  929. {
  930. gi.sound (self, CHAN_VOICE, sound_death, 1, ATTN_NONE, 0);
  931. self->deadflag = DEAD_DEAD;
  932. self->takedamage = DAMAGE_NO;
  933. self->count = 0;
  934. self->monsterinfo.currentmove = &carrier_move_death;
  935. }
  936. qboolean Carrier_CheckAttack (edict_t *self)
  937. {
  938. vec3_t spot1, spot2;
  939. vec3_t temp;
  940. float chance;
  941. trace_t tr;
  942. qboolean enemy_infront, enemy_inback, enemy_below;
  943. int enemy_range;
  944. float enemy_yaw;
  945. if (self->enemy->health > 0)
  946. {
  947. // see if any entities are in the way of the shot
  948. VectorCopy (self->s.origin, spot1);
  949. spot1[2] += self->viewheight;
  950. VectorCopy (self->enemy->s.origin, spot2);
  951. spot2[2] += self->enemy->viewheight;
  952. tr = gi.trace (spot1, NULL, NULL, spot2, self, CONTENTS_SOLID|CONTENTS_MONSTER|CONTENTS_SLIME|CONTENTS_LAVA);
  953. // do we have a clear shot?
  954. if (tr.ent != self->enemy)
  955. {
  956. // go ahead and spawn stuff if we're mad a a client
  957. if (self->enemy->client && self->monsterinfo.monster_slots > 2)
  958. {
  959. self->monsterinfo.attack_state = AS_BLIND;
  960. return true;
  961. }
  962. // PGM - we want them to go ahead and shoot at info_notnulls if they can.
  963. if(self->enemy->solid != SOLID_NOT || tr.fraction < 1.0) //PGM
  964. return false;
  965. }
  966. }
  967. enemy_infront = infront(self, self->enemy);
  968. enemy_inback = inback(self, self->enemy);
  969. enemy_below = below (self, self->enemy);
  970. enemy_range = range(self, self->enemy);
  971. VectorSubtract (self->enemy->s.origin, self->s.origin, temp);
  972. enemy_yaw = vectoyaw2(temp);
  973. self->ideal_yaw = enemy_yaw;
  974. // PMM - shoot out the back if appropriate
  975. if ((enemy_inback) || (!enemy_infront && enemy_below))
  976. {
  977. // this is using wait because the attack is supposed to be independent
  978. if (level.time >= self->wait)
  979. {
  980. self->wait = level.time + CARRIER_ROCKET_TIME;
  981. self->monsterinfo.attack(self);
  982. if (random() < 0.6)
  983. self->monsterinfo.attack_state = AS_SLIDING;
  984. else
  985. self->monsterinfo.attack_state = AS_STRAIGHT;
  986. return true;
  987. }
  988. }
  989. // melee attack
  990. if (enemy_range == RANGE_MELEE)
  991. {
  992. self->monsterinfo.attack_state = AS_MISSILE;
  993. return true;
  994. }
  995. // if (level.time < self->monsterinfo.attack_finished)
  996. // return false;
  997. if (self->monsterinfo.aiflags & AI_STAND_GROUND)
  998. {
  999. chance = 0.4;
  1000. }
  1001. else if (enemy_range == RANGE_MELEE)
  1002. {
  1003. chance = 0.8;
  1004. }
  1005. else if (enemy_range == RANGE_NEAR)
  1006. {
  1007. chance = 0.8;
  1008. }
  1009. else if (enemy_range == RANGE_MID)
  1010. {
  1011. chance = 0.8;
  1012. }
  1013. else if (enemy_range == RANGE_FAR)
  1014. {
  1015. chance = 0.5;
  1016. }
  1017. // PGM - go ahead and shoot every time if it's a info_notnull
  1018. if ((random () < chance) || (self->enemy->solid == SOLID_NOT))
  1019. {
  1020. self->monsterinfo.attack_state = AS_MISSILE;
  1021. // self->monsterinfo.attack_finished = level.time + 2*random();
  1022. return true;
  1023. }
  1024. if (self->flags & FL_FLY)
  1025. {
  1026. if (random() < 0.6)
  1027. self->monsterinfo.attack_state = AS_SLIDING;
  1028. else
  1029. self->monsterinfo.attack_state = AS_STRAIGHT;
  1030. }
  1031. return false;
  1032. }
  1033. void CarrierPrecache ()
  1034. {
  1035. gi.soundindex ("flyer/flysght1.wav");
  1036. gi.soundindex ("flyer/flysrch1.wav");
  1037. gi.soundindex ("flyer/flypain1.wav");
  1038. gi.soundindex ("flyer/flypain2.wav");
  1039. gi.soundindex ("flyer/flyatck2.wav");
  1040. gi.soundindex ("flyer/flyatck1.wav");
  1041. gi.soundindex ("flyer/flydeth1.wav");
  1042. gi.soundindex ("flyer/flyatck3.wav");
  1043. gi.soundindex ("flyer/flyidle1.wav");
  1044. gi.soundindex ("weapons/rockfly.wav");
  1045. gi.soundindex ("infantry/infatck1.wav");
  1046. gi.soundindex ("gunner/gunatck3.wav");
  1047. gi.soundindex ("weapons/grenlb1b.wav");
  1048. gi.soundindex ("tank/rocket.wav");
  1049. gi.modelindex ("models/monsters/flyer/tris.md2");
  1050. gi.modelindex ("models/objects/rocket/tris.md2");
  1051. gi.modelindex ("models/objects/debris2/tris.md2");
  1052. gi.modelindex ("models/objects/grenade/tris.md2");
  1053. gi.modelindex("models/items/spawngro/tris.md2");
  1054. gi.modelindex("models/items/spawngro2/tris.md2");
  1055. gi.modelindex ("models/objects/gibs/sm_metal/tris.md2");
  1056. gi.modelindex ("models/objects/gibs/gear/tris.md2");
  1057. }
  1058. /*QUAKED monster_carrier (1 .5 0) (-56 -56 -44) (56 56 44) Ambush Trigger_Spawn Sight
  1059. */
  1060. void SP_monster_carrier (edict_t *self)
  1061. {
  1062. if (deathmatch->value)
  1063. {
  1064. G_FreeEdict (self);
  1065. return;
  1066. }
  1067. sound_pain1 = gi.soundindex ("carrier/pain_md.wav");
  1068. sound_pain2 = gi.soundindex ("carrier/pain_lg.wav");
  1069. sound_pain3 = gi.soundindex ("carrier/pain_sm.wav");
  1070. sound_death = gi.soundindex ("carrier/death.wav");
  1071. // sound_search1 = gi.soundindex ("bosshovr/bhvunqv1.wav");
  1072. sound_rail = gi.soundindex ("gladiator/railgun.wav");
  1073. sound_sight = gi.soundindex ("carrier/sight.wav");
  1074. sound_spawn = gi.soundindex ("medic_commander/monsterspawn1.wav");
  1075. self->s.sound = gi.soundindex ("bosshovr/bhvengn1.wav");
  1076. self->movetype = MOVETYPE_STEP;
  1077. self->solid = SOLID_BBOX;
  1078. self->s.modelindex = gi.modelindex ("models/monsters/carrier/tris.md2");
  1079. VectorSet (self->mins, -56, -56, -44);
  1080. VectorSet (self->maxs, 56, 56, 44);
  1081. // 2000 - 4000 health
  1082. self->health = max (2000, 2000 + 1000*((skill->value)-1));
  1083. // add health in coop (500 * skill)
  1084. if (coop->value)
  1085. self->health += 500*(skill->value);
  1086. self->gib_health = -200;
  1087. self->mass = 1000;
  1088. self->yaw_speed = 15;
  1089. orig_yaw_speed = self->yaw_speed;
  1090. // self->yaw_speed = 1;
  1091. self->flags |= FL_IMMUNE_LASER;
  1092. self->monsterinfo.aiflags |= AI_IGNORE_SHOTS;
  1093. self->pain = carrier_pain;
  1094. self->die = carrier_die;
  1095. self->monsterinfo.melee = NULL;
  1096. self->monsterinfo.stand = carrier_stand;
  1097. self->monsterinfo.walk = carrier_walk;
  1098. self->monsterinfo.run = carrier_run;
  1099. self->monsterinfo.attack = carrier_attack;
  1100. // self->monsterinfo.search = carrier_search;
  1101. self->monsterinfo.sight = carrier_sight;
  1102. self->monsterinfo.checkattack = Carrier_CheckAttack;
  1103. gi.linkentity (self);
  1104. self->monsterinfo.currentmove = &carrier_move_stand;
  1105. self->monsterinfo.scale = MODEL_SCALE;
  1106. CarrierPrecache();
  1107. flymonster_start (self);
  1108. self->monsterinfo.attack_finished = 0;
  1109. switch ((int)skill->value)
  1110. {
  1111. case 0:
  1112. self->monsterinfo.monster_slots = 3;
  1113. break;
  1114. case 1:
  1115. case 2:
  1116. self->monsterinfo.monster_slots = 6;
  1117. break;
  1118. case 3:
  1119. self->monsterinfo.monster_slots = 9;
  1120. break;
  1121. default:
  1122. self->monsterinfo.monster_slots = 6;
  1123. break;
  1124. }
  1125. }