Files
GTASource/game/script/script_areas.cpp

886 lines
26 KiB
C++
Raw Permalink Normal View History

2025-02-23 17:40:52 +08:00
#include "script/script_areas.h"
// Framework headers
#include "fwmaths/angle.h"
#include "fwmaths/Vector.h"
// Game headers
#include "frontend/minimap.h"
#include "physics/WorldProbe/worldprobe.h"
#include "scene/world/GameWorld.h"
#include "script/script.h"
#include "script/script_channel.h"
#include "script/script_debug.h"
#include "vfx/misc/Markers.h"
float CScriptAreas::ms_distThreshNear = 10.0f;
float CScriptAreas::ms_distThreshFar = 20.0f;
s32 CScriptAreas::ms_alphaNear = 140;
s32 CScriptAreas::ms_alphaFar = 160;
bool CScriptAreas::ms_arrowEnabled = false;
float CScriptAreas::ms_arrowOffsetZ = 3.1f;
float CScriptAreas::ms_arrowScaleNear = 0.3f;
float CScriptAreas::ms_arrowScaleFar = 0.3f;
float CScriptAreas::ms_cylinderOffsetZ = 1.85f;
float CScriptAreas::ms_cylinderScaleZNear = 0.5f;
float CScriptAreas::ms_cylinderScaleZFar = 1.0f;
float CScriptAreas::ms_cylinderScaleXYNear = 0.6f;
float CScriptAreas::ms_cylinderScaleXYFar = 0.6f;
Color32 CScriptAreas::OverrideMarkerColour = Color32(0, 0, 0, 0);
bool CScriptAreas::bOverrideMarkerColour = false;
void CScriptAreas::Init(unsigned initMode)
{
if(initMode == INIT_CORE)
{
}
else if(initMode == INIT_SESSION)
{
OverrideMarkerColour = Color32(0, 0, 0, 0);
bOverrideMarkerColour = false;
}
}
void CScriptAreas::Shutdown(unsigned shutdownMode)
{
if(shutdownMode == SHUTDOWN_CORE)
{
}
else if(shutdownMode == SHUTDOWN_SESSION)
{
}
}
void CScriptAreas::Process(void)
{
}
void CScriptAreas::SetOverrideMarkerColour(int Red, int Green, int Blue, int Alpha)
{
OverrideMarkerColour = Color32(Red, Green, Blue, Alpha);
bOverrideMarkerColour = true;
}
void CScriptAreas::HighlightScriptArea(Vector3 &vecCentre/*, float fWidth*/, int CalculationToUse)
{
if (!CGameWorld::FindLocalPlayer())
return;
Color32 MarkerColour = CMiniMap_Common::GetColourFromBlipSettings(BLIP_COLOUR_MISSION_MARKER, TRUE);
if (bOverrideMarkerColour)
{ // should only be set for CALCULATION_COLOURED_CYLINDER which is only used by the DRAW_COLOURED_CYLINDER script command
MarkerColour = OverrideMarkerColour;
bOverrideMarkerColour = false;
}
scriptAssertf(CTheScripts::GetCurrentGtaScriptThread(), "CTheScripts::HighlightScriptArea - can only call this from a script command");
Vec3V vCentrePos = Vec3V(vecCentre.x, vecCentre.y, vecCentre.z);
Vector3 playerPos = CGameWorld::FindLocalPlayerCentreOfWorld();
Vec3V vPlayerPos = RCC_VEC3V(playerPos);
float distToMarker = DistXY(vCentrePos, vPlayerPos).Getf();
float t = CVfxHelper::GetInterpValue(distToMarker, ms_distThreshNear, ms_distThreshFar);
s32 currAlpha = static_cast<s32>(ms_alphaNear + t*(ms_alphaFar-ms_alphaNear));
float currArrowScale = ms_arrowScaleNear + t*(ms_arrowScaleFar-ms_arrowScaleNear);
float currCylinderScaleXY = ms_cylinderScaleXYNear + t*(ms_cylinderScaleXYFar-ms_cylinderScaleXYNear);
float currCylinderScaleZ = ms_cylinderScaleZNear + t*(ms_cylinderScaleZFar-ms_cylinderScaleZNear);
// arrow
if (ms_arrowEnabled)
{
MarkerInfo_t markerInfo;
markerInfo.type = MARKERTYPE_ARROW;
markerInfo.vPos = Vec3V(vecCentre.x, vecCentre.y, vecCentre.z+ms_arrowOffsetZ);
markerInfo.vDir = Vec3V(V_ZERO);
markerInfo.vRot = Vec4V(0.0f, PI, 0.0f, 0.0f);
markerInfo.vScale = Vec3V(currArrowScale, currArrowScale, currArrowScale);
markerInfo.col = Color32(MarkerColour.GetRed(), MarkerColour.GetGreen(), MarkerColour.GetBlue(), currAlpha);
markerInfo.bounce = true;
markerInfo.faceCam = true;
g_markers.Register(markerInfo);
}
// cylinder
if (CalculationToUse==CALCULATION_ENTITY_AT_COORD)
{
MarkerInfo_t markerInfo;
markerInfo.type = MARKERTYPE_CYLINDER;
markerInfo.vPos = Vec3V(vecCentre.x, vecCentre.y, vecCentre.z+ms_cylinderOffsetZ);
markerInfo.vDir = Vec3V(V_ZERO);
markerInfo.vRot = Vec4V(V_ZERO);
markerInfo.vScale = Vec3V(currCylinderScaleXY, currCylinderScaleXY, currCylinderScaleZ);
markerInfo.col = Color32(MarkerColour.GetRed(), MarkerColour.GetGreen(), MarkerColour.GetBlue(), currAlpha/2);
markerInfo.txdIdx = -1;
markerInfo.texIdx = -1;
markerInfo.bounce = false;
markerInfo.rotate = false;
markerInfo.faceCam = false;
markerInfo.clip = false;
g_markers.Register(markerInfo);
}
}
float CScriptAreas::CalculateZ(float CentreX, float CentreY, float InZ, float Width, float Depth, bool Do3dCheck, int CalculationToUse)
{
float ReturnZ = 0.0f;
if (Do3dCheck)
{
switch (CalculationToUse)
{
case CALCULATION_ENTITY_IN_AREA :
case CALCULATION_ENTITY_AT_ENTITY :
case CALCULATION_OBJECT_IN_AREA :
case CALCULATION_PED_IN_AREA :
case CALCULATION_LOCATE_PED_OBJECT :
case CALCULATION_LOCATE_PED_CAR :
case CALCULATION_LOCATE_PED_PED :
case CALCULATION_THIS_PED_SHOOTING_IN_AREA : // Do3dCheck is always false for this one so should never get here
case CALCULATION_ANY_PED_SHOOTING_IN_AREA : // Do3dCheck is always true for this one // old calculation was ( (TargetZ1 + TargetZ2) * 0.5f)
case CALCULATION_CAR_IN_AREA :
case CALCULATION_COLOURED_CYLINDER :
{
ReturnZ = InZ; // Either the z of the target entity or the lower z of the area cuboid
}
break;
case CALCULATION_ENTITY_AT_COORD :
case CALCULATION_LOCATE_OBJECT :
case CALCULATION_LOCATE_PED :
case CALCULATION_LOCATE_CAR :
{
if (Depth < 0.0f) // InZ is the midpoint of the area cuboid
{
ReturnZ = InZ + Depth;
}
else
{
ReturnZ = InZ - Depth;
}
}
break;
default :
scriptAssertf(0, "CTheScripts::CalculateZ - unexpected value for CalculationToUse");
break;
}
}
else
{
// ReturnZ = WorldProbe::FindGroundZForCoord(CentreX, CentreY); // + 2.0f; // + 2.0f to make sure shadow is also cast on higher bits
// now the z check starting point from the point given by the level designer
#define MAX_DIFF_TO_LOOK_FOR (1.5f) // 1.5 metres is the max amount we look down from the original highest point found
// we need to look for 4 points and use the lowest:
float fNorth[4];
if (InZ <= INVALID_MINIMUM_WORLD_Z)
{
fNorth[0] = WorldProbe::FindGroundZForCoord(TOP_SURFACE, CentreX, CentreY+Width);
fNorth[1] = WorldProbe::FindGroundZForCoord(TOP_SURFACE, CentreX, CentreY-Width);
fNorth[2] = WorldProbe::FindGroundZForCoord(TOP_SURFACE, CentreX+Width, CentreY);
fNorth[3] = WorldProbe::FindGroundZForCoord(TOP_SURFACE, CentreX-Width, CentreY);
}
else
{
fNorth[0] = WorldProbe::FindGroundZFor3DCoord(TOP_SURFACE, CentreX, CentreY+Width, InZ);
fNorth[1] = WorldProbe::FindGroundZFor3DCoord(TOP_SURFACE, CentreX, CentreY-Width, InZ);
fNorth[2] = WorldProbe::FindGroundZFor3DCoord(TOP_SURFACE, CentreX+Width, CentreY, InZ);
fNorth[3] = WorldProbe::FindGroundZFor3DCoord(TOP_SURFACE, CentreX-Width, CentreY, InZ);
}
// ensure we have the highest we can find:
float HighestZ = fNorth[0];
for (s32 i = 1; i < 4; i++)
{
HighestZ = rage::Max(fNorth[i], HighestZ);
}
ReturnZ = HighestZ;
// now find the lowest point within MAX_DIFF_TO_LOOK_FOR of the highest point:
for (s32 i = 0; i < 4; i++)
{
if (fNorth[i] > HighestZ-MAX_DIFF_TO_LOOK_FOR)
{
ReturnZ = rage::Min(fNorth[i], ReturnZ);
}
}
}
return ReturnZ;
}
// coordinates could be two corners or centre and (width, height, depth)
void CScriptAreas::NewHighlightImportantArea(float TargetX1, float TargetY1, float TargetZ1, float TargetX2, float TargetY2, float TargetZ2, bool Do3dCheck, int CalculationToUse)
{
Vector3 vecCentre = Vector3(0.0f, 0.0f, 0.0f);
float Width = 0.0f;
float Depth = 0.0f;
switch (CalculationToUse)
{
case CALCULATION_ENTITY_IN_AREA :
case CALCULATION_OBJECT_IN_AREA :
case CALCULATION_PED_IN_AREA :
case CALCULATION_THIS_PED_SHOOTING_IN_AREA :
case CALCULATION_ANY_PED_SHOOTING_IN_AREA :
case CALCULATION_CAR_IN_AREA :
{
vecCentre.x = (TargetX1 + TargetX2) * 0.5f;
vecCentre.y = (TargetY1 + TargetY2) * 0.5f;
Width = MAX( (TargetX2 - vecCentre.x), (TargetY2 - vecCentre.y) );
Depth = 0.0f; // not required for these cases
}
break;
case CALCULATION_ENTITY_AT_COORD :
case CALCULATION_ENTITY_AT_ENTITY :
case CALCULATION_LOCATE_OBJECT :
case CALCULATION_LOCATE_PED_OBJECT :
case CALCULATION_LOCATE_PED_CAR :
case CALCULATION_LOCATE_PED_PED :
case CALCULATION_LOCATE_PED :
case CALCULATION_LOCATE_CAR :
case CALCULATION_COLOURED_CYLINDER :
{ // TargetX2, TargetY2, TargetZ2 are actually Width, Height, Depth
vecCentre.x = TargetX1;
vecCentre.y = TargetY1;
Width = MAX( TargetX2, TargetY2 );
Depth = TargetZ2;
}
break;
default :
scriptAssertf(0, "CTheScripts::NewHighlightImportantArea - unexpected value for CalculationToUse");
break;
}
vecCentre.z = CalculateZ(vecCentre.x, vecCentre.y, TargetZ1, Width, Depth, Do3dCheck, CalculationToUse);
HighlightScriptArea(vecCentre/*, Width*/,CalculationToUse);
}
// Name : CTheScripts::HighlightImportantAngledArea
// Purpose : Highlights an area of the map which is important in a mission
// Parameters : A unique ID for the area and it's coordinates
// Returns : nothing
void CScriptAreas::HighlightImportantAngledArea(u32 UNUSED_PARAM(AreaID), float X1, float Y1, float X2, float Y2,
float X3, float Y3, float X4, float Y4, float CentreZ)
{
Vector3 Temp;
float Centre1X = (X1 + X2) * 0.5f;
float Centre1Y = (Y1 + Y2) * 0.5f;
float Centre2X = (X2 + X3) * 0.5f;
float Centre2Y = (Y2 + Y3) * 0.5f;
float Centre3X = (X3 + X4) * 0.5f;
float Centre3Y = (Y3 + Y4) * 0.5f;
float Centre4X = (X4 + X1) * 0.5f;
float Centre4Y = (Y4 + Y1) * 0.5f;
float MinX = MIN(Centre1X, Centre2X);
float MaxX = MAX(Centre1X, Centre2X);
float MinY = MIN(Centre1Y, Centre2Y);
float MaxY = MAX(Centre1Y, Centre2Y);
MinX = MIN(MinX, Centre3X);
MinX = MIN(MinX, Centre4X);
MaxX = MAX(MaxX, Centre3X);
MaxX = MAX(MaxX, Centre4X);
MinY = MIN(MinY, Centre3Y);
MinY = MIN(MinY, Centre4Y);
MaxY = MAX(MaxY, Centre3Y);
MaxY = MAX(MaxY, Centre4Y);
Temp.x = (MinX + MaxX) * 0.5f;
Temp.y = (MinY + MaxY) * 0.5f;
// Temp.z = FindPlayerCoors().z;
if (CentreZ <= INVALID_MINIMUM_WORLD_Z)
{
Temp.z = WorldProbe::FindGroundZForCoord(TOP_SURFACE, Temp.x, Temp.y);
}
else
{
Temp.z = CentreZ;
}
HighlightScriptArea(Temp/*, MAX( (MaxX - Temp.x), (MaxY - Temp.y ) )*/, -1);
}
bool CScriptAreas::IsVecIn2dAngledArea(const Vector3& vecPos, float TargetX1, float TargetY1, float TargetX2, float TargetY2, float DistanceFrom1To4, bool bDrawDebug)
{
float RadiansBetweenFirstTwoPoints = fwAngle::GetRadianAngleBetweenPoints(TargetX1, TargetY1, TargetX2, TargetY2);
float RadiansBetweenPoints1and4 = RadiansBetweenFirstTwoPoints + (PI / 2);
while (RadiansBetweenPoints1and4 < 0.0f)
{
RadiansBetweenPoints1and4 += (2 * PI);
}
while (RadiansBetweenPoints1and4 > (2 * PI))
{
RadiansBetweenPoints1and4 -= (2 * PI);
}
float TargetX3 = (DistanceFrom1To4 * rage::Sinf(RadiansBetweenPoints1and4)) + TargetX2;
float TargetY3 = (DistanceFrom1To4 * -rage::Cosf(RadiansBetweenPoints1and4)) + TargetY2;
float TargetX4 = (DistanceFrom1To4 * rage::Sinf(RadiansBetweenPoints1and4)) + TargetX1;
float TargetY4 = (DistanceFrom1To4 * -rage::Cosf(RadiansBetweenPoints1and4)) + TargetY1;
Vector2 vec1To2 = Vector2((TargetX2 - TargetX1), (TargetY2 - TargetY1));
Vector2 vec1To4 = Vector2((TargetX4 - TargetX1), (TargetY4 - TargetY1));
float DistanceFrom1To2 = vec1To2.Mag();
float DistanceFrom1To4Test = vec1To4.Mag();
Vector2 vec1ToPos = Vector2((vecPos.x - TargetX1), (vecPos.y - TargetY1));
vec1To2.Normalize();
float TestDistance = vec1ToPos.Dot(vec1To2);
//////////////////////////
bool IsWithinRange = FALSE;
// Check that the position Passed is within the specified area
if ((TestDistance >= 0.0f) && (TestDistance <= DistanceFrom1To2))
{
vec1To4.Normalize();
TestDistance = vec1ToPos.Dot(vec1To4);
if ((TestDistance >= 0.0f)
&& (TestDistance <= DistanceFrom1To4Test))
{
IsWithinRange = TRUE;
}
}
if (bDrawDebug)
{
CScriptDebug::DrawDebugAngledSquare(TargetX1, TargetY1, TargetX2, TargetY2, TargetX3, TargetY3, TargetX4, TargetY4);
}
return IsWithinRange;
}
bool CScriptAreas::IsVecIn3dAngledArea(const Vector3& vecPointToBeChecked, const Vector3& vecFacePoint1, const Vector3& vecFacePoint2, float fDistanceToOppositeFace, bool bDrawDebug)
{
float TargetZ1 = vecFacePoint1.z;
float TargetZ2 = vecFacePoint2.z;
if (TargetZ1 > TargetZ2)
{
float temp_float = TargetZ1;
TargetZ1 = TargetZ2;
TargetZ2 = temp_float;
}
if ((vecPointToBeChecked.z >= TargetZ1) && (vecPointToBeChecked.z <= TargetZ2))
{
if (IsVecIn2dAngledArea(vecPointToBeChecked, vecFacePoint1.x, vecFacePoint1.y, vecFacePoint2.x, vecFacePoint2.y, fDistanceToOppositeFace, bDrawDebug))
{
return true;
}
}
return false;
}
bool CScriptAreas::IsPointInAngledArea(const Vector3& vPoint, Vector3& vAreaStart, Vector3& vAreaEnd, float AreaWidth, bool HighlightArea, bool Do3dCheck, bool bDrawDebug)
{
// Tests if the given entity is contained within a non-axis aligned rectangle which is defined by the midpoints of two parallel edges
// and the length of those sides:
//
// <--AreaWidth-->
// vAreaStart
// -------x-------
// | |
// | |
// -------x-------
// vAreaEnd
bool bResult = false;
Vector3 temp_vec;
float RadiansBetweenFirstTwoPoints;
float RadiansBetweenPoints1and4;
float TestDistance;
Vector2 vec1ToEntity;
float DistanceFrom1To2, DistanceFrom1To4Test;
if (Do3dCheck)
{
if (vAreaStart.z > vAreaEnd.z)
{
temp_vec = vAreaStart;
vAreaStart = vAreaEnd;
vAreaEnd = temp_vec;
}
}
else
{
vAreaStart.z = INVALID_MINIMUM_WORLD_Z;
vAreaEnd.z = vAreaStart.z;
}
// calculate the angle between vectors
RadiansBetweenFirstTwoPoints = fwAngle::GetRadianAngleBetweenPoints(vAreaStart.x, vAreaStart.y, vAreaEnd.x, vAreaEnd.y);
// get the right angle from these 2 points
RadiansBetweenPoints1and4 = RadiansBetweenFirstTwoPoints + (PI / 2);
//work out a right angle from point
while (RadiansBetweenPoints1and4 < 0.0f)
{
RadiansBetweenPoints1and4 += (2 * PI);
}
while (RadiansBetweenPoints1and4 > (2 * PI))
{
RadiansBetweenPoints1and4 -= (2 * PI);
}
//calculate the two points at right angles to the passed in vectors
const Vector2 vBottomLeft (((AreaWidth * 0.5f) * rage::Sinf(RadiansBetweenPoints1and4)) + vAreaStart.x, ((AreaWidth * 0.5f) * -rage::Cosf(RadiansBetweenPoints1and4)) + vAreaStart.y) ;
const Vector2 vBottomRight (((AreaWidth * 0.5f) * rage::Sinf(RadiansBetweenPoints1and4)) + vAreaEnd.x, ((AreaWidth * 0.5f) * -rage::Cosf(RadiansBetweenPoints1and4)) + vAreaEnd.y);
const Vector2 vTopLeft( vAreaStart.x, vAreaStart.y );
const Vector2 vTopRight( vAreaEnd.x, vAreaEnd.y );
//calculate the vectors across the locate and to one corner, used when checking against the players vector
Vector2 vec1To2 = vTopRight - vTopLeft;
Vector2 vec1To4 = vTopLeft - vBottomLeft;
// used for drawing the locate area
Vector2 vec1To4Copy = vec1To4;
DistanceFrom1To2 = vec1To2.Mag();
DistanceFrom1To4Test = vec1To4.Mag();
vec1ToEntity = Vector2((vPoint.x - vTopLeft.x), (vPoint.y - vTopLeft.y));
vec1To2.Normalize();
TestDistance = vec1ToEntity.Dot(vec1To2);
// Check that the entity is within the specified area
if ((TestDistance >= 0.0f)
&& (TestDistance <= DistanceFrom1To2))
{
vec1To4.Normalize();
TestDistance = vec1ToEntity.Dot(vec1To4);
if (fabsf(TestDistance) <= DistanceFrom1To4Test)
{
if (Do3dCheck)
{
if ((vPoint.z >= vAreaStart.z) && (vPoint.z <= vAreaEnd.z))
{
bResult = true;
}
}
else
{
bResult = true;
}
}
}
if (HighlightArea)
{
if (Do3dCheck)
{
CScriptAreas::HighlightImportantAngledArea( (u32)(CTheScripts::GetCurrentGtaScriptThread()->GetIDForThisLineInThisThread()),
vAreaStart.x+ vec1To4Copy.x, vAreaStart.y+ vec1To4Copy.y,
vAreaEnd.x+ vec1To4Copy.x, vAreaEnd.y+ vec1To4Copy.y,
vBottomRight.x, vBottomRight.y,
vBottomLeft.x, vBottomLeft.y,
vAreaStart.z);
}
else
{
CScriptAreas::HighlightImportantAngledArea( (u32)(CTheScripts::GetCurrentGtaScriptThread()->GetIDForThisLineInThisThread()),
vAreaStart.x+ vec1To4Copy.x, vAreaStart.y+ vec1To4Copy.y,
vAreaEnd.x+ vec1To4Copy.x, vAreaEnd.y+ vec1To4Copy.y,
vBottomRight.x, vBottomRight.y,
vBottomLeft.x, vBottomLeft.y,
INVALID_MINIMUM_WORLD_Z);
}
}
if (bDrawDebug)
{
if (Do3dCheck)
{
CScriptDebug::DrawDebugAngledCube(vAreaStart.x + vec1To4Copy.x, vAreaStart.y + vec1To4Copy.y, vAreaStart.z, vAreaEnd.x + vec1To4Copy.x, vAreaEnd.y + vec1To4Copy.y, vAreaEnd.z, vBottomRight.x, vBottomRight.y,
vBottomLeft.x, vBottomLeft.y);
}
else
{
CScriptDebug::DrawDebugAngledSquare(vAreaStart.x+ vec1To4Copy.x, vAreaStart.y+ vec1To4Copy.y, vAreaEnd.x+ vec1To4Copy.x, vAreaEnd.y+ vec1To4Copy.y, vBottomRight.x, vBottomRight.y,
vBottomLeft.x, vBottomLeft.y);
}
}
return(bResult);
}
bool CScriptAreas::IsAngledAreaInAngledArea(Vector3& vArea1Start, Vector3& vArea1End, float Area1Width, bool Area1Do3dCheck, Vector3& vArea2Start, Vector3& vArea2End, float Area2Width, bool HighlightArea, bool Do3dCheck, bool bDrawDebug)
{
// Tests if the given area (1) is contained within a non-axis aligned rectangle which is defined by the midpoints of two parallel edges
// and the length of those sides:
//
// <--AreaWidth-->
// vAreaStart
// -------x-------
// | |
// | |
// -------x-------
// vAreaEnd
bool bResult = false;
Vector3 temp_vec;
float Area1RadiansBetweenFirstTwoPoints;
float Area1RadiansBetweenPoints1and4;
float Area2RadiansBetweenFirstTwoPoints;
float Area2RadiansBetweenPoints1and4;
float TestDistance;
Vector2 vec1ToEntity;
float DistanceFrom1To2, DistanceFrom1To4Test;
if (Area1Do3dCheck == false && Do3dCheck == true)
{
// can't be contained (inner area is a 2d area, outer is 3d)
return false;
}
if (Do3dCheck)
{
if (vArea2Start.z > vArea2End.z)
{
temp_vec = vArea2Start;
vArea2Start = vArea2End;
vArea2End = temp_vec;
}
}
if (Area1Do3dCheck)
{
if (vArea1Start.z > vArea1End.z)
{
temp_vec = vArea1Start;
vArea1Start = vArea1End;
vArea1End = temp_vec;
}
}
// calculate the angle between vectors
Area2RadiansBetweenFirstTwoPoints = fwAngle::GetRadianAngleBetweenPoints(vArea2Start.x, vArea2Start.y, vArea2End.x, vArea2End.y);
// get the right angle from these 2 points
Area2RadiansBetweenPoints1and4 = Area2RadiansBetweenFirstTwoPoints + (PI / 2.0f);
//work out a right angle from point
while (Area2RadiansBetweenPoints1and4 < 0.0f)
{
Area2RadiansBetweenPoints1and4 += (2.0f * PI);
}
while (Area2RadiansBetweenPoints1and4 > (2.0f * PI))
{
Area2RadiansBetweenPoints1and4 -= (2.0f * PI);
}
//calculate the two points at right angles to the passed in vectors
const Vector2 vBottomLeft2 (((Area2Width * 0.5f) * rage::Sinf(Area2RadiansBetweenPoints1and4)) + vArea2Start.x, ((Area2Width * 0.5f) * -rage::Cosf(Area2RadiansBetweenPoints1and4)) + vArea2Start.y) ;
const Vector2 vBottomRight2 (((Area2Width * 0.5f) * rage::Sinf(Area2RadiansBetweenPoints1and4)) + vArea2End.x, ((Area2Width * 0.5f) * -rage::Cosf(Area2RadiansBetweenPoints1and4)) + vArea2End.y);
const Vector2 vTopLeft2( vArea2Start.x, vArea2Start.y );
const Vector2 vTopRight2( vArea2End.x, vArea2End.y );
//calculate the vectors across the locate and to one corner
Vector2 vec1To2 = vTopRight2 - vTopLeft2;
Vector2 vec1To4 = vTopLeft2 - vBottomLeft2;
// used for drawing the locate area
Vector2 vec1To4Copy = vec1To4;
// Only need to do the 3d check if the outer check area is 3d (if the inner is 3d it doesn't matter, would be contained in Z by a 2d check)
if (Do3dCheck && ((vArea1Start.z < vArea2Start.z) || (vArea1End.z > vArea2End.z)))
{
// failed the height test
bResult = false;
}
else
{
// calculate the angle between vectors
Area1RadiansBetweenFirstTwoPoints = fwAngle::GetRadianAngleBetweenPoints(vArea1Start.x, vArea1Start.y, vArea1End.x, vArea1End.y);
// get the right angle from these 2 points
Area1RadiansBetweenPoints1and4 = Area1RadiansBetweenFirstTwoPoints + (PI / 2.0f);
//work out a right angle from point
while (Area1RadiansBetweenPoints1and4 < 0.0f)
{
Area1RadiansBetweenPoints1and4 += (2.0f * PI);
}
while (Area1RadiansBetweenPoints1and4 > (2.0f * PI))
{
Area1RadiansBetweenPoints1and4 -= (2.0f * PI);
}
//calculate the two points at right angles to the passed in vectors
Vector2 area1vertices[4];
area1vertices[0].Set(((Area1Width * 0.5f) * rage::Sinf(Area1RadiansBetweenPoints1and4)) + vArea1Start.x, ((Area1Width * 0.5f) * -rage::Cosf(Area1RadiansBetweenPoints1and4)) + vArea1Start.y) ; //vBottomLeft1
area1vertices[1].Set(((Area1Width * 0.5f) * rage::Sinf(Area1RadiansBetweenPoints1and4)) + vArea1End.x, ((Area1Width * 0.5f) * -rage::Cosf(Area1RadiansBetweenPoints1and4)) + vArea1End.y); //vBottomRight1
area1vertices[2].Set( vArea1Start.x, vArea1Start.y ); //vTopLeft1
area1vertices[3].Set( vArea1End.x, vArea1End.y ); // vTopRight1
DistanceFrom1To2 = vec1To2.Mag();
DistanceFrom1To4Test = vec1To4.Mag();
for(int i=0;i<4 && bResult==true;i++)
{
vec1ToEntity = Vector2((area1vertices[i].x - vTopLeft2.x), (area1vertices[i].y - vTopLeft2.y));
vec1To2.Normalize();
TestDistance = vec1ToEntity.Dot(vec1To2);
// Check that the entity is within the specified area
if ((TestDistance < 0.0f) || (TestDistance > DistanceFrom1To2))
{
bResult = false;
break;
}
vec1To4.Normalize();
TestDistance = vec1ToEntity.Dot(vec1To4);
if (fabsf(TestDistance) > DistanceFrom1To4Test)
{
bResult = false;
break;
}
}
}
if (HighlightArea)
{
if (Do3dCheck)
{
CScriptAreas::HighlightImportantAngledArea( (u32)(CTheScripts::GetCurrentGtaScriptThread()->GetIDForThisLineInThisThread()),
vArea2Start.x+ vec1To4Copy.x, vArea2Start.y+ vec1To4Copy.y,
vArea2End.x+ vec1To4Copy.x, vArea2End.y+ vec1To4Copy.y,
vBottomRight2.x, vBottomRight2.y,
vBottomLeft2.x, vBottomLeft2.y,
vArea2Start.z);
}
else
{
CScriptAreas::HighlightImportantAngledArea( (u32)(CTheScripts::GetCurrentGtaScriptThread()->GetIDForThisLineInThisThread()),
vArea2Start.x+ vec1To4Copy.x, vArea2Start.y+ vec1To4Copy.y,
vArea2End.x+ vec1To4Copy.x, vArea2End.y+ vec1To4Copy.y,
vBottomRight2.x, vBottomRight2.y,
vBottomLeft2.x, vBottomLeft2.y,
INVALID_MINIMUM_WORLD_Z);
}
}
if (bDrawDebug)
{
if (Do3dCheck)
{
CScriptDebug::DrawDebugAngledCube(vArea2Start.x + vec1To4Copy.x, vArea2Start.y + vec1To4Copy.y, vArea2Start.z, vArea2End.x + vec1To4Copy.x, vArea2End.y + vec1To4Copy.y, vArea2End.z, vBottomRight2.x, vBottomRight2.y,
vBottomLeft2.x, vBottomLeft2.y);
}
else
{
CScriptDebug::DrawDebugAngledSquare(vArea2Start.x+ vec1To4Copy.x, vArea2Start.y+ vec1To4Copy.y, vArea2End.x+ vec1To4Copy.x, vArea2End.y+ vec1To4Copy.y, vBottomRight2.x, vBottomRight2.y,
vBottomLeft2.x, vBottomLeft2.y);
}
}
return(bResult);
}
CScriptAngledArea::CScriptAngledArea() { }
CScriptAngledArea::CScriptAngledArea(const Vector3 & vPt1, const Vector3 & vPt2, const float fWidth, Vector3 * pvOutMinMax)
{
Set(vPt1, vPt2, fWidth, pvOutMinMax);
}
void CScriptAngledArea::Set(const Vector3 & vPt1, const Vector3 & vPt2, const float fWidth, Vector3 * pvOutMinMax)
{
s32 e;
m_vPt1 = vPt1;
m_vPt2 = vPt2;
// Ensure that
if (m_vPt1.z > m_vPt2.z)
{
SwapEm(m_vPt1.z, m_vPt2.z);
}
if(m_vPt2.z - m_vPt1.z < 1.0f)
m_vPt2.z = m_vPt1.z + 1.0f;
m_vPt1.z -= 0.5f;
Vector3 vEdge3 = m_vPt2 - m_vPt1;
vEdge3.z = 0.0f;
vEdge3.Normalize();
Vector3 vNormal3 = CrossProduct(ZAXIS, vEdge3);
Vector3 vCorners3[4] =
{
m_vPt1 - (vNormal3 * fWidth * 0.5f),
m_vPt2 - (vNormal3 * fWidth * 0.5f),
m_vPt2 + (vNormal3 * fWidth * 0.5f),
m_vPt1 + (vNormal3 * fWidth * 0.5f)
};
Vector2 vCorners[4];
for(e=0; e<4; e++)
{
vCorners[e] = Vector2(vCorners3[e], Vector2::kXY);
}
s32 laste = 3;
for(e=0; e<4; e++)
{
Vector2 vEdge = vCorners[e] - vCorners[laste];
vEdge.Normalize();
Vector2 vNormal = Vector2(-vEdge.y, vEdge.x);
vEdgePlanes[e].x = vNormal.x;
vEdgePlanes[e].y = vNormal.y;
vEdgePlanes[e].z = - vNormal.Dot(vCorners[e]);
laste = e;
}
m_fWidth = fWidth;
if(pvOutMinMax)
{
Vector3 vMin(FLT_MAX, FLT_MAX, FLT_MAX);
Vector3 vMax(-FLT_MAX, -FLT_MAX, -FLT_MAX);
for(s32 s=0; s<4; s++)
{
vMin.x = Min(vMin.x, vCorners[s].x);
vMin.y = Min(vMin.y, vCorners[s].y);
vMax.x = Max(vMax.x, vCorners[s].x);
vMax.y = Max(vMax.y, vCorners[s].y);
}
pvOutMinMax[0] = vMin;
pvOutMinMax[1] = vMax;
}
}
bool CScriptAngledArea::TestPoint(const Vector3 & vPos) const
{
if(vPos.z < m_vPt1.z || vPos.z > m_vPt2.z)
return false;
for(s32 e=0; e<4; e++)
{
// Outside any edge plane?
if( (vEdgePlanes[e].x * vPos.x + vEdgePlanes[e].y * vPos.y) + vEdgePlanes[e].z < 0.0f )
{
return false;
}
}
return true;
}
void CScriptAngledArea::DebugDraw(const Color32 &colour)
{
Vector3 vAreaStart = m_vPt1;
Vector3 vAreaEnd = m_vPt2;
float RadiansBetweenFirstTwoPoints;
float RadiansBetweenPoints1and4;
Vector3 temp_vec;
if (vAreaStart.z > vAreaEnd.z)
{
temp_vec = vAreaStart;
vAreaStart = vAreaEnd;
vAreaEnd = temp_vec;
}
// calculate the angle between vectors
RadiansBetweenFirstTwoPoints = fwAngle::GetRadianAngleBetweenPoints(vAreaStart.x, vAreaStart.y, vAreaEnd.x, vAreaEnd.y);
// get the right angle from these 2 points
RadiansBetweenPoints1and4 = RadiansBetweenFirstTwoPoints + (PI / 2);
//work out a right angle from point
while (RadiansBetweenPoints1and4 < 0.0f)
{
RadiansBetweenPoints1and4 += (2 * PI);
}
while (RadiansBetweenPoints1and4 > (2 * PI))
{
RadiansBetweenPoints1and4 -= (2 * PI);
}
const Vector2 vBottomLeft (((m_fWidth * 0.5f) * rage::Sinf(RadiansBetweenPoints1and4)) + vAreaStart.x, ((m_fWidth * 0.5f) * -rage::Cosf(RadiansBetweenPoints1and4)) + vAreaStart.y) ;
const Vector2 vBottomRight (((m_fWidth * 0.5f) * rage::Sinf(RadiansBetweenPoints1and4)) + vAreaEnd.x, ((m_fWidth * 0.5f) * -rage::Cosf(RadiansBetweenPoints1and4)) + vAreaEnd.y);
const Vector2 vTopLeft( vAreaStart.x, vAreaStart.y );
const Vector2 vTopRight( vAreaEnd.x, vAreaEnd.y );
//calculate the vectors across the locate and to one corner, used when checking against the players vector
// Vector2 vec1To2 = vTopRight - vTopLeft;
Vector2 vec1To4 = vTopLeft - vBottomLeft;
// used for drawing the locate area
Vector2 vec1To4Copy = vec1To4;
CScriptDebug::DrawDebugAngledCube(vAreaStart.x + vec1To4Copy.x,
vAreaStart.y + vec1To4Copy.y,
vAreaStart.z,
vAreaEnd.x + vec1To4Copy.x,
vAreaEnd.y + vec1To4Copy.y,
vAreaEnd.z,
vBottomRight.x,
vBottomRight.y,
vBottomLeft.x,
vBottomLeft.y, colour);
}