PHP Code:
bool:IsAbleToSee(entity, client)
{
// Skip all traces if the player isn't within the field of view.
// - Temporarily disabled until eye angle prediction is added.
// if (IsInFieldOfView(g_vEyePos[client], g_vEyeAngles[client], g_vAbsCentre[entity]))
decl Float:vecOrigin[3], Float:vecEyePos[3];
GetClientAbsOrigin(entity, vecOrigin);
GetClientEyePosition(client, vecEyePos);
// Check if centre is visible.
if (IsPointVisible(vecEyePos, vecOrigin))
{
return true;
}
decl Float:vecEyePos_ent[3], Float:vecEyeAng[3];
GetClientEyeAngles(entity, vecEyeAng);
GetClientEyePosition(entity, vecEyePos_ent);
// Check if weapon tip is visible.
if (IsFwdVecVisible(vecEyePos, vecEyeAng, vecEyePos_ent))
{
return true;
}
decl Float:mins[3], Float:maxs[3];
GetClientMins(client, mins);
GetClientMaxs(client, maxs);
// Check outer 4 corners of player.
if (IsRectangleVisible(vecEyePos, vecOrigin, mins, maxs, 1.30))
{
return true;
}
// Check inner 4 corners of player.
if (IsRectangleVisible(vecEyePos, vecOrigin, mins, maxs, 0.65))
{
return true;
}
return false;
}
stock bool:IsInFieldOfView(client, const Float:start[3], const Float:angles[3], Float:fov = 90.0)
{
decl Float:normal[3], Float:plane[3];
decl Float:end[3];
GetClientAbsOrigin(client, end);
GetAngleVectors(angles, normal, NULL_VECTOR, NULL_VECTOR);
SubtractVectors(end, start, plane);
NormalizeVector(plane, plane);
return GetVectorDotProduct(plane, normal) > Cosine(DegToRad(fov/2.0));
}
public bool:Filter_NoPlayers(entity, mask)
{
return (entity > MaxClients && !(0 < GetEntPropEnt(entity, Prop_Data, "m_hOwnerEntity") <= MaxClients));
}
bool:IsPointVisible(const Float:start[3], const Float:end[3])
{
TR_TraceRayFilter(start, end, MASK_VISIBLE, RayType_EndPoint, Filter_NoPlayers);
return TR_GetFraction() == 1.0;
}
bool:IsFwdVecVisible(const Float:start[3], const Float:angles[3], const Float:end[3])
{
decl Float:fwd[3];
GetAngleVectors(angles, fwd, NULL_VECTOR, NULL_VECTOR);
ScaleVector(fwd, 50.0);
AddVectors(end, fwd, fwd);
return IsPointVisible(start, fwd);
}
bool:IsRectangleVisible(const Float:start[3], const Float:end[3], const Float:mins[3], const Float:maxs[3], Float:scale=1.0)
{
new Float:ZpozOffset = maxs[2];
new Float:ZnegOffset = mins[2];
new Float:WideOffset = ((maxs[0] - mins[0]) + (maxs[1] - mins[1])) / 4.0;
// This rectangle is just a point!
if (ZpozOffset == 0.0 && ZnegOffset == 0.0 && WideOffset == 0.0)
{
return IsPointVisible(start, end);
}
// Adjust to scale.
ZpozOffset *= scale;
ZnegOffset *= scale;
WideOffset *= scale;
// Prepare rotation matrix.
decl Float:angles[3], Float:fwd[3], Float:right[3];
SubtractVectors(start, end, fwd);
NormalizeVector(fwd, fwd);
GetVectorAngles(fwd, angles);
GetAngleVectors(angles, fwd, right, NULL_VECTOR);
decl Float:vRectangle[4][3], Float:vTemp[3];
// If the player is on the same level as us, we can optimize by only rotating on the z-axis.
if (FloatAbs(fwd[2]) <= 0.7071)
{
ScaleVector(right, WideOffset);
// Corner 1, 2
vTemp = end;
vTemp[2] += ZpozOffset;
AddVectors(vTemp, right, vRectangle[0]);
SubtractVectors(vTemp, right, vRectangle[1]);
// Corner 3, 4
vTemp = end;
vTemp[2] += ZnegOffset;
AddVectors(vTemp, right, vRectangle[2]);
SubtractVectors(vTemp, right, vRectangle[3]);
}
else if (fwd[2] > 0.0) // Player is below us.
{
fwd[2] = 0.0;
NormalizeVector(fwd, fwd);
ScaleVector(fwd, scale);
ScaleVector(fwd, WideOffset);
ScaleVector(right, WideOffset);
// Corner 1
vTemp = end;
vTemp[2] += ZpozOffset;
AddVectors(vTemp, right, vTemp);
SubtractVectors(vTemp, fwd, vRectangle[0]);
// Corner 2
vTemp = end;
vTemp[2] += ZpozOffset;
SubtractVectors(vTemp, right, vTemp);
SubtractVectors(vTemp, fwd, vRectangle[1]);
// Corner 3
vTemp = end;
vTemp[2] += ZnegOffset;
AddVectors(vTemp, right, vTemp);
AddVectors(vTemp, fwd, vRectangle[2]);
// Corner 4
vTemp = end;
vTemp[2] += ZnegOffset;
SubtractVectors(vTemp, right, vTemp);
AddVectors(vTemp, fwd, vRectangle[3]);
}
else // Player is above us.
{
fwd[2] = 0.0;
NormalizeVector(fwd, fwd);
ScaleVector(fwd, scale);
ScaleVector(fwd, WideOffset);
ScaleVector(right, WideOffset);
// Corner 1
vTemp = end;
vTemp[2] += ZpozOffset;
AddVectors(vTemp, right, vTemp);
AddVectors(vTemp, fwd, vRectangle[0]);
// Corner 2
vTemp = end;
vTemp[2] += ZpozOffset;
SubtractVectors(vTemp, right, vTemp);
AddVectors(vTemp, fwd, vRectangle[1]);
// Corner 3
vTemp = end;
vTemp[2] += ZnegOffset;
AddVectors(vTemp, right, vTemp);
SubtractVectors(vTemp, fwd, vRectangle[2]);
// Corner 4
vTemp = end;
vTemp[2] += ZnegOffset;
SubtractVectors(vTemp, right, vTemp);
SubtractVectors(vTemp, fwd, vRectangle[3]);
}
// Run traces on all corners.
for (new i = 0; i < 4; i++)
{
if (IsPointVisible(start, vRectangle[i]))
{
return true;
}
}
return false;
}