g_vis.c

Go to the documentation of this file.
00001 
00005 /*
00006 Copyright (C) 2002-2010 UFO: Alien Invasion.
00007 
00008 This program is free software; you can redistribute it and/or
00009 modify it under the terms of the GNU General Public License
00010 as published by the Free Software Foundation; either version 2
00011 of the License, or (at your option) any later version.
00012 
00013 This program is distributed in the hope that it will be useful,
00014 but WITHOUT ANY WARRANTY; without even the implied warranty of
00015 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
00016 
00017 See the GNU General Public License for more details.
00018 
00019 You should have received a copy of the GNU General Public License
00020 along with this program; if not, write to the Free Software
00021 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
00022 
00023 */
00024 
00025 #include "g_local.h"
00026 
00031 qboolean G_FrustumVis (const edict_t *from, const vec3_t point)
00032 {
00033     return FrustumVis(from->origin, from->dir, point);
00034 }
00035 
00042 static qboolean G_LineVis (const vec3_t from, const vec3_t to)
00043 {
00044     return G_TestLineWithEnts(from, to);
00045 }
00046 
00063 float G_ActorVis (const vec3_t from, const edict_t *check, qboolean full)
00064 {
00065     vec3_t test, dir;
00066     float delta;
00067     int i, n;
00068 
00069     /* start on eye height */
00070     VectorCopy(check->origin, test);
00071     if (G_IsDead(check)) {
00072         test[2] += PLAYER_DEAD;
00073         delta = 0;
00074     } else if (G_IsCrouched(check)) {
00075         test[2] += PLAYER_CROUCH - 2;
00076         delta = (PLAYER_CROUCH - PLAYER_MIN) / 2 - 2;
00077     } else {
00078         test[2] += PLAYER_STAND;
00079         delta = (PLAYER_STAND - PLAYER_MIN) / 2 - 2;
00080     }
00081 
00082     /* side shifting -> better checks */
00083     dir[0] = from[1] - check->origin[1];
00084     dir[1] = check->origin[0] - from[0];
00085     dir[2] = 0;
00086     VectorNormalize(dir);
00087     VectorMA(test, -7, dir, test);
00088 
00089     /* do 3 tests */
00090     n = 0;
00091     for (i = 0; i < 3; i++) {
00092         if (!G_LineVis(from, test)) {
00093             if (full)
00094                 n++;
00095             else
00096                 return ACTOR_VIS_100;
00097         }
00098 
00099         /* look further down or stop */
00100         if (!delta) {
00101             if (n > 0)
00102                 return ACTOR_VIS_100;
00103             else
00104                 return ACTOR_VIS_0;
00105         }
00106         VectorMA(test, 7, dir, test);
00107         test[2] -= delta;
00108     }
00109 
00110     /* return factor */
00111     switch (n) {
00112     case 0:
00113         return ACTOR_VIS_0;
00114     case 1:
00115         return ACTOR_VIS_10;
00116     case 2:
00117         return ACTOR_VIS_50;
00118     default:
00119         return ACTOR_VIS_100;
00120     }
00121 }
00122 
00132 float G_Vis (const int team, const edict_t *from, const edict_t *check, int flags)
00133 {
00134     vec3_t eye;
00135 
00136     /* if any of them isn't in use, then they're not visible */
00137     if (!from->inuse || !check->inuse)
00138         return ACTOR_VIS_0;
00139 
00140     /* only actors and 2x2 units can see anything */
00141     if (!G_IsLivingActor(from))
00142         return ACTOR_VIS_0;
00143 
00144     /* living team members are always visible */
00145     if (team >= 0 && check->team == team && !G_IsDead(check))
00146         return ACTOR_VIS_100;
00147 
00148     /* standard team rules */
00149     if (team >= 0 && from->team != team)
00150         return ACTOR_VIS_0;
00151 
00152     /* inverse team rules */
00153     if (team < 0 && (from->team == -team || G_IsCivilian(from) || check->team != -team))
00154         return ACTOR_VIS_0;
00155 
00156     /* check for same pos */
00157     if (VectorCompare(from->pos, check->pos))
00158         return ACTOR_VIS_100;
00159 
00160     if (!G_IsVisibleOnBattlefield(check))
00161         return ACTOR_VIS_0;
00162 
00163     /* view distance check */
00164     if (VectorDistSqr(from->origin, check->origin) > MAX_SPOT_DIST * MAX_SPOT_DIST)
00165         return ACTOR_VIS_0;
00166 
00167     /* view frustum check */
00168     if (!(flags & VT_NOFRUSTUM) && !G_FrustumVis(from, check->origin))
00169         return ACTOR_VIS_0;
00170 
00171     /* get viewers eye height */
00172     VectorCopy(from->origin, eye);
00173     if (G_IsCrouched(from) || G_IsPaniced(from))
00174         eye[2] += EYE_CROUCH;
00175     else
00176         eye[2] += EYE_STAND;
00177 
00178     /* line trace check */
00179     switch (check->type) {
00180     case ET_ACTOR:
00181     case ET_ACTOR2x2:
00182         return G_ActorVis(eye, check, qfalse);
00183     case ET_ITEM:
00184     case ET_PARTICLE:
00185         return !G_LineVis(eye, check->origin);
00186     default:
00187         return ACTOR_VIS_0;
00188     }
00189 }
00190 
00205 int G_TestVis (const int team, edict_t * check, int flags)
00206 {
00207     edict_t *from = NULL;
00208     /* store old flag */
00209     const int old = G_IsVisibleForTeam(check, team) ? 1 : 0;
00210 
00211     if (g_aidebug->integer)
00212         return VIS_YES | !old;
00213 
00214     if (!(flags & VT_PERISH) && old)
00215         return VIS_YES;
00216 
00217     /* test if check is visible */
00218     while ((from = G_EdictsGetNextInUse(from)))
00219         if (G_Vis(team, from, check, flags))
00220             /* visible */
00221             return VIS_YES | !old;
00222 
00223     /* just return the old state */
00224     return old;
00225 }
00226 
00227 static qboolean G_VisShouldStop (const edict_t *ent)
00228 {
00229     return G_IsLivingActor(ent) && !G_IsCivilian(ent);
00230 }
00231 
00232 static int G_DoTestVis (const int team, edict_t * check, qboolean perish, int playerMask, const edict_t *ent)
00233 {
00234     int status = 0;
00235     const int visFlags = perish ? VT_PERISH : 0;
00236     const int vis = G_TestVis(team, check, visFlags);
00237 
00238     /* visibility has changed ... */
00239     if (vis & VIS_CHANGE) {
00240         /* swap the vis mask for the given team */
00241         check->visflags ^= G_TeamToVisMask(team);
00242         G_AppearPerishEvent(playerMask, vis & VIS_YES, check, ent);
00243 
00244         /* ... to visible */
00245         if (vis & VIS_YES) {
00246             status |= VIS_APPEAR;
00247             if (G_VisShouldStop(check))
00248                 status |= VIS_STOP;
00249         } else
00250             status |= VIS_PERISH;
00251     }
00252     return status;
00253 }
00254 
00261 int G_CheckVisPlayer (player_t* player, qboolean perish)
00262 {
00263     int status = 0;
00264     edict_t* ent = NULL;
00265 
00266     /* check visibility */
00267     while ((ent = G_EdictsGetNextInUse(ent))) {
00268         /* check if he's visible */
00269         status |= G_DoTestVis(player->pers.team, ent, perish, G_PlayerToPM(player), NULL);
00270     }
00271 
00272     return status;
00273 }
00274 
00298 int G_CheckVisTeam (const int team, edict_t *check, qboolean perish, const edict_t *ent)
00299 {
00300     int status = 0;
00301 
00302     /* check visibility */
00303     if (check->inuse) {
00304         /* check if he's visible */
00305         status |= G_DoTestVis(team, check, perish, G_TeamToPM(team), ent);
00306     }
00307 
00308     return status;
00309 }
00310 
00314 int G_CheckVisTeamAll (const int team, qboolean perish, const edict_t *ent)
00315 {
00316     edict_t *chk = NULL;
00317     int status = 0;
00318 
00319     while ((chk = G_EdictsGetNextInUse(chk))) {
00320         status |= G_CheckVisTeam(team, chk, perish, ent);
00321     }
00322     return status;
00323 }
00324 
00334 int G_CheckVis (edict_t * check, qboolean perish)
00335 {
00336     int team;
00337     int status;
00338 
00339     status = 0;
00340     for (team = 0; team < MAX_TEAMS; team++)
00341         if (level.num_alive[team]) {
00342             if (!check) /* no special entity given, so check them all */
00343                 status |= G_CheckVisTeamAll(team, perish, NULL);
00344             else
00345                 status |= G_CheckVisTeam(team, check, perish, NULL);
00346         }
00347 
00348     return status;
00349 }
00350 
00355 void G_ClearVisFlags (int team)
00356 {
00357     edict_t *ent = NULL;
00358     int mask;
00359 
00360     mask = ~G_TeamToVisMask(team);
00361     while ((ent = G_EdictsGetNextInUse(ent)))
00362         ent->visflags &= mask;
00363 }

Generated by  doxygen 1.6.2