UFO: Alien Invasion
cl_localentity.cpp
Go to the documentation of this file.
1 
6 /*
7 Copyright (C) 2002-2022 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 */
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. */
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);
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 }
vec3_t size
int pathContents[MAX_ROUTE]
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 attenuation
const char * impactSound
Definition: inv_shared.h:114
int state
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
woundInfo_t wounds
vec_t VectorLength(const vec3_t v)
Calculate the length of a vector.
Definition: mathlib.cpp:434
const char * hitBodySound
Definition: inv_shared.h:116
Inventory inv
float impactAttenuation
Definition: inv_shared.h:121
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
struct localModel_s * parent
void CL_RecalcRouting(const le_t *le)
int maxTU
int pathLength
void init()
#define VectorSet(v, x, y, z)
Definition: vector.h:59
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)
unsigned int modelnum2
vec3_t omega
Definition: cl_renderer.h:155
const fireDef_t * fd
void LE_ExecuteThink(le_t *le)
Call think function for the given local entity if its still in use.
unsigned int headSkin
QGL_EXTERN GLint GLenum type
Definition: r_gl.h:94
Defines all attributes of objects used in the inventory.
Definition: inv_shared.h:264
const struct cBspModel_s * model_clip[MAX_MODELS]
mapTiles_t * mapTiles
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.
localEntitiyAddFunc_t addFunc
int S_LoadSampleIdx(const char *soundFile)
Loads and registers a sound file for later use.
Definition: s_sample.cpp:105
vec3_t origin
Definition: r_entity.h:101
#define SF_BODY
Definition: q_shared.h:249
vec3_t origin
Definition: cl_camera.h:31
vec3_t oldOrigin
#define LE_IsItem(le)
localEntityThinkFunc_t think
int INVSH_ShapeSize(const uint32_t shape)
Counts the used bits in a shape (item shape).
Definition: inv_shared.cpp:435
const char * va(const char *format,...)
does a varargs printf into a temp buffer, so I don&#39;t need to have varargs versions of all text functi...
Definition: shared.cpp:410
int damStunGas
Definition: q_shared.h:533
void LE_CenterView(const le_t *le)
Center the camera on the local entity&#39;s origin.
#define ROLL
Definition: mathlib.h:56
local models
const terrainType_t * Com_GetTerrainType(const char *textureName)
Searches the terrain definition if given.
Definition: scripts.cpp:3067
static const vec3_t scale
const cBspModel_t * LE_GetClipModel(const le_t *le)
int STUN
int morale
#define CONTENTS_SOLID
Definition: defines.h:223
struct le_s * clientAction
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
byte change
Definition: r_entity.h:65
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
void LM_AddToScene(void)
Add the local models to the scene.
bool LE_IsLocked(int entnum)
Checks if a given le_t structure is locked, i.e., used by another event at this time.
bool startsolid
Definition: tracing.h:57
Definition: aabb.h:42
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 leStep_s * next
void LE_Unlock(le_t *le)
Unlocks a previously locked le_t struct.
#define LE_IsInvisible(le)
float vec_t
Definition: ufotypes.h:37
bool allsolid
Definition: tracing.h:56
const image_t * R_FindPics(const char *name)
Searches for an image in the image array.
Definition: r_image.cpp:673
int flags
int integer
Definition: cvar.h:81
voidpf void uLong size
Definition: ioapi.h:42
#define UNIT_HEIGHT
Definition: defines.h:122
cvar_t * cl_centerview
Definition: cl_camera.cpp:69
TR_TILE_TYPE mapTiles[MAX_MAPTILES]
Definition: tracing.h:79
static int oldPos
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.
int pnum
static void LE_GenerateInlineModelList(void)
InventoryInterface i
Definition: client.h:101
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)
float alpha
Definition: r_entity.h:111
int skinnum
Definition: r_entity.h:110
float speed
Definition: inv_shared.h:143
model_t * model
model_t * model2
localModel_t LMs[MAX_LOCALMODELS]
byte actorMoveLength
The TUs that the current selected actor needs to walk to the current grid position marked by the mous...
int contents
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
lighting_t lighting
void getCenter(vec3_t center) const
Calculates the center of the bounding box.
Definition: aabb.h:155
le_t * LE_GetFromPos(const pos3_t pos)
Searches a local entity on a given grid field.
void LET_BrushModel(le_t *le)
void(* localEntityThinkFunc_t)(struct le_s *le)
vec3_t origin
void LMT_Init(localModel_t *localModel)
#define SF_BOUNCING
Definition: q_shared.h:250
#define STATE_CROUCHED
Definition: q_shared.h:263
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
vec3_t center
Definition: inv_shared.h:276
fireDefIndex_t currentSelectedFiremode
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 entnum
static void CL_GridRecalcRouting(const le_t *le)
this is a fire definition for our weapons/ammo
Definition: inv_shared.h:110
void LE_PlaceItem(le_t *le)
The bounding box of a moving object.
Definition: moveclip.h:33
const char * id
Definition: inv_shared.h:268
#define CONTENTS_DETAIL
Definition: defines.h:251
int angle
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.
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
AABB eBox
Definition: r_entity.h:103
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.
#define SOUND_ATTN_IDLE
Definition: common.h:187
char animationIndex
Definition: inv_shared.h:327
#define YAW
Definition: mathlib.h:55
int right
void Com_Error(int code, const char *fmt,...)
Definition: common.cpp:417
#define SKIP_LOCAL_ENTITY
Definition: q_shared.h:255
pos3_t oldPos
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
int tile
Definition: typedefs.h:31
float getMaxX() const
Definition: aabb.h:131
void setScale(const vec3_t scale_)
Definition: r_entity.h:154
model_t * model1
int thinkDelay
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
bool isOurRound() const
Definition: client.h:106
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
AABB objBox
Definition: moveclip.h:37
client_static_t cls
Definition: cl_main.cpp:83
float volume
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
const char * hitBody
Definition: inv_shared.h:115
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
cvar_t * cl_le_debug
void CL_ActorConditionalMoveCalc(le_t *le)
Recalculate forbidden list, available moves and actor&#39;s move length for the current selected actor...
Definition: cl_actor.cpp:682
vec3_t color
Definition: r_entity.h:100
void CL_CompleteRecalcRouting(void)
struct le_s * le
Definition: tracing.h:66
float angles[3]
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
a local entity
#define DEBUG_CLIENT
Definition: defines.h:59
#define SND_VOLUME_FOOTSTEPS
Definition: scripts.h:212
int headgear
vec2_t damage
Definition: inv_shared.h:158
int flags
Definition: r_entity.h:112
cvar_t * cl_map_draw_rescue_zone
void calcBounds()
Create the bounding box for the entire move.
Definition: moveclip.h:48
#define OBJZERO(obj)
Definition: shared.h:178
static bool LE_IsOriginBrush(const le_t *const le)
#define MAX_VAR
Definition: shared.h:36
vec3_t shift
Definition: typedefs.h:28
QGL_EXTERN GLuint GLsizei GLsizei * length
Definition: r_gl.h:110
#define DOOR_ROTATION_ANGLE
Definition: q_shared.h:187
#define RF_BOX
Definition: r_entity.h:36
Item * getNext() const
Definition: inv_shared.h:451
vec3_t oldorigin
Definition: r_entity.h:102
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
const char * ref1
void setScale(const vec3_t scale_)
bool isOriginBrushModel
Definition: r_entity.h:115
int32_t headnode
Definition: typedefs.h:29
int maxMorale
int slidingSpeed
int gender
float frametime
Definition: client.h:59
struct entity_s * tagent
Definition: r_entity.h:106
void _LE_NotFoundError(int entnum, int type, const char *file, const int line)
#define LE_IsSelected(le)
void VecToAngles(const vec3_t value1, vec3_t angles)
Converts a vector to an angle vector.
Definition: mathlib.cpp:934
#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
le_t * LE_Add(int entnum)
Add a new local entity to the scene.
char hitParticle[MAX_VAR]
Definition: chr_shared.h:342
Line moveLine
Definition: moveclip.h:38
int left
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)
int startTime
clientBattleScape_t cl
#define VectorEmpty(a)
Definition: vector.h:73
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
#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
const char * tagname
Definition: r_entity.h:107
#define MASK_SOLID
Definition: defines.h:272
int dir
#define MAX_LOCALMODELS
Definition: line.h:31
int maxHP
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
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
int levelflags
#define RF_NONE
Definition: r_entity.h:34
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.
int team
static void LE_DoPathMove(le_t *le)
pos_t pos3_t[3]
Definition: ufotypes.h:58
int positionContents
static const objDef_t * LE_BiggestItem(const Item *ic)
Returns the index of the biggest item in the inventory list.
static localModel_t * LM_Find(int entnum)
Checks whether a local model with the same entity number is already registered.
model_t * model_draw[MAX_MODELS]
const char * leInlineModelList[MAX_EDICTS+1]
QGL_EXTERN GLenum GLuint * dest
Definition: r_gl.h:101
void init()
Definition: inv_shared.cpp:703
dvec_t dvtab[MAX_ROUTE]
void LM_Register(void)
Register misc_models.
#define PosAddDV(p, crouch, dv)
Definition: mathlib.h:253
lighting_t lighting
#define GET_SLIDING_DOOR_SHIFT_VECTOR(dir, speed, vecout)
Definition: q_shared.h:294
QGL_EXTERN GLuint index
Definition: r_gl.h:110
float getMinY() const
Definition: aabb.h:122
#define DIRECTION_FALL
Definition: defines.h:335
#define UNIT_SIZE
Definition: defines.h:121
int sampleIdx
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)
const struct le_s * ref3
Different terrain definitions for footsteps and particles.
Definition: scripts.h:215
int HP
ptlDef_t * ctrl
Definition: cl_renderer.h:137
#define VectorCompare(a, b)
Definition: vector.h:63
QGL_EXTERN GLfloat f
Definition: r_gl.h:114
#define VectorClear(a)
Definition: vector.h:55
void setFloor(le_s *other)
le_t * LE_GetNextInUse(le_t *lastLE)
Iterate through the entities that are in use.
void(* think)(struct localModel_s *localModel)
vec3_t angles
Definition: cl_renderer.h:124
#define Vector2Dist(a, b)
Definition: vector.h:70
char name[MAX_QPATH]
Definition: r_model.h:44
#define VectorAdd(a, b, dest)
Definition: vector.h:47
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...
int endTime
char name[MAX_VAR]
Definition: cl_renderer.h:82
float fraction
Definition: tracing.h:58
model_t * modelPool[MAX_OBJDEFS]
Definition: client.h:96
Routing routing
Definition: typedefs.h:341
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 bounce
Definition: inv_shared.h:149
const char * projectile
Definition: inv_shared.h:112
static void CL_ClipMoveToLEs(MoveClipCL *clip)
Clip against solid entities.
vec3_t v
Definition: cl_renderer.h:153
static void LE_PlayFootStepSound(le_t *le)
pos3_t mousePendPos
const char * footstepSound
Definition: scripts.h:217
int pathPos
unsigned int modelnum1
QGL_EXTERN GLint i
Definition: r_gl.h:113
#define LE_IsDead(le)
#define SOUND_ATTN_STATIC
Definition: common.h:188
uint32_t shape
Definition: inv_shared.h:273
float rotationSpeed
#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.
char animname[MAX_QPATH]
struct model_s * model
Definition: r_entity.h:97
void CL_ParticleFree(ptl_t *p)
Free a particle and all it&#39;s children.
AABB cbmBox
Definition: typedefs.h:27
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...
void resetFloor()
#define Mem_Free(ptr)
Definition: mem.h:35
cBspModel_t * CM_SetInlineModelOrientation(mapTiles_t *mapTiles, const char *name, const vec3_t origin, const vec3_t angles)
This function updates a model&#39;s orientation.
Definition: bsp.cpp:963
static void LE_AddEdictHighlight(const le_t *le)
Adds a box that highlights the current active door.
lighting_t * lighting
Definition: r_entity.h:125
char name[MAX_QPATH]
HUD related routines.
animState_t as
Definition: r_entity.h:117
void LE_AddToScene(void)
void R_EntitySetOrigin(entity_t *ent, const vec3_t origin)
setter for entity origin
Definition: r_entity.cpp:47
float getMinX() const
Definition: aabb.h:119
float crand(void)
Return random values between -1 and 1.
Definition: mathlib.cpp:517
char target[MAX_VAR]
char tagname[MAX_VAR]
vec2_t size
Definition: cl_renderer.h:118
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
const char * impact
Definition: inv_shared.h:113
#define SOUND_ATTN_NORM
Definition: common.h:186
float splrad
Definition: inv_shared.h:161
entity_type_t
Definition: q_shared.h:145
teamDef_t * teamDef
vec3_t angles
Definition: r_entity.h:98
const struct objDef_s * obj
Definition: inv_shared.h:125
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
AABB aabb
const char * type
Definition: inv_shared.h:271
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)
unsigned int bodySkin
#define lengthof(x)
Definition: shared.h:105
#define LE_LOCKED
#define DEBUG_SOUND
Definition: defines.h:63
float footstepVolume
Definition: scripts.h:220
const float directionAngles[CORE_DIRECTIONS]
Definition: mathlib.cpp:105
entity_type_t type
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)
#define NONE
Definition: defines.h:68
float getMaxY() const
Definition: aabb.h:134
#define Q_streq(a, b)
Definition: shared.h:136
void LET_HiddenMove(le_t *le)
Handle move for invisible actors.
actorModes_t actorMode
int ucn
cBspSurface_t * surface
Definition: tracing.h:61
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
const char * ref2
animState_t as
int frame
Definition: r_entity.h:55
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.
vec3_t s
Definition: cl_renderer.h:121
const objDef_t * def(void) const
Definition: inv_shared.h:469
const char * particleID
static const AABB EMPTY
Definition: aabb.h:44
const char * bounceSound
Definition: inv_shared.h:118
actorSizeEnum_t fieldSize
void R_DrawBoundingBoxBatched(const AABB &absbox)
Definition: r_draw.cpp:670
#define ACTOR_SIZE_NORMAL
Definition: defines.h:302
Client side moveclip.
char inlineModelName[8]
char id[MAX_VAR]
pos3_t newPos
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
Item * getFloorContainer() const
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
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
#define ACTOR_SIZE_INVALID
Definition: defines.h:301
char name[MAX_QPATH]
Definition: typedefs.h:38
bool inuse
char footstepSound[MAX_VAR]
Definition: chr_shared.h:312
const char * particle
Definition: scripts.h:218
float getMinZ() const
Definition: aabb.h:125
This is a cvar definition. Cvars can be user modified and used in our menus e.g.
Definition: cvar.h:71
const image_t * texture
Definition: r_entity.h:123
int Com_ServerState(void)
Check whether we are the server or have a singleplayer tactical mission.
Definition: common.cpp:538
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
leStep_t * stepList
const le_t * passle
int speed[MAX_ROUTE]
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...
#define VectorSubtract(a, b, dest)
Definition: vector.h:45
ptl_t * ptl
animState_t as
connstate_t state
Definition: client.h:55
int TU
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
int stepIndex
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.
float alpha
vec3_t origin
Definition: typedefs.h:28
le_t LEs[MAX_EDICTS]
pos3_t pos
#define MAX_EDICTS
Definition: defines.h:99
#define MAX_MAP_NODES
Definition: defines.h:140