g_monster.c 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876
  1. // Copyright (c) ZeniMax Media Inc.
  2. // Licensed under the GNU General Public License 2.0.
  3. #include "g_local.h"
  4. //
  5. // monster weapons
  6. //
  7. //FIXME mosnters should call these with a totally accurate direction
  8. // and we can mess it up based on skill. Spread should be for normal
  9. // and we can tighten or loosen based on skill. We could muck with
  10. // the damages too, but I'm not sure that's such a good idea.
  11. void monster_fire_bullet (edict_t *self, vec3_t start, vec3_t dir, int damage, int kick, int hspread, int vspread, int flashtype)
  12. {
  13. fire_bullet (self, start, dir, damage, kick, hspread, vspread, MOD_UNKNOWN);
  14. gi.WriteByte (svc_muzzleflash2);
  15. gi.WriteShort (self - g_edicts);
  16. gi.WriteByte (flashtype);
  17. gi.multicast (start, MULTICAST_PVS);
  18. }
  19. void monster_fire_shotgun (edict_t *self, vec3_t start, vec3_t aimdir, int damage, int kick, int hspread, int vspread, int count, int flashtype)
  20. {
  21. fire_shotgun (self, start, aimdir, damage, kick, hspread, vspread, count, MOD_UNKNOWN);
  22. gi.WriteByte (svc_muzzleflash2);
  23. gi.WriteShort (self - g_edicts);
  24. gi.WriteByte (flashtype);
  25. gi.multicast (start, MULTICAST_PVS);
  26. }
  27. void monster_fire_blaster (edict_t *self, vec3_t start, vec3_t dir, int damage, int speed, int flashtype, int effect)
  28. {
  29. fire_blaster (self, start, dir, damage, speed, effect, false);
  30. gi.WriteByte (svc_muzzleflash2);
  31. gi.WriteShort (self - g_edicts);
  32. gi.WriteByte (flashtype);
  33. gi.multicast (start, MULTICAST_PVS);
  34. }
  35. // RAFAEL
  36. void monster_fire_blueblaster (edict_t *self, vec3_t start, vec3_t dir, int damage, int speed, int flashtype, int effect)
  37. {
  38. fire_blueblaster (self, start, dir, damage, speed, effect);
  39. gi.WriteByte (svc_muzzleflash2);
  40. gi.WriteShort (self - g_edicts);
  41. gi.WriteByte (MZ_BLUEHYPERBLASTER);
  42. gi.multicast (start, MULTICAST_PVS);
  43. }
  44. // RAFAEL
  45. void monster_fire_ionripper (edict_t *self, vec3_t start, vec3_t dir, int damage, int speed, int flashtype, int effect)
  46. {
  47. fire_ionripper (self, start, dir, damage, speed, effect);
  48. gi.WriteByte (svc_muzzleflash2);
  49. gi.WriteShort (self - g_edicts);
  50. gi.WriteByte (flashtype);
  51. gi.multicast (start, MULTICAST_PVS);
  52. }
  53. // RAFAEL
  54. void monster_fire_heat (edict_t *self, vec3_t start, vec3_t dir, int damage, int speed, int flashtype)
  55. {
  56. fire_heat (self, start, dir, damage, speed, damage, damage);
  57. gi.WriteByte (svc_muzzleflash2);
  58. gi.WriteShort (self - g_edicts);
  59. gi.WriteByte (flashtype);
  60. gi.multicast (start, MULTICAST_PVS);
  61. }
  62. // RAFAEL
  63. void dabeam_hit (edict_t *self)
  64. {
  65. edict_t *ignore;
  66. vec3_t start;
  67. vec3_t end;
  68. trace_t tr;
  69. int count;
  70. static vec3_t lmins = {-4, -4, -4};
  71. static vec3_t lmaxs = {4, 4, 4};
  72. if (self->spawnflags & 0x80000000)
  73. count = 8;
  74. else
  75. count = 4;
  76. ignore = self;
  77. VectorCopy (self->s.origin, start);
  78. VectorMA (start, 2048, self->movedir, end);
  79. while(1)
  80. {
  81. tr = gi.trace (start, NULL, NULL, end, ignore, CONTENTS_SOLID|CONTENTS_MONSTER|CONTENTS_DEADMONSTER);
  82. if (!tr.ent)
  83. break;
  84. // hurt it if we can
  85. if ((tr.ent->takedamage) && !(tr.ent->flags & FL_IMMUNE_LASER) && (tr.ent != self->owner))
  86. T_Damage (tr.ent, self, self->owner, self->movedir, tr.endpos, vec3_origin, self->dmg, skill->value, DAMAGE_ENERGY, MOD_TARGET_LASER);
  87. if (self->dmg < 0) // healer ray
  88. {
  89. // when player is at 100 health
  90. // just undo health fix
  91. // keeping fx
  92. if (tr.ent->client && tr.ent->health > 100)
  93. tr.ent->health += self->dmg;
  94. }
  95. // if we hit something that's not a monster or player or is immune to lasers, we're done
  96. if (!(tr.ent->svflags & SVF_MONSTER) && (!tr.ent->client))
  97. {
  98. if (self->spawnflags & 0x80000000)
  99. {
  100. self->spawnflags &= ~0x80000000;
  101. gi.WriteByte (svc_temp_entity);
  102. gi.WriteByte (TE_LASER_SPARKS);
  103. gi.WriteByte (10);
  104. gi.WritePosition (tr.endpos);
  105. gi.WriteDir (tr.plane.normal);
  106. gi.WriteByte (self->s.skinnum);
  107. gi.multicast (tr.endpos, MULTICAST_PVS);
  108. }
  109. break;
  110. }
  111. ignore = tr.ent;
  112. VectorCopy (tr.endpos, start);
  113. }
  114. VectorCopy (tr.endpos, self->s.old_origin);
  115. self->nextthink = level.time + 0.1;
  116. self->think = G_FreeEdict;
  117. }
  118. // RAFAEL
  119. void monster_dabeam (edict_t *self)
  120. {
  121. vec3_t last_movedir;
  122. vec3_t point;
  123. self->movetype = MOVETYPE_NONE;
  124. self->solid = SOLID_NOT;
  125. self->s.renderfx |= RF_BEAM|RF_TRANSLUCENT;
  126. self->s.modelindex = 1;
  127. self->s.frame = 2;
  128. if (self->owner->monsterinfo.aiflags & AI_MEDIC)
  129. self->s.skinnum = 0xf3f3f1f1;
  130. else
  131. self->s.skinnum = 0xf2f2f0f0;
  132. if (self->enemy)
  133. {
  134. VectorCopy (self->movedir, last_movedir);
  135. VectorMA (self->enemy->absmin, 0.5, self->enemy->size, point);
  136. if (self->owner->monsterinfo.aiflags & AI_MEDIC)
  137. point[0] += sin (level.time) * 8;
  138. VectorSubtract (point, self->s.origin, self->movedir);
  139. VectorNormalize (self->movedir);
  140. if (!VectorCompare(self->movedir, last_movedir))
  141. self->spawnflags |= 0x80000000;
  142. }
  143. else
  144. G_SetMovedir (self->s.angles, self->movedir);
  145. self->think = dabeam_hit;
  146. self->nextthink = level.time + 0.1;
  147. VectorSet (self->mins, -8, -8, -8);
  148. VectorSet (self->maxs, 8, 8, 8);
  149. gi.linkentity (self);
  150. self->spawnflags |= 0x80000001;
  151. self->svflags &= ~SVF_NOCLIENT;
  152. }
  153. void monster_fire_grenade (edict_t *self, vec3_t start, vec3_t aimdir, int damage, int speed, int flashtype)
  154. {
  155. fire_grenade (self, start, aimdir, damage, speed, 2.5, damage+40);
  156. gi.WriteByte (svc_muzzleflash2);
  157. gi.WriteShort (self - g_edicts);
  158. gi.WriteByte (flashtype);
  159. gi.multicast (start, MULTICAST_PVS);
  160. }
  161. void monster_fire_rocket (edict_t *self, vec3_t start, vec3_t dir, int damage, int speed, int flashtype)
  162. {
  163. fire_rocket (self, start, dir, damage, speed, damage+20, damage);
  164. gi.WriteByte (svc_muzzleflash2);
  165. gi.WriteShort (self - g_edicts);
  166. gi.WriteByte (flashtype);
  167. gi.multicast (start, MULTICAST_PVS);
  168. }
  169. void monster_fire_railgun (edict_t *self, vec3_t start, vec3_t aimdir, int damage, int kick, int flashtype)
  170. {
  171. fire_rail (self, start, aimdir, damage, kick);
  172. gi.WriteByte (svc_muzzleflash2);
  173. gi.WriteShort (self - g_edicts);
  174. gi.WriteByte (flashtype);
  175. gi.multicast (start, MULTICAST_PVS);
  176. }
  177. void monster_fire_bfg (edict_t *self, vec3_t start, vec3_t aimdir, int damage, int speed, int kick, float damage_radius, int flashtype)
  178. {
  179. fire_bfg (self, start, aimdir, damage, speed, damage_radius);
  180. gi.WriteByte (svc_muzzleflash2);
  181. gi.WriteShort (self - g_edicts);
  182. gi.WriteByte (flashtype);
  183. gi.multicast (start, MULTICAST_PVS);
  184. }
  185. //
  186. // Monster utility functions
  187. //
  188. static void M_FliesOff (edict_t *self)
  189. {
  190. self->s.effects &= ~EF_FLIES;
  191. self->s.sound = 0;
  192. }
  193. static void M_FliesOn (edict_t *self)
  194. {
  195. if (self->waterlevel)
  196. return;
  197. self->s.effects |= EF_FLIES;
  198. self->s.sound = gi.soundindex ("infantry/inflies1.wav");
  199. self->think = M_FliesOff;
  200. self->nextthink = level.time + 60;
  201. }
  202. void M_FlyCheck (edict_t *self)
  203. {
  204. if (self->waterlevel)
  205. return;
  206. if (random() > 0.5)
  207. return;
  208. self->think = M_FliesOn;
  209. self->nextthink = level.time + 5 + 10 * random();
  210. }
  211. void AttackFinished (edict_t *self, float time)
  212. {
  213. self->monsterinfo.attack_finished = level.time + time;
  214. }
  215. void M_CheckGround (edict_t *ent)
  216. {
  217. vec3_t point;
  218. trace_t trace;
  219. if (ent->flags & (FL_SWIM|FL_FLY))
  220. return;
  221. if (ent->velocity[2] > 100)
  222. {
  223. ent->groundentity = NULL;
  224. return;
  225. }
  226. // if the hull point one-quarter unit down is solid the entity is on ground
  227. point[0] = ent->s.origin[0];
  228. point[1] = ent->s.origin[1];
  229. point[2] = ent->s.origin[2] - 0.25;
  230. trace = gi.trace (ent->s.origin, ent->mins, ent->maxs, point, ent, MASK_MONSTERSOLID);
  231. // check steepness
  232. if ( trace.plane.normal[2] < 0.7 && !trace.startsolid)
  233. {
  234. ent->groundentity = NULL;
  235. return;
  236. }
  237. // ent->groundentity = trace.ent;
  238. // ent->groundentity_linkcount = trace.ent->linkcount;
  239. // if (!trace.startsolid && !trace.allsolid)
  240. // VectorCopy (trace.endpos, ent->s.origin);
  241. if (!trace.startsolid && !trace.allsolid)
  242. {
  243. VectorCopy (trace.endpos, ent->s.origin);
  244. ent->groundentity = trace.ent;
  245. ent->groundentity_linkcount = trace.ent->linkcount;
  246. ent->velocity[2] = 0;
  247. }
  248. }
  249. void M_CatagorizePosition (edict_t *ent)
  250. {
  251. vec3_t point;
  252. int cont;
  253. //
  254. // get waterlevel
  255. //
  256. point[0] = ent->s.origin[0];
  257. point[1] = ent->s.origin[1];
  258. point[2] = ent->s.origin[2] + ent->mins[2] + 1;
  259. cont = gi.pointcontents (point);
  260. if (!(cont & MASK_WATER))
  261. {
  262. ent->waterlevel = 0;
  263. ent->watertype = 0;
  264. return;
  265. }
  266. ent->watertype = cont;
  267. ent->waterlevel = 1;
  268. point[2] += 26;
  269. cont = gi.pointcontents (point);
  270. if (!(cont & MASK_WATER))
  271. return;
  272. ent->waterlevel = 2;
  273. point[2] += 22;
  274. cont = gi.pointcontents (point);
  275. if (cont & MASK_WATER)
  276. ent->waterlevel = 3;
  277. }
  278. void M_WorldEffects (edict_t *ent)
  279. {
  280. int dmg;
  281. if (ent->health > 0)
  282. {
  283. if (!(ent->flags & FL_SWIM))
  284. {
  285. if (ent->waterlevel < 3)
  286. {
  287. ent->air_finished = level.time + 12;
  288. }
  289. else if (ent->air_finished < level.time)
  290. { // drown!
  291. if (ent->pain_debounce_time < level.time)
  292. {
  293. dmg = 2 + 2 * floor(level.time - ent->air_finished);
  294. if (dmg > 15)
  295. dmg = 15;
  296. T_Damage (ent, world, world, vec3_origin, ent->s.origin, vec3_origin, dmg, 0, DAMAGE_NO_ARMOR, MOD_WATER);
  297. ent->pain_debounce_time = level.time + 1;
  298. }
  299. }
  300. }
  301. else
  302. {
  303. if (ent->waterlevel > 0)
  304. {
  305. ent->air_finished = level.time + 9;
  306. }
  307. else if (ent->air_finished < level.time)
  308. { // suffocate!
  309. if (ent->pain_debounce_time < level.time)
  310. {
  311. dmg = 2 + 2 * floor(level.time - ent->air_finished);
  312. if (dmg > 15)
  313. dmg = 15;
  314. T_Damage (ent, world, world, vec3_origin, ent->s.origin, vec3_origin, dmg, 0, DAMAGE_NO_ARMOR, MOD_WATER);
  315. ent->pain_debounce_time = level.time + 1;
  316. }
  317. }
  318. }
  319. }
  320. if (ent->waterlevel == 0)
  321. {
  322. if (ent->flags & FL_INWATER)
  323. {
  324. gi.sound (ent, CHAN_BODY, gi.soundindex("player/watr_out.wav"), 1, ATTN_NORM, 0);
  325. ent->flags &= ~FL_INWATER;
  326. }
  327. return;
  328. }
  329. if ((ent->watertype & CONTENTS_LAVA) && !(ent->flags & FL_IMMUNE_LAVA))
  330. {
  331. if (ent->damage_debounce_time < level.time)
  332. {
  333. ent->damage_debounce_time = level.time + 0.2;
  334. T_Damage (ent, world, world, vec3_origin, ent->s.origin, vec3_origin, 10*ent->waterlevel, 0, 0, MOD_LAVA);
  335. }
  336. }
  337. if ((ent->watertype & CONTENTS_SLIME) && !(ent->flags & FL_IMMUNE_SLIME))
  338. {
  339. if (ent->damage_debounce_time < level.time)
  340. {
  341. ent->damage_debounce_time = level.time + 1;
  342. T_Damage (ent, world, world, vec3_origin, ent->s.origin, vec3_origin, 4*ent->waterlevel, 0, 0, MOD_SLIME);
  343. }
  344. }
  345. if ( !(ent->flags & FL_INWATER) )
  346. {
  347. if (!(ent->svflags & SVF_DEADMONSTER))
  348. {
  349. if (ent->watertype & CONTENTS_LAVA)
  350. if (random() <= 0.5)
  351. gi.sound (ent, CHAN_BODY, gi.soundindex("player/lava1.wav"), 1, ATTN_NORM, 0);
  352. else
  353. gi.sound (ent, CHAN_BODY, gi.soundindex("player/lava2.wav"), 1, ATTN_NORM, 0);
  354. else if (ent->watertype & CONTENTS_SLIME)
  355. gi.sound (ent, CHAN_BODY, gi.soundindex("player/watr_in.wav"), 1, ATTN_NORM, 0);
  356. else if (ent->watertype & CONTENTS_WATER)
  357. gi.sound (ent, CHAN_BODY, gi.soundindex("player/watr_in.wav"), 1, ATTN_NORM, 0);
  358. }
  359. ent->flags |= FL_INWATER;
  360. ent->damage_debounce_time = 0;
  361. }
  362. }
  363. void M_droptofloor (edict_t *ent)
  364. {
  365. vec3_t end;
  366. trace_t trace;
  367. ent->s.origin[2] += 1;
  368. VectorCopy (ent->s.origin, end);
  369. end[2] -= 256;
  370. trace = gi.trace (ent->s.origin, ent->mins, ent->maxs, end, ent, MASK_MONSTERSOLID);
  371. if (trace.fraction == 1 || trace.allsolid)
  372. return;
  373. VectorCopy (trace.endpos, ent->s.origin);
  374. gi.linkentity (ent);
  375. M_CheckGround (ent);
  376. M_CatagorizePosition (ent);
  377. }
  378. void M_SetEffects (edict_t *ent)
  379. {
  380. ent->s.effects &= ~(EF_COLOR_SHELL|EF_POWERSCREEN);
  381. ent->s.renderfx &= ~(RF_SHELL_RED|RF_SHELL_GREEN|RF_SHELL_BLUE);
  382. if (ent->monsterinfo.aiflags & AI_RESURRECTING)
  383. {
  384. ent->s.effects |= EF_COLOR_SHELL;
  385. ent->s.renderfx |= RF_SHELL_RED;
  386. }
  387. if (ent->health <= 0)
  388. return;
  389. if (ent->powerarmor_time > level.time)
  390. {
  391. if (ent->monsterinfo.power_armor_type == POWER_ARMOR_SCREEN)
  392. {
  393. ent->s.effects |= EF_POWERSCREEN;
  394. }
  395. else if (ent->monsterinfo.power_armor_type == POWER_ARMOR_SHIELD)
  396. {
  397. ent->s.effects |= EF_COLOR_SHELL;
  398. ent->s.renderfx |= RF_SHELL_GREEN;
  399. }
  400. }
  401. }
  402. void M_MoveFrame (edict_t *self)
  403. {
  404. mmove_t *move;
  405. int index;
  406. move = self->monsterinfo.currentmove;
  407. self->nextthink = level.time + FRAMETIME;
  408. if ((self->monsterinfo.nextframe) && (self->monsterinfo.nextframe >= move->firstframe) && (self->monsterinfo.nextframe <= move->lastframe))
  409. {
  410. self->s.frame = self->monsterinfo.nextframe;
  411. self->monsterinfo.nextframe = 0;
  412. }
  413. else
  414. {
  415. if (self->s.frame == move->lastframe)
  416. {
  417. if (move->endfunc)
  418. {
  419. move->endfunc (self);
  420. // regrab move, endfunc is very likely to change it
  421. move = self->monsterinfo.currentmove;
  422. // check for death
  423. if (self->svflags & SVF_DEADMONSTER)
  424. return;
  425. }
  426. }
  427. if (self->s.frame < move->firstframe || self->s.frame > move->lastframe)
  428. {
  429. self->monsterinfo.aiflags &= ~AI_HOLD_FRAME;
  430. self->s.frame = move->firstframe;
  431. }
  432. else
  433. {
  434. if (!(self->monsterinfo.aiflags & AI_HOLD_FRAME))
  435. {
  436. self->s.frame++;
  437. if (self->s.frame > move->lastframe)
  438. self->s.frame = move->firstframe;
  439. }
  440. }
  441. }
  442. index = self->s.frame - move->firstframe;
  443. if (move->frame[index].aifunc)
  444. if (!(self->monsterinfo.aiflags & AI_HOLD_FRAME))
  445. move->frame[index].aifunc (self, move->frame[index].dist * self->monsterinfo.scale);
  446. else
  447. move->frame[index].aifunc (self, 0);
  448. if (move->frame[index].thinkfunc)
  449. move->frame[index].thinkfunc (self);
  450. }
  451. void monster_think (edict_t *self)
  452. {
  453. M_MoveFrame (self);
  454. if (self->linkcount != self->monsterinfo.linkcount)
  455. {
  456. self->monsterinfo.linkcount = self->linkcount;
  457. M_CheckGround (self);
  458. }
  459. M_CatagorizePosition (self);
  460. M_WorldEffects (self);
  461. M_SetEffects (self);
  462. }
  463. /*
  464. ================
  465. monster_use
  466. Using a monster makes it angry at the current activator
  467. ================
  468. */
  469. void monster_use (edict_t *self, edict_t *other, edict_t *activator)
  470. {
  471. if (self->enemy)
  472. return;
  473. if (self->health <= 0)
  474. return;
  475. if (activator->flags & FL_NOTARGET)
  476. return;
  477. if (!(activator->client) && !(activator->monsterinfo.aiflags & AI_GOOD_GUY))
  478. return;
  479. // delay reaction so if the monster is teleported, its sound is still heard
  480. self->enemy = activator;
  481. FoundTarget (self);
  482. }
  483. void monster_start_go (edict_t *self);
  484. void monster_triggered_spawn (edict_t *self)
  485. {
  486. self->s.origin[2] += 1;
  487. KillBox (self);
  488. self->solid = SOLID_BBOX;
  489. self->movetype = MOVETYPE_STEP;
  490. self->svflags &= ~SVF_NOCLIENT;
  491. self->air_finished = level.time + 12;
  492. gi.linkentity (self);
  493. monster_start_go (self);
  494. // RAFAEL
  495. if (strcmp (self->classname, "monster_fixbot") == 0)
  496. {
  497. if (self->spawnflags &16 || self->spawnflags &8 || self->spawnflags &4)
  498. {
  499. self->enemy = NULL;
  500. return;
  501. }
  502. }
  503. if (self->enemy && !(self->spawnflags & 1) && !(self->enemy->flags & FL_NOTARGET))
  504. {
  505. FoundTarget (self);
  506. }
  507. else
  508. {
  509. self->enemy = NULL;
  510. }
  511. }
  512. void monster_triggered_spawn_use (edict_t *self, edict_t *other, edict_t *activator)
  513. {
  514. // we have a one frame delay here so we don't telefrag the guy who activated us
  515. self->think = monster_triggered_spawn;
  516. self->nextthink = level.time + FRAMETIME;
  517. if (activator->client)
  518. self->enemy = activator;
  519. self->use = monster_use;
  520. }
  521. void monster_triggered_start (edict_t *self)
  522. {
  523. self->solid = SOLID_NOT;
  524. self->movetype = MOVETYPE_NONE;
  525. self->svflags |= SVF_NOCLIENT;
  526. self->nextthink = 0;
  527. self->use = monster_triggered_spawn_use;
  528. }
  529. /*
  530. ================
  531. monster_death_use
  532. When a monster dies, it fires all of its targets with the current
  533. enemy as activator.
  534. ================
  535. */
  536. void monster_death_use (edict_t *self)
  537. {
  538. self->flags &= ~(FL_FLY|FL_SWIM);
  539. self->monsterinfo.aiflags &= AI_GOOD_GUY;
  540. if (self->item)
  541. {
  542. Drop_Item (self, self->item);
  543. self->item = NULL;
  544. }
  545. if (self->deathtarget)
  546. self->target = self->deathtarget;
  547. if (!self->target)
  548. return;
  549. G_UseTargets (self, self->enemy);
  550. }
  551. //============================================================================
  552. qboolean monster_start (edict_t *self)
  553. {
  554. if (deathmatch->value)
  555. {
  556. G_FreeEdict (self);
  557. return false;
  558. }
  559. if ((self->spawnflags & 4) && !(self->monsterinfo.aiflags & AI_GOOD_GUY))
  560. {
  561. self->spawnflags &= ~4;
  562. self->spawnflags |= 1;
  563. // gi.dprintf("fixed spawnflags on %s at %s\n", self->classname, vtos(self->s.origin));
  564. }
  565. if (!(self->monsterinfo.aiflags & AI_GOOD_GUY))
  566. level.total_monsters++;
  567. self->nextthink = level.time + FRAMETIME;
  568. self->svflags |= SVF_MONSTER;
  569. self->s.renderfx |= RF_FRAMELERP;
  570. self->takedamage = DAMAGE_AIM;
  571. self->air_finished = level.time + 12;
  572. self->use = monster_use;
  573. self->max_health = self->health;
  574. self->clipmask = MASK_MONSTERSOLID;
  575. self->s.skinnum = 0;
  576. self->deadflag = DEAD_NO;
  577. self->svflags &= ~SVF_DEADMONSTER;
  578. if (!self->monsterinfo.checkattack)
  579. self->monsterinfo.checkattack = M_CheckAttack;
  580. VectorCopy (self->s.origin, self->s.old_origin);
  581. if (st.item)
  582. {
  583. self->item = FindItemByClassname (st.item);
  584. if (!self->item)
  585. gi.dprintf("%s at %s has bad item: %s\n", self->classname, vtos(self->s.origin), st.item);
  586. }
  587. // randomize what frame they start on
  588. if (self->monsterinfo.currentmove)
  589. self->s.frame = self->monsterinfo.currentmove->firstframe + (rand() % (self->monsterinfo.currentmove->lastframe - self->monsterinfo.currentmove->firstframe + 1));
  590. return true;
  591. }
  592. void monster_start_go (edict_t *self)
  593. {
  594. vec3_t v;
  595. if (self->health <= 0)
  596. return;
  597. // check for target to combat_point and change to combattarget
  598. if (self->target)
  599. {
  600. qboolean notcombat;
  601. qboolean fixup;
  602. edict_t *target;
  603. target = NULL;
  604. notcombat = false;
  605. fixup = false;
  606. while ((target = G_Find (target, FOFS(targetname), self->target)) != NULL)
  607. {
  608. if (strcmp(target->classname, "point_combat") == 0)
  609. {
  610. self->combattarget = self->target;
  611. fixup = true;
  612. }
  613. else
  614. {
  615. notcombat = true;
  616. }
  617. }
  618. if (notcombat && self->combattarget)
  619. gi.dprintf("%s at %s has target with mixed types\n", self->classname, vtos(self->s.origin));
  620. if (fixup)
  621. self->target = NULL;
  622. }
  623. // validate combattarget
  624. if (self->combattarget)
  625. {
  626. edict_t *target;
  627. target = NULL;
  628. while ((target = G_Find (target, FOFS(targetname), self->combattarget)) != NULL)
  629. {
  630. if (strcmp(target->classname, "point_combat") != 0)
  631. {
  632. gi.dprintf("%s at (%i %i %i) has a bad combattarget %s : %s at (%i %i %i)\n",
  633. self->classname, (int)self->s.origin[0], (int)self->s.origin[1], (int)self->s.origin[2],
  634. self->combattarget, target->classname, (int)target->s.origin[0], (int)target->s.origin[1],
  635. (int)target->s.origin[2]);
  636. }
  637. }
  638. }
  639. if (self->target)
  640. {
  641. self->goalentity = self->movetarget = G_PickTarget(self->target);
  642. if (!self->movetarget)
  643. {
  644. gi.dprintf ("%s can't find target %s at %s\n", self->classname, self->target, vtos(self->s.origin));
  645. self->target = NULL;
  646. self->monsterinfo.pausetime = 100000000;
  647. self->monsterinfo.stand (self);
  648. }
  649. else if (strcmp (self->movetarget->classname, "path_corner") == 0)
  650. {
  651. VectorSubtract (self->goalentity->s.origin, self->s.origin, v);
  652. self->ideal_yaw = self->s.angles[YAW] = vectoyaw(v);
  653. self->monsterinfo.walk (self);
  654. self->target = NULL;
  655. }
  656. else
  657. {
  658. self->goalentity = self->movetarget = NULL;
  659. self->monsterinfo.pausetime = 100000000;
  660. self->monsterinfo.stand (self);
  661. }
  662. }
  663. else
  664. {
  665. self->monsterinfo.pausetime = 100000000;
  666. self->monsterinfo.stand (self);
  667. }
  668. self->think = monster_think;
  669. self->nextthink = level.time + FRAMETIME;
  670. }
  671. void walkmonster_start_go (edict_t *self)
  672. {
  673. if (!(self->spawnflags & 2) && level.time < 1)
  674. {
  675. M_droptofloor (self);
  676. if (self->groundentity)
  677. if (!M_walkmove (self, 0, 0))
  678. gi.dprintf ("%s in solid at %s\n", self->classname, vtos(self->s.origin));
  679. }
  680. if (!self->yaw_speed)
  681. self->yaw_speed = 20;
  682. self->viewheight = 25;
  683. monster_start_go (self);
  684. if (self->spawnflags & 2)
  685. monster_triggered_start (self);
  686. }
  687. void walkmonster_start (edict_t *self)
  688. {
  689. self->think = walkmonster_start_go;
  690. monster_start (self);
  691. }
  692. void flymonster_start_go (edict_t *self)
  693. {
  694. if (!M_walkmove (self, 0, 0))
  695. gi.dprintf ("%s in solid at %s\n", self->classname, vtos(self->s.origin));
  696. if (!self->yaw_speed)
  697. self->yaw_speed = 10;
  698. self->viewheight = 25;
  699. monster_start_go (self);
  700. if (self->spawnflags & 2)
  701. monster_triggered_start (self);
  702. }
  703. void flymonster_start (edict_t *self)
  704. {
  705. self->flags |= FL_FLY;
  706. self->think = flymonster_start_go;
  707. monster_start (self);
  708. }
  709. void swimmonster_start_go (edict_t *self)
  710. {
  711. if (!self->yaw_speed)
  712. self->yaw_speed = 10;
  713. self->viewheight = 10;
  714. monster_start_go (self);
  715. if (self->spawnflags & 2)
  716. monster_triggered_start (self);
  717. }
  718. void swimmonster_start (edict_t *self)
  719. {
  720. self->flags |= FL_SWIM;
  721. self->think = swimmonster_start_go;
  722. monster_start (self);
  723. }