UFO: Alien Invasion
Loading...
Searching...
No Matches
g_vis.cpp
Go to the documentation of this file.
1
4
5/*
6Copyright (C) 2002-2025 UFO: Alien Invasion.
7
8This program is free software; you can redistribute it and/or
9modify it under the terms of the GNU General Public License
10as published by the Free Software Foundation; either version 2
11of the License, or (at your option) any later version.
12
13This program is distributed in the hope that it will be useful,
14but WITHOUT ANY WARRANTY; without even the implied warranty of
15MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
16
17See the GNU General Public License for more details.
18
19You should have received a copy of the GNU General Public License
20along with this program; if not, write to the Free Software
21Foundation, 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
38bool 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
54static bool G_LineVis (const vec3_t from, const vec3_t to)
55{
56 return G_TestLineWithEnts(from, to);
57}
58
65bool 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
100float 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;
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
163int G_VisCheckDist (const Edict* const ent)
164{
165 if (G_IsActiveCamera(ent))
167
168 if (G_IsActor(ent))
170
171 return MAX_SPOT_DIST;
172}
173
183bool 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
255int 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
277static bool G_VisShouldStop (const Edict* ent)
278{
279 return G_IsLivingActor(ent) && !G_IsCivilian(ent);
280}
281
290static 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
327void 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
359static 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
376int 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
409void 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
424void 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
433void G_VisFlagsAdd (Edict& ent, teammask_t teamMask)
434{
435 ent.visflags |= teamMask;
436}
437
439{
440 ent.visflags = 0;
441}
442
443void G_VisFlagsSwap (Edict& ent, teammask_t teamMask)
444{
445 ent.visflags ^= teamMask;
446}
@ MODIFIER_SIGHT
Definition chr_shared.h:259
vec3_t maxs
Definition aabb.h:258
vec3_t mins
Definition aabb.h:257
teammask_t visflags
Definition g_edict.h:82
camera_edict_data_t camera
Definition g_edict.h:134
vec3_t origin
Definition g_edict.h:53
pos3_t pos
Definition g_edict.h:55
byte dir
Definition g_edict.h:86
bool inuse
Definition g_edict.h:47
int getTeam() const
Definition g_edict.h:269
AABB absBox
Definition g_edict.h:61
entity_type_t type
Definition g_edict.h:81
#define MAX_TEAMS
Definition defines.h:98
#define UNIT_SIZE
Definition defines.h:121
bool G_IsLivingActor(const Edict *ent)
Checks whether the given edict is a living actor.
Definition g_actor.cpp:43
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 G_IsCrouched(ent)
Definition g_actor.h:32
#define G_IsDead(ent)
Definition g_actor.h:34
playermask_t G_TeamToPM(int team)
Generates the player bit mask for a given team.
Definition g_client.cpp:144
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
playermask_t G_VisToPM(teammask_t teamMask)
Converts vis mask to player mask.
Definition g_client.cpp:186
Interface for g_client.cpp.
Edict * G_EdictsGetNextInUse(Edict *lastEnt)
Iterate through the entities that are in use.
Definition g_edicts.cpp:166
functions to handle the storage and lifecycle of all edicts in the game module.
void G_EventActorAdd(playermask_t playerMask, const Edict &ent, const bool instant)
Definition g_events.cpp:511
#define G_PlayerToPM(player)
Definition g_events.h:37
unsigned int playermask_t
Definition g_events.h:34
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
void G_SendInventory(playermask_t playerMask, const Edict &ent)
Sends whole inventory through the network buffer.
Local definitions for game module.
#define G_IsVisibleOnBattlefield(ent)
Definition g_local.h:140
#define MAX_SPOT_DIST_CAMERA
Definition g_local.h:51
level_locals_t level
Definition g_main.cpp:38
cvar_t * g_aidebug
Definition g_main.cpp:114
#define G_IsActor(ent)
Definition g_local.h:127
#define G_IsVisibleForTeam(ent, team)
Definition g_local.h:144
#define G_TeamToVisMask(team)
Definition g_local.h:143
#define G_IsCivilian(ent)
Definition g_local.h:148
#define MAX_SPOT_DIST
Definition g_local.h:52
#define G_IsActiveCamera(ent)
Definition g_local.h:130
#define G_IsSmoke(ent)
Definition g_local.h:131
bool G_TestLineWithEnts(const vec3_t start, const vec3_t end)
fast version of a line trace including entities
Definition g_utils.cpp:237
Misc utility functions for game module.
void G_VisFlagsAdd(Edict &ent, teammask_t teamMask)
Definition g_vis.cpp:433
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
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
int G_VisCheckDist(const Edict *const ent)
Definition g_vis.cpp:163
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
static bool G_VisShouldStop(const Edict *ent)
Definition g_vis.cpp:277
static bool G_LineVis(const vec3_t from, const vec3_t to)
tests the visibility between two points
Definition g_vis.cpp:54
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 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
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
void G_VisFlagsReset(Edict &ent)
Definition g_vis.cpp:438
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
void G_VisFlagsSwap(Edict &ent, teammask_t teamMask)
Definition g_vis.cpp:443
bool G_SmokeVis(const vec3_t from, const Edict *check)
tests for smoke interference
Definition g_vis.cpp:65
void G_VisMakeEverythingVisible(void)
Make everything visible to anyone who can't already see it.
Definition g_vis.cpp:390
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
void G_CheckVisPlayer(Player &player, const vischeckflags_t visFlags)
Sets visible edict on player spawn.
Definition g_vis.cpp:327
float G_ActorVis(const Edict *ent, const Edict *check, bool full)
calculate how much check is "visible" by ent
Definition g_vis.cpp:100
#define ACTOR_VIS_100
Definition g_vis.h:61
#define VIS_STOP
Definition g_vis.h:40
#define VS_CHANGE
Definition g_vis.h:44
#define VIS_PERISH
Definition g_vis.h:38
#define ACTOR_VIS_0
Definition g_vis.h:64
#define ACTOR_VIS_10
Definition g_vis.h:63
#define VT_NOFRUSTUM
Definition g_vis.h:55
#define VIS_APPEAR
Definition g_vis.h:36
#define VT_PERISHCHK
Definition g_vis.h:53
unsigned int teammask_t
Definition g_vis.h:30
#define VS_YES
Definition g_vis.h:46
unsigned int vischeckflags_t
Definition g_vis.h:49
#define VT_NEW
Definition g_vis.h:58
#define ACTOR_VIS_50
Definition g_vis.h:62
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
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
bool RayIntersectAABB(const vec3_t start, const vec3_t end, const AABB &aabb)
Definition mathlib.cpp:1110
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
@ ET_ACTOR
Definition q_shared.h:148
@ ET_ACTOR2x2
Definition q_shared.h:160
@ ET_PARTICLE
Definition q_shared.h:164
@ ET_CAMERA
Definition q_shared.h:171
@ ET_ITEM
Definition q_shared.h:149
#define PLAYER_DEAD
Definition q_sizes.h:8
#define PLAYER_MIN
Definition q_sizes.h:9
#define PLAYER_CROUCH
Definition q_sizes.h:7
#define PLAYER_STAND
Definition q_sizes.h:6
QGL_EXTERN GLint i
Definition r_gl.h:113
vec_t vec3_t[3]
Definition ufotypes.h:39
#define VectorDist(a, b)
Definition vector.h:69
#define VectorCopy(src, dest)
Definition vector.h:51
#define VectorCompare(a, b)
Definition vector.h:63
#define VectorDistSqr(a, b)
Definition vector.h:68