g_utils.c 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552
  1. // Copyright (c) ZeniMax Media Inc.
  2. // Licensed under the GNU General Public License 2.0.
  3. // g_utils.c -- misc utility functions for game module
  4. #include "g_local.h"
  5. void G_ProjectSource (vec3_t point, vec3_t distance, vec3_t forward, vec3_t right, vec3_t result)
  6. {
  7. result[0] = point[0] + forward[0] * distance[0] + right[0] * distance[1];
  8. result[1] = point[1] + forward[1] * distance[0] + right[1] * distance[1];
  9. result[2] = point[2] + forward[2] * distance[0] + right[2] * distance[1] + distance[2];
  10. }
  11. /*
  12. =============
  13. G_Find
  14. Searches all active entities for the next one that holds
  15. the matching string at fieldofs (use the FOFS() macro) in the structure.
  16. Searches beginning at the edict after from, or the beginning if NULL
  17. NULL will be returned if the end of the list is reached.
  18. =============
  19. */
  20. edict_t *G_Find (edict_t *from, int fieldofs, char *match)
  21. {
  22. char *s;
  23. if (!from)
  24. from = g_edicts;
  25. else
  26. from++;
  27. for ( ; from < &g_edicts[globals.num_edicts] ; from++)
  28. {
  29. if (!from->inuse)
  30. continue;
  31. s = *(char **) ((byte *)from + fieldofs);
  32. if (!s)
  33. continue;
  34. if (!Q_stricmp (s, match))
  35. return from;
  36. }
  37. return NULL;
  38. }
  39. /*
  40. =================
  41. findradius
  42. Returns entities that have origins within a spherical area
  43. findradius (origin, radius)
  44. =================
  45. */
  46. edict_t *findradius (edict_t *from, vec3_t org, float rad)
  47. {
  48. vec3_t eorg;
  49. int j;
  50. if (!from)
  51. from = g_edicts;
  52. else
  53. from++;
  54. for ( ; from < &g_edicts[globals.num_edicts]; from++)
  55. {
  56. if (!from->inuse)
  57. continue;
  58. if (from->solid == SOLID_NOT)
  59. continue;
  60. for (j=0 ; j<3 ; j++)
  61. eorg[j] = org[j] - (from->s.origin[j] + (from->mins[j] + from->maxs[j])*0.5);
  62. if (VectorLength(eorg) > rad)
  63. continue;
  64. return from;
  65. }
  66. return NULL;
  67. }
  68. /*
  69. =============
  70. G_PickTarget
  71. Searches all active entities for the next one that holds
  72. the matching string at fieldofs (use the FOFS() macro) in the structure.
  73. Searches beginning at the edict after from, or the beginning if NULL
  74. NULL will be returned if the end of the list is reached.
  75. =============
  76. */
  77. #define MAXCHOICES 8
  78. edict_t *G_PickTarget (char *targetname)
  79. {
  80. edict_t *ent = NULL;
  81. int num_choices = 0;
  82. edict_t *choice[MAXCHOICES];
  83. if (!targetname)
  84. {
  85. gi.dprintf("G_PickTarget called with NULL targetname\n");
  86. return NULL;
  87. }
  88. while(1)
  89. {
  90. ent = G_Find (ent, FOFS(targetname), targetname);
  91. if (!ent)
  92. break;
  93. choice[num_choices++] = ent;
  94. if (num_choices == MAXCHOICES)
  95. break;
  96. }
  97. if (!num_choices)
  98. {
  99. gi.dprintf("G_PickTarget: target %s not found\n", targetname);
  100. return NULL;
  101. }
  102. return choice[rand() % num_choices];
  103. }
  104. void Think_Delay (edict_t *ent)
  105. {
  106. G_UseTargets (ent, ent->activator);
  107. G_FreeEdict (ent);
  108. }
  109. /*
  110. ==============================
  111. G_UseTargets
  112. the global "activator" should be set to the entity that initiated the firing.
  113. If self.delay is set, a DelayedUse entity will be created that will actually
  114. do the SUB_UseTargets after that many seconds have passed.
  115. Centerprints any self.message to the activator.
  116. Search for (string)targetname in all entities that
  117. match (string)self.target and call their .use function
  118. ==============================
  119. */
  120. void G_UseTargets (edict_t *ent, edict_t *activator)
  121. {
  122. edict_t *t;
  123. //
  124. // check for a delay
  125. //
  126. if (ent->delay)
  127. {
  128. // create a temp object to fire at a later time
  129. t = G_Spawn();
  130. t->classname = "DelayedUse";
  131. t->nextthink = level.time + ent->delay;
  132. t->think = Think_Delay;
  133. t->activator = activator;
  134. if (!activator)
  135. gi.dprintf ("Think_Delay with no activator\n");
  136. t->message = ent->message;
  137. t->target = ent->target;
  138. t->killtarget = ent->killtarget;
  139. return;
  140. }
  141. //
  142. // print the message
  143. //
  144. if ((ent->message) && !(activator->svflags & SVF_MONSTER))
  145. {
  146. gi.centerprintf (activator, "%s", ent->message);
  147. if (ent->noise_index)
  148. gi.sound (activator, CHAN_AUTO, ent->noise_index, 1, ATTN_NORM, 0);
  149. else
  150. gi.sound (activator, CHAN_AUTO, gi.soundindex ("misc/talk1.wav"), 1, ATTN_NORM, 0);
  151. }
  152. //
  153. // kill killtargets
  154. //
  155. if (ent->killtarget)
  156. {
  157. t = NULL;
  158. while ((t = G_Find (t, FOFS(targetname), ent->killtarget)))
  159. {
  160. G_FreeEdict (t);
  161. if (!ent->inuse)
  162. {
  163. gi.dprintf("entity was removed while using killtargets\n");
  164. return;
  165. }
  166. }
  167. }
  168. //
  169. // fire targets
  170. //
  171. if (ent->target)
  172. {
  173. t = NULL;
  174. while ((t = G_Find (t, FOFS(targetname), ent->target)))
  175. {
  176. // doors fire area portals in a specific way
  177. if (!Q_stricmp(t->classname, "func_areaportal") &&
  178. (!Q_stricmp(ent->classname, "func_door") || !Q_stricmp(ent->classname, "func_door_rotating")))
  179. continue;
  180. if (t == ent)
  181. {
  182. gi.dprintf ("WARNING: Entity used itself.\n");
  183. }
  184. else
  185. {
  186. if (t->use)
  187. t->use (t, ent, activator);
  188. }
  189. if (!ent->inuse)
  190. {
  191. gi.dprintf("entity was removed while using targets\n");
  192. return;
  193. }
  194. }
  195. }
  196. }
  197. /*
  198. =============
  199. TempVector
  200. This is just a convenience function
  201. for making temporary vectors for function calls
  202. =============
  203. */
  204. float *tv (float x, float y, float z)
  205. {
  206. static int index;
  207. static vec3_t vecs[8];
  208. float *v;
  209. // use an array so that multiple tempvectors won't collide
  210. // for a while
  211. v = vecs[index];
  212. index = (index + 1)&7;
  213. v[0] = x;
  214. v[1] = y;
  215. v[2] = z;
  216. return v;
  217. }
  218. /*
  219. =============
  220. VectorToString
  221. This is just a convenience function
  222. for printing vectors
  223. =============
  224. */
  225. char *vtos (vec3_t v)
  226. {
  227. static int index;
  228. static char str[8][32];
  229. char *s;
  230. // use an array so that multiple vtos won't collide
  231. s = str[index];
  232. index = (index + 1)&7;
  233. Com_sprintf (s, 32, "(%i %i %i)", (int)v[0], (int)v[1], (int)v[2]);
  234. return s;
  235. }
  236. vec3_t VEC_UP = {0, -1, 0};
  237. vec3_t MOVEDIR_UP = {0, 0, 1};
  238. vec3_t VEC_DOWN = {0, -2, 0};
  239. vec3_t MOVEDIR_DOWN = {0, 0, -1};
  240. void G_SetMovedir (vec3_t angles, vec3_t movedir)
  241. {
  242. if (VectorCompare (angles, VEC_UP))
  243. {
  244. VectorCopy (MOVEDIR_UP, movedir);
  245. }
  246. else if (VectorCompare (angles, VEC_DOWN))
  247. {
  248. VectorCopy (MOVEDIR_DOWN, movedir);
  249. }
  250. else
  251. {
  252. AngleVectors (angles, movedir, NULL, NULL);
  253. }
  254. VectorClear (angles);
  255. }
  256. float vectoyaw (vec3_t vec)
  257. {
  258. float yaw;
  259. if (/*vec[YAW] == 0 &&*/ vec[PITCH] == 0)
  260. {
  261. yaw = 0;
  262. if (vec[YAW] > 0)
  263. yaw = 90;
  264. else if (vec[YAW] < 0)
  265. yaw = -90;
  266. }
  267. else
  268. {
  269. yaw = (int) (atan2(vec[YAW], vec[PITCH]) * 180 / M_PI);
  270. if (yaw < 0)
  271. yaw += 360;
  272. }
  273. return yaw;
  274. }
  275. void vectoangles (vec3_t value1, vec3_t angles)
  276. {
  277. float forward;
  278. float yaw, pitch;
  279. if (value1[1] == 0 && value1[0] == 0)
  280. {
  281. yaw = 0;
  282. if (value1[2] > 0)
  283. pitch = 90;
  284. else
  285. pitch = 270;
  286. }
  287. else
  288. {
  289. if (value1[0])
  290. yaw = (int) (atan2(value1[1], value1[0]) * 180 / M_PI);
  291. else if (value1[1] > 0)
  292. yaw = 90;
  293. else
  294. yaw = -90;
  295. if (yaw < 0)
  296. yaw += 360;
  297. forward = sqrt (value1[0]*value1[0] + value1[1]*value1[1]);
  298. pitch = (int) (atan2(value1[2], forward) * 180 / M_PI);
  299. if (pitch < 0)
  300. pitch += 360;
  301. }
  302. angles[PITCH] = -pitch;
  303. angles[YAW] = yaw;
  304. angles[ROLL] = 0;
  305. }
  306. char *G_CopyString (char *in)
  307. {
  308. char *out;
  309. out = gi.TagMalloc (strlen(in)+1, TAG_LEVEL);
  310. strcpy (out, in);
  311. return out;
  312. }
  313. void G_InitEdict (edict_t *e)
  314. {
  315. e->inuse = true;
  316. e->classname = "noclass";
  317. e->gravity = 1.0;
  318. e->s.number = e - g_edicts;
  319. }
  320. /*
  321. =================
  322. G_Spawn
  323. Either finds a free edict, or allocates a new one.
  324. Try to avoid reusing an entity that was recently freed, because it
  325. can cause the client to think the entity morphed into something else
  326. instead of being removed and recreated, which can cause interpolated
  327. angles and bad trails.
  328. =================
  329. */
  330. edict_t *G_Spawn (void)
  331. {
  332. int i;
  333. edict_t *e;
  334. e = &g_edicts[(int)maxclients->value+1];
  335. for ( i=maxclients->value+1 ; i<globals.num_edicts ; i++, e++)
  336. {
  337. // the first couple seconds of server time can involve a lot of
  338. // freeing and allocating, so relax the replacement policy
  339. if (!e->inuse && ( e->freetime < 2 || level.time - e->freetime > 0.5 ) )
  340. {
  341. G_InitEdict (e);
  342. return e;
  343. }
  344. }
  345. if (i == game.maxentities)
  346. gi.error ("ED_Alloc: no free edicts");
  347. globals.num_edicts++;
  348. G_InitEdict (e);
  349. return e;
  350. }
  351. /*
  352. =================
  353. G_FreeEdict
  354. Marks the edict as free
  355. =================
  356. */
  357. void G_FreeEdict (edict_t *ed)
  358. {
  359. gi.unlinkentity (ed); // unlink from world
  360. if ((ed - g_edicts) <= (maxclients->value + BODY_QUEUE_SIZE))
  361. {
  362. // gi.dprintf("tried to free special edict\n");
  363. return;
  364. }
  365. memset (ed, 0, sizeof(*ed));
  366. ed->classname = "freed";
  367. ed->freetime = level.time;
  368. ed->inuse = false;
  369. }
  370. /*
  371. ============
  372. G_TouchTriggers
  373. ============
  374. */
  375. void G_TouchTriggers (edict_t *ent)
  376. {
  377. int i, num;
  378. edict_t *touch[MAX_EDICTS], *hit;
  379. // dead things don't activate triggers!
  380. if ((ent->client || (ent->svflags & SVF_MONSTER)) && (ent->health <= 0))
  381. return;
  382. num = gi.BoxEdicts (ent->absmin, ent->absmax, touch
  383. , MAX_EDICTS, AREA_TRIGGERS);
  384. // be careful, it is possible to have an entity in this
  385. // list removed before we get to it (killtriggered)
  386. for (i=0 ; i<num ; i++)
  387. {
  388. hit = touch[i];
  389. if (!hit->inuse)
  390. continue;
  391. if (!hit->touch)
  392. continue;
  393. hit->touch (hit, ent, NULL, NULL);
  394. }
  395. }
  396. /*
  397. ============
  398. G_TouchSolids
  399. Call after linking a new trigger in during gameplay
  400. to force all entities it covers to immediately touch it
  401. ============
  402. */
  403. void G_TouchSolids (edict_t *ent)
  404. {
  405. int i, num;
  406. edict_t *touch[MAX_EDICTS], *hit;
  407. num = gi.BoxEdicts (ent->absmin, ent->absmax, touch
  408. , MAX_EDICTS, AREA_SOLID);
  409. // be careful, it is possible to have an entity in this
  410. // list removed before we get to it (killtriggered)
  411. for (i=0 ; i<num ; i++)
  412. {
  413. hit = touch[i];
  414. if (!hit->inuse)
  415. continue;
  416. if (ent->touch)
  417. ent->touch (hit, ent, NULL, NULL);
  418. if (!ent->inuse)
  419. break;
  420. }
  421. }
  422. /*
  423. ==============================================================================
  424. Kill box
  425. ==============================================================================
  426. */
  427. /*
  428. =================
  429. KillBox
  430. Kills all entities that would touch the proposed new positioning
  431. of ent. Ent should be unlinked before calling this!
  432. =================
  433. */
  434. qboolean KillBox (edict_t *ent)
  435. {
  436. trace_t tr;
  437. while (1)
  438. {
  439. tr = gi.trace (ent->s.origin, ent->mins, ent->maxs, ent->s.origin, NULL, MASK_PLAYERSOLID);
  440. if (!tr.ent)
  441. break;
  442. // nail it
  443. T_Damage (tr.ent, ent, ent, vec3_origin, ent->s.origin, vec3_origin, 100000, 0, DAMAGE_NO_PROTECTION, MOD_TELEFRAG);
  444. // if we didn't kill it, fail
  445. if (tr.ent->solid)
  446. return false;
  447. }
  448. return true; // all clear
  449. }