libvwad: updated -- vwadwrite: free file buffers on close (otherwise archive creation...
[k8vavoom.git] / source / psim / p_entity_sight.cpp
blobab4a01e8e66fa79fa9b99902354e8f01cd132c1b
1 //**************************************************************************
2 //**
3 //** ## ## ## ## ## #### #### ### ###
4 //** ## ## ## ## ## ## ## ## ## ## #### ####
5 //** ## ## ## ## ## ## ## ## ## ## ## ## ## ##
6 //** ## ## ######## ## ## ## ## ## ## ## ### ##
7 //** ### ## ## ### ## ## ## ## ## ##
8 //** # ## ## # #### #### ## ##
9 //**
10 //** Copyright (C) 1999-2006 Jānis Legzdiņš
11 //** Copyright (C) 2018-2023 Ketmar Dark
12 //**
13 //** This program is free software: you can redistribute it and/or modify
14 //** it under the terms of the GNU General Public License as published by
15 //** the Free Software Foundation, version 3 of the License ONLY.
16 //**
17 //** This program is distributed in the hope that it will be useful,
18 //** but WITHOUT ANY WARRANTY; without even the implied warranty of
19 //** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 //** GNU General Public License for more details.
21 //**
22 //** You should have received a copy of the GNU General Public License
23 //** along with this program. If not, see <http://www.gnu.org/licenses/>.
24 //**
25 //**************************************************************************
26 //**
27 //** LineOfSight/Visibility checks, uses REJECT Lookup Table.
28 //**
29 //** This uses specialized forms of the maputils routines for optimized
30 //** performance
31 //**
32 //**************************************************************************
33 #include "../gamedefs.h"
34 #include "p_entity.h"
37 static VCvarB compat_better_sight("compat_better_sight", true, "Check more points in LOS calculations?", CVAR_Archive);
38 static VCvarB dbg_disable_cansee("dbg_disable_cansee", false, "Disable CanSee processing (for debug)?", CVAR_PreInit|CVAR_NoShadow);
40 //k8: for some reason, sight checks ignores base sector region
41 // i don't think that this is a right thing to do, so i removed that
44 //==========================================================================
46 // VEntity::CanSeeEx
48 // LineOfSight/Visibility checks, uses REJECT Lookup Table. This uses
49 // specialised forms of the maputils routines for optimized performance
50 // Returns true if a straight line between t1 and t2 is unobstructed.
52 //==========================================================================
53 bool VEntity::CanSee (VEntity *Other, bool forShooting, bool alwaysBetter) {
54 return CanSeeEx(Other, (forShooting ? CSE_ForShooting : CSE_NothingZero)|(alwaysBetter ? CSE_AlwaysBetter : CSE_NothingZero)|CSE_CheckBaseRegion);
58 //==========================================================================
60 // VEntity::CanSeeEx
62 // LineOfSight/Visibility checks, uses REJECT Lookup Table. This uses
63 // specialised forms of the maputils routines for optimized performance
64 // Returns true if a straight line between t1 and t2 is unobstructed.
66 //==========================================================================
67 bool VEntity::CanSeeEx (VEntity *Other, unsigned flags) {
68 if (dbg_disable_cansee) return false;
70 if (Other == this) return true; // it can see itself (obviously)
72 // if we have no base sector for any object, it cannot see each other
73 if (!Other || !Other->BaseSector || !BaseSector) return false;
74 if (IsGoingToDie() || Other->IsGoingToDie()) return false;
76 // first check for trivial rejection
77 if (XLevel->IsRejectedVis(BaseSector, Other->BaseSector)) return false; // can't possibly be connected
79 // killough 11/98: shortcut for melee situations
80 // same subsector? obviously visible
81 // this is not true for base sectors, though
82 if (SubSector == Other->SubSector) {
83 // if we have some 3d pobjs or 3d floors at this subsector, do not early exit
84 if (!SubSector->Has3DPObjs() && !SubSector->sector->HasAnyExtraFloors()) return true;
85 // check for the same polyobject
86 if (SubSector->isInnerPObj()) {
87 // two entities can have some 3d pobj subsector only if they're on or inside a pobj
88 //const float pz1 = SubSector->sector->ownpobj->poceiling.maxz;
89 //if (Origin.z == pz1 || Other.Origin.z == pz1) return true;
90 return true;
94 bool forShooting = !!(flags&CSE_ForShooting);
95 bool alwaysBetter = !!(flags&CSE_AlwaysBetter);
97 if (alwaysBetter) forShooting = false;
99 bool cbs = (!forShooting && (alwaysBetter || compat_better_sight));
101 if (cbs && !alwaysBetter) {
102 // turn off "better sight" if it is not forced, and neither entity is monster
103 //cbs = (IsPlayerOrMonster() && Other->IsPlayerOrMonster());
104 cbs = (IsMonster() || Other->IsMonster());
105 //if (!cbs) GCon->Logf(NAME_Debug, "%s: better sight forced to 'OFF', checking sight to '%s' (not a player, not a monster)", GetClass()->GetName(), Other->GetClass()->GetName());
108 // if too far, don't do "better sight" (it doesn't worth it anyway)
109 if (cbs) {
110 const float distSq = (Origin-Other->Origin).length2DSquared();
111 cbs = (distSq < 680.0*680.0); // arbitrary number
112 //if (!cbs) GCon->Logf(NAME_Debug, "%s: better sight forced to 'OFF', checking sight to '%s' (dist=%g)", GetClass()->GetName(), Other->GetClass()->GetName(), sqrtf(distSq));
115 TVec dirF, dirR;
116 if (cbs) {
117 //dirR = YawVectorRight(Angles.yaw);
118 TVec dirU;
119 TAVec ang;
120 ang.yaw = Angles.yaw;
121 ang.pitch = 0.0f;
122 ang.roll = 0.0f;
123 AngleVectors(ang, dirF, dirR, dirU);
124 } else {
125 dirF = dirR = TVec::ZeroVector;
127 //if (forShooting) dirR = TVec::ZeroVector; // just in case, lol
128 return XLevel->CastCanSee(BaseSubSector, Origin, Height, dirF, dirR, Other->Origin, Other->GetMoveRadius(), Other->Height,
129 !(flags&CSE_CheckBaseRegion)/*skip base region*/, Other->BaseSubSector, /*alwaysBetter*/cbs,
130 !!(flags&CSE_IgnoreBlockAll), !!(flags&CSE_IgnoreFakeFloors));
135 //==========================================================================
137 // Script natives
139 //==========================================================================
140 IMPLEMENT_FUNCTION(VEntity, CanSee) {
141 VEntity *Other;
142 VOptParamBool disableBetterSight(false);
143 vobjGetParamSelf(Other, disableBetterSight);
144 //if (!Self) { VObject::VMDumpCallStack(); Sys_Error("empty `self`!"); }
145 RET_BOOL(Self->CanSee(Other, disableBetterSight));
148 IMPLEMENT_FUNCTION(VEntity, CanSeeAdv) {
149 VEntity *Other;
150 vobjGetParamSelf(Other);
151 //if (!Self) { VObject::VMDumpCallStack(); Sys_Error("empty `self`!"); }
152 RET_BOOL(Self->CanSee(Other, false, true));
155 IMPLEMENT_FUNCTION(VEntity, CanShoot) {
156 VEntity *Other;
157 vobjGetParamSelf(Other);
158 //if (!Self) { VObject::VMDumpCallStack(); Sys_Error("empty `self`!"); }
159 RET_BOOL(Self->CanShoot(Other));