UFO: Alien Invasion
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
cl_localentity.cpp
Go to the documentation of this file.
1 
6 /*
7 Copyright (C) 2002-2020 UFO: Alien Invasion.
8 
9 This program is free software; you can redistribute it and/or
10 modify it under the terms of the GNU General Public License
11 as published by the Free Software Foundation; either version 2
12 of the License, or (at your option) any later version.
13 
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
17 
18 See the GNU General Public License for more details.
19 
20 You should have received a copy of the GNU General Public License
21 along with this program; if not, write to the Free Software
22 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
23 
24 */
25 
26 #include "../client.h"
27 #include "cl_localentity.h"
28 #include "../sound/s_main.h"
29 #include "../sound/s_sample.h"
30 #include "cl_particle.h"
31 #include "cl_actor.h"
32 #include "cl_hud.h"
33 #include "../renderer/r_mesh_anim.h"
34 #include "../renderer/r_draw.h"
35 #include "../../common/tracing.h"
36 #include "../../common/grid.h"
37 #include "../../shared/moveclip.h"
38 
42 
43 void le_t::init ()
44 {
45  inuse = false;
46  entnum = angle = dir = TU= maxTU = morale = maxMorale = HP = maxHP = STUN = state = team = pnum = ucn = flags = contents = thinkDelay = 0;
48  gender = 0;
51  actorMoveLength = 0;
52  clientAction = nullptr;
53  inlineModelName[0] = '\0';
55  model1 = model2 = nullptr;
56  think = nullptr;
57  stepList = nullptr;
58  particleID = ref1 = ref2 = nullptr;
59  ptl = nullptr;
60  ref3 = nullptr;
61  teamDef = nullptr;
62  fd = nullptr;
63  addFunc = nullptr;
64  type = ET_NULL;
65  actorMode = M_MOVE;
66  aabb = AABB::EMPTY;
68 
77  OBJZERO(wounds);
78  OBJZERO(dvtab);
80  OBJZERO(speed);
81  OBJZERO(as);
83 
84  inv.init();
85 }
86 
87 /*===========================================================================
88 Local Model (LM) handling
89 =========================================================================== */
90 
91 static inline void LE_GenerateInlineModelList (void)
92 {
93  le_t* le = nullptr;
94  int i = 0;
95 
96  while ((le = LE_GetNextInUse(le))) {
97  if (le->model1 && le->inlineModelName[0] == '*')
99  }
100  cl.leInlineModelList[i] = nullptr;
101 }
102 
103 static void CL_GridRecalcRouting (const le_t* le)
104 {
105  /* We ALWAYS check against a model, even if it isn't in use.
106  * An unused model is NOT included in the inline list, so it doesn't get
107  * traced against. */
108  if (!le->model1 || le->inlineModelName[0] != '*')
109  return;
110 
111  if (Com_ServerState())
112  return;
113 
115  if (!model) {
116  return;
117  }
118  AABB absBox(model->cbmBox);
119  absBox.shift(model->origin);
120  GridBox rerouteBox(absBox);
121 
123 }
124 
129 {
130  const double start = time(nullptr); /* stopwatch */
131 
133 
134  int i = 0;
135  for (const le_t* le = cl.LEs; i < cl.numLEs; i++, le++)
137 
138  Com_Printf("Rerouted for %i LEs in %5.2fs\n", i, time(nullptr) - start);
139 }
140 
145 void CL_RecalcRouting (const le_t* le)
146 {
148 
150 
152 }
153 
154 static void LM_AddToSceneOrder (bool parents)
155 {
156  for (int i = 0; i < cl.numLMs; i++) {
157  localModel_t& lm = cl.LMs[i];
158  if (!lm.inuse)
159  continue;
160 
161  /* check for visibility */
162  if (!((1 << cl_worldlevel->integer) & lm.levelflags))
163  continue;
164 
165  /* if we want to render the parents and this is a child (has a parent assigned)
166  * then skip it */
167  if (parents && lm.parent)
168  continue;
169 
170  /* if we want to render the children and this is a parent (no further parent
171  * assigned), then skip it. */
172  if (!parents && lm.parent == nullptr)
173  continue;
174 
175  /* set entity values */
176  entity_t ent(RF_NONE);
177  assert(lm.model);
178  ent.model = lm.model;
179  ent.skinnum = lm.skin;
180  ent.lighting = &lm.lighting;
181  ent.setScale(lm.scale);
182 
183  if (lm.parent) {
185  ent.tagent = R_GetEntity(lm.parent->renderEntityNum);
186  if (ent.tagent == nullptr)
187  Com_Error(ERR_DROP, "Invalid parent entity num for local model (%s/%s): %i",
188  lm.model->name, lm.id, lm.parent->renderEntityNum);
189  ent.tagname = lm.tagname;
190  } else {
191  R_EntitySetOrigin(&ent, lm.origin);
192  VectorCopy(lm.origin, ent.oldorigin);
193  VectorCopy(lm.angles, ent.angles);
194 
195  if (lm.animname[0] != '\0') {
196  ent.as = lm.as;
197  /* do animation */
198  R_AnimRun(&lm.as, ent.model, cls.frametime * 1000);
199  } else {
200  ent.as.frame = lm.frame;
201  }
202  }
203 
204  /* renderflags like RF_PULSE */
205  ent.flags = lm.renderFlags;
206 
207  /* add it to the scene */
208  lm.renderEntityNum = R_AddEntity(&ent);
209  }
210 }
211 
218 void LM_AddToScene (void)
219 {
220  LM_AddToSceneOrder(true);
221  LM_AddToSceneOrder(false);
222 }
223 
227 static inline localModel_t* LM_Find (int entnum)
228 {
229  for (int i = 0; i < cl.numLMs; i++)
230  if (cl.LMs[i].entnum == entnum)
231  return &cl.LMs[i];
232 
233  return nullptr;
234 }
235 
240 {
241  le_t* floorItem = LE_Find(ET_ITEM, le->pos);
242  if (floorItem)
243  le->setFloor(floorItem);
244  else
245  le->resetFloor();
246 }
247 
253 bool LE_IsActor (const le_t* le)
254 {
255  assert(le);
256  return le->type == ET_ACTOR || le->type == ET_ACTOR2x2 || le->type == ET_ACTORHIDDEN;
257 }
258 
265 bool LE_IsLivingActor (const le_t* le)
266 {
267  assert(le);
268  return LE_IsActor(le) && (LE_IsStunned(le) || !LE_IsDead(le));
269 }
270 
278 {
279  assert(le);
280  if (LE_IsInvisible(le))
281  return false;
282 
283  assert(le->type != ET_ACTORHIDDEN);
284 
285  return LE_IsLivingActor(le);
286 }
287 
292 void LM_Register (void)
293 {
294  for (int i = 0; i < cl.numLMs; i++) {
295  localModel_t& lm = cl.LMs[i];
296 
297  /* register the model */
298  lm.model = R_FindModel(lm.name);
299  if (lm.animname[0]) {
300  R_AnimChange(&lm.as, lm.model, lm.animname);
301  if (!lm.as.change)
302  Com_Printf("LM_Register: Could not change anim of %s to '%s'\n",
303  lm.name, lm.animname);
304  }
305  if (!lm.model)
306  lm.inuse = false;
307  }
308 }
309 
311 {
312  le->think = think;
313 }
314 
315 localModel_t* LM_GetByID (const char* id)
316 {
317  if (Q_strnull(id))
318  return nullptr;
319 
320  for (int i = 0; i < cl.numLMs; i++) {
321  localModel_t* lm = &cl.LMs[i];
322  if (Q_streq(lm->id, id))
323  return lm;
324  }
325  return nullptr;
326 }
327 
341 localModel_t* LM_AddModel (const char* model, const vec3_t origin, const vec3_t angles, int entnum, int levelflags, int renderFlags, const vec3_t scale)
342 {
343  if (cl.numLMs >= MAX_LOCALMODELS)
344  Com_Error(ERR_DROP, "Too many local models\n");
345 
346  /* check whether there is already a model with that number */
347  if (LM_Find(entnum))
348  Com_Error(ERR_DROP, "Already a local model with the same id (%i) loaded\n", entnum);
349 
350  localModel_t* lm = &cl.LMs[cl.numLMs++];
351  OBJZERO(*lm);
352  Q_strncpyz(lm->name, model, sizeof(lm->name));
353  VectorCopy(origin, lm->origin);
354  VectorCopy(angles, lm->angles);
355  lm->entnum = entnum;
356  lm->levelflags = levelflags;
357  lm->renderFlags = renderFlags;
358  lm->inuse = true;
359  lm->setScale(scale);
360 
361  return lm;
362 }
363 
364 /*===========================================================================
365 LE thinking
366 =========================================================================== */
367 
372 {
373  if (le->inuse && le->think) {
374  le->think(le);
375  }
376 }
377 
387 void LE_Think (void)
388 {
389  if (cls.state != ca_active)
390  return;
391 
392  le_t* le = nullptr;
393  while ((le = LE_GetNext(le))) {
394  LE_ExecuteThink(le);
395  /* do animation - even for invisible entities */
396  R_AnimRun(&le->as, le->model1, cls.frametime * 1000);
397  }
398 }
399 
400 void LM_Think (void)
401 {
402  for (int i = 0; i < cl.numLMs; i++) {
403  localModel_t& lm = cl.LMs[i];
404  if (lm.think)
405  lm.think(&lm);
406  }
407 }
408 
409 
410 /*===========================================================================
411  LE think functions
412 =========================================================================== */
413 
423 const char* LE_GetAnim (const char* anim, int right, int left, int state)
424 {
425  if (!anim)
426  return "";
427 
428  static char retAnim[MAX_VAR];
429  char* mod = retAnim;
430  size_t length = sizeof(retAnim);
431 
432  /* add crouched flag */
433  if (state & STATE_CROUCHED) {
434  *mod++ = 'c';
435  length--;
436  }
437 
438  /* determine relevant data */
439  char animationIndex;
440  char const* type;
441  if (right == NONE) {
442  animationIndex = '0';
443  if (left == NONE)
444  type = "item";
445  else {
446  type = INVSH_GetItemByIDX(left)->type;
447  /* left hand grenades look OK with default anim; others don't */
448  if (!Q_streq(type, "grenade")) {
449  type = "pistol_d";
450  }
451  }
452  } else {
453  const objDef_t* od = INVSH_GetItemByIDX(right);
454  animationIndex = od->animationIndex;
455  type = od->type;
456  if (left != NONE && Q_streq(od->type, "pistol") && Q_streq(INVSH_GetItemByIDX(left)->type, "pistol")) {
457  type = "pistol_d";
458  }
459  }
460 
461  if (Q_strstart(anim, "stand") || Q_strstart(anim, "walk")) {
462  Com_sprintf(mod, length, "%s%c", anim, animationIndex);
463  } else {
464  Com_sprintf(mod, length, "%s_%s", anim, type);
465  }
466 
467  return retAnim;
468 }
469 
478 void LET_StartIdle (le_t* le)
479 {
480  /* hidden actors don't have models assigned, thus we can not change the
481  * animation for any model */
482  if (!LE_IsInvisible(le)) {
483  if (LE_IsDead(le))
484  R_AnimChange(&le->as, le->model1, va("dead%i", LE_GetAnimationIndexForDeath(le)));
485  else if (LE_IsPanicked(le))
486  R_AnimChange(&le->as, le->model1, "panic0");
487  else
488  R_AnimChange(&le->as, le->model1, LE_GetAnim("stand", le->right, le->left, le->state));
489  }
490 
491  le->pathPos = le->pathLength = 0;
492  if (le->stepList != nullptr) {
493  leStep_t* step = le->stepList->next;
494  Mem_Free(le->stepList);
495  le->stepList = step;
496  if (step != nullptr) {
497  le->stepIndex--;
498  } else if (le->stepIndex != 0) {
499  Com_Error(ERR_DROP, "stepindex for entnum %i is out of sync (%i should be 0)\n", le->entnum, le->stepIndex);
500  }
501  }
502 
503  /* keep this animation until something happens */
504  LE_SetThink(le, nullptr);
505 }
506 
514 static void LE_PlaySoundFileForContents (le_t* le, int contents)
515 {
516  /* only play those water sounds when an actor jumps into the water - but not
517  * if he enters carefully in crouched mode */
518  if (!LE_IsCrouched(le)) {
519  if (contents & CONTENTS_WATER) {
520  /* were we already in the water? */
521  if (le->positionContents & CONTENTS_WATER) {
522  /* play water moving sound */
524  } else {
525  /* play water entering sound */
527  }
528  return;
529  }
530 
531  if (le->positionContents & CONTENTS_WATER) {
532  /* play water leaving sound */
534  }
535  }
536 }
537 
544 static void LE_PlaySoundFileAndParticleForSurface (le_t* le, const char* textureName)
545 {
546  const terrainType_t* t = Com_GetTerrainType(textureName);
547  if (!t)
548  return;
549 
550  /* origin might not be up-to-date here - but pos should be */
551  vec3_t origin;
552  PosToVec(le->pos, origin);
553 
556  if (t->particle) {
557  /* check whether actor is visible */
559  CL_ParticleSpawn(t->particle, 0, origin);
560  }
561  if (t->footstepSound) {
562  Com_DPrintf(DEBUG_SOUND, "LE_PlaySoundFileAndParticleForSurface: volume %.2f\n", t->footstepVolume);
564  }
565 }
566 
570 int LE_ActorGetStepTime (const le_t* le, const pos3_t pos, const pos3_t oldPos, const int dir, const int speed)
571 {
572  if (dir != DIRECTION_FALL) {
573  return (((dir & (CORE_DIRECTIONS - 1)) >= BASE_DIRECTIONS ? UNIT_SIZE * 1.41 : UNIT_SIZE) * 1000 / speed);
574  } else {
575  vec3_t start, dest;
576  /* This needs to account for the distance of the fall. */
577  Grid_PosToVec(cl.mapData->routing, le->fieldSize, oldPos, start);
578  Grid_PosToVec(cl.mapData->routing, le->fieldSize, pos, dest);
579  /* 1/1000th of a second per model unit in height change */
580  return (start[2] - dest[2]);
581  }
582 }
583 
584 static void LE_PlayFootStepSound (le_t* le)
585 {
586  if (Q_strvalid(le->teamDef->footstepSound)) {
588  return;
589  }
590  /* walking in water will not play the normal footstep sounds */
591  if (!le->pathContents[le->pathPos]) {
592  vec3_t from, to;
593 
594  /* prepare trace vectors */
595  PosToVec(le->pos, from);
596  VectorCopy(from, to);
597  /* we should really hit the ground with this */
598  to[2] -= UNIT_HEIGHT;
599 
600  const trace_t trace = CL_Trace(Line(from, to), AABB::EMPTY, nullptr, nullptr, MASK_SOLID, cl_worldlevel->integer);
601  if (trace.surface)
603  } else
605 }
606 
607 static void LE_DoPathMove (le_t* le)
608 {
609  /* next part */
610  const dvec_t dvec = le->dvtab[le->pathPos];
611  const byte dir = getDVdir(dvec);
612  const byte crouchingState = LE_IsCrouched(le) ? 1 : 0;
613  /* newCrouchingState needs to be set to the current crouching state
614  * and is possibly updated by PosAddDV. */
615  byte newCrouchingState = crouchingState;
616  PosAddDV(le->pos, newCrouchingState, dvec);
617 
619 
620  /* only change the direction if the actor moves horizontally. */
621  if (dir < CORE_DIRECTIONS || dir >= FLYING_DIRECTIONS)
622  le->angle = dir & (CORE_DIRECTIONS - 1);
623  le->angles[YAW] = directionAngles[le->angle];
624  le->startTime = le->endTime;
625  /* check for straight movement or diagonal movement */
626  assert(le->speed[le->pathPos]);
627  le->endTime += LE_ActorGetStepTime(le, le->pos, le->oldPos, dir, le->speed[le->pathPos]);
628 
629  le->positionContents = le->pathContents[le->pathPos];
630  le->pathPos++;
631 }
632 
637 {
638  /* Verify the current position */
639  if (!VectorCompare(le->pos, le->newPos))
640  Com_Error(ERR_DROP, "LE_DoEndPathMove: Actor movement is out of sync: %i:%i:%i should be %i:%i:%i (step %i of %i) (team %i)",
641  le->pos[0], le->pos[1], le->pos[2], le->newPos[0], le->newPos[1], le->newPos[2], le->pathPos, le->pathLength, le->team);
642 
644  /* if the moving actor was not the selected one, */
645  /* recalc the pathing table for the selected one, too. */
646  if (!LE_IsSelected(le)) {
648  }
649 
651 
653  LE_ExecuteThink(le);
654  LE_Unlock(le);
655 }
656 
663 static void LE_ActorBodyHit (const le_t* le, const vec3_t impact, int normal)
664 {
665  if (le->teamDef) {
666  /* Spawn "hit_particle" if defined in teamDef. */
667  if (le->teamDef->hitParticle[0] != '\0')
668  CL_ParticleSpawn(le->teamDef->hitParticle, 0, impact, bytedirs[normal]);
669  }
670 }
671 
677 static void LET_PathMove (le_t* le)
678 {
679  /* check for start of the next step */
680  if (cl.time < le->startTime)
681  return;
682 
683  /* move ahead */
684  while (cl.time >= le->endTime) {
685  /* Ensure that we are displayed where we are supposed to be, in case the last frame came too quickly. */
687 
688  /* Record the last position of movement calculations. */
689  VectorCopy(le->pos, le->oldPos);
690 
691  if (le->pathPos < le->pathLength) {
692  LE_DoPathMove(le);
693  } else {
694  LE_DoEndPathMove(le);
695  return;
696  }
697  }
698 
699  /* interpolate the position */
700  vec3_t start, dest, delta;
701  Grid_PosToVec(cl.mapData->routing, le->fieldSize, le->oldPos, start);
702  Grid_PosToVec(cl.mapData->routing, le->fieldSize, le->pos, dest);
703  VectorSubtract(dest, start, delta);
704 
705  const float frac = (float) (cl.time - le->startTime) / (float) (le->endTime - le->startTime);
706 
707  /* calculate the new interpolated actor origin in the world */
708  VectorMA(start, frac, delta, le->origin);
709 }
710 
717 {
718  /* center view (if wanted) */
719  if (!cls.isOurRound() && le->team != TEAM_CIVILIAN)
720  LE_CenterView(le);
721 
722  /* initial animation or animation change */
723  R_AnimChange(&le->as, le->model1, LE_GetAnim("walk", le->right, le->left, le->state));
724  if (!le->as.change)
725  Com_Printf("LET_StartPathMove: Could not change anim of le: %i, team: %i, pnum: %i\n",
726  le->entnum, le->team, le->pnum);
727 
729  LE_ExecuteThink(le);
730 }
731 
738 {
739  VectorCopy(le->newPos, le->pos);
741  LE_ExecuteThink(le);
742  LE_Unlock(le);
743 }
744 
748 static void LET_Projectile (le_t* le)
749 {
750  if (cl.time >= le->endTime) {
751  vec3_t impact;
752  VectorCopy(le->origin, impact);
753  CL_ParticleFree(le->ptl);
754  /* don't run the think function again */
755  le->inuse = false;
756  if (Q_strvalid(le->ref1)) {
757  VectorCopy(le->ptl->s, impact);
758  le->ptl = CL_ParticleSpawn(le->ref1, 0, impact, bytedirs[le->angle]);
759  VecToAngles(bytedirs[le->state], le->ptl->angles);
760  }
761  if (Q_strvalid(le->ref2)) {
763  }
764  if (le->ref3) {
765  /* Spawn blood particles (if defined) if actor(-body) was hit. Even if actor is dead. */
768  if (le->fd->obj->dmgtype != csi.damStunGas)
769  LE_ActorBodyHit(le->ref3, impact, le->angle);
771  }
772  } else if (CL_OutsideMap(le->ptl->s, UNIT_SIZE * 10)) {
773  le->endTime = cl.time;
774  CL_ParticleFree(le->ptl);
775  /* don't run the think function again */
776  le->inuse = false;
777  }
778 }
779 
780 /*===========================================================================
781  LE Special Effects
782 =========================================================================== */
783 
784 void LE_AddProjectile (const fireDef_t* fd, int flags, const vec3_t muzzle, const vec3_t impact, int normal, le_t* leVictim)
785 {
786  /* add le */
787  le_t* le = LE_Add(0);
788  if (!le)
789  return;
790  LE_SetInvisible(le);
791  /* bind particle */
792  le->ptl = CL_ParticleSpawn(fd->projectile, 0, muzzle);
793  if (!le->ptl) {
794  le->inuse = false;
795  return;
796  }
797 
798  /* calculate parameters */
799  vec3_t delta;
800  VectorSubtract(impact, muzzle, delta);
801  const float dist = VectorLength(delta);
802 
803  VecToAngles(delta, le->ptl->angles);
804  /* direction - bytedirs index */
805  le->angle = normal;
806  le->fd = fd;
807 
808  /* infinite speed projectile? */
809  if (!fd->speed) {
810  le->inuse = false;
811  le->ptl->size[0] = dist;
812  VectorMA(muzzle, 0.5, delta, le->ptl->s);
813  if ((flags & (SF_IMPACT | SF_BODY)) || (fd->splrad && !fd->bounce)) {
814  ptl_t* ptl = nullptr;
815  const float* dir = bytedirs[le->angle];
816  if (flags & SF_BODY) {
817  if (fd->hitBodySound != nullptr) {
819  }
820  if (fd->hitBody != nullptr)
821  ptl = CL_ParticleSpawn(fd->hitBody, 0, impact, dir);
822 
823  /* Spawn blood particles (if defined) if actor(-body) was hit. Even if actor is dead. */
826  if (leVictim) {
827  if (fd->obj->dmgtype != csi.damStunGas)
828  LE_ActorBodyHit(leVictim, impact, le->angle);
829  if (fd->damage[0] >= 0)
830  CL_ActorPlaySound(leVictim, SND_HURT);
831  }
832  } else {
833  if (fd->impactSound != nullptr) {
835  }
836  if (fd->impact != nullptr)
837  ptl = CL_ParticleSpawn(fd->impact, 0, impact, dir);
838  }
839  if (ptl)
840  VecToAngles(dir, ptl->angles);
841  }
842  return;
843  }
844  /* particle properties */
845  VectorScale(delta, fd->speed / dist, le->ptl->v);
846  le->endTime = cl.time + 1000 * dist / fd->speed;
847 
848  /* think function */
849  if (flags & SF_BODY) {
850  le->ref1 = fd->hitBody;
851  le->ref2 = fd->hitBodySound;
852  le->ref3 = leVictim;
853  } else if ((flags & SF_IMPACT) || (fd->splrad && !fd->bounce)) {
854  le->ref1 = fd->impact;
855  le->ref2 = fd->impactSound;
856  } else {
857  le->ref1 = nullptr;
858  if (flags & SF_BOUNCING)
859  le->ref2 = fd->bounceSound;
860  }
861 
863  LE_ExecuteThink(le);
864 }
865 
873 static const objDef_t* LE_BiggestItem (const Item* ic)
874 {
875  assert(ic);
876  const objDef_t* max;
877  int maxSize = 0;
878 
879  for (max = ic->def(); ic; ic = ic->getNext()) {
880  const int size = INVSH_ShapeSize(ic->def()->shape);
881  if (size > maxSize) {
882  max = ic->def();
883  maxSize = size;
884  }
885  }
886 
887  /* there must be an item in the Item */
888  assert(max);
889  return max;
890 }
891 
896 void LE_PlaceItem (le_t* le)
897 {
898  assert(LE_IsItem(le));
899 
900  /* search owners (there can be many, some of them dead) */
901  le_t* actor = nullptr;
902  while ((actor = LE_GetNextInUse(actor))) {
903  if ((actor->type == ET_ACTOR || actor->type == ET_ACTOR2x2)
904  && VectorCompare(actor->pos, le->pos)) {
905  if (le->getFloorContainer())
906  actor->setFloor(le);
907  }
908  }
909 
910  /* the le is an ET_ITEM entity, this entity is there to render dropped items
911  * if there are no items in the floor container, this entity can be
912  * deactivated */
913  Item* floorCont = le->getFloorContainer();
914  if (floorCont) {
915  const objDef_t* biggest = LE_BiggestItem(floorCont);
916  le->model1 = cls.modelPool[biggest->idx];
917  if (!le->model1)
918  Com_Error(ERR_DROP, "Model for item %s is not precached in the cls.model_weapons array",
919  biggest->id);
921  VectorSubtract(le->origin, biggest->center, le->origin);
922  le->angles[ROLL] = 90;
923  /*le->angles[YAW] = 10*(int)(le->origin[0] + le->origin[1] + le->origin[2]) % 360; */
924  le->origin[2] -= GROUND_DELTA;
925  } else {
926  /* If no items in floor inventory, don't draw this le - the container is
927  * maybe empty because an actor picked up the last items here */
929  }
930 }
931 
940 void LE_AddGrenade (const fireDef_t* fd, int flags, const vec3_t muzzle, const vec3_t v0, int dt, le_t* leVictim)
941 {
942  /* add le */
943  le_t* le = LE_Add(0);
944  if (!le)
945  return;
946  LE_SetInvisible(le);
947 
948  /* bind particle */
949  vec3_t accel;
950  VectorSet(accel, 0, 0, -GRAVITY);
951  le->ptl = CL_ParticleSpawn(fd->projectile, 0, muzzle, v0, accel);
952  if (!le->ptl) {
953  le->inuse = false;
954  return;
955  }
956  /* particle properties */
957  VectorSet(le->ptl->angles, 360 * crand(), 360 * crand(), 360 * crand());
958  VectorSet(le->ptl->omega, 500 * crand(), 500 * crand(), 500 * crand());
959 
960  /* think function */
961  if (flags & SF_BODY) {
962  le->ref1 = fd->hitBody;
963  le->ref2 = fd->hitBodySound;
964  le->ref3 = leVictim;
965  } else if ((flags & SF_IMPACT) || (fd->splrad && !fd->bounce)) {
966  le->ref1 = fd->impact;
967  le->ref2 = fd->impactSound;
968  } else {
969  le->ref1 = nullptr;
970  if (flags & SF_BOUNCING)
971  le->ref2 = fd->bounceSound;
972  }
973 
974  le->endTime = cl.time + dt;
975  /* direction - bytedirs index (0,0,1) */
976  le->angle = 5;
977  le->fd = fd;
979  LE_ExecuteThink(le);
980 }
981 
987 {
988  switch (le->type) {
989  case ET_ROTATING:
990  case ET_DOOR:
991  /* These cause the model to render correctly */
992  le->aabb.set(ent->eBox);
993  VectorCopy(ent->origin, le->origin);
994  VectorCopy(ent->angles, le->angles);
995  break;
996  case ET_DOOR_SLIDING:
997  VectorCopy(le->origin, ent->origin);
998  break;
999  case ET_BREAKABLE:
1000  break;
1001  case ET_TRIGGER_RESCUE: {
1002  const int drawFlags = cl_map_draw_rescue_zone->integer;
1003 
1004  if (!((1 << cl_worldlevel->integer) & le->levelflags))
1005  return false;
1006 
1007  ent->flags = 0; /* Do not draw anything at all, if drawFlags set to 0 */
1008  enum { DRAW_TEXTURE = 0x1, DRAW_CIRCLES = 0x2 };
1009  ent->model = nullptr;
1010  ent->alpha = 0.3f;
1011  VectorSet(ent->color, 0.5f, 1.0f, 0.0f);
1012  if ((drawFlags & DRAW_TEXTURE) && ent->texture == nullptr) {
1013  ent->flags = RF_BOX;
1014  ent->texture = R_FindPics("sfx/misc/rescue");
1015  VectorSet(ent->color, 1, 1, 1);
1016  }
1017  ent->eBox.set(le->aabb);
1018 
1019  if (!(drawFlags & DRAW_CIRCLES))
1020  return false;
1021 
1022  /* The triggerbox seems to be 'off-by-one'. The '- UNIT_SIZE' compensates for that. */
1023  for (vec_t x = le->aabb.getMinX(); x < le->aabb.getMaxX() - UNIT_SIZE; x += UNIT_SIZE) {
1024  for (vec_t y = le->aabb.getMinY(); y < le->aabb.getMaxY() - UNIT_SIZE; y += UNIT_SIZE) {
1025  const vec3_t center = {x + UNIT_SIZE / 2, y + UNIT_SIZE / 2, le->aabb.getMinZ()};
1026 
1027  entity_t circle(RF_PATH);
1028  VectorCopy(center, circle.origin);
1029  circle.oldorigin[0] = circle.oldorigin[1] = circle.oldorigin[2] = UNIT_SIZE / 2.0f;
1030  VectorCopy(ent->color, circle.color);
1031  circle.alpha = ent->alpha;
1032 
1033  R_AddEntity(&circle);
1034  }
1035  }
1036 
1037  /* no other rendering entities should be added for the local entity */
1038  return false;
1039  }
1040  default:
1041  break;
1042  }
1043 
1044  return true;
1045 }
1046 
1048 {
1049  const int delay = cl.time - le->thinkDelay;
1050 
1051  /* Updating model faster than 1000 times per second seems to be pretty much pointless */
1052  if (delay < 1)
1053  return;
1054 
1055  if (le->type == ET_ROTATING) {
1056  const float angle = le->angles[le->angle] + 0.001 * delay * le->rotationSpeed; /* delay is in msecs, speed in degrees per second */
1057  le->angles[le->angle] = (angle >= 360.0 ? angle - 360.0 : angle);
1058  }
1059 
1060  le->thinkDelay = cl.time;
1061 }
1062 
1063 void LMT_Init (localModel_t* localModel)
1064 {
1065  if (localModel->target[0] != '\0') {
1066  localModel->parent = LM_GetByID(localModel->target);
1067  if (!localModel->parent)
1068  Com_Error(ERR_DROP, "Could not find local model entity with the id: '%s'.", localModel->target);
1069  }
1070 
1071  /* no longer needed */
1072  localModel->think = nullptr;
1073 }
1074 
1081 void LET_RotateDoor (le_t* le, int speed)
1082 {
1084  const int angle = speed > 0 ? DOOR_ROTATION_ANGLE : -DOOR_ROTATION_ANGLE;
1085  if (le->dir & DOOR_OPEN_REVERSE)
1086  le->angles[le->dir & 3] -= angle;
1087  else
1088  le->angles[le->dir & 3] += angle;
1089 
1091  CL_RecalcRouting(le);
1092 
1093  /* reset the think function as the movement finished */
1094  LE_SetThink(le, nullptr);
1095 }
1096 
1110 void LET_SlideDoor (le_t* le, int speed)
1111 {
1112  vec3_t moveAngles, moveDir;
1113 
1114  /* get the movement angle vector */
1115  GET_SLIDING_DOOR_SHIFT_VECTOR(le->dir, speed, moveAngles);
1116 
1117  /* this origin is only an offset to the absolute mins/maxs for rendering */
1118  VectorAdd(le->origin, moveAngles, le->origin);
1119 
1120  /* get the direction vector from the movement angles that were set on the entity */
1121  AngleVectors(moveAngles, moveDir, nullptr, nullptr);
1122  moveDir[0] = fabsf(moveDir[0]);
1123  moveDir[1] = fabsf(moveDir[1]);
1124  moveDir[2] = fabsf(moveDir[2]);
1125  /* calculate the distance from the movement angles and the entity size */
1126  const int distance = DotProduct(moveDir, le->size);
1127 
1128  bool endPos = false;
1129  if (speed > 0) {
1130  /* check whether the distance the door may slide is slided already
1131  * - if so, stop the movement of the door */
1132  if (fabs(le->origin[le->dir & 3]) >= distance)
1133  endPos = true;
1134  } else {
1135  /* the sliding door has not origin set - except when it is opened. This door type is no
1136  * origin brush based bmodel entity. So whenever the origin vector is not the zero vector,
1137  * the door is opened. */
1138  if (VectorEmpty(le->origin))
1139  endPos = true;
1140  }
1141 
1142  if (endPos) {
1143  vec3_t distanceVec;
1144  /* the door finished its move - either close or open, so make sure to recalc the routing
1145  * data and set the mins/maxs for the inline brush model */
1147 
1148  assert(model);
1149 
1150  /* we need the angles vector normalized */
1151  GET_SLIDING_DOOR_SHIFT_VECTOR(le->dir, (speed < 0) ? -1 : 1, moveAngles);
1152 
1153  /* the bounding box of the door is updated in one step - here is no lerping needed */
1154  VectorMul(distance, moveAngles, distanceVec);
1155 
1156  model->cbmBox.shift(distanceVec);
1157  CL_RecalcRouting(le);
1158 
1159  /* reset the think function as the movement finished */
1160  LE_SetThink(le, nullptr);
1161  } else
1162  le->thinkDelay = 1000;
1163 }
1164 
1169 void LE_AddAmbientSound (const char* sound, const vec3_t origin, int levelflags, float volume, float attenuation)
1170 {
1171  if (strstr(sound, "sound/"))
1172  sound += 6;
1173 
1174  int sampleIdx = S_LoadSampleIdx(sound);
1175  if (!sampleIdx)
1176  return;
1177 
1178  le_t* le = LE_Add(0);
1179  if (!le) {
1180  Com_Printf("Could not add ambient sound entity\n");
1181  return;
1182  }
1183  le->type = ET_SOUND;
1184  le->sampleIdx = sampleIdx;
1185  VectorCopy(origin, le->origin);
1186  LE_SetInvisible(le);
1187  le->levelflags = levelflags;
1188  le->attenuation = attenuation;
1189 
1190  if (volume < 0.0f || volume > 1.0f) {
1191  le->volume = SND_VOLUME_DEFAULT;
1192  Com_Printf("Invalid volume for local entity given - only values between 0.0 and 1.0 are valid\n");
1193  } else {
1194  le->volume = volume;
1195  }
1196 
1197  Com_DPrintf(DEBUG_SOUND, "Add ambient sound '%s' with volume %f\n", sound, volume);
1198 }
1199 
1200 /*===========================================================================
1201  LE Management functions
1202 =========================================================================== */
1203 
1209 le_t* LE_Add (int entnum)
1210 {
1211  le_t* le = nullptr;
1212 
1213  while ((le = LE_GetNext(le))) {
1214  if (!le->inuse)
1215  /* found a free LE */
1216  break;
1217  }
1218 
1219  /* list full, try to make list longer */
1220  if (!le) {
1221  if (cl.numLEs >= MAX_EDICTS) {
1222  /* no free LEs */
1223  Com_Error(ERR_DROP, "Too many LEs");
1224  }
1225 
1226  /* list isn't too long */
1227  le = &cl.LEs[cl.numLEs];
1228  cl.numLEs++;
1229  }
1230 
1231  /* initialize the new LE */
1232  le->init();
1233  le->inuse = true;
1234  le->entnum = entnum;
1236  return le;
1237 }
1238 
1239 void _LE_NotFoundError (int entnum, int type, const char* file, const int line)
1240 {
1241  Cmd_ExecuteString("debug_listle");
1242  Cmd_ExecuteString("debug_listedicts");
1243  if (type >= 0) {
1244  Com_Error(ERR_DROP, "LE_NotFoundError: Could not get LE with entnum %i of type: %i (%s:%i)\n", entnum, type, file, line);
1245  } else {
1246  Com_Error(ERR_DROP, "LE_NotFoundError: Could not get LE with entnum %i (%s:%i)\n", entnum, file, line);
1247  }
1248 }
1249 
1257 void LE_CenterView (const le_t* le)
1258 {
1259  if (!cl_centerview->integer)
1260  return;
1261 
1262  assert(le);
1263  if (le->team == cls.team) {
1264  const float minDistToMove = 4.0f * UNIT_SIZE;
1265  const float dist = Vector2Dist(cl.cam.origin, le->origin);
1266  if (dist < minDistToMove) {
1267  pos3_t currentCamPos;
1268  VecToPos(cl.cam.origin, currentCamPos);
1269  if (le->pos[2] != currentCamPos[2])
1270  Cvar_SetValue("cl_worldlevel", le->pos[2]);
1271  return;
1272  }
1273 
1274  VectorCopy(le->origin, cl.cam.origin);
1275  } else {
1276  pos3_t pos;
1277  VecToPos(cl.cam.origin, pos);
1278  CL_CheckCameraRoute(pos, le->pos);
1279  }
1280 }
1281 
1287 le_t* LE_Get (int entnum)
1288 {
1289  le_t* le = nullptr;
1290 
1291  if (entnum == SKIP_LOCAL_ENTITY)
1292  return nullptr;
1293 
1294  while ((le = LE_GetNextInUse(le))) {
1295  if (le->entnum == entnum)
1296  /* found the LE */
1297  return le;
1298  }
1299 
1300  /* didn't find it */
1301  return nullptr;
1302 }
1303 
1309 bool LE_IsLocked (int entnum)
1310 {
1311  le_t* le = LE_Get(entnum);
1312  return (le != nullptr && (le->flags & LE_LOCKED));
1313 }
1314 
1322 void LE_Lock (le_t* le)
1323 {
1324  if (le->flags & LE_LOCKED)
1325  Com_Error(ERR_DROP, "LE_Lock: Trying to lock %i which is already locked\n", le->entnum);
1326 
1327  le->flags |= LE_LOCKED;
1328 }
1329 
1341 void LE_Unlock (le_t* le)
1342 {
1343  if (!(le->flags & LE_LOCKED))
1344  Com_Error(ERR_DROP, "LE_Unlock: Trying to unlock %i which is already unlocked\n", le->entnum);
1345 
1346  le->flags &= ~LE_LOCKED;
1347 }
1348 
1354 {
1355  le_t* le = nullptr;
1356 
1357  while ((le = LE_GetNextInUse(le))) {
1358  if (VectorCompare(le->pos, pos))
1359  return le;
1360  }
1361 
1362  /* didn't find it */
1363  return nullptr;
1364 }
1365 
1371 {
1372  if (!cl.numLEs)
1373  return nullptr;
1374 
1375  if (!lastLE)
1376  return cl.LEs;
1377 
1378  le_t* endOfLEs = &cl.LEs[cl.numLEs];
1379 
1380  assert(lastLE >= cl.LEs);
1381  assert(lastLE < endOfLEs);
1382 
1383  le_t* le = lastLE;
1384 
1385  le++;
1386  if (le >= endOfLEs)
1387  return nullptr;
1388  else
1389  return le;
1390 }
1391 
1399 {
1400  le_t* le = lastLE;
1401 
1402  while ((le = LE_GetNext(le))) {
1403  if (le->inuse)
1404  break;
1405  }
1406  return le;
1407 }
1408 
1416 le_t* LE_FindRadius (le_t* from, const vec3_t org, float rad, entity_type_t type)
1417 {
1418  le_t* le = from;
1419 
1420  while ((le = LE_GetNextInUse(le))) {
1421  if (type != ET_NULL && le->type != type)
1422  continue;
1423  vec3_t eorg;
1424  vec3_t leCenter;
1425  le->aabb.getCenter(leCenter);
1426  for (int j = 0; j < 3; j++)
1427  eorg[j] = org[j] - (le->origin[j] + leCenter[j]);
1428  if (VectorLength(eorg) > rad)
1429  continue;
1430  return le;
1431  }
1432 
1433  return nullptr;
1434 }
1435 
1442 {
1443  le_t* le = nullptr;
1444 
1445  while ((le = LE_GetNextInUse(le))) {
1446  if (le->type == type && VectorCompare(le->pos, pos))
1447  /* found the LE */
1448  return le;
1449  }
1450 
1451  /* didn't find it */
1452  return nullptr;
1453 }
1454 
1462 static inline bool LE_IsOriginBrush (const le_t* const le)
1463 {
1464  return (le->type == ET_DOOR || le->type == ET_ROTATING);
1465 }
1466 
1470 static void LE_AddEdictHighlight (const le_t* le)
1471 {
1472  const cBspModel_t* model = LE_GetClipModel(le);
1473 
1474  entity_t ent(RF_BOX);
1475  VectorSet(ent.color, 1, 1, 1);
1476  ent.alpha = (sin(cl.time * 6.28) + 1.0) / 2.0;
1477  CalculateMinsMaxs(le->angles, model->cbmBox, le->origin, ent.eBox);
1478  R_AddEntity(&ent);
1479 }
1480 
1486 void LE_AddToScene (void)
1487 {
1488  for (int i = 0; i < cl.numLEs; i++) {
1489  le_t& le = cl.LEs[i];
1490  if (le.flags & LE_REMOVE_NEXT_FRAME) {
1491  le.inuse = false;
1492  le.flags &= ~LE_REMOVE_NEXT_FRAME;
1493  }
1494  if (le.inuse && !LE_IsInvisible(&le)) {
1495  if (le.flags & LE_CHECK_LEVELFLAGS) {
1496  if (!((1 << cl_worldlevel->integer) & le.levelflags))
1497  continue;
1498  } else if (le.flags & LE_ALWAYS_VISIBLE) {
1499  /* show them always */
1500  } else if (le.pos[2] > cl_worldlevel->integer)
1501  continue;
1502 
1503  entity_t ent(RF_NONE);
1504  ent.alpha = le.alpha;
1505 
1506  VectorCopy(le.angles, ent.angles);
1507  ent.model = le.model1;
1508  ent.skinnum = le.bodySkin;
1509  ent.lighting = &le.lighting;
1510 
1511  switch (le.contents) {
1512  /* Only breakables do not use their origin; func_doors and func_rotating do!!!
1513  * But none of them have animations. */
1514  case CONTENTS_SOLID:
1515  case CONTENTS_DETAIL: /* they use mins/maxs */
1516  break;
1517  default:
1518  /* set entity values */
1519  R_EntitySetOrigin(&ent, le.origin);
1520  VectorCopy(le.origin, ent.oldorigin);
1521  /* store animation values */
1522  ent.as = le.as;
1523  break;
1524  }
1525 
1526  if (LE_IsOriginBrush(&le)) {
1527  ent.isOriginBrushModel = true;
1528  R_EntitySetOrigin(&ent, le.origin);
1529  VectorCopy(le.origin, ent.oldorigin);
1530  }
1531 
1532  if (LE_IsSelected(&le) && le.clientAction != nullptr) {
1533  const le_t* action = le.clientAction;
1534  if (action->inuse && action->type > ET_NULL && action->type < ET_MAX)
1535  LE_AddEdictHighlight(action);
1536  }
1537 
1538  /* call add function */
1539  /* if it returns false, don't draw */
1540  if (le.addFunc)
1541  if (!le.addFunc(&le, &ent))
1542  continue;
1543 
1544  /* add it to the scene */
1545  R_AddEntity(&ent);
1546 
1547  if (cl_le_debug->integer)
1548  CL_ParticleSpawn("cross", 0, le.origin);
1549  }
1550  }
1551 }
1552 
1557 void LE_Cleanup (void)
1558 {
1559  Com_DPrintf(DEBUG_CLIENT, "LE_Cleanup: Clearing up to %i unused LE inventories\n", cl.numLEs);
1560  for (int i = cl.numLEs - 1; i >= 0; i--) {
1561  le_t* le = &cl.LEs[i];
1562  if (!le->inuse)
1563  continue;
1564  if (LE_IsActor(le))
1565  CL_ActorCleanup(le);
1566  else if (LE_IsItem(le))
1567  cls.i.emptyContainer(&le->inv, CID_FLOOR);
1568 
1569  le->inuse = false;
1570  }
1571 }
1572 
1573 #ifdef DEBUG
1574 
1577 void LE_List_f (void)
1578 {
1579  Com_Printf("number | entnum | type | inuse | invis | pnum | team | size | HP | state | level | model/ptl\n");
1580  for (int i = 0; i < cl.numLEs; i++) {
1581  le_t& le = cl.LEs[i];
1582  Com_Printf("#%5i | #%5i | %4i | %5i | %5i | %4i | %4i | %4i | %3i | %5i | %5i | ",
1583  i, le.entnum, le.type, le.inuse, LE_IsInvisible(&le), le.pnum, le.team,
1584  le.fieldSize, le.HP, le.state, le.levelflags);
1585  if (le.type == ET_PARTICLE) {
1586  if (le.ptl)
1587  Com_Printf("%s\n", le.ptl->ctrl->name);
1588  else
1589  Com_Printf("no ptl\n");
1590  } else if (le.model1)
1591  Com_Printf("%s\n", le.model1->name);
1592  else
1593  Com_Printf("no mdl\n");
1594  }
1595 }
1596 
1600 void LM_List_f (void)
1601 {
1602  Com_Printf("number | entnum | skin | frame | lvlflg | renderflags | origin | name\n");
1603  for (int i = 0; i < cl.numLMs; i++) {
1604  localModel_t& lm = cl.LMs[i];
1605  Com_Printf("#%5i | #%5i | #%3i | #%4i | %6i | %11i | %5.0f:%5.0f:%3.0f | %s\n",
1606  i, lm.entnum, lm.skin, lm.frame, lm.levelflags, lm.renderFlags,
1607  lm.origin[0], lm.origin[1], lm.origin[2], lm.name);
1608  }
1609 }
1610 
1611 #endif
1612 
1613 /*===========================================================================
1614  LE Tracing
1615 =========================================================================== */
1616 
1618 class MoveClipCL : public MoveClip
1619 {
1620 public:
1622  const le_t* passle, *passle2;
1623 };
1624 
1626 {
1627  const cBspModel_t* model;
1628  const unsigned int index = le->modelnum1;
1629  if (index > lengthof(cl.model_clip))
1630  Com_Error(ERR_DROP, "Clip model index out of bounds");
1631  model = cl.model_clip[index];
1632  if (!model)
1633  Com_Error(ERR_DROP, "LE_GetClipModel: Could not find inline model %u", index);
1634  return model;
1635 }
1636 
1638 {
1639  if (index == 0 || index > lengthof(cl.model_draw))
1640  Com_Error(ERR_DROP, "Draw model index out of bounds");
1641  model_t* model = cl.model_draw[index];
1642  if (!model)
1643  Com_Error(ERR_DROP, "LE_GetDrawModel: Could not find model %u", index);
1644  return model;
1645 }
1646 
1659 static int32_t CL_HullForEntity (const le_t* le, int* tile, vec3_t rmaShift, vec3_t angles)
1660 {
1661  /* special case for bmodels */
1662  if (le->contents & CONTENTS_SOLID) {
1663  const cBspModel_t* model = LE_GetClipModel(le);
1664  /* special value for bmodel */
1665  if (!model)
1666  Com_Error(ERR_DROP, "CL_HullForEntity: Error - le with nullptr bmodel (%i)\n", le->type);
1667  *tile = model->tile;
1668  VectorCopy(le->angles, angles);
1669  VectorCopy(model->shift, rmaShift);
1670  return model->headnode;
1671  } else {
1672  /* might intersect, so do an exact clip */
1673  *tile = 0;
1674  VectorCopy(vec3_origin, angles);
1675  VectorCopy(vec3_origin, rmaShift);
1676  return CM_HeadnodeForBox(cl.mapTiles->mapTiles[*tile], le->aabb);
1677  }
1678 }
1679 
1685 static void CL_ClipMoveToLEs (MoveClipCL* clip)
1686 {
1687  if (clip->trace.allsolid)
1688  return;
1689 
1690  le_t* le = nullptr;
1691  while ((le = LE_GetNextInUse(le))) {
1692  int tile = 0;
1693 
1694  if (!(le->contents & clip->contentmask))
1695  continue;
1696  if (le == clip->passle || le == clip->passle2)
1697  continue;
1698 
1699  vec3_t angles, shift;
1700  const int32_t headnode = CL_HullForEntity(le, &tile, shift, angles);
1701  assert(headnode < MAX_MAP_NODES);
1702 
1703  vec3_t origin;
1704  VectorCopy(le->origin, origin);
1705 
1707  headnode, clip->contentmask, 0, origin, angles, shift, 1.0);
1708 
1709  if (trace.fraction < clip->trace.fraction) {
1710  /* make sure we keep a startsolid from a previous trace */
1711  const bool oldStart = clip->trace.startsolid;
1712  trace.le = le;
1713  clip->trace = trace;
1714  clip->trace.startsolid |= oldStart;
1715  /* if true, plane is not valid */
1716  } else if (trace.allsolid) {
1717  trace.le = le;
1718  clip->trace = trace;
1719  /* if true, the initial point was in a solid area */
1720  } else if (trace.startsolid) {
1721  trace.le = le;
1722  clip->trace.startsolid = true;
1723  }
1724  }
1725 }
1726 
1739 trace_t CL_Trace (const Line& traceLine, const AABB& box, const le_t* passle, le_t* passle2, int contentmask, int worldLevel)
1740 {
1741  if (cl_trace_debug->integer)
1743 
1744  /* clip to world */
1745  MoveClipCL clip;
1746  clip.trace = CM_CompleteBoxTrace(cl.mapTiles, traceLine, box, (1 << (worldLevel + 1)) - 1, contentmask, 0);
1747  clip.trace.le = nullptr;
1748  if (clip.trace.fraction == 0)
1749  return clip.trace; /* blocked by the world */
1750 
1751  clip.contentmask = contentmask;
1752  clip.moveLine.set(traceLine);
1753  clip.objBox.set(box);
1754  clip.passle = passle;
1755  clip.passle2 = passle2;
1756 
1757  /* create the bounding box of the entire move */
1758  clip.calcBounds();
1759 
1760  /* clip to other solid entities */
1761  CL_ClipMoveToLEs(&clip);
1762 
1763  return clip.trace;
1764 }
const char * bounceSound
Definition: inv_shared.h:118
void LET_SlideDoor(le_t *le, int speed)
Slides a door.
const vec3_t bytedirs[]
Definition: netpack.cpp:27
bool Q_strnull(const char *string)
Definition: shared.h:138
#define LE_IsStunned(le)
float rotationSpeed
void CalculateMinsMaxs(const vec3_t angles, const AABB &relBox, const vec3_t origin, AABB &absBox)
Calculates the bounding box in absolute coordinates, also for rotating objects. WARNING: do not use t...
Definition: mathlib.cpp:546
float getMaxX() const
Definition: aabb.h:131
vec_t VectorLength(const vec3_t v)
Calculate the length of a vector.
Definition: mathlib.cpp:434
animState_t as
const le_t * passle2
static ipos3_t shift
The shift array is used for random map assemblies (RMA) to shift the mins/maxs and stuff like that...
#define VectorCopy(src, dest)
Definition: vector.h:51
entity_t * R_GetEntity(int id)
Returns a specific entity from the list.
Definition: r_entity.cpp:694
pos3_t newPos
void CL_RecalcRouting(const le_t *le)
const char * impact
Definition: inv_shared.h:113
int ucn
vec3_t size
char hitParticle[MAX_VAR]
Definition: chr_shared.h:331
teamDef_t * teamDef
#define VectorSet(v, x, y, z)
Definition: vector.h:59
vec3_t origin
Definition: typedefs.h:28
void set(const Line &other)
Copies the values from the given Line.
Definition: line.h:47
void LE_AddGrenade(const fireDef_t *fd, int flags, const vec3_t muzzle, const vec3_t v0, int dt, le_t *leVictim)
#define LE_IsCrouched(le)
void LE_ExecuteThink(le_t *le)
Call think function for the given local entity if its still in use.
vec3_t omega
Definition: cl_renderer.h:155
QGL_EXTERN GLint GLenum type
Definition: r_gl.h:94
vec3_t s
Definition: cl_renderer.h:121
int contentmask
Definition: moveclip.h:39
void VectorMA(const vec3_t veca, const float scale, const vec3_t vecb, vec3_t outVector)
Sets vector_out (vc) to vevtor1 (va) + scale * vector2 (vb)
Definition: mathlib.cpp:261
const char * LE_GetAnim(const char *anim, int right, int left, int state)
Get the correct animation for the given actor state and weapons.
int S_LoadSampleIdx(const char *soundFile)
Loads and registers a sound file for later use.
Definition: s_sample.cpp:105
vec3_t origin
Definition: bspfile.h:47
#define SF_BODY
Definition: q_shared.h:249
int thinkDelay
this is a fire definition for our weapons/ammo
Definition: inv_shared.h:110
InventoryInterface i
Definition: client.h:101
#define LE_IsItem(le)
int pnum
int INVSH_ShapeSize(const uint32_t shape)
Counts the used bits in a shape (item shape).
Definition: inv_shared.cpp:435
int entnum
const char * va(const char *format,...)
does a varargs printf into a temp buffer, so I don't need to have varargs versions of all text functi...
Definition: shared.cpp:410
int dir
int startTime
void LE_CenterView(const le_t *le)
Center the camera on the local entity's origin.
#define ROLL
Definition: mathlib.h:56
const terrainType_t * Com_GetTerrainType(const char *textureName)
Searches the terrain definition if given.
Definition: scripts.cpp:3089
static const vec3_t scale
float angles[3]
int damStunGas
Definition: q_shared.h:533
int gender
This is a cvar definition. Cvars can be user modified and used in our menus e.g.
Definition: cvar.h:71
pos3_t pos
const cBspModel_t * LE_GetClipModel(const le_t *le)
bool isOurRound() const
Definition: client.h:106
#define CONTENTS_SOLID
Definition: defines.h:223
float alpha
ptl_t * CL_ParticleSpawn(const char *name, int levelFlags, const vec3_t s, const vec3_t v, const vec3_t a)
Spawn a new particle to the map.
voidpf uLong int origin
Definition: ioapi.h:45
csi_t csi
Definition: common.cpp:39
bool Com_sprintf(char *dest, size_t size, const char *fmt,...)
copies formatted string with buffer-size checking
Definition: shared.cpp:494
int pathPos
int positionContents
void LM_AddToScene(void)
Add the local models to the scene.
char animationIndex
Definition: inv_shared.h:327
bool LE_IsLocked(int entnum)
Checks if a given le_t structure is locked, i.e., used by another event at this time.
Definition: aabb.h:42
void init()
void LE_AddProjectile(const fireDef_t *fd, int flags, const vec3_t muzzle, const vec3_t impact, int normal, le_t *leVictim)
#define BASE_DIRECTIONS
Number of direct connected fields for a position.
Definition: mathlib.h:84
const vec3_t vec3_origin
Definition: mathlib.cpp:35
struct le_s * le
Definition: tracing.h:66
void LE_Unlock(le_t *le)
Unlocks a previously locked le_t struct.
#define LE_IsInvisible(le)
char inlineModelName[8]
float vec_t
Definition: ufotypes.h:37
const image_t * R_FindPics(const char *name)
Searches for an image in the image array.
Definition: r_image.cpp:673
float getMinZ() const
Definition: aabb.h:125
localModel_t LMs[MAX_LOCALMODELS]
const objDef_t * def(void) const
Definition: inv_shared.h:469
#define UNIT_HEIGHT
Definition: defines.h:122
cvar_t * cl_centerview
Definition: cl_camera.cpp:69
static int oldPos
int angle
struct le_s * clientAction
bool S_LoadAndPlaySample(const char *s, const vec3_t origin, float attenuation, float volume)
does what the name implies in just one function to avoid exposing s_sample_t
Definition: s_main.cpp:314
bool CL_OutsideMap(const vec3_t position, const float delta)
Checks whether give position is still inside the map borders.
float speed
Definition: inv_shared.h:143
static void LE_GenerateInlineModelList(void)
void LM_Think(void)
void set(const AABB &other)
Copies the values from the given aabb.
Definition: aabb.h:60
#define TEAM_CIVILIAN
Definition: q_shared.h:61
void Com_Printf(const char *const fmt,...)
Definition: common.cpp:386
model_t * LE_GetDrawModel(unsigned int index)
vec3_t origin
pos3_t oldPos
void Grid_RecalcRouting(mapTiles_t *mapTiles, Routing &routing, const char *name, const GridBox &box, const char **list)
This function recalculates the routing surrounding the entity name.
Definition: grid.cpp:922
actorModes_t actorMode
le_t * LE_GetFromPos(const pos3_t pos)
Searches a local entity on a given grid field.
int headgear
void LET_BrushModel(le_t *le)
const char * hitBodySound
Definition: inv_shared.h:116
const char * leInlineModelList[MAX_EDICTS+1]
Item * getNext() const
Definition: inv_shared.h:451
model_t * model
void LMT_Init(localModel_t *localModel)
Defines all attributes of objects used in the inventory.
Definition: inv_shared.h:264
le_t LEs[MAX_EDICTS]
#define SF_BOUNCING
Definition: q_shared.h:250
byte dmgtype
Definition: inv_shared.h:325
const char * type
Definition: inv_shared.h:271
#define STATE_CROUCHED
Definition: q_shared.h:263
const char * impactSound
Definition: inv_shared.h:114
int integer
Definition: cvar.h:81
void CL_CheckCameraRoute(const pos3_t from, const pos3_t target)
Only moves the camera to the given target location if its not yet close enough.
Definition: cl_camera.cpp:285
struct localModel_s * parent
bool LE_IsActor(const le_t *le)
Checks whether the given le is a living actor.
#define VectorScale(in, scale, out)
Definition: vector.h:79
int slidingSpeed
static void CL_GridRecalcRouting(const le_t *le)
int morale
void LE_PlaceItem(le_t *le)
The bounding box of a moving object.
Definition: moveclip.h:33
#define CONTENTS_DETAIL
Definition: defines.h:251
static void LET_PathMove(le_t *le)
Move the actor along the path to the given location.
static void LE_PlaySoundFileAndParticleForSurface(le_t *le, const char *textureName)
Plays step sounds and draw particles for different terrain types.
int tile
Definition: typedefs.h:31
void setScale(const vec3_t scale_)
float fraction
Definition: tracing.h:58
const struct objDef_s * obj
Definition: inv_shared.h:125
void R_AnimChange(animState_t *as, const model_t *mod, const char *name)
Changes the animation for md2 models.
#define Q_strvalid(string)
Definition: shared.h:141
trace_t CL_Trace(const Line &traceLine, const AABB &box, const le_t *passle, le_t *passle2, int contentmask, int worldLevel)
Moves the given mins/maxs volume through the world from start to end.
int maxMorale
#define SOUND_ATTN_IDLE
Definition: common.h:187
#define YAW
Definition: mathlib.h:55
void Com_Error(int code, const char *fmt,...)
Definition: common.cpp:417
#define SKIP_LOCAL_ENTITY
Definition: q_shared.h:255
vec3_t shift
Definition: typedefs.h:28
actorSizeEnum_t fieldSize
int LE_ActorGetStepTime(const le_t *le, const pos3_t pos, const pos3_t oldPos, const int dir, const int speed)
#define CONTENTS_WATER
Definition: defines.h:226
void Cmd_ExecuteString(const char *text,...)
A complete command line has been parsed, so try to execute it.
Definition: cmd.cpp:1007
void resetFloor()
const char * particle
Definition: scripts.h:219
void LE_Cleanup(void)
Cleanup unused LE inventories that the server sent to the client also free some unused LE memory...
cvar_t * cl_trace_debug
trace_t CM_HintedTransformedBoxTrace(MapTile &tile, const Line &traceLine, const AABB &traceBox, const int headnode, const int contentmask, const int brushrejects, const vec3_t origin, const vec3_t angles, const vec3_t rmaShift, const float fraction)
Handles offseting and rotation of the end points for moving and rotating entities.
Definition: cmodel.cpp:84
mapTiles_t * mapTiles
AABB objBox
Definition: moveclip.h:37
client_static_t cls
Definition: cl_main.cpp:83
item instance data, with linked list capability
Definition: inv_shared.h:402
void Q_strncpyz(char *dest, const char *src, size_t destsize)
Safe strncpy that ensures a trailing zero.
Definition: shared.cpp:457
#define LE_CHECK_LEVELFLAGS
void AngleVectors(const vec3_t angles, vec3_t forward, vec3_t right, vec3_t up)
Create the rotation matrix in order to rotate something.
Definition: mathlib.cpp:631
#define RF_PATH
Definition: r_entity.h:37
int flags
cvar_t * cl_le_debug
void CL_ActorConditionalMoveCalc(le_t *le)
Recalculate forbidden list, available moves and actor's move length for the current selected actor...
Definition: cl_actor.cpp:682
void CL_CompleteRecalcRouting(void)
const char * hitBody
Definition: inv_shared.h:115
int right
void CL_ActorPlaySound(const le_t *le, actorSound_t soundType)
Plays various sounds on actor action.
Definition: cl_actor.cpp:2134
#define VectorMul(scalar, b, dest)
Definition: vector.h:48
cvar_t * cl_worldlevel
Definition: cl_hud.cpp:46
#define DotProduct(x, y)
Returns the distance between two 3-dimensional vectors.
Definition: vector.h:44
#define FLYING_DIRECTIONS
Definition: mathlib.h:89
#define LE_GetAnimationIndexForDeath(le)
Valid indices from 1 - MAX_DEATH.
#define ERR_DROP
Definition: common.h:211
float frametime
Definition: client.h:59
#define DEBUG_CLIENT
Definition: defines.h:59
#define SND_VOLUME_FOOTSTEPS
Definition: scripts.h:213
vec3_t origin
Definition: cl_camera.h:31
float impactAttenuation
Definition: inv_shared.h:121
GLsizei size
Definition: r_gl.h:152
model_t * modelPool[MAX_OBJDEFS]
Definition: client.h:96
cvar_t * cl_map_draw_rescue_zone
lighting_t lighting
void calcBounds()
Create the bounding box for the entire move.
Definition: moveclip.h:48
#define OBJZERO(obj)
Definition: shared.h:178
uint32_t shape
Definition: inv_shared.h:273
static bool LE_IsOriginBrush(const le_t *const le)
#define MAX_VAR
Definition: shared.h:36
QGL_EXTERN GLuint GLsizei GLsizei * length
Definition: r_gl.h:110
#define DOOR_ROTATION_ANGLE
Definition: q_shared.h:187
model_t * model_draw[MAX_MODELS]
#define RF_BOX
Definition: r_entity.h:36
vec3_t center
Definition: inv_shared.h:276
le_t * LE_Get(int entnum)
Searches all local entities for the one with the searched entnum.
void S_PlayStdSample(const stdsound_t sId, const vec3_t origin, float attenuation, float volume)
plays one of the precached samples
Definition: s_main.cpp:333
int32_t CM_HeadnodeForBox(MapTile &tile, const AABB &box)
To keep everything totally uniform, bounding boxes are turned into small BSP trees instead of being c...
Definition: cmodel.cpp:151
void(* localEntityThinkFunc_t)(struct le_s *le)
void _LE_NotFoundError(int entnum, int type, const char *file, const int line)
#define LE_IsSelected(le)
pos3_t mousePendPos
void VecToAngles(const vec3_t value1, vec3_t angles)
Converts a vector to an angle vector.
Definition: mathlib.cpp:934
struct leStep_s * next
#define VecToPos(v, p)
Map boundary is +/- MAX_WORLD_WIDTH - to get into the positive area we add the possible max negative ...
Definition: mathlib.h:100
float footstepVolume
Definition: scripts.h:221
le_t * LE_Add(int entnum)
Add a new local entity to the scene.
int stepIndex
Line moveLine
Definition: moveclip.h:38
bool LE_IsLivingAndVisibleActor(const le_t *le)
Checks whether the given le is a living and visible actor.
#define PosToVec(p, v)
Pos boundary size is +/- 128 - to get into the positive area we add the possible max negative value a...
Definition: mathlib.h:110
localModel_t * LM_GetByID(const char *id)
model_t * model1
char target[MAX_VAR]
clientBattleScape_t cl
#define VectorEmpty(a)
Definition: vector.h:73
localEntitiyAddFunc_t addFunc
char const * Q_strstart(char const *str, char const *start)
Matches the start of a string.
Definition: shared.cpp:587
#define CID_FLOOR
Definition: inv_shared.h:55
char name[MAX_QPATH]
Definition: r_model.h:44
#define LE_REMOVE_NEXT_FRAME
void LE_DoEndPathMove(le_t *le)
Ends the move of an actor.
#define SF_IMPACT
Definition: q_shared.h:248
int endTime
ptl_t * ptl
#define MASK_SOLID
Definition: defines.h:272
#define MAX_LOCALMODELS
Definition: line.h:31
Item * getFloorContainer() const
void Com_DPrintf(int level, const char *fmt,...)
A Com_Printf that only shows up if the "developer" cvar is set.
Definition: common.cpp:398
vec2_t size
Definition: cl_renderer.h:118
static void LM_AddToSceneOrder(bool parents)
#define GRAVITY
Definition: q_shared.h:276
model_t * R_FindModel(const char *name)
Tries to load a model.
Definition: r_model.cpp:203
#define RF_NONE
Definition: r_entity.h:34
lighting_t lighting
char name[MAX_QPATH]
void LET_RotateDoor(le_t *le, int speed)
Rotates a door in the given speed.
void R_AnimRun(animState_t *as, const model_t *mod, int msec)
Run the animation of the given model.
byte change
Definition: r_entity.h:65
char footstepSound[MAX_VAR]
Definition: chr_shared.h:301
float getMaxY() const
Definition: aabb.h:134
static void LE_DoPathMove(le_t *le)
pos_t pos3_t[3]
Definition: ufotypes.h:58
model_t * model2
const struct cBspModel_s * model_clip[MAX_MODELS]
static const objDef_t * LE_BiggestItem(const Item *ic)
Returns the index of the biggest item in the inventory list.
int sampleIdx
static localModel_t * LM_Find(int entnum)
Checks whether a local model with the same entity number is already registered.
vec2_t damage
Definition: inv_shared.h:158
void getCenter(vec3_t center) const
Calculates the center of the bounding box.
Definition: aabb.h:155
QGL_EXTERN GLenum GLuint * dest
Definition: r_gl.h:101
AABB cbmBox
Definition: typedefs.h:27
void init()
Definition: inv_shared.cpp:703
float volume
void LM_Register(void)
Register misc_models.
#define PosAddDV(p, crouch, dv)
Definition: mathlib.h:253
#define GET_SLIDING_DOOR_SHIFT_VECTOR(dir, speed, vecout)
Definition: q_shared.h:294
unsigned int bodySkin
QGL_EXTERN GLuint index
Definition: r_gl.h:110
#define DIRECTION_FALL
Definition: defines.h:335
#define UNIT_SIZE
Definition: defines.h:121
void LE_LinkFloorContainer(le_t *le)
link any floor container into the actor temp floor container
cBspModel_t * CM_InlineModel(const mapTiles_t *mapTiles, const char *name)
Searches all inline models and return the cBspModel_t pointer for the given modelnumber or -name...
Definition: bsp.cpp:929
#define LE_SetInvisible(le)
char id[MAX_VAR]
const struct le_s * ref3
#define VectorCompare(a, b)
Definition: vector.h:63
a local entity
QGL_EXTERN GLfloat f
Definition: r_gl.h:114
#define VectorClear(a)
Definition: vector.h:55
le_t * LE_GetNextInUse(le_t *lastLE)
Iterate through the entities that are in use.
Inventory inv
#define Vector2Dist(a, b)
Definition: vector.h:70
const fireDef_t * fd
int speed[MAX_ROUTE]
int pathContents[MAX_ROUTE]
#define VectorAdd(a, b, dest)
Definition: vector.h:47
entity_type_t type
localModel_t * LM_AddModel(const char *model, const vec3_t origin, const vec3_t angles, int entnum, int levelflags, int renderFlags, const vec3_t scale)
Prepares local (not known or handled by the server) models to the map, which will be added later in L...
le_t * selActor
Definition: cl_actor.cpp:49
#define SND_VOLUME_WEAPONS
Definition: s_main.h:43
void LE_Think(void)
Calls the le think function and updates the animation. The animation updated even if the particular l...
int HP
vec3_t v
Definition: cl_renderer.h:153
static void CL_ClipMoveToLEs(MoveClipCL *clip)
Clip against solid entities.
char name[MAX_QPATH]
Definition: typedefs.h:38
float getMinY() const
Definition: aabb.h:122
static void LE_PlayFootStepSound(le_t *le)
int maxTU
TR_TILE_TYPE mapTiles[MAX_MAPTILES]
Definition: tracing.h:79
ptlDef_t * ctrl
Definition: cl_renderer.h:137
QGL_EXTERN GLint i
Definition: r_gl.h:113
const char * ref1
int pathLength
#define LE_IsDead(le)
const char * projectile
Definition: inv_shared.h:112
vec3_t angles
Definition: cl_renderer.h:124
float attenuation
#define SOUND_ATTN_STATIC
Definition: common.h:188
unsigned int modelnum2
localEntityThinkFunc_t think
#define GROUND_DELTA
Definition: defines.h:115
#define CORE_DIRECTIONS
Definition: mathlib.h:88
static void LE_PlaySoundFileForContents(le_t *le, int contents)
Plays sound of content for moving actor.
byte actorMoveLength
The TUs that the current selected actor needs to walk to the current grid position marked by the mous...
void CL_ParticleFree(ptl_t *p)
Free a particle and all it's children.
AABB aabb
void LE_Lock(le_t *le)
Markes a le_t struct as locked. Should be called at the beginning of an event handler on this le_t...
#define Mem_Free(ptr)
Definition: mem.h:35
bool inuse
cBspModel_t * CM_SetInlineModelOrientation(mapTiles_t *mapTiles, const char *name, const vec3_t origin, const vec3_t angles)
This function updates a model's orientation.
Definition: bsp.cpp:963
static void LE_AddEdictHighlight(const le_t *le)
Adds a box that highlights the current active door.
dvec_t dvtab[MAX_ROUTE]
float getMinX() const
Definition: aabb.h:119
HUD related routines.
void LE_AddToScene(void)
void R_EntitySetOrigin(entity_t *ent, const vec3_t origin)
setter for entity origin
Definition: r_entity.cpp:47
float crand(void)
Return random values between -1 and 1.
Definition: mathlib.cpp:517
bool startsolid
Definition: tracing.h:57
int R_AddEntity(const entity_t *ent)
Adds a copy of the specified entity to the list of all known render entities.
Definition: r_entity.cpp:706
vec_t vec3_t[3]
Definition: ufotypes.h:39
#define SOUND_ATTN_NORM
Definition: common.h:186
entity_type_t
Definition: q_shared.h:145
float splrad
Definition: inv_shared.h:161
const char * particleID
void(* think)(struct localModel_s *localModel)
void LE_AddAmbientSound(const char *sound, const vec3_t origin, int levelflags, float volume, float attenuation)
Adds ambient sounds from misc_sound entities.
void shift(const vec3_t shiftVec)
shove the whole box by the given vector
Definition: aabb.h:246
const objDef_t * INVSH_GetItemByIDX(int index)
Returns the item that belongs to the given index or nullptr if the index is invalid.
Definition: inv_shared.cpp:266
char name[MAX_VAR]
Definition: cl_renderer.h:82
le_t * LE_Find(entity_type_t type, const pos3_t pos)
Searches a local entity on a given grid field.
#define getDVdir(dv)
Definition: mathlib.h:249
bool LE_BrushModelAction(le_t *le, entity_t *ent)
Add function for brush models.
static void LET_Projectile(le_t *le)
int32_t headnode
Definition: typedefs.h:29
animState_t as
int contents
#define lengthof(x)
Definition: shared.h:105
#define LE_LOCKED
int TU
#define DEBUG_SOUND
Definition: defines.h:63
Different terrain definitions for footsteps and particles.
Definition: scripts.h:216
const float directionAngles[CORE_DIRECTIONS]
Definition: mathlib.cpp:105
int levelflags
short dvec_t
The direction vector tells us where the actor came from (in his previous step). The pathing table hol...
Definition: mathlib.h:236
#define LE_IsPanicked(le)
const char * footstepSound
Definition: scripts.h:218
connstate_t state
Definition: client.h:55
#define NONE
Definition: defines.h:68
#define Q_streq(a, b)
Definition: shared.h:136
void LET_HiddenMove(le_t *le)
Handle move for invisible actors.
void emptyContainer(Inventory *const inv, const containerIndex_t container)
Clears the linked list of a container - removes all items from this container.
Definition: inventory.cpp:501
int team
unsigned int headSkin
bool LE_IsLivingActor(const le_t *le)
Checks whether the given le is a living actor (but might be hidden)
le_t * LE_FindRadius(le_t *from, const vec3_t org, float rad, entity_type_t type)
Returns entities that have origins within a spherical area.
int bounce
Definition: inv_shared.h:149
static const AABB EMPTY
Definition: aabb.h:44
cBspSurface_t * surface
Definition: tracing.h:61
bool allsolid
Definition: tracing.h:56
void R_DrawBoundingBoxBatched(const AABB &absbox)
Definition: r_draw.cpp:670
#define ACTOR_SIZE_NORMAL
Definition: defines.h:302
int maxHP
Client side moveclip.
void setFloor(le_s *other)
void Grid_PosToVec(const Routing &routing, const actorSizeEnum_t actorSize, const pos3_t pos, vec3_t vec)
Converts a grid position to world coordinates.
Definition: grid.cpp:832
vec3_t oldOrigin
void Cvar_SetValue(const char *varName, float value)
Expands value to a string and calls Cvar_Set.
Definition: cvar.cpp:671
#define LE_ALWAYS_VISIBLE
Routing routing
Definition: typedefs.h:341
char tagname[MAX_VAR]
void LE_SetThink(le_t *le, localEntityThinkFunc_t think)
le_t * LE_GetNext(le_t *lastLE)
Iterate through the list of entities.
uint8_t byte
Definition: ufotypes.h:34
#define DOOR_OPEN_REVERSE
Definition: q_shared.h:293
local models
#define ACTOR_SIZE_INVALID
Definition: defines.h:301
leStep_t * stepList
int STUN
int Com_ServerState(void)
Check whether we are the server or have a singleplayer tactical mission.
Definition: common.cpp:538
fireDefIndex_t currentSelectedFiremode
void LET_StartIdle(le_t *le)
Change the animation of an actor to the idle animation (which can be panic, dead or stand) ...
void CL_ActorCleanup(le_t *le)
Definition: cl_actor.cpp:389
const le_t * passle
static int32_t CL_HullForEntity(const le_t *le, int *tile, vec3_t rmaShift, vec3_t angles)
Returns a headnode that can be used for testing or clipping an object of mins/maxs size...
char animname[MAX_QPATH]
#define VectorSubtract(a, b, dest)
Definition: vector.h:45
unsigned int modelnum1
int state
const char * id
Definition: inv_shared.h:268
trace_t CM_CompleteBoxTrace(mapTiles_t *mapTiles, const Line &trLine, const AABB &box, int levelmask, int brushmask, int brushreject)
Traces all submodels in all tiles. Used by ufo and ufo_ded.
Definition: cmodel.cpp:283
void LET_StartPathMove(le_t *le)
Change the actors animation to walking.
#define SND_VOLUME_DEFAULT
Definition: s_main.h:42
static void LE_ActorBodyHit(const le_t *le, const vec3_t impact, int normal)
Spawns particle effects for a hit actor.
woundInfo_t wounds
int left
#define MAX_EDICTS
Definition: defines.h:99
#define MAX_MAP_NODES
Definition: defines.h:140
const char * ref2