UFO: Alien Invasion
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
g_vis.cpp
Go to the documentation of this file.
1 
5 /*
6 Copyright (C) 2002-2020 UFO: Alien Invasion.
7 
8 This program is free software; you can redistribute it and/or
9 modify it under the terms of the GNU General Public License
10 as published by the Free Software Foundation; either version 2
11 of the License, or (at your option) any later version.
12 
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
16 
17 See the GNU General Public License for more details.
18 
19 You should have received a copy of the GNU General Public License
20 along with this program; if not, write to the Free Software
21 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
22 
23 */
24 
25 #include "g_local.h"
26 #include "g_actor.h"
27 #include "g_client.h"
28 #include "g_edicts.h"
29 #include "g_health.h"
30 #include "g_inventory.h"
31 #include "g_utils.h"
32 #include "g_vis.h"
33 
38 bool G_FrustumVis (const Edict* from, const vec3_t point)
39 {
40  if (G_IsActiveCamera(from)) {
41  /* it's a 360 degree camera */
42  if (from->camera.rotate)
43  return true;
44  }
45  return FrustumVis(from->origin, from->dir, point);
46 }
47 
54 static bool G_LineVis (const vec3_t from, const vec3_t to)
55 {
56  return G_TestLineWithEnts(from, to);
57 }
58 
65 bool G_SmokeVis (const vec3_t from, const Edict* check)
66 {
67  const float distance = VectorDist(check->origin, from);
68  /* units that are very close are visible in the smoke */
69  if (distance > UNIT_SIZE * 1.5f) {
70  Edict* e = nullptr;
71 
72  while ((e = G_EdictsGetNextInUse(e))) {
73  if (G_IsSmoke(e)) {
74  if (RayIntersectAABB(from, check->absBox.mins, e->absBox)
75  || RayIntersectAABB(from, check->absBox.maxs, e->absBox)) {
76  return true;
77  }
78  }
79  }
80  }
81  return false;
82 }
83 
100 float G_ActorVis (const Edict* ent, const Edict* check, bool full)
101 {
102  vec3_t eyeEnt;
103  G_ActorGetEyeVector(ent, eyeEnt);
104  if (G_SmokeVis(eyeEnt, check))
105  return ACTOR_VIS_0;
106 
107  vec3_t test, dir;
108  float delta;
109  /* start on eye height */
110  VectorCopy(check->origin, test);
111  if (G_IsDead(check)) {
112  test[2] += PLAYER_DEAD;
113  delta = 0;
114  } else if (G_IsCrouched(check)) {
115  test[2] += PLAYER_CROUCH - 2;
116  delta = (PLAYER_CROUCH - PLAYER_MIN) / 2 - 2;
117  } else {
118  test[2] += PLAYER_STAND;
119  delta = (PLAYER_STAND - PLAYER_MIN) / 2 - 2;
120  }
121 
122  /* side shifting -> better checks */
123  dir[0] = eyeEnt[1] - check->origin[1];
124  dir[1] = check->origin[0] - eyeEnt[0];
125  dir[2] = 0;
126  VectorNormalizeFast(dir);
127  VectorMA(test, -7, dir, test);
128 
129  /* do 3 tests */
130  int n = 0;
131  for (int i = 0; i < 3; i++) {
132  if (!G_LineVis(eyeEnt, test)) {
133  if (full)
134  n++;
135  else
136  return ACTOR_VIS_100;
137  }
138 
139  /* look further down or stop */
140  if (!delta) {
141  if (n > 0)
142  return ACTOR_VIS_100;
143  else
144  return ACTOR_VIS_0;
145  }
146  VectorMA(test, 7, dir, test);
147  test[2] -= delta;
148  }
149 
150  /* return factor */
151  switch (n) {
152  case 0:
153  return ACTOR_VIS_0;
154  case 1:
155  return ACTOR_VIS_10;
156  case 2:
157  return ACTOR_VIS_50;
158  default:
159  return ACTOR_VIS_100;
160  }
161 }
162 
163 int G_VisCheckDist (const Edict* const ent)
164 {
165  if (G_IsActiveCamera(ent))
166  return MAX_SPOT_DIST_CAMERA;
167 
168  if (G_IsActor(ent))
170 
171  return MAX_SPOT_DIST;
172 }
173 
183 bool G_Vis (const int team, const Edict* from, const Edict* check, const vischeckflags_t flags)
184 {
185  /* if any of them isn't in use, then they're not visible */
186  if (!from->inuse || !check->inuse)
187  return false;
188 
189  /* only actors and 2x2 units can see anything */
190  if (!G_IsLivingActor(from) && !G_IsActiveCamera(from))
191  return false;
192 
193  /* living team members are always visible */
194  if (team >= 0 && check->getTeam() == team && !G_IsDead(check))
195  return true;
196 
197  /* standard team rules */
198  if (team >= 0 && from->getTeam() != team)
199  return false;
200 
201  /* inverse team rules */
202  if (team < 0 && from->getTeam() == -team)
203  return false;
204 
205  /* check for same pos */
206  if (VectorCompare(from->pos, check->pos))
207  return true;
208 
209  if (!G_IsVisibleOnBattlefield(check))
210  return false;
211 
212  /* view distance check */
213  const int spotDist = G_VisCheckDist(from);
214  if (VectorDistSqr(from->origin, check->origin) > spotDist * spotDist)
215  return false;
216 
217  /* view frustum check */
218  if (!(flags & VT_NOFRUSTUM) && !G_FrustumVis(from, check->origin))
219  return false;
220 
221  /* line trace check */
222  switch (check->type) {
223  case ET_ACTOR:
224  case ET_ACTOR2x2:
225  return G_ActorVis(from, check, false) > ACTOR_VIS_0;
226  case ET_ITEM:
227  case ET_CAMERA:
228  case ET_PARTICLE: {
229  /* get viewers eye height */
230  vec3_t eye;
231  G_ActorGetEyeVector(from, eye);
232  return !G_LineVis(eye, check->origin);
233  }
234  default:
235  return false;
236  }
237 }
238 
255 int G_TestVis (const int team, Edict* check, const vischeckflags_t flags)
256 {
257  /* store old flag */
258  const int old = G_IsVisibleForTeam(check, team) ? VS_CHANGE : 0;
259 
260  if (g_aidebug->integer)
261  return VS_YES | !old;
262 
263  if (!(flags & VT_PERISHCHK) && old)
264  return VS_YES;
265 
266  /* test if check is visible */
267  Edict* from = nullptr;
268  while ((from = G_EdictsGetNextInUse(from)))
269  if (G_Vis(team, from, check, flags))
270  /* visible */
271  return VS_YES | !old;
272 
273  /* just return the old state */
274  return old;
275 }
276 
277 static bool G_VisShouldStop (const Edict* ent)
278 {
279  return G_IsLivingActor(ent) && !G_IsCivilian(ent);
280 }
281 
290 static int G_DoTestVis (const int team, Edict* check, const vischeckflags_t visFlags, playermask_t playerMask, const Edict* ent)
291 {
292  int status = 0;
293  const int vis = G_TestVis(team, check, visFlags);
294 
295  /* visibility has changed ... */
296  if (vis & VS_CHANGE) {
297  /* swap the vis mask for the given team */
298  const bool appear = (vis & VS_YES) == VS_YES;
299  if (playerMask == 0) {
300  G_VisFlagsSwap(*check, G_TeamToVisMask(team));
301  } else {
302  G_AppearPerishEvent(playerMask, appear, *check, ent);
303  }
304 
305  /* ... to visible */
306  if (vis & VS_YES) {
307  status |= VIS_APPEAR;
308  if (G_VisShouldStop(check))
309  status |= VIS_STOP;
310  } else {
311  status |= VIS_PERISH;
312  }
313  } else if (vis == 0 && (visFlags & VT_NEW)) {
314  if (G_IsActor(check)) {
315  G_EventActorAdd(playerMask, *check);
316  }
317  }
318  return status;
319 }
320 
327 void G_CheckVisPlayer (Player& player, const vischeckflags_t visFlags)
328 {
329  Edict* ent = nullptr;
330 
331  /* check visibility */
332  while ((ent = G_EdictsGetNextInUse(ent))) {
333  /* check if he's visible */
334  G_DoTestVis(player.getTeam(), ent, visFlags, G_PlayerToPM(player), nullptr);
335  }
336 }
337 
359 static int G_CheckVisTeam (const int team, Edict* check, const vischeckflags_t visFlags, const Edict* ent)
360 {
361  int status = 0;
362 
363  /* check visibility */
364  if (check->inuse) {
365  /* check if he's visible */
366  status |= G_DoTestVis(team, check, visFlags, G_TeamToPM(team), ent);
367  }
368 
369  return status;
370 }
371 
376 int G_CheckVisTeamAll (const int team, const vischeckflags_t visFlags, const Edict* ent)
377 {
378  Edict* chk = nullptr;
379  int status = 0;
380 
381  while ((chk = G_EdictsGetNextInUse(chk))) {
382  status |= G_CheckVisTeam(team, chk, visFlags, ent);
383  }
384  return status;
385 }
386 
391 {
392  Edict* ent = nullptr;
393  while ((ent = G_EdictsGetNextInUse(ent))) {
394  const int playerMask = G_VisToPM(ent->visflags);
395  G_AppearPerishEvent(~playerMask, true, *ent, nullptr);
396  if (G_IsActor(ent))
397  G_SendInventory(~G_TeamToPM(ent->getTeam()), *ent);
398  }
399 }
400 
409 void G_CheckVis (Edict* check, const vischeckflags_t visFlags)
410 {
411  for (int team = 0; team < MAX_TEAMS; team++)
412  if (level.num_alive[team]) {
413  if (!check) /* no special entity given, so check them all */
414  G_CheckVisTeamAll(team, visFlags, nullptr);
415  else
416  G_CheckVisTeam(team, check, visFlags, nullptr);
417  }
418 }
419 
424 void G_VisFlagsClear (int team)
425 {
426  Edict* ent = nullptr;
427  const teammask_t teamMask = ~G_TeamToVisMask(team);
428  while ((ent = G_EdictsGetNextInUse(ent))) {
429  ent->visflags &= teamMask;
430  }
431 }
432 
433 void G_VisFlagsAdd (Edict& ent, teammask_t teamMask)
434 {
435  ent.visflags |= teamMask;
436 }
437 
439 {
440  ent.visflags = 0;
441 }
442 
443 void G_VisFlagsSwap (Edict& ent, teammask_t teamMask)
444 {
445  ent.visflags ^= teamMask;
446 }
bool FrustumVis(const vec3_t origin, int dir, const vec3_t point)
Checks whether a point is visible from a given position.
Definition: mathlib.cpp:666
Edict * G_EdictsGetNextInUse(Edict *lastEnt)
Iterate through the entities that are in use.
Definition: g_edicts.cpp:166
#define VectorCopy(src, dest)
Definition: vector.h:51
#define ACTOR_VIS_10
Definition: g_vis.h:63
static int G_DoTestVis(const int team, Edict *check, const vischeckflags_t visFlags, playermask_t playerMask, const Edict *ent)
Definition: g_vis.cpp:290
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
#define MAX_TEAMS
Definition: defines.h:98
bool G_SmokeVis(const vec3_t from, const Edict *check)
tests for smoke interference
Definition: g_vis.cpp:65
void G_CheckVis(Edict *check, const vischeckflags_t visFlags)
Check if the edict appears/perishes for the other teams. If they appear for other teams...
Definition: g_vis.cpp:409
#define VIS_APPEAR
Definition: g_vis.h:36
Misc utility functions for game module.
void G_VisFlagsSwap(Edict &ent, teammask_t teamMask)
Definition: g_vis.cpp:443
unsigned int playermask_t
Definition: g_events.h:34
bool inuse
Definition: g_edict.h:47
AABB absBox
Definition: g_edict.h:61
#define VectorDist(a, b)
Definition: vector.h:69
#define ACTOR_VIS_50
Definition: g_vis.h:62
void G_SendInventory(playermask_t playerMask, const Edict &ent)
Sends whole inventory through the network buffer.
#define VIS_PERISH
Definition: g_vis.h:38
static bool G_VisShouldStop(const Edict *ent)
Definition: g_vis.cpp:277
#define G_IsCrouched(ent)
Definition: g_actor.h:32
void VectorNormalizeFast(vec3_t v)
fast vector normalize routine that does not check to make sure that length != 0, nor does it return l...
Definition: mathlib.cpp:762
vec3_t maxs
Definition: aabb.h:258
byte dir
Definition: g_edict.h:86
#define G_IsActor(ent)
Definition: g_local.h:127
void G_AppearPerishEvent(playermask_t playerMask, bool appear, Edict &check, const Edict *ent)
Send the appear or perish event to the affected clients.
Definition: g_client.cpp:245
int integer
Definition: cvar.h:81
#define VT_NOFRUSTUM
Definition: g_vis.h:55
void G_VisFlagsClear(int team)
Reset the visflags for all edicts in the global list for the given team - and only for the given team...
Definition: g_vis.cpp:424
bool G_IsLivingActor(const Edict *ent)
Checks whether the given edict is a living actor.
Definition: g_actor.cpp:43
float G_ActorVis(const Edict *ent, const Edict *check, bool full)
calculate how much check is "visible" by ent
Definition: g_vis.cpp:100
camera_edict_data_t camera
Definition: g_edict.h:134
#define G_IsActiveCamera(ent)
Definition: g_local.h:130
int getTeam() const
Definition: g_edict.h:269
#define VT_NEW
Definition: g_vis.h:58
#define PLAYER_DEAD
Definition: q_sizes.h:8
#define PLAYER_MIN
Definition: q_sizes.h:9
#define ACTOR_VIS_0
Definition: g_vis.h:64
#define VT_PERISHCHK
Definition: g_vis.h:53
#define G_IsCivilian(ent)
Definition: g_local.h:148
teammask_t visflags
Definition: g_edict.h:82
#define G_PlayerToPM(player)
Definition: g_events.h:37
#define VS_CHANGE
Definition: g_vis.h:44
pos3_t pos
Definition: g_edict.h:55
byte num_alive[MAX_TEAMS]
Definition: g_local.h:115
playermask_t G_VisToPM(teammask_t teamMask)
Converts vis mask to player mask.
Definition: g_client.cpp:186
static int G_CheckVisTeam(const int team, Edict *check, const vischeckflags_t visFlags, const Edict *ent)
Checks whether an edict appear/perishes for a specific team - also updates the visflags each edict ca...
Definition: g_vis.cpp:359
#define G_IsVisibleOnBattlefield(ent)
Definition: g_local.h:140
void G_VisMakeEverythingVisible(void)
Make everything visible to anyone who can't already see it.
Definition: g_vis.cpp:390
#define UNIT_SIZE
Definition: defines.h:121
#define PLAYER_STAND
Definition: q_sizes.h:6
#define VectorCompare(a, b)
Definition: vector.h:63
QGL_EXTERN GLfloat f
Definition: r_gl.h:114
#define G_TeamToVisMask(team)
Definition: g_local.h:143
int G_CheckVisTeamAll(const int team, const vischeckflags_t visFlags, const Edict *ent)
Do G_CheckVisTeam for all entities ent is the one that is looking at the others.
Definition: g_vis.cpp:376
int G_TestVis(const int team, Edict *check, const vischeckflags_t flags)
test if check is visible by team (or if visibility changed?)
Definition: g_vis.cpp:255
cvar_t * g_aidebug
Definition: g_main.cpp:114
void G_VisFlagsReset(Edict &ent)
Definition: g_vis.cpp:438
#define VS_YES
Definition: g_vis.h:46
QGL_EXTERN GLint i
Definition: r_gl.h:113
#define G_IsDead(ent)
Definition: g_actor.h:34
Local definitions for game module.
entity_type_t type
Definition: g_edict.h:81
bool G_FrustumVis(const Edict *from, const vec3_t point)
Checks whether a point is "visible" from the edicts position.
Definition: g_vis.cpp:38
functions to handle the storage and lifecycle of all edicts in the game module.
void G_CheckVisPlayer(Player &player, const vischeckflags_t visFlags)
Sets visible edict on player spawn.
Definition: g_vis.cpp:327
vec3_t origin
Definition: g_edict.h:53
bool G_Vis(const int team, const Edict *from, const Edict *check, const vischeckflags_t flags)
test if check is visible by from
Definition: g_vis.cpp:183
unsigned int vischeckflags_t
Definition: g_vis.h:49
vec_t vec3_t[3]
Definition: ufotypes.h:39
void G_EventActorAdd(playermask_t playerMask, const Edict &ent, const bool instant)
Definition: g_events.cpp:511
bool RayIntersectAABB(const vec3_t start, const vec3_t end, const AABB &aabb)
Definition: mathlib.cpp:1110
unsigned int teammask_t
Definition: g_vis.h:30
void G_ActorGetEyeVector(const Edict *actor, vec3_t eye)
Fills a vector with the eye position of a given actor.
Definition: g_actor.cpp:357
#define MAX_SPOT_DIST_CAMERA
Definition: g_local.h:51
vec3_t mins
Definition: aabb.h:257
#define G_IsVisibleForTeam(ent, team)
Definition: g_local.h:144
bool G_TestLineWithEnts(const vec3_t start, const vec3_t end)
fast version of a line trace including entities
Definition: g_utils.cpp:237
static bool G_LineVis(const vec3_t from, const vec3_t to)
tests the visibility between two points
Definition: g_vis.cpp:54
void G_VisFlagsAdd(Edict &ent, teammask_t teamMask)
Definition: g_vis.cpp:433
Definition: g_edict.h:45
#define G_IsSmoke(ent)
Definition: g_local.h:131
#define VectorDistSqr(a, b)
Definition: vector.h:68
float G_ActorGetInjuryPenalty(const Edict *const ent, const modifier_types_t type)
Returns the penalty to the given stat caused by the actor wounds.
Definition: g_health.cpp:177
#define PLAYER_CROUCH
Definition: q_sizes.h:7
#define ACTOR_VIS_100
Definition: g_vis.h:61
#define MAX_SPOT_DIST
Definition: g_local.h:52
int G_VisCheckDist(const Edict *const ent)
Definition: g_vis.cpp:163
Interface for g_client.cpp.
playermask_t G_TeamToPM(int team)
Generates the player bit mask for a given team.
Definition: g_client.cpp:144
#define VIS_STOP
Definition: g_vis.h:40
level_locals_t level
Definition: g_main.cpp:38