Files
GTASource/game/frontend/MiniMap.cpp
expvintl 419f2e4752 init
2025-02-23 17:40:52 +08:00

9915 lines
296 KiB
C++

////////////////////////////////////////////////////////////////////////////////
//
// FILE : MiniMap.cpp
// PURPOSE : manages the Scaleform radar code
// AUTHOR : Derek Payne
// STARTED : 18/08/2010
//
/////////////////////////////////////////////////////////////////////////////////
// rage:
#include "parser/manager.h"
#include "grcore/viewport.h"
// fw:
#include "fwscript/scriptguid.h"
// game:
#include "audio/emitteraudioentity.h"
#include "audio/scriptaudioentity.h"
#include "frontend/ui_channel.h"
#include "MiniMap.h"
#include "camera/viewports/ViewportManager.h"
#include "camera/CamInterface.h"
#include "camera/cinematic/camera/mounted/CinematicMountedCamera.h"
#include "camera/debug/DebugDirector.h"
#include "Control/gamelogic.h"
#include "Control/gps.h"
#include "Core/Game.h"
#include "Cutscene/CutSceneManagerNew.h"
#include "debug/LightProbe.h"
#include "debug/TiledScreenCapture.h"
#include "frontend/FrontendStatsMgr.h" // for checking whether we need metric measurements or not
#include "frontend/GameStreamMgr.h"
#include "frontend/CMapMenu.h"
#include "frontend/MiniMapRenderThread.h"
#include "frontend/MobilePhone.h"
#include "frontend/NewHud.h"
#include "frontend/PauseMenu.h"
#include "frontend/WarningScreen.h"
#include "frontend/SocialClubMenu.h"
#include "frontend/Map/BlipEnums.h"
#include "frontend/Scaleform/ScaleformMgr.h"
#include "frontend/Store/StoreScreenMgr.h"
#include "modelinfo/PedModelInfo.h"
#include "vehicles/vehicle.h"
#include "vehicles/Submarine.h"
#include "vehicles/Heli.h"
#include "renderer/rendertargets.h"
#include "scene/world/GameWorld.h"
#include "scene/world/GameWorldHeightMap.h"
#include "physics/WaterTestHelper.h"
#include "text/TextConversion.h"
#include "Game/user.h"
#include "game/weather.h"
#include "peds/Ped.h"
#include "peds/PedDebugVisualiser.h"
#include "Peds/PedGeometryAnalyser.h"
#include "peds/PedIntelligence.h"
#include "pickups/Data/PickupDataManager.h"
#include "pickups/PickupManager.h"
#include "scene/EntityIterator.h"
#include "script/Handlers/GameScriptResources.h"
#include "script/script.h"
#include "script/script_hud.h"
#include "streaming/streamingvisualize.h"
#include "system/Control.h"
#include "system/controlMgr.h"
#include "system/param.h"
#include "task/Combat/TaskInvestigate.h"
#include "task/movement/TaskParachute.h"
#include "vehicles/Planes.h"
#include "vehicles/Bike.h"
#include "vehicles/AmphibiousAutomobile.h"
#include "vehicles/vehiclepopulation.h"
#include "vfx/misc/markers.h"
#include "frontend/Metadata_parser.h"
// Include and libs for SmartGlass stuff
#include "system/companion.h"
#if RSG_PC
#include "rline/rlpc.h"
#include "system/TamperActions.h"
#endif // RSG_PC
#if __BANK
#include "system/controlmgr.h"
#include "debug/VectorMap.h"
#endif // __BANK
#if DEBUG_PAD_INPUT
#include "debug/debug.h"
#endif // #if DEBUG_PAD_INPUT
FRONTEND_OPTIMISATIONS()
PF_PAGE(MiniMap, "MiniMap");
PF_GROUP(MiniMapSonar);
PF_LINK(MiniMap, MiniMapSonar);
PF_TIMER(AddSonarBlip, MiniMapSonar);
#define TIME_TO_ZOOM_OUT_MINIMAP (2000)
#if !__FINAL
PARAM(nominimap, "[code] hide minimap");
PARAM(revealmap, "[code] reveal map on boot");
#endif
#if __DEV
u32 iTimeTaken = 0;
#endif // __DEV
#if __BANK
enum
{
SONAR_STYLE_NONE = 0,
SONAR_STYLE_RED_BLIPS_SONAR,
SONAR_STYLE_RED_BLIPS_FLASH,
SONAR_STYLE_SONAR_ONLY,
SONAR_STYLE_RED_BLIPS_FLASH_5_SECONDS,
MAX_SONAR_STYLES
};
extern CWeather g_weather;
bool bDisplayInteriorInfoToLog = false;
bool bDebug3DBlips = false;
float s_fDebugForceTilesAroundPlayer = -2.0f;
Vector2 s_vDebugForceTilesAroundPlayer(-1.0f, -1.0f);
float fDebugTiltValue = -1.0f;
float fDebugOffsetValue = -1.0f;
bool bDebugAlwaysDrawSonarBlips = false;
bool bDebugDrawSonarBlipRange = false;
bool bDebugVisibilityOfSonarBlips = false;
bool s_bRenderMapPositions = false;
bool noUIAA = false;
bool noUIAAOnBitMap = true;
static s32 iDebugSonarStyle = SONAR_STYLE_RED_BLIPS_SONAR;
static bool bAllPedBlipsAsStealth = false;
static float s_fRadarZoomDistanceThisFrameWidget = 0.0f;
static bool s_bZoomToWaypointBlip = false;
//static Vector2 vMax2dRadarDistanceSquareTest(0.43f, 0.461f);
#endif // __BANK
#define MAX_BLIP_REFERENCE_INDEX (0xffff)
#define BLIP_REFERENCE_SHIFT (16)
#define BLIP_REFERENCE_MASK (0xffff0000)
#define DEFAULT_BLIP_FLASH_INTERVAL (500) // default blip flash time in milliseconds
#define XML_CORE_NODE_NAME "minimap"
#define XML_VERSION 1.0
CMiniMap::Tunables CMiniMap::sm_Tunables;
IMPLEMENT_MINIMAP_TUNABLES(CMiniMap, 0xb3bbe4a1);
sMiniReappearanceState CMiniMap::ms_MiniMapReappearanceState;
bool CMiniMap::ms_bIsHiddenAfterTransition = false;
//bool CMiniMap::bSkipBlipUpdate = false;
sMiniMapInterior CMiniMap::ms_previousInterior;
CBlipCones CMiniMap::ms_blipCones;
atArray<sMinimapFakeCone> CMiniMap::m_FakeCones;
atMap<int, eHUD_COLOURS> CMiniMap::m_ConeColors;
eSETUP_STATE CMiniMap::MinimapModeState = MINIMAP_MODE_STATE_NONE;
eSETUP_STATE CMiniMap::ms_pendingMinimapModeState = MINIMAP_MODE_STATE_NONE;
float CMiniMap::ms_fBlipZoom = 40.0f;
float CMiniMap::ms_fMapZoom = 0.0014f;
bool CMiniMap::ms_bBigMapFullZoom = false;
bool CMiniMap::ms_bBitmapInitialized = false;
bool CMiniMap::ms_bEntityWaypointAllowed = false;
eWaypointClearOnArrivalMode CMiniMap::ms_bWaypointClearOnArrivalMode = eWaypointClearOnArrivalMode::Enabled;
u16 CMiniMap::ms_waypointGpsFlags = 0;
sWaypointStruct CMiniMap::ms_Waypoint[MAX_WAYPOINT_MARKERS];
atMultiArray3d<sBitmapStruct> CMiniMap::ms_BitmapBackground;
sBitmapStruct CMiniMap::ms_BitmapSuperLowRes;
atFixedArray<sPointOfInterestStruct, MAX_POI_STANDARD_USER> CMiniMap::ms_PointOfInterest;
atArray<sMiniMapInteriorStruct> CMiniMap::sm_InteriorInfo;
bool CMiniMap::ms_bFoundMatchingOverrideInterior = false;
bool CMiniMap::ms_bBlipVisibilityHighDetail = false;
#if __BANK
bool CMiniMap::ms_g_bDisplayGameMiniMap = true;
bool CMiniMap::ms_bRenderMiniMapBackground = true;
bool CMiniMap::ms_bRenderMiniMapForeground = true;
float CMiniMap::ms_fDebugRange = 2.0f;
s32 CMiniMap::ms_iDebugInteriorHash = 0;
s32 CMiniMap::ms_iDebugInteriorLevel = sMiniMapInterior::INVALID_LEVEL;
s32 CMiniMap::ms_iDebugGolfCourseMap = -1;
bool CMiniMap::ms_bCullDistantBlips = true;
bool CMiniMap::ms_bShowBlipVectorMap = false;
bool CMiniMap::ms_bDebugDrawTiles = false;
bool CMiniMap::ms_bOverrideConeColour = false;
s32 CMiniMap::ms_ConeColourRed = 47;
s32 CMiniMap::ms_ConeColourGreen = 92;
s32 CMiniMap::ms_ConeColourBlue = 115;
s32 CMiniMap::ms_ConeColourAlpha = CMiniMap_Common::ALPHA_OF_POLICE_PERCEPTION_CONES;
float CMiniMap::ms_fConeFocusRangeMultiplier = 1.05f;
bool CMiniMap::ms_bDrawActualRangeCone = false;
s32 CMiniMap::ms_iDebugBlip = INVALID_BLIP_ID;
bool ms_bUseNewAwesomeAltimeter = true;
#else
#define ms_bUseNewAwesomeAltimeter true
#endif
// sMiniMapRenderStateStruct CMiniMap::MiniMapUpdateState;
#if __DEV
s32 CMiniMap::iNumCreatedTraces = 0;
u32 CMiniMap::iSizeOfBlipsCreated = 0;
#endif
atVector<sSonarBlipStruct> CMiniMap::ms_SonarBlips;
Vector3 CMiniMap::ms_vMapPosition;
float CMiniMap::ms_fMaxDistance = MINIMAP_DISTANCE_SCALER_2D;
bool CMiniMap::bVisible = true;
#if __BANK
bool CMiniMap::bDisplayAllBlipNames = false;
#endif // __BANK
#if __DEV
bool CMiniMap::ms_bRenderPedPerceptionCone = false;
#endif // __DEV
// private variables
bool CMiniMap::ms_bXmlDataHasBeenRead = false;
bool CMiniMap::ms_bCentreBlipPosChangedThisFrame = false;
s32 CMiniMap::ms_iCentreBlip = INVALID_BLIP_ID;
s32 CMiniMap::ms_iNorthBlip = INVALID_BLIP_ID;
s32 CMiniMap::ms_iMiniMapPedPoolIndex = 0;
// s32 CMiniMap::ms_iBlipHovering = -1;
CMiniMap::MiniMapDesc CMiniMap::sm_miniMaps[MAX_MINIMAP_VALUES];
bool CMiniMap::ms_bSonarBlipsActive = true;
//char CMiniMap::ms_cMiniMapFileName[MAX_MINIMAP_VALUES][MAX_LENGTH_OF_MINIMAP_FILENAME];
//Vector2 CMiniMap::ms_vMiniMapPosition[MAX_MINIMAP_VALUES];
//Vector2 CMiniMap::ms_vMiniMapSize[MAX_MINIMAP_VALUES];
bool CMiniMap::ms_bInStealthMode = false;
bool CMiniMap::ms_bHideBackgroundMap = false;
bool CMiniMap::ms_bBlockWaypoint = false;
bool CMiniMap::ms_bInPrologue = false;
bool CMiniMap::ms_bOnIslandMap = false;
bool CMiniMap::ms_bInPauseMap = false;
bool CMiniMap::ms_bInCustomMap = false;
bool CMiniMap::ms_bInBigMap = false;
bool CMiniMap::ms_bInGolfMap = false;
bool CMiniMap::ms_bIsRendering = false;
//bool CMiniMap::ms_bShowingGPSDisplay = false;
bool CMiniMap::ms_bShowingYoke = false;
bool CMiniMap::ms_bShowSonarSweep = false;
bool CMiniMap::ms_bAllowFoWInMP = false;
bool CMiniMap::ms_bRequestRevealFoW = false;
bool CMiniMap::ms_bBigMapFullScreen = false;
bool CMiniMap::ms_bIsWaypointLocal = false;
unsigned CMiniMap::ms_WaypointLocalDirtyTimestamp = 0;
bool CMiniMap::ms_bFlashWantedOverlay = false;
bool CMiniMap::ms_bForceSonarBlipsOn = false;
bool CMiniMap::ms_bUseWeaponRangeForMPSonarDistance = true;
u32 CMiniMap::ms_uFlashStartTime = 0u;
eHUD_COLOURS CMiniMap::ms_eFlashColour = HUD_COLOUR_WHITE;
KEYBOARD_MOUSE_ONLY(eALTIMETER_MODES CMiniMap::ms_iPrevAltimeterMode = ALTIMETER_OFF;)
eGOLF_COURSE_HOLES CMiniMap::ms_iGolfCourseMap = GOLF_COURSE_OFF;
s32 CMiniMap::ms_iLockedMiniMapAngle = -1;
Vector2 CMiniMap::ms_vLockedMiniMapPosition = Vector2(-9999.0f,-9999.0f);
Vector2 CMiniMap::ms_vPauseMenuMapCursor;
float CMiniMap::ms_fPauseMenuMapScale;
s32 CMiniMap::iSimpleBlip = -1;
u16 CMiniMap::iReferenceCount = 0;
bool CMiniMap::bActive = false;
s32 CMiniMap::iMovieId[MAX_MINIMAP_MOVIE_LAYERS];
CMiniMapBlip *CMiniMap::blip[MAX_NUM_BLIPS];
s32 CMiniMap::iMaxCreatedBlips = 0;
// float CMiniMap::fPreviousWantedLevel = 0.0f;
bool CMiniMap::bPreviousMultiplayerStatus = false; // Not sure whether this should be false or true
bool CMiniMap::ms_bPreviousShowDepthGauge = false;
s32 CMiniMap::iPreviousGpsInstruction = -1;
s32 CMiniMap::ms_iPreviousMapRotation = -1;
float CMiniMap::fPreviousGPSDistance = -1.0f;
float CMiniMap::fPreviousMinimapFloor = -1.0f;
u32 CMiniMap::iMiniMapDpadZoomTimer = 0;
#if ENABLE_FOG_OF_WAR
bool CMiniMap::ms_bRequestFoWClear = true;
bool CMiniMap::ms_bSetFowIsValid = false;
bool CMiniMap::ms_bHideFoW = false;
bool CMiniMap::ms_bDoNotUpdateFoW = false;
bool CMiniMap::ms_bIgnoreFoWOnInit = false;
bool CMiniMap::ms_bUploadFoWTextureData = false;
bool CMiniMap::ms_bFoWUseCustomExtents = false;
Vector2 CMiniMap::ms_vecFoWCustomWorldPos = Vector2(0.0f,0.0f);
Vector2 CMiniMap::ms_vecFoWCustomWorldSize = Vector2(1.0f,1.0f);
Vector2 CMiniMap::ms_ScriptReveal[8];
int CMiniMap::ms_numScriptRevealRequested = 0;
#endif // ENABLE_FOG_OF_WAR
bool CMiniMap::ms_bInsideReInit = false;
#if RSG_PC
u8 s_iDeviceLostResetCountdown = 0;
#endif
const float CMiniMap::fMinTimeBetweenBlipsMS = 250;
//
// tilt & offset values:
//
#if __BANK
#define MINIMAP_MIN_TILT (0.0f)
#define MINIMAP_MAX_TILT (200.0f)
#define MINIMAP_TILT_STEP (1.0f)
#define MINIMAP_MIN_OFFSET (0.0f)
#define MINIMAP_MAX_OFFSET (100.0f)
#define MINIMAP_OFFSET_STEP (0.1f)
#define MINIMAP_ZOOM_STEP (1.0f)
#define MINIMAP_MIN_ZOOM_SCALER (0.1f)
#define MINIMAP_MAX_ZOOM_SCALER (10.0f)
#define MINIMAP_ZOOM_SCALER_STEP (0.01f)
#endif // __BANK
float ALTIMETER_GROUND_LEVEL_FUDGE_FACTOR = 0.0f;
float ALTIMETER_TICK_PIXEL_HEIGHT = 91.0f;
BankFloat ALTIMETER_HEIGHTMAP_WIGGLE_ROOM = 15.0f;
float MINIMAP_GPS_DISPLAY_LIMIT = 100.0f;
float MAP_BLIP_ROUND_THRESHOLD = 50.0f;
extern bool bMiniMap3D;
extern bool bMiniMapSquare;
#if __BANK && ENABLE_FOG_OF_WAR
extern bool DebugDrawFOW;
extern float DebugFOWX1;
extern float DebugFOWY1;
extern float DebugFOWX2;
extern float DebugFOWY2;
bool displayRevealFoWRatio = false;
bool testRevealFoWCoord = false;
float testRevealX = 0.0f;
float testRevealY = 0.0f;
bool bIgnoreFogOfWarValueOf255 = false;
s32 fogOfWarMinX = FOG_OF_WAR_RT_SIZE;
s32 fogOfWarMinY = FOG_OF_WAR_RT_SIZE;
s32 fogOfWarMaxX = -1;
s32 fogOfWarMaxY = -1;
#endif // __BANK
/////////////////////////////////////////////////////////////////////////////////////
// NAME: CEntityPoolIndexForBlip
/////////////////////////////////////////////////////////////////////////////////////
CEntityPoolIndexForBlip::CEntityPoolIndexForBlip(const CEntity *pEntity, eBLIP_TYPE blipType)
{
m_iPoolIndex = sysMemPoolAllocator::s_invalidIndex;
if (uiVerifyf(pEntity, "CEntityPoolIndexForBlip::CEntityPoolIndexForBlip - entity pointer is NULL"))
{
switch (blipType)
{
case BLIP_TYPE_CAR:
if (uiVerifyf(pEntity->GetIsTypeVehicle(), "CEntityPoolIndexForBlip::CEntityPoolIndexForBlip - blip type is BLIP_TYPE_CAR so expected entity to be a vehicle"))
{
m_iPoolIndex = (s32) CVehicle::GetPool()->GetJustIndex(pEntity);
}
break;
case BLIP_TYPE_CHAR:
if (uiVerifyf(pEntity->GetIsTypePed(), "CEntityPoolIndexForBlip::CEntityPoolIndexForBlip - blip type is BLIP_TYPE_CHAR so expected entity to be a ped"))
{
m_iPoolIndex = CPed::GetPool()->GetJustIndex(pEntity);
}
break;
case BLIP_TYPE_STEALTH:
if (uiVerifyf(pEntity->GetIsTypePed(), "CEntityPoolIndexForBlip::CEntityPoolIndexForBlip - blip type is BLIP_TYPE_STEALTH so expected entity to be a ped"))
{
m_iPoolIndex = CPed::GetPool()->GetJustIndex(pEntity);
}
break;
case BLIP_TYPE_OBJECT:
{
if (uiVerifyf(pEntity->GetIsTypeObject(), "CEntityPoolIndexForBlip::CEntityPoolIndexForBlip - blip type is BLIP_TYPE_OBJECT so expected entity to be an object"))
{
const CObject *pObject = static_cast<const CObject*>(pEntity);
if (uiVerifyf(!pObject->m_nObjectFlags.bIsPickUp, "CEntityPoolIndexForBlip::CEntityPoolIndexForBlip - blip type is BLIP_TYPE_OBJECT so expected bIsPickUp to be FALSE"))
{
m_iPoolIndex = (s32) CObject::GetPool()->GetJustIndex(pEntity);
}
}
}
break;
case BLIP_TYPE_PICKUP_OBJECT :
{
if (uiVerifyf(pEntity->GetIsTypeObject(), "CEntityPoolIndexForBlip::CEntityPoolIndexForBlip - blip type is BLIP_TYPE_PICKUP_OBJECT so expected entity to be an object"))
{
const CObject *pObject = static_cast<const CObject*>(pEntity);
if (uiVerifyf(pObject->m_nObjectFlags.bIsPickUp, "CEntityPoolIndexForBlip::CEntityPoolIndexForBlip - blip type is BLIP_TYPE_PICKUP_OBJECT so expected bIsPickUp to be TRUE"))
{
m_iPoolIndex = CPickup::GetPool()->GetJustIndex(pEntity);
}
}
}
break;
case BLIP_TYPE_COP:
if (uiVerifyf(pEntity->GetIsTypePed(), "CEntityPoolIndexForBlip::CEntityPoolIndexForBlip - blip type is BLIP_TYPE_COP so expected entity to be a ped"))
{
m_iPoolIndex = CPed::GetPool()->GetJustIndex(pEntity);
}
break;
default:
uiAssertf(0, "CEntityPoolIndexForBlip::CEntityPoolIndexForBlip - unsupported blip type %d", blipType);
break;
}
}
}
CEntityPoolIndexForBlip::CEntityPoolIndexForBlip(const CPickupPlacement *pPickupPlacement)
{
m_iPoolIndex = sysMemPoolAllocator::s_invalidIndex;
if (uiVerifyf(pPickupPlacement, "CEntityPoolIndexForBlip::CEntityPoolIndexForBlip - pickup placement pointer is NULL"))
{
m_iPoolIndex = CPickupPlacement::GetPool()->GetJustIndex(pPickupPlacement);
}
}
eBLIP_TYPE CEntityPoolIndexForBlip::GetBlipTypeForEntity(const CEntity *pEntity)
{
eBLIP_TYPE blipType = BLIP_TYPE_UNUSED;
if (uiVerifyf(pEntity, "CEntityPoolIndexForBlip::GetBlipTypeForEntity - invalid entity"))
{
if (pEntity->GetIsTypeVehicle())
{
blipType = BLIP_TYPE_CAR;
}
else if (pEntity->GetIsTypePed())
{
blipType = BLIP_TYPE_CHAR;
}
else if (pEntity->GetIsTypeObject())
{
blipType = BLIP_TYPE_OBJECT;
}
else
{
uiAssertf(0, "CEntityPoolIndexForBlip::GetBlipTypeForEntity - failed to resolve blip type for: %s", pEntity->GetDebugName());
}
}
return blipType;
}
CEntity *CEntityPoolIndexForBlip::GetEntity(eBLIP_TYPE blipType) const
{
if (IsValid())
{
switch (blipType)
{
case BLIP_TYPE_CAR:
return CVehicle::GetPool()->GetSlot(m_iPoolIndex);
case BLIP_TYPE_CHAR:
case BLIP_TYPE_STEALTH:
return CPed::GetPool()->GetSlot(m_iPoolIndex);
case BLIP_TYPE_OBJECT:
return CObject::GetPool()->GetSlot(m_iPoolIndex);
case BLIP_TYPE_PICKUP_OBJECT :
return CPickup::GetPool()->GetSlot(m_iPoolIndex);
case BLIP_TYPE_COP:
return CPed::GetPool()->GetSlot(m_iPoolIndex);
default:
break;
}
}
return NULL;
}
CPickupPlacement *CEntityPoolIndexForBlip::GetPickupPlacement()
{
if (IsValid())
{
if (uiVerifyf(m_iPoolIndex >= 0 && m_iPoolIndex < CPickupPlacement::GetPool()->GetSize(), "CEntityPoolIndexForBlip::GetPickupPlacement - placement index %d is out of range", m_iPoolIndex))
{
return CPickupPlacement::GetPool()->GetSlot(m_iPoolIndex);
}
}
return NULL;
}
/////////////////////////////////////////////////////////////////////////////////////
// NAME: CBlipComplex::CBlipComplex()
// PURPOSE: constructor for a complex blip
/////////////////////////////////////////////////////////////////////////////////////
CBlipComplex::CBlipComplex() : CMiniMapBlip(true), m_PoolIndex()
{
m_flags.Reset();
cLocName.Reset();
vPosition.Set(0.0f, 0.0f, 0.0f); // position
fDirection = DEFAULT_BLIP_ROTATION; // direction set to 360 degrees (instead of 0) so we can determine later if we have rotated it or its never been rotated without having to store a flag
priority = BLIP_PRIORITY_LOW; // priority of blip
type = BLIP_TYPE_UNUSED; // type of blip
display = BLIP_DISPLAY_NEITHER; // display type
vScale.Set(1.0f, 1.0f); // scale of the blip
iColour = BLIP_COLOUR_DEFAULT; // colour
iAlpha = 0; // alpha of the blip
iNumberToDisplay = -1;
#if HASHED_BLIP_IDS
iLinkageId.Clear();
#else
iLinkageId = -1;
#endif
}
void CBlipCones::Init(unsigned initMode)
{
if (INIT_SESSION == initMode)
{
m_MapOfBlipCones.Reset();
}
}
void CBlipCones::ClearUsedFlagsForAllBlipCones()
{
BlipConeMap::Iterator mapIter = m_MapOfBlipCones.CreateIterator();
while (!mapIter.AtEnd())
{
mapIter.GetData().m_bUsedThisFrame = false;
mapIter.Next();
}
}
void CBlipCones::RemoveUnusedBlipCones()
{
BlipConeMap::Iterator mapIter = m_MapOfBlipCones.CreateIterator();
while (!mapIter.AtEnd())
{
if (mapIter.GetData().m_bUsedThisFrame == false)
{
m_MapOfBlipCones.Delete(mapIter.GetKey());
mapIter.Start();
}
else
{
mapIter.Next();
}
}
}
// Returns true if the cone should be redrawn either because it's a new cone or because the focus range has changed
bool CBlipCones::UpdateBlipConeParameters(s32 UniqueBlipId, float fFocusRange, bool bRedrawIfOtherParametersChange, float fPeripheralRange, float fGazeAngle, float fVisualFieldMinAzimuthAngle, float fVisualFieldMaxAzimuthAngle)
{
bool bReturnValue = false;
sConeDetails *pConeDetails = m_MapOfBlipCones.Access(UniqueBlipId);
if (pConeDetails)
{
pConeDetails->m_bUsedThisFrame = true;
if (pConeDetails->m_fFocusRange != fFocusRange)
{
pConeDetails->m_fFocusRange = fFocusRange;
bReturnValue = true;
}
if (bRedrawIfOtherParametersChange)
{
// Update all other cone parameters and flag a redraw if needed.
if (pConeDetails->m_fPeripheralRange != fPeripheralRange)
{
pConeDetails->m_fPeripheralRange = fPeripheralRange;
bReturnValue = true;
}
if (pConeDetails->m_fGazeAngle != fGazeAngle)
{
pConeDetails->m_fFocusRange = fFocusRange;
bReturnValue = true;
}
if (pConeDetails->m_fVisualFieldMinAzimuthAngle != fVisualFieldMinAzimuthAngle)
{
pConeDetails->m_fVisualFieldMinAzimuthAngle = fVisualFieldMinAzimuthAngle;
bReturnValue = true;
}
if (pConeDetails->m_fVisualFieldMaxAzimuthAngle != fVisualFieldMaxAzimuthAngle)
{
pConeDetails->m_fVisualFieldMaxAzimuthAngle = fVisualFieldMaxAzimuthAngle;
bReturnValue = true;
}
}
}
else
{
sConeDetails newConeDetails(fFocusRange, true, fPeripheralRange, fGazeAngle, fVisualFieldMinAzimuthAngle, fVisualFieldMaxAzimuthAngle);
m_MapOfBlipCones.Insert(UniqueBlipId, newConeDetails);
bReturnValue = true;
}
return bReturnValue;
}
/////////////////////////////////////////////////////////////////////////////////////
// NAME: CMiniMap::CMiniMap()
// PURPOSE: constructor for the minimap manager class
/////////////////////////////////////////////////////////////////////////////////////
// CMiniMap::CMiniMap() // Init()
void CMiniMap::OldMiniMapConstructor()
{
bActive = false;
MinimapModeState = MINIMAP_MODE_STATE_NONE;
#if __DEV
iNumCreatedTraces = 0;
iSizeOfBlipsCreated = 0;
#endif
#if __BANK
bDisplayAllBlipNames = false;
#endif
for (s32 i = 0; i < MAX_MINIMAP_MOVIE_LAYERS; i++)
{
iMovieId[i] = -1;
}
iReferenceCount = 0;
iSimpleBlip = -1;
iMaxCreatedBlips = 0;
// fPreviousWantedLevel = 0.0f;
bVisible = true;
iPreviousGpsInstruction = -1;
fPreviousGPSDistance = -1.0f;
fPreviousMinimapFloor = -1.0f;
ms_bPreviousShowDepthGauge = false;
if (CreateMiniMapMovie())
{
bPreviousMultiplayerStatus = !NetworkInterface::IsGameInProgress(); // this is initialised as this so the 1st update gets trigged and ActionScript is told
iMiniMapDpadZoomTimer = 0;
// initalise the global:
// MiniMapUpdateState.vPos = ORIGIN;
// MiniMapUpdateState.bDeadOrArrested = false;
// MiniMapUpdateState.bInPlaneOrHeli = false;
// MiniMapUpdateState.fRoll = 0.0f;
// MiniMapUpdateState.fSpeed = 0.0f;
// MiniMapUpdateState.bRunning = false;
// initialise all blips:
for (s32 iCount = 0; iCount < MAX_NUM_BLIPS; iCount++)
{
blip[iCount] = NULL;
}
CMiniMap_Common::EnumerateBlipLinkages(GetMovieId(MINIMAP_MOVIE_FOREGROUND));
CMiniMap_RenderThread::SetupContainers();
// turn off all components
for (s32 iComponentId = 0; iComponentId < MAX_MINIMAP_COMPONENTS; iComponentId++)
{
ToggleComponent(iComponentId, false, true);
}
CNewHud::RepopulateHealthInfoDisplay();
}
else
{
uiAssertf(0, "MiniMap: Couldnt set up MiniMap Scaleform movie!");
}
}
/////////////////////////////////////////////////////////////////////////////////////////
// NAME: CMiniMap::SetActive();
// PURPOSE: signals that we are done with initialization and starts the movie
/////////////////////////////////////////////////////////////////////////////////////////
void CMiniMap::SetActive()
{
bActive = true;
CScaleformMgr::UnlockMovie(GetMovieId(MINIMAP_MOVIE_BACKGROUND));
CScaleformMgr::UnlockMovie(GetMovieId(MINIMAP_MOVIE_FOREGROUND));
}
/////////////////////////////////////////////////////////////////////////////////////////
// NAME: CMiniMap::SetSimpleBlipDefaults()
// PURPOSE: this creates an invisible complex blip that all the simple blips get based on
/////////////////////////////////////////////////////////////////////////////////////////
void CMiniMap::SetSimpleBlipDefaults()
{
iSimpleBlip = CreateGenericBlip(true, BLIP_TYPE_WEAPON_PICKUP, CEntityPoolIndexForBlip(), Vector3(0.0f,0.0f,1.0f), BLIP_DISPLAY_BLIPONLY, "SimpleBlip");
iSimpleBlip = ConvertUniqueBlipToActualBlip(iSimpleBlip); // store the actual blip id
CMiniMapBlip *pBlip = GetBlipFromActualId(iSimpleBlip);
if (pBlip)
{
// set the default simple blips as shortrange, low priority & very small
SetBlipPriorityValue(pBlip, BLIP_PRIORITY_LOW);
SetBlipScaleValue(pBlip, 0.4f);
SetBlipColourValue(pBlip, BLIP_COLOUR_SIMPLEBLIP_DEFAULT);
SetBlipNameValue(pBlip, "BLIP_PICK", true);
SetFlag(pBlip, BLIP_FLAG_SHORTRANGE);
}
}
/////////////////////////////////////////////////////////////////////////////////////
// NAME: CreateSimpleBlip()
// PURPOSE: creates a 'simple' blip which just holds position
/////////////////////////////////////////////////////////////////////////////////////
s32 CMiniMap::CreateSimpleBlip(const Vector3& vPosition, const char *pScriptName)
{
return (CreateGenericBlip(false, BLIP_TYPE_COORDS, CEntityPoolIndexForBlip(), vPosition, BLIP_DISPLAY_BOTH, pScriptName));
}
/////////////////////////////////////////////////////////////////////////////////////
// NAME: CreateBlip()
// PURPOSE: calls the generic blip creation function with relevant values for either
// entity or coord blip values
/////////////////////////////////////////////////////////////////////////////////////
s32 CMiniMap::CreateBlip(bool bComplex, eBLIP_TYPE iBlipType, const CEntityPoolIndexForBlip& iPoolIndex, eBLIP_DISPLAY_TYPE iDisplayFlag, const char *pScriptName)
{
return (CreateGenericBlip(bComplex, iBlipType, iPoolIndex, Vector3(ORIGIN), iDisplayFlag, pScriptName));
}
s32 CMiniMap::CreateBlip(bool bComplex, eBLIP_TYPE iBlipType, const Vector3& vPosition, eBLIP_DISPLAY_TYPE iDisplayFlag, const char *pScriptName)
{
s32 iReturnUniqueId = CreateGenericBlip(bComplex, iBlipType, CEntityPoolIndexForBlip(), vPosition, iDisplayFlag, pScriptName);
if (vPosition == ORIGIN)
{
uiAssertf(0, "MiniMap: Blip %d was created at origin! Suspect=%s", iReturnUniqueId, pScriptName);
// DestroyBlipObject(iReturnUniqueId); // eventually we will want to return invalid blip ID but we will give them a chance to fix stuff 1st
// return INVALID_BLIP_ID;
}
return (iReturnUniqueId);
}
/////////////////////////////////////////////////////////////////////////////////////
// NAME: CreateGenericBlip()
// PURPOSE: one function that deals with creating all the default settings for a new
// blip
/////////////////////////////////////////////////////////////////////////////////////
s32 CMiniMap::CreateGenericBlip(bool bComplex, eBLIP_TYPE iBlipType, const CEntityPoolIndexForBlip& iPoolIndex, const Vector3& vPosition, eBLIP_DISPLAY_TYPE iDisplayFlag, const char *DEV_ONLY(pScriptName) )
{
s32 iIndex = FindAndCreateNextEmptyBlipSpace(bComplex); // create rage_new blip & active it
if (iIndex != -1)
{
CMiniMapBlip *pBlip = GetBlipFromActualId(iIndex);
uiAssertf(pBlip, "MiniMap: Invalid blip at array index %d", iIndex);
if (bComplex)
{
// set new blip settings:
ResetFlag(pBlip); // set no initial flags (0)
SetBlipPriorityValue(pBlip, BLIP_PRIORITY_HIGH);
SetBlipDirectionValue(pBlip, 360.0f, false); // set to 360 degrees and do not clamp back to 0 (we later check this to see if the blip has been rotated out of its default 360 by using 0-359 degrees range
SetBlipCategoryValue(pBlip, BLIP_CATEGORY_OTHER); // none unless specified by script
SetBlipTypeValue(pBlip, iBlipType);
SetBlipScaleValue(pBlip, 1.0f);
CRGBA secondaryBlipColour = CHudColour::GetRGBA(HUD_COLOUR_BLUE); // default to BLUE so the existing FRIEND blips still work as they used to in script till this syncs up
SetBlipSecondaryColourValue(pBlip, secondaryBlipColour);
SetBlipAlphaValue(pBlip, 255);
SetBlipFlashInterval(pBlip, DEFAULT_BLIP_FLASH_INTERVAL);
SetBlipDisplayValue(pBlip, iDisplayFlag);
SetBlipObjectName(pBlip, BLIP_LEVEL); // default blip style
SetBlipFlashDuration(pBlip, MAX_UINT16);
SetFlag(pBlip, BLIP_FLAG_SHOW_HEIGHT);
SetFlag(pBlip, BLIP_FLAG_HIGH_DETAIL); // all blips are high detail as default
SetBlipOn3dMap(pBlip, GetBlipTypeValue(pBlip) == BLIP_TYPE_RADIUS || GetBlipTypeValue(pBlip) == BLIP_TYPE_AREA);
#if __BANK
SetBlipDebugNumberValue(pBlip, -1);
// if we currently want to have all standard ped blips as stealth then set them here
if (bAllPedBlipsAsStealth)
{
if (iBlipType == BLIP_TYPE_CHAR)
{
SetBlipTypeValue(pBlip, BLIP_TYPE_STEALTH);
}
}
#endif // __BANK
}
// set the appropriate default name for the blip
switch (iBlipType)
{
case BLIP_TYPE_COORDS:
SetBlipNameValue(pBlip, "BLIP_DEST", true);
break;
case BLIP_TYPE_CONTACT:
SetBlipNameValue(pBlip, "BLIP_CONT", true);
break;
case BLIP_TYPE_OBJECT:
SetBlipNameValue(pBlip, "BLIP_OBJ", true);
break;
case BLIP_TYPE_PICKUP_OBJECT :
SetBlipNameValue(pBlip, "BLIP_PICK_OBJ", true);
break;
case BLIP_TYPE_CAR:
SetBlipNameValue(pBlip, "BLIP_CAR", true);
break;
case BLIP_TYPE_CHAR:
SetBlipNameValue(pBlip, "BLIP_ENEMY", true);
break;
case BLIP_TYPE_CUSTOM:
SetBlipNameValue(pBlip, "BLIP_GALLERY", true);
break;
case BLIP_TYPE_PICKUP:
SetBlipNameValue(pBlip, "BLIP_PICK", true);
break;
case BLIP_TYPE_WEAPON_PICKUP:
SetBlipNameValue(pBlip, "BLIP_PICK", true);
break;
case BLIP_TYPE_COP:
SetBlipNameValue(pBlip, "BLIP_COP", true);
break;
case BLIP_TYPE_STEALTH:
SetBlipNameValue(pBlip, "BLIP_ENEMY", true);
break;
default:
SetBlipNameValue(pBlip, "BLIP_DEST", true);
break;
}
if( (iBlipType == BLIP_TYPE_CAR)
|| (iBlipType == BLIP_TYPE_CHAR)
|| (iBlipType == BLIP_TYPE_STEALTH)
|| (iBlipType == BLIP_TYPE_OBJECT)
|| (iBlipType == BLIP_TYPE_PICKUP_OBJECT)
|| (iBlipType == BLIP_TYPE_COP))
{
CEntity* pEntity = iPoolIndex.GetEntity((eBLIP_TYPE)iBlipType);
if(pEntity && pEntity->GetIsPhysical())
{
Assertf(!smart_cast<CPhysical*>(pEntity)->GetCreatedBlip(), "Creating duplicate %s blips for %s %s from script: %s. Please call REMOVE_BLIP() first.",
GetBlipNameValue(pBlip), pEntity->GetDebugName(), pEntity->GetModelName(), pScriptName);
smart_cast<CPhysical*>(pEntity)->SetCreatedBlip(true);
}
}
// set specific details for certain types of blip:
switch (iBlipType)
{
case BLIP_TYPE_WEAPON_PICKUP:
{
SetBlipPositionValue(pBlip, vPosition);
if (bComplex)
{
SetBlipColourValue(pBlip, BLIP_COLOUR_COORD);
SetFlag(pBlip, BLIP_FLAG_VALUE_CHANGED_COLOUR);
}
break;
}
case BLIP_TYPE_STEALTH:
{
SetBlipPositionValue(pBlip, vPosition);
#if __BANK
if (iDebugSonarStyle == SONAR_STYLE_SONAR_ONLY)
{
if (GetBlipDisplayValue(pBlip) != BLIP_DISPLAY_NEITHER)
{
SetBlipDisplayValue(pBlip, BLIP_DISPLAY_NEITHER);
}
}
#endif // __BANK
if (bComplex)
{
SetBlipPoolIndexValue(pBlip, iPoolIndex);
SetBlipColourValue(pBlip, BLIP_COLOUR_RED);
SetFlag(pBlip, BLIP_FLAG_VALUE_CHANGED_COLOUR);
SetBlipScaleValue(pBlip, 0.4f);
}
break;
}
case BLIP_TYPE_COORDS:
case BLIP_TYPE_CONTACT:
{
SetBlipPositionValue(pBlip, vPosition);
if (bComplex)
{
SetBlipColourValue(pBlip, BLIP_COLOUR_COORD);
SetFlag(pBlip, BLIP_FLAG_VALUE_CHANGED_COLOUR);
}
break;
}
case BLIP_TYPE_RADIUS:
{
SetBlipObjectName(pBlip, BLIP_RADIUS); // radius blip style
SetBlipPositionValue(pBlip, vPosition);
SetBlipPriorityValue(pBlip, BLIP_PRIORITY_LOW);
SetFlag(pBlip, BLIP_FLAG_HIDDEN_ON_LEGEND);
break;
}
case BLIP_TYPE_AREA:
{
SetBlipObjectName(pBlip, BLIP_LEVEL); // default style, we use BLIP_AREA exclusively when we render. Let's us override it later for edge blips
SetBlipPositionValue(pBlip, vPosition);
SetBlipPriorityValue(pBlip, BLIP_PRIORITY_LOW);
SetFlag(pBlip, BLIP_FLAG_HIDDEN_ON_LEGEND);
break;
}
case BLIP_TYPE_CUSTOM:
{
SetBlipObjectName(pBlip, sMiniMapMenuComponent.GetBlipObject());
if (sMiniMapMenuComponent.GetBlipObject() == 144)
{
SetBlipColourValue(pBlip, BLIP_COLOUR_RED);
}
else if ( sMiniMapMenuComponent.GetBlipObject() == 145)
{
SetBlipColourValue(pBlip, BLIP_COLOUR_GREEN);
}
SetBlipPositionValue(pBlip, vPosition);
SetBlipPoolIndexValue(pBlip, iPoolIndex);
SetFlag(pBlip, BLIP_FLAG_SHORTRANGE);
break;
}
case BLIP_TYPE_OBJECT:
case BLIP_TYPE_PICKUP_OBJECT :
{
uiAssert(pBlip->IsComplex());
SetBlipColourValue(pBlip, BLIP_COLOUR_MISSION_OBJECT);
SetBlipPoolIndexValue(pBlip, iPoolIndex);
SetFlag(pBlip, BLIP_FLAG_VALUE_CHANGED_COLOUR);
break;
}
case BLIP_TYPE_PICKUP:
{
uiAssert(pBlip->IsComplex());
SetBlipColourValue(pBlip, BLIP_COLOUR_GREEN);
SetFlag(pBlip, BLIP_FLAG_VALUE_CHANGED_COLOUR);
SetBlipPoolIndexValue(pBlip, iPoolIndex);
break;
}
case BLIP_TYPE_COP:
{
SetFlag(pBlip, BLIP_FLAG_HIDDEN_ON_LEGEND);
SetBlipPoolIndexValue(pBlip, iPoolIndex);
break;
}
default:
{
uiAssert(pBlip->IsComplex());
SetBlipColourValue(pBlip, BLIP_COLOUR_FRIENDLY);
SetBlipPoolIndexValue(pBlip, iPoolIndex);
SetFlag(pBlip, BLIP_FLAG_VALUE_CHANGED_COLOUR);
break;
}
}
#if __DEV
if (pScriptName)
{
formatf(blip[iIndex]->m_cBlipCreatedByScriptName, pScriptName);
}
#endif // __DEV
blip[iIndex]->m_iActualId = iIndex;
blip[iIndex]->m_iUniqueId = CreateNewUniqueBlipFromActualBlipId(iIndex); // store the unique id that was used
// Graeme - hopefully it's okay to skip this. The GfxValue is stored on the RenderThread so I can't set it here
// SetBlipGfxValue(pBlip, NULL); // set blip gfx value as null once we have a unique id to handle
if (CPauseMenu::IsActive() && CPauseMenu::IsInMapScreen())
{
#if __DEV
uiDebugf1("Updating pausemap legend because '%s' blip created by '%s'", GetBlipNameValue(pBlip), blip[iIndex]->m_cBlipCreatedByScriptName);
#else
uiDebugf1("Updating pausemap legend because '%s' blip created", GetBlipNameValue(pBlip));
#endif // __DEV
CPauseMenu::UpdatePauseMapLegend();
}
uiDebugf1("Created '%s' blip as Actual id: %d and unique id %d", GetBlipNameValue(pBlip), blip[iIndex]->m_iActualId, blip[iIndex]->m_iUniqueId);
return (blip[iIndex]->m_iUniqueId);
}
return INVALID_BLIP_ID;
}
///////////////////////////////////////////////////////////////////////////////////////
// NAME: RemoveBlip
// PURPOSE: sets a request to remove the blip from the stage and eventually destory it
///////////////////////////////////////////////////////////////////////////////////////
bool CMiniMap::RemoveBlip(CMiniMapBlip *pBlip)
{
if (!pBlip)
return false;
SetFlag(pBlip, BLIP_FLAG_VALUE_REMOVE_FROM_STAGE);
#if COMPANION_APP
CCompanionData::GetInstance()->RemoveBlip((CBlipComplex*)pBlip);
#endif
return true;
}
///////////////////////////////////////////////////////////////////////////////////////
// NAME: DestroyBlipObject
// PURPOSE: actually destroys the blip object - should be removed from the stage 1st
///////////////////////////////////////////////////////////////////////////////////////
void CMiniMap::DestroyBlipObject(CMiniMapBlip *pBlip)
{
if (CSystem::IsThisThreadId(SYS_THREAD_RENDER)) // only on UT
{
uiAssertf(0, "CMiniMap:: DestroyBlipObject can only be called on the UpdateThread!");
return;
}
if (!pBlip)
return;
CGps::StopRadarBlipGps(GetUniqueBlipUsed(pBlip)); // remove any GPS that may be attached this blip
if (CPauseMenu::IsActive() && CMiniMap::GetBlipTypeValue(pBlip) != BLIP_TYPE_CUSTOM )
{
uiDebugf1("Updating pausemap legend because '%s' blip was removed", GetBlipNameValue(pBlip));
CMapMenu::OnBlipDelete(pBlip);
CPauseMenu::UpdatePauseMapLegend();
}
#if __DEV
if (pBlip->IsComplex())
iSizeOfBlipsCreated -= (u32)sizeof(CBlipComplex);
else
iSizeOfBlipsCreated -= (u32)sizeof(CBlipSimple);
iNumCreatedTraces--;
if (pBlip->IsComplex())
{
uiDebugf1("MiniMap: Blip Deleted (%s) Num Blips Active: %d Size: %d", GetBlipNameValue(pBlip), iNumCreatedTraces, iSizeOfBlipsCreated);
}
#endif
s32 iActualId = GetActualBlipUsed(pBlip);
delete blip[iActualId];
blip[iActualId] = NULL;
// if this blip was the blip that is the maximum blip, then we can shorten the max list by 1
if (iActualId+1 == iMaxCreatedBlips)
{
iMaxCreatedBlips--;
uiDebugf1("MiniMap: Max blip count decreased to %d", iMaxCreatedBlips);
}
else
{
bool bFoundBlip = false;
// if not, then run through between this blip and the current max, looking to see if there are any blips left, if not set the max to be this blip
for (s32 i = iMaxCreatedBlips-1; ((!bFoundBlip) && i > iActualId); i--)
{
if (blip[i])
{
iMaxCreatedBlips = i + 1;
uiDebugf1("MiniMap: Max blip count recalculated to %d", iMaxCreatedBlips);
bFoundBlip = true;
}
}
if (!bFoundBlip)
{
uiDebugf1("MiniMap: Max blip count stayed static at %d", iMaxCreatedBlips);
}
}
}
/////////////////////////////////////////////////////////////////////////////////////
// NAME: CMiniMap::CreateSonarBlip
// PURPOSE: creates a self-removing "sonar" stealth blip. We do not need to keep
// track of these as these blips self-remove via ActionScript
/////////////////////////////////////////////////////////////////////////////////////
void CMiniMap::CreateSonarBlip(const Vector3& vPos, float fSize, eHUD_COLOURS iHudColour, CPed* pPed /*= NULL*/, bool bScriptRequested, bool overrideBlipPos)
{
PF_FUNC(AddSonarBlip);
if (CSystem::IsThisThreadId(SYS_THREAD_RENDER)) // only on UT
{
uiAssertf(0, "CMiniMap:: CreateSonarBlip can only be called on the UpdateThread!");
return;
}
if (!ms_bSonarBlipsActive)
{
#if __BANK
if (bDebugVisibilityOfSonarBlips)
{
uiDisplayf("MiniMap: SONAR_BLIP - Not adding sonar blip because ms_bSonarBlipsActive");
}
#endif // __BANK
return;
}
if ( (!bScriptRequested) && (pPed != GetMiniMapPed()) ) // fix for 1162373
{
#if __BANK
if (bDebugVisibilityOfSonarBlips)
{
uiDisplayf("MiniMap: SONAR_BLIP - Not adding sonar blip because ( (!bScriptRequested) && (pPed != GetMiniMapPed()) )");
}
#endif // __BANK
return;
}
if (!ShouldAddSonarBlips())
{
// debug is added in the ShouldAddSonarBlips function
return;
}
if (fSize > 0.0f)
{
bool bFoundExistingSlot = false;
bool bHasRedBlipActive = CHudColour::IsHudColourRed(iHudColour);
for (s32 i = 0; i < ms_SonarBlips.GetCount(); i++)
{
if (ms_SonarBlips[i].pPed == pPed)
{
bHasRedBlipActive |= CHudColour::IsHudColourRed(ms_SonarBlips[i].iHudColour);
}
}
if ((CHudColour::IsHudColourRed(iHudColour) || !bHasRedBlipActive))
{
for (s32 i = 0; ((!bFoundExistingSlot) && (i < ms_SonarBlips.GetCount())); i++)
{
if (ms_SonarBlips[i].pPed == pPed && ms_SonarBlips[i].iHudColour == iHudColour) // reuse the existing slot so the blip can move with the ped but we dont need to store too much info about it
{
#if __BANK
if (bDebugVisibilityOfSonarBlips)
{
uiDisplayf("MiniMap: SONAR_BLIP - Reusing sonar blip %d", i);
}
#endif
s32 iFrameCheck = (s32)(floor)(ms_SonarBlips[i].fSize / 5.0f); // work out how long to allow the existing sized blip to continue before re-sizing
if ( (fSize * 2.0f >= ms_SonarBlips[i].fSize) || (ms_SonarBlips[i].iFramesAlive > iFrameCheck) ) // allow any existing anim a few frames before we restart it on a sound
{
ms_SonarBlips[i].fSize = fSize * 2.0f;
ms_SonarBlips[i].iFramesAlive = 0;
}
ms_SonarBlips[i].vPos = Vector2(vPos.x, vPos.y);
ms_SonarBlips[i].bShouldOverridePos = overrideBlipPos;
bFoundExistingSlot = true;
break;
}
}
if (!bFoundExistingSlot)
{
#define SONAR_BLIP_ID_START (0)
#define SONAR_BLIP_ID_RANGE (1000)
static s32 iSonarBlipIdCounter = SONAR_BLIP_ID_START;
sSonarBlipStruct newSonarItem;
newSonarItem.iId = iSonarBlipIdCounter++;
newSonarItem.pPed = pPed;
newSonarItem.vPos = Vector2(vPos.x, vPos.y);
newSonarItem.fSize = fSize * 2.0f;
newSonarItem.iHudColour = iHudColour;
newSonarItem.iFramesAlive = 0;
newSonarItem.bShouldOverridePos = overrideBlipPos;
ms_SonarBlips.PushAndGrow(newSonarItem);
#if __BANK
if (bDebugVisibilityOfSonarBlips)
{
uiDisplayf("MiniMap: SONAR_BLIP - Creating new sonar blip %d", newSonarItem.iId);
}
#endif
if (iSonarBlipIdCounter > (SONAR_BLIP_ID_START+SONAR_BLIP_ID_RANGE))
iSonarBlipIdCounter = SONAR_BLIP_ID_START;
}
}
}
}
// Reduces the noise passed in for environmental factors, does ReportStealthNoise if pPed is a player,
// then optionally creates a sonar blip for the noise.
float CMiniMap::CreateSonarBlipAndReportStealthNoise(CPed* pPed, const Vec3V& vPos, float fSize, eHUD_COLOURS iHudColor, bool bCreateSonarBlip, bool overrideBlipPos)
{
// Current design is to not draw sonar blips for non-player characters [2/4/2013 mdawe]
if (uiVerify(pPed) && fSize > 0.f && pPed->IsPlayer())
{
ReduceSoundSizeForEnvironment(fSize, vPos, pPed);
CPlayerInfo* pPlayerInfo = pPed->GetPlayerInfo();
if (pPlayerInfo)
{
fSize *= pPlayerInfo->GetStealthMultiplier();
pPlayerInfo->ReportStealthNoise(fSize);
}
if (bCreateSonarBlip)
{
CreateSonarBlip(VEC3V_TO_VECTOR3(vPos), fSize, iHudColor, pPed, false, overrideBlipPos);
}
}
return fSize;
}
void CMiniMap::ClearSonarBlips()
{
ms_SonarBlips.resize(0);
}
// Under certain conditions, reduce the size of this sound event.
void CMiniMap::ReduceSoundSizeForEnvironment( float& fInOutSize, Vec3V_In vPos, const CPed* pPed )
{
#if __BANK && DEBUG_DRAW
// We will use these variables below if (CPedDebugVisualiser::GetDebugDisplay() == CPedDebugVisualiser::eStealth)
int iNoOfTexts = 3; // 3 lines of text in VisualizeStealth
Vector3 vTextPos = VEC3V_TO_VECTOR3(pPed->GetTransform().GetPosition()) + ZAXIS;
#endif //__BANK && DEBUG_DRAW
if (g_weather.IsRaining())
{
fInOutSize -= CMiniMap::sm_Tunables.Sonar.fRainSnowSoundReductionAmount;
#if __BANK && DEBUG_DRAW
if (CPedDebugVisualiser::GetDebugDisplay() == CPedDebugVisualiser::eStealth)
{
char debugText[50];
sprintf(debugText, "Player sound reduced for RAIN from %f to %f", fInOutSize + CMiniMap::sm_Tunables.Sonar.fRainSnowSoundReductionAmount,fInOutSize);
grcDebugDraw::Text(vTextPos,Color_blue,0,iNoOfTexts*grcDebugDraw::GetScreenSpaceTextHeight(),debugText);
iNoOfTexts++;
}
#endif //__BANK && DEBUG_DRAW
}
if (pPed && pPed->IsPlayer())
{
// If nearby a playing radio or other peds conversing, reduce the sound.
if (g_EmitterAudioEntity.IsWithinRangeOfRadio(VEC3V_TO_VECTOR3(vPos), CMiniMap::sm_Tunables.Sonar.fRadioSoundReductionDistance))
{
fInOutSize -= CMiniMap::sm_Tunables.Sonar.fRadioSoundReductionAmount;
}
else if (pPed->GetPedIntelligence())
{
// Go through nearby vehicles to look for radios playing.
CEntityScannerIterator vehicleList = pPed->GetPedIntelligence()->GetNearbyVehicles();
ScalarV vSoundReductionDist2(rage::square(CMiniMap::sm_Tunables.Sonar.fRadioSoundReductionDistance));
for( CEntity* pEnt = vehicleList.GetFirst(); pEnt; pEnt = vehicleList.GetNext() )
{
CVehicle* pThisVehicle = static_cast<CVehicle*>(pEnt);
const audVehicleAudioEntity* pVehAudioEntity = pThisVehicle->GetVehicleAudioEntity();
if (pVehAudioEntity)
{
if (pVehAudioEntity->GetRadioStation() && pVehAudioEntity->IsRadioSwitchedOn())
{
ScalarV positionDist2 = DistSquared(pThisVehicle->GetTransform().GetPosition(), vPos);
if ( IsLessThanAll(positionDist2, vSoundReductionDist2) )
{
fInOutSize -= CMiniMap::sm_Tunables.Sonar.fRadioSoundReductionAmount;
#if __BANK && DEBUG_DRAW
if (CPedDebugVisualiser::GetDebugDisplay() == CPedDebugVisualiser::eStealth)
{
char debugText[50];
sprintf(debugText, "Player sound reduced for RADIO from %f to %f", fInOutSize + CMiniMap::sm_Tunables.Sonar.fRadioSoundReductionAmount,fInOutSize);
grcDebugDraw::Text(vTextPos,Color_blue,0,iNoOfTexts*grcDebugDraw::GetScreenSpaceTextHeight(),debugText, true, 33);
grcDebugDraw::Line(vTextPos, VEC3V_TO_VECTOR3(pThisVehicle->GetTransform().GetPosition()), Color_BlanchedAlmond, 33);
iNoOfTexts++;
}
#endif // __BANK && DEBUG_DRAW
return;
}
}
}
}
// If we haven't already found a radio, check for nearby conversations.
vSoundReductionDist2.Set(rage::square(CMiniMap::sm_Tunables.Sonar.fConversationSoundReductionDistance));
CEntityScannerIterator pedList = pPed->GetPedIntelligence()->GetNearbyPeds();
for( CEntity* pEnt = pedList.GetFirst(); pEnt; pEnt = pedList.GetNext() )
{
CPed* pPed = static_cast<CPed*>(pEnt);
if (pPed)
{
if (pPed->GetSpeechAudioEntity() && pPed->GetSpeechAudioEntity()->GetIsAnySpeechPlaying())
{
ScalarV positionDist2 = DistSquared(pPed->GetTransform().GetPosition(), vPos);
if ( IsLessThanAll(positionDist2, vSoundReductionDist2) )
{
fInOutSize -= CMiniMap::sm_Tunables.Sonar.fConversationSoundReductionAmount;
#if DEBUG_DRAW
if (CPedDebugVisualiser::GetDebugDisplay() == CPedDebugVisualiser::eStealth)
{
char debugText[50];
sprintf(debugText, "Player sound reduced for CONVERSATION from %f to %f", fInOutSize + CMiniMap::sm_Tunables.Sonar.fConversationSoundReductionAmount,fInOutSize);
grcDebugDraw::Text(vTextPos,Color_blue,0,iNoOfTexts*grcDebugDraw::GetScreenSpaceTextHeight(),debugText, true, 10);
iNoOfTexts++;
}
#endif
return;
}
}
}
}
}
}
}
/////////////////////////////////////////////////////////////////////////////////////
// NAME: FindAndCreateNextEmptyBlipSpace()
// PURPOSE: returns the 1st empty/unused blip space we can find in the array
/////////////////////////////////////////////////////////////////////////////////////
s32 CMiniMap::FindAndCreateNextEmptyBlipSpace(bool bComplex)
{
// find a new slot in the blip array:
for (s32 iIndex = 0; iIndex < MAX_NUM_BLIPS; iIndex++)
{
if (!blip[iIndex])
{
if (bComplex)
{
blip[iIndex] = rage_new CBlipComplex(); // lets point this to a complex blip
#if __DEV
iSizeOfBlipsCreated += (u32)sizeof(CBlipComplex);
iNumCreatedTraces++;
uiDebugf1("MiniMap: New Complex Blip Created! Num Blips Active: %d Size: %d Slot: %d\n", iNumCreatedTraces, iSizeOfBlipsCreated, iIndex);
#endif
}
else
{
blip[iIndex] = rage_new CBlipSimple(); // lets point this to a simple blip#
#if __DEV
iSizeOfBlipsCreated += (u32)sizeof(CBlipSimple);
iNumCreatedTraces++;
uiDebugf1("MiniMap: New Simple Blip Created! Num Blips Active: %d Size: %d Slot: %d\n", iNumCreatedTraces, iSizeOfBlipsCreated, iIndex);
#endif
}
/*#define MAX_TRIAL_BUG_COUNT (150) // I want to trial a smaller amount of blips - so this assert will catch it if 150 isnt enough
if (iIndex == MAX_TRIAL_BUG_COUNT)
{
uiAssertf(0, "MiniMap: Trial max of %d blips has been hit (can be safely ignored but please bug to DerekP, continue playing and include logs at end of session)", MAX_TRIAL_BUG_COUNT);
}*/
if ( (iIndex + 1) > iMaxCreatedBlips )
{
iMaxCreatedBlips = (iIndex + 1);
uiDebugf1("MiniMap: Max blip count increased to %d", iMaxCreatedBlips);
}
return (iIndex);
}
}
uiAssertf(0, "MiniMap: Cannot find a free blip slot - maximum has been hit!");
return -1;
}
////////////////////////////////////////////////////////////////////////////
// name: CreateNewUniqueBlipFromActualBlipId
//
// purpose: Increases the Reference Index of the entry in the blip array and
// adds this Reference Index to the Array Index
// (Call this when first setting up a blip)
// params: Index without Reference Index (i.e. Array Index)
// returns: Index including Reference Index
////////////////////////////////////////////////////////////////////////////
s32 CMiniMap::CreateNewUniqueBlipFromActualBlipId(s32 iIndex)
{
s32 iUniqueIndex = INVALID_BLIP_ID;
if (CSystem::IsThisThreadId(SYS_THREAD_RENDER)) // only on UT
{
uiAssertf(0, "CMiniMap: CreateNewUniqueBlipFromActualBlipId can only be called on the UpdateThread!");
return iUniqueIndex;
}
if (iIndex != -1 && blip[iIndex])
{
if (iReferenceCount < (MAX_BLIP_REFERENCE_INDEX - 1))
iReferenceCount++;
else
iReferenceCount = 1;
blip[iIndex]->m_iReferenceIndex = iReferenceCount;
iUniqueIndex = iIndex | (blip[iIndex]->m_iReferenceIndex << BLIP_REFERENCE_SHIFT);
}
return (iUniqueIndex);
}
////////////////////////////////////////////////////////////////////////////
// name: ConvertUniqueBlipToActualBlip
//
// purpose: Checks the Reference Index part of Index and then removes it so
// that the remainder of Index can be treated as an index
// into the blip array
// params: Index including Reference Index
// returns: Index without Reference Index (i.e. Array Index)
// or -1 if the Reference Index shows that Index refers to an old blip
////////////////////////////////////////////////////////////////////////////
s32 CMiniMap::ConvertUniqueBlipToActualBlip(s32 iIndex)
{
u32 iReferenceIndexOfThisBlip;
s32 ArrayIndex;
if (iIndex != INVALID_BLIP_ID)
{
ArrayIndex = (iIndex & ~BLIP_REFERENCE_MASK);
iReferenceIndexOfThisBlip = (iIndex & BLIP_REFERENCE_MASK) >> BLIP_REFERENCE_SHIFT;
uiAssertf(ArrayIndex >= 0, "MiniMap: ConvertUniqueBlipToActualBlip - Array Index is less than 0");
uiAssertf(ArrayIndex < MAX_NUM_BLIPS, "MiniMap: ConvertUniqueBlipToActualBlip - Radar Blip Array Index is too big (%d)", ArrayIndex);
if (blip[ArrayIndex] && iReferenceIndexOfThisBlip == blip[ArrayIndex]->m_iReferenceIndex)
{
return (ArrayIndex);
}
}
return(-1);
}
////////////////////////////////////////////////////////////////////////////
// name: UpdateBitmapOnUT
//
// purpose: deals with placing bitmap tiles onto the map as LOD
// still need to make the 'active' tile selection a bit more
// intellegent so we only render tiles we need to.
////////////////////////////////////////////////////////////////////////////
void CMiniMap::UpdateBitmapOnUT(MM_BITMAP_VERSION mmOverride /* = MAX_MM_BITMAP_VERSIONS */)
{
if (!ms_bBitmapInitialized) return;
Vector3 vCentrePos;
GetCentrePosition(vCentrePos);
Vector2 vTestPos(vCentrePos.x - sm_Tunables.Bitmap.vBitmapStart.x, -(vCentrePos.y - sm_Tunables.Bitmap.vBitmapStart.y - sm_Tunables.Bitmap.vBitmapTileSize.y));
Vector2 vBitmapTile((sm_Tunables.Bitmap.iBitmapTilesX / (sm_Tunables.Bitmap.iBitmapTilesX * sm_Tunables.Bitmap.vBitmapTileSize.x)) * vTestPos.x, (sm_Tunables.Bitmap.iBitmapTilesY / (sm_Tunables.Bitmap.iBitmapTilesY * sm_Tunables.Bitmap.vBitmapTileSize.y)) * vTestPos.y);
float fCurrentTileX = vBitmapTile.x;
float fCurrentTileY = vBitmapTile.y-1;
#define TILE_RANGE_CHECK (0.4f)
// get the max tiles we need around the player
float CurrentTopTile = rage::Max((floorf(fCurrentTileY - TILE_RANGE_CHECK)), 0.0f);
float CurrentBottomTile = rage::Min((ceilf(fCurrentTileY + TILE_RANGE_CHECK)), (float)(sm_Tunables.Bitmap.iBitmapTilesY-1));
float CurrentLeftTile = rage::Max((floorf(fCurrentTileX - TILE_RANGE_CHECK)), 0.0f);
float CurrentRightTile = rage::Min((ceilf(fCurrentTileX + TILE_RANGE_CHECK)), (float)(sm_Tunables.Bitmap.iBitmapTilesX-1));
bool bInUseThisFrame = false;
char cBitmapString[50];
UpdateBitmapState(ms_BitmapSuperLowRes, true, !IsInPauseMap() && !IsInCustomMap(), "minimap_LOD_128");
for (s32 i = 0; i < MM_BITMAP_VERSION_NUM_ENUMS; i++)
{
const char* pszPrefix = NULL;
switch(i)
{
case MM_BITMAP_VERSION_MINIMAP: pszPrefix = "minimap"; break;
case MM_BITMAP_VERSION_ALPHA: pszPrefix = "minimap_alpha"; break;
case MM_BITMAP_VERSION_SEA: pszPrefix = "minimap_sea"; break;
default: pszPrefix = NULL; break;
}
for (s32 x = 0; x < sm_Tunables.Bitmap.iBitmapTilesX; x++)
{
for (s32 y = 0; y < sm_Tunables.Bitmap.iBitmapTilesY; y++)
{
if( mmOverride != MM_BITMAP_VERSION_NUM_ENUMS )
{
bInUseThisFrame = (i == mmOverride);
}
else if (IsInPauseMap() || IsInCustomMap())
{
if (i == sm_Tunables.Bitmap.eBitmapForPause)
{
bInUseThisFrame = true;
}
else
{
bInUseThisFrame = false;
}
}
else
{
if (i == sm_Tunables.Bitmap.eBitmapForMinimap &&
(IsInBigMap() ||
GetRange() < sm_Tunables.Camera.fBitmapRequiredZoom ||
fwTimer::GetTimeInMilliseconds() <= iMiniMapDpadZoomTimer+TIME_TO_ZOOM_OUT_MINIMAP+1000 ||
sm_Tunables.Bitmap.bAlwaysDrawBitmap)
)
{
bInUseThisFrame = true;
}
else
{
bInUseThisFrame = false;
}
if ( bInUseThisFrame && !IsInBigMap()) // fix for 1353935
{
if (x < CurrentLeftTile)
bInUseThisFrame = false;
if (x > CurrentRightTile)
bInUseThisFrame = false;
if (y < CurrentTopTile)
bInUseThisFrame = false;
if (y > CurrentBottomTile)
bInUseThisFrame = false;
}
}
formatf(cBitmapString, "%s_%d_%d", pszPrefix, y, x, NELEM(cBitmapString));
sBitmapStruct& bitmap = ms_BitmapBackground(i,x,y);
UpdateBitmapState(bitmap, bInUseThisFrame, bInUseThisFrame, cBitmapString);
}
}
}
}
bool CMiniMap::AreAllTexturesActive(MM_BITMAP_VERSION mm)
{
UpdateBitmapOnUT(mm);
for (s32 x = 0; x < sm_Tunables.Bitmap.iBitmapTilesX; x++)
{
for (s32 y = 0; y < sm_Tunables.Bitmap.iBitmapTilesY; y++)
{
if( ms_BitmapBackground(mm,x,y).iState != MM_BITMAP_ACTIVE )
return false;
}
}
return true;
}
/////////////////////////////////////////////////////////////////////////////////////
// NAME: CMiniMap::Update
// PURPOSE: updates the minimap
/////////////////////////////////////////////////////////////////////////////////////
void CMiniMap::UpdateMiniMap()
{
if (!bActive)
return;
STRVIS_AUTO_CONTEXT(strStreamingVisualize::MINIMAP);
UpdateDpadDown();
UpdateMultiplayerInformation();
UpdateStatesOnUT();
UpdateBitmapOnUT();
UpdateBlips(); // this needs to update on UT but call DLC commands to be run on RT later
// UpdateBlipMarkers(); // added back in for 820689 but commented out pending decisions
UpdateGPS();
// Report the position & size to gamestream.
CGameStream* GameStream = CGameStreamMgr::GetGameStream();
if( GameStream != NULL )
{
Vector2 vPos = GetCurrentMiniMapPosition();
Vector2 vSize = GetCurrentMiniMapSize();
GameStream->ReportMinimapPosAndSize( vPos.x, vPos.y, vSize.x, vSize.y );
}
#if __BANK
if (!IsInPauseMap())
{
if (CControlMgr::GetKeyboard().GetKeyJustDown(KEY_N, KEYBOARD_MODE_DEBUG, "show blip names"))
{
bDisplayAllBlipNames = !bDisplayAllBlipNames;
ModifyLabelsToAllActiveBlips(bDisplayAllBlipNames, false);
}
}
if( displayRevealFoWRatio )
{
float ratio = CMiniMap_Common::GetFogOfWarDiscoveryRatio();
grcDebugDraw::AddDebugOutput("FoW Discovery Ratio %f",ratio);
}
if( testRevealFoWCoord )
{
bool revealed = CMiniMap_Common::IsCoordinateRevealed(Vector3(testRevealX,testRevealY,0.0f));
grcDebugDraw::AddDebugOutput("%fx%f : %s",testRevealX,testRevealY,revealed ? "Been" : "Not Been");
}
#endif // __BANK
}
/////////////////////////////////////////////////////////////////////////////////////
// NAME: CMiniMap::GetMiniMapPed
// PURPOSE: returns the ped the minimap is running from (usually player ped unless
// specified by script (ie spectator in MP games))
/////////////////////////////////////////////////////////////////////////////////////
CPed *CMiniMap::GetMiniMapPed()
{
if (ms_iMiniMapPedPoolIndex != 0)
{
CPed *pPed = CPed::GetPool()->GetAt(ms_iMiniMapPedPoolIndex);
if (pPed)
{
if(CNetwork::IsGameInProgress() && NetworkInterface::IsInSpectatorMode())
{
ObjectId objid = NetworkInterface::GetSpectatorObjectId();
netObject* obj = NetworkInterface::GetNetworkObject(objid);
if (obj && (gnetVerify(NET_OBJ_TYPE_PLAYER == obj->GetObjectType() || NET_OBJ_TYPE_PED == obj->GetObjectType())))
{
CPed* pSpectatedPed = static_cast<CPed*>(static_cast<CNetObjPed*>(obj)->GetPed());
if (gnetVerify(pSpectatedPed))
{
pPed = pSpectatedPed;
}
}
}
return (pPed);
}
}
uiAssertf(CGameWorld::FindLocalPlayer(), "CMiniMap::GetMiniMapPed - failed to get a valid ped to base the minimap on");
return CGameWorld::FindLocalPlayer();
}
/////////////////////////////////////////////////////////////////////////////////////
// NAME: CMiniMap::GetIsInsideInterior
// PURPOSE: whether the minimap thinks its in an interior or not
// can be called from either thread
/////////////////////////////////////////////////////////////////////////////////////
bool CMiniMap::GetIsInsideInterior(bool bIgnorePauseMapSettings)
{
if (!CSystem::IsThisThreadId(SYS_THREAD_UPDATE)) // only on UT
{
uiAssertf(0, "CMiniMap::GetIsInsideInterior can only be called on the UpdateThread!");
return false;
}
if ( (!bIgnorePauseMapSettings) && (IsInPauseMap()) )
{
return (CMapMenu::GetIsInInteriorMode());
}
if (CScriptHud::ms_fMiniMapForcedZoomPercentage == 0.0f)
{
if (CScriptHud::ms_bFakeExteriorThisFrame)
{
return false;
}
}
bool bInsideInterior = false;
if (ms_bInPrologue || ms_bOnIslandMap) // as prologue is now always an interior throughout we have a slightly different check to ensure it all still works as expected
{
const CPed *pLocalPlayer = GetMiniMapPed();
CPortalTracker* pPT = const_cast<CPortalTracker*>(pLocalPlayer ? pLocalPlayer->GetPortalTracker() : NULL);
bInsideInterior = ( (CScriptHud::FakeInterior.bActive) || ( (pPT) && (pPT->IsInsideInterior()) && (!pPT->IsAllowedToRunInInterior()) ) );
}
else // general game checks movie being active on the stage:
{
if (!CScriptHud::ms_bFakeExteriorThisFrame) // fix for 1500837 - script are faking an interior but also faking an exterior, so they can have the map and zoom it out so I know not to zoom in here!
{
// Fix for 1623055 - return that we are not in an interior as soon as script stop faking an interior
// if fake interior is active, then return true. if its not anymore but was, return false. if the interior was not set up
// from a fake interior, then return based on the current movie settings as was done previously
if (CScriptHud::FakeInterior.bActive)
{
bInsideInterior = true;
}
else if (!CMiniMap_RenderThread::IsInteriorSetupFromScript())
{
bInsideInterior = ( (CMiniMap_RenderThread::IsInteriorMovieActiveAndSetupOnStage()) ||
((CMiniMap_RenderThread::IsInteriorMovieActive()) && (!IsInPauseMap())) );
}
}
}
return bInsideInterior;
}
void CMiniMap::ExitPauseMapState()
{
SetMinimapModeState(GetCurrentGolfMap() == GOLF_COURSE_OFF ? MINIMAP_MODE_STATE_SETUP_FOR_MINIMAP : MINIMAP_MODE_STATE_SETUP_FOR_GOLFMAP);
}
void CMiniMap::SetMinimapModeState(eSETUP_STATE newState, bool bForceIt /*= false*/)
{
if (MinimapModeState != MINIMAP_MODE_STATE_NONE)
{
// if we haven't finished current transition, then store up latest request and apply that once current
#if !__FINAL
if(CMiniMap_Common::OutputDebugTransitions())
{
if (ms_pendingMinimapModeState == MINIMAP_MODE_STATE_NONE)
uiDisplayf("MINIMAP_TRANSITION: CMiniMap::SetMinimapModeState - Already in a transition (%d) so set new transition (%d) as pending (UT)", MinimapModeState, newState);
else
uiDisplayf("MINIMAP_TRANSITION: CMiniMap::SetMinimapModeState - Already in a transition (%d) so set new transition (%d) as pending replacing old pending value (%d)(UT)", MinimapModeState, newState, ms_pendingMinimapModeState);
}
#endif
ms_pendingMinimapModeState = newState;
return;
}
if (newState == MINIMAP_MODE_STATE_SETUP_FOR_MINIMAP && (IsInPauseMap()||IsInCustomMap()) && GetCurrentGolfMap() != GOLF_COURSE_OFF) // if we are coming out of pausemenu and setting minimap active, we need to switch to golfmap setup if we currently have a valid golf map active
{
newState = MINIMAP_MODE_STATE_SETUP_FOR_GOLFMAP;
}
if (newState == MINIMAP_MODE_STATE_SETUP_FOR_MINIMAP && IsInPauseMap() && WasInBigMap()) // if we are coming out of pausemenu and setting minimap active, we need to switch to bigmap setup if thats what was previously set up
{
newState = MINIMAP_MODE_STATE_SETUP_FOR_BIGMAP;
}
if ( !bForceIt && newState == MinimapModeState) // if already in that state, ignore any idential states as the transition will already be set to go
{
return;
}
switch (newState)
{
case MINIMAP_MODE_STATE_NONE :
break;
case MINIMAP_MODE_STATE_SETUP_FOR_MINIMAP :
{
SetInPauseMap(false);
SetInBigMap(false); // we are now in "minimap" so set bigmap to false
SetInGolfMap(false);
UpdateBitmapOnUT();
#if __BANK
// switch off any blip names when leave pausemap
if (!bDisplayAllBlipNames)
{
ModifyLabelsToAllActiveBlips(false, false);
}
#endif
}
break;
case MINIMAP_MODE_STATE_SETUP_FOR_GOLFMAP :
{
// do not check the state of the golf map as we need to set it up again regardless as we need to setup any new course maps
SetInGolfMap(true);
SetInPauseMap(false);
SetInBigMap(false); // we are now in "minimap" so set bigmap to false
UpdateBitmapOnUT();
#if __BANK
// switch off any blip names when leave pausemap
if (!bDisplayAllBlipNames)
{
ModifyLabelsToAllActiveBlips(false, false);
}
#endif
}
break;
case MINIMAP_MODE_STATE_SETUP_FOR_PAUSEMAP :
{
if ( !bForceIt && IsInPauseMap()) // just return out if already in pausemap
return;
SetInPauseMap(true);
UpdateBitmapOnUT();
#if __BANK
ModifyLabelsToAllActiveBlips(true, true);
#endif // __BANK
}
break;
case MINIMAP_MODE_STATE_SETUP_FOR_CUSTOMMAP:
{
SetInCustomMap(true);
UpdateBitmapOnUT();
//setup starting positions:
Vector2 vFakePlayerPos;
if (CScriptHud::GetFakedPauseMapPlayerPos(vFakePlayerPos))
{
SetPauseMapCursor(vFakePlayerPos);
}
else
{
CPed *pLocalPlayer = GetMiniMapPed();
if (uiVerifyf(pLocalPlayer, "CMiniMap::SetMinimapModeState - failed to get a pointer to the local player"))
{
Vector3 vPlayerPos = VEC3V_TO_VECTOR3(pLocalPlayer->GetTransform().GetPosition());
SetPauseMapCursor(Vector2(vPlayerPos.x, vPlayerPos.y));
}
}
CMapMenu::SetMapZoom(ZOOM_LEVEL_GALLERY, true);
}
break;
case MINIMAP_MODE_STATE_SETUP_FOR_BIGMAP :
{
if ( !bForceIt && IsInBigMap()) // just return out if already in bigmap
return;
SetInBigMap(true); // we are now in "bigmap" so set bigmap to true here
SetInPauseMap(false);
SetInGolfMap(false);
UpdateBitmapOnUT();
#if __BANK
// switch off any blip names when leave pausemap
if (!bDisplayAllBlipNames)
{
ModifyLabelsToAllActiveBlips(false, false);
}
#endif
}
break;
case MINIMAP_MODE_STATE_SETUP_FOR_MINIMAP_HAS_BEEN_PROCESSED_BY_RENDER_THREAD :
case MINIMAP_MODE_STATE_SETUP_FOR_PAUSEMAP_HAS_BEEN_PROCESSED_BY_RENDER_THREAD :
case MINIMAP_MODE_STATE_SETUP_FOR_BIGMAP_HAS_BEEN_PROCESSED_BY_RENDER_THREAD :
case MINIMAP_MODE_STATE_SETUP_FOR_CUSTOMMAP_HAS_BEEN_PROCESSED_BY_RENDER_THREAD :
case MINIMAP_MODE_STATE_SETUP_FOR_GOLFMAP_HAS_BEEN_PROCESSED_BY_RENDER_THREAD :
break;
}
#if !__FINAL
if(CMiniMap_Common::OutputDebugTransitions())
uiDisplayf("MINIMAP_TRANSITION: CMiniMap::SetMinimapModeState(%d) [old state=%d] (UT)", newState, MinimapModeState);
#endif
MinimapModeState = newState; // return this state which will be sent over to RT to process
#if DEBUG_PAD_INPUT
CDebug::UpdateDebugPadMoviePositions();
#endif // #if DEBUG_PAD_INPUT
}
void CMiniMap::UpdateMapPositionAndScaleOnUT(float &fReturnAngle, float &fReturnOffset, Vector3 &vReturnPosition, float &fReturnRange, s32 &iReturnRotation)
{
if (CSystem::IsThisThreadId(SYS_THREAD_RENDER)) // only on UT
{
uiAssertf(0, "CMiniMap::UpdateMapPositionAndScaleOnUT can only be called on the UpdateThread!");
return;
}
fReturnAngle = 0.0f;
fReturnOffset = 0.0f;
if (!IsInPauseMap() && !IsInCustomMap())
{
if ( (!IsInBigMap()) && (!IsInGolfMap()) )
{
if (!CScriptHud::bDontTiltMiniMapThisFrame)
{
if (GetIsInsideInterior())
{
if (bMiniMap3D) // only tilt minimap if rag has set it
{
fReturnAngle = -sm_Tunables.Camera.fInteriorFootTilt;
fReturnOffset = sm_Tunables.Camera.fInteriorFootOffset;
}
}
else
{
if (bMiniMap3D) // only tilt minimap if rag has set it
{
// centered and from above if swimmin' or in a plane
if( ms_bUseNewAwesomeAltimeter && (IsPlayerInPlaneOrHelicopter() /*|| IsPlayerUnderwaterOrInSub()*/))
{
if( GetMiniMapPed() && !GetMiniMapPed()->GetVehiclePedInside() )
fReturnAngle = -sm_Tunables.Camera.fInteriorFootTilt;
else
fReturnAngle = -sm_Tunables.Camera.fAltimeterTilt;
fReturnOffset = sm_Tunables.Camera.fAltimeterOffset;
}
else if (CGameWorld::FindLocalPlayerVehicle() || IsPlayerOnHorse())
{
// in vehicle
fReturnAngle = -sm_Tunables.Camera.fVehicleTilt;
fReturnOffset = sm_Tunables.Camera.fVehicleOffset;
}
else
{
// on foot
fReturnAngle = -sm_Tunables.Camera.fExteriorFootTilt;
fReturnOffset = sm_Tunables.Camera.fExteriorFootOffset;
}
}
}
}
}
}
#if __BANK
if (fDebugTiltValue != -1.0f)
fReturnAngle = -fDebugTiltValue;
if (fDebugOffsetValue != -1.0f)
fReturnOffset = fDebugOffsetValue;
#endif // __BANK
GetCentrePosition(vReturnPosition);
if ( (IsInPauseMap()) || (IsInCustomMap() && CScriptHud::ms_fRadarZoomDistanceThisFrame == 0.0f) )
{
fReturnRange = GetPauseMapScale();
}
else
{
fReturnRange = GetRange();
}
if (!IsInPauseMap() && !IsInCustomMap())
{
#if !__FINAL
if (camInterface::GetDebugDirector().IsFreeCamActive() BANK_ONLY( DEBUG_DRAW_ONLY( && !CMiniMap_RenderThread::sm_bDrawCollisionVolumes)) )
{
vReturnPosition = camInterface::GetPos();
fReturnAngle = 1.0f; // no angle in debug cam - a quick and simple fix for 1314669
fReturnOffset = 0.0f;
}
#endif // __FINAL
if (IsInBigMap())
{
if (ms_bBigMapFullZoom)
{
vReturnPosition.x = BIGMAP_OFFSET_X;
vReturnPosition.y = BIGMAP_OFFSET_Y;
}
else
{
fReturnAngle = sm_Tunables.Camera.fBigmapTilt;
fReturnOffset = sm_Tunables.Camera.fBigmapOffset;
}
}
if ( (GetSpeedOfPlayersVehicle() == 0.0f) && (fReturnRange < MAP_BLIP_ROUND_THRESHOLD) )
{
vReturnPosition.x = floor(vReturnPosition.x+0.5f);
vReturnPosition.y = floor(vReturnPosition.y+0.5f);
}
}
if ( (!IsInPauseMap()) && (!ms_bBigMapFullZoom) && (!IsInCustomMap()) ) // bigmap (non full zoom) can rotate as per Les request 614280
{
if (GetLockedAngle() == -1)
{
CPed* pLocalPed = GetMiniMapPed();
CTask* pTask = pLocalPed ? pLocalPed->GetPedIntelligence()->FindTaskActiveByType(CTaskTypes::TASK_PARACHUTE) : NULL;
bool bIsSkydiving = pTask && pTask->GetState() == CTaskParachute::State_Skydiving;
s32 iCamHeading = (s32)(camInterface::ComputeMiniMapHeading() * RtoD);
s32 iRotDelta = abs(iCamHeading - ms_iPreviousMapRotation);
if(iRotDelta > 180)
{
iRotDelta = 360 - iRotDelta;
}
//@@: range CMINIMAP_UPDATEMAPPOSITIONANDSCALEONUT {
if(bIsSkydiving && camInterface::IsRenderingFirstPersonShooterCamera() && iRotDelta > 20)
{
iReturnRotation = ms_iPreviousMapRotation;
}
else
{
#if TAMPERACTIONS_ENABLED && TAMPERACTIONS_ROTATEMINIMAP
if (TamperActions::ShouldRotateMiniMap())
{
iReturnRotation = CMiniMap_RenderThread::GetMiniMapRenderRotation()-1;
if(iReturnRotation <= -180)
iReturnRotation = 180;
}
else
#endif
iReturnRotation = iCamHeading;
}
}
else
{
iReturnRotation = GetLockedAngle();
}
//@@: } CMINIMAP_UPDATEMAPPOSITIONANDSCALEONUT
}
else
{
iReturnRotation = 0; // declare this as an s32
}
ms_iPreviousMapRotation = iReturnRotation;
// set static variables for use inside UpdateBlips
ms_vMapPosition = vReturnPosition;
// This max distance calculation was pulled from MiniMapRenderThread
// And is used to cull blips that would not have been rendered
if (fReturnAngle != 0.0f) // if we have an angle
{
// use stored range value
ms_fMaxDistance = MINIMAP_DISTANCE_SCALER_3D * (MIN_MINIMAP_RANGE/fReturnRange); // more zoomed out you are, the less we need to restrict the check
ms_fMaxDistance *= 2.f; // take the max possible distance
}
else // ... or a 2D view?
{
ms_fMaxDistance = MINIMAP_DISTANCE_SCALER_2D * (MIN_MINIMAP_RANGE/fReturnRange);
if ((IsInPauseMap() || IsInCustomMap()) && CMapMenu::GetCurrentZoomLevel() == MAX_ZOOMED_IN) // increase amount for pausemap when very zoomed in
{
ms_fMaxDistance *= 2.f; // take the max possible distance
}
}
}
/////////////////////////////////////////////////////////////////////////////////////
// NAME: CMiniMap::UpdateAltimeter
// PURPOSE: updates the altimeter
/////////////////////////////////////////////////////////////////////////////////////
void CMiniMap::UpdateAltimeter(sMiniMapRenderStateStruct& out_Results)
{
if (CSystem::IsThisThreadId(SYS_THREAD_RENDER)) // only on UT
{
uiAssertf(0, "CMiniMap::UpdateAltimeter can only be called on the UpdateThread!");
return;
}
out_Results.m_AltimeterMode = ALTIMETER_OFF;
bool bPlaneIsStalling = false;
if (!IsInPauseMap() && !IsInBigMap() && !IsInCustomMap())
{
#define __MAX_HEIGHT_OF_VEHICLE (2500.0f) // ie planes, closely matches a "tunable" in Planes.cpp, FLIGHT_CEILING_PLANE, but momentum carries you above it
#define __MAX_HEIGHT_OF_NON_VEHICLE (2500.0f) // ie parachute
#define __MIN_HEIGHT_OF_ABYSS (-250.0f);
out_Results.m_fMaxAltimeterHeight = __MAX_HEIGHT_OF_VEHICLE;
out_Results.m_fMinAltimeterHeight = 0.0f; // sea level
CPed *pLocalPlayer = GetMiniMapPed();
Vector3 vPlayerPos( out_Results.m_vCentrePosition );
CVehicle* pVehicle = NULL;
if (pLocalPlayer)
{
pVehicle = pLocalPlayer->GetVehiclePedInside();
// prefer vehicle position if we can get it
if( pVehicle )
{
vPlayerPos = pVehicle->GetBoundCentre();
}
}
bool bMinNeedsSetting = true;
out_Results.m_bColourAltimeter = false;
if (CScriptHud::fFakeMinimapAltimeterHeight != 0.0f)
{
out_Results.m_fMaxAltimeterHeight = CScriptHud::fFakeMinimapAltimeterHeight;
out_Results.m_AltimeterMode = CScriptHud::fFakeMinimapAltimeterHeight > 0 ? ALTIMETER_FLYING : ALTIMETER_SWIMMING;
out_Results.m_bColourAltimeter = CScriptHud::ms_bColourMinimapAltimeter;
out_Results.m_AltimeterColor = CScriptHud::ms_MinimapAltimeterColor;
}
else
{
if (IsPlayerInPlaneOrHelicopter())
{
if (pVehicle && pVehicle->InheritsFromPlane())
{
bPlaneIsStalling = verify_cast<CPlane*>(pVehicle)->IsStalling();
}
Vector2 minMaxHeight(0.0f, 0.0f);
if (CVehiclePopulation::GetFlightHeightsFromFlightZones(vPlayerPos, minMaxHeight))
{
out_Results.m_fMinAltimeterHeight = minMaxHeight.x;
out_Results.m_fMaxAltimeterHeight = minMaxHeight.y;
bMinNeedsSetting = false;
}
else
{
out_Results.m_fMaxAltimeterHeight = __MAX_HEIGHT_OF_VEHICLE;
}
out_Results.m_AltimeterMode = ALTIMETER_FLYING;
}
else
{
if (IsPlayerUsingParachute())
{
out_Results.m_AltimeterMode = ALTIMETER_FLYING;
out_Results.m_fMaxAltimeterHeight = __MAX_HEIGHT_OF_NON_VEHICLE;
}
}
}
#if KEYBOARD_MOUSE_SUPPORT
if (out_Results.m_AltimeterMode == ALTIMETER_FLYING || out_Results.m_AltimeterMode == ALTIMETER_SWIMMING)
{
bool bMouseFlySteering = CControl::GetMouseSteeringMode(PREF_MOUSE_FLY) == CControl::eMSM_Vehicle;
bool bCameraMouseFlySteering = CControl::GetMouseSteeringMode(PREF_MOUSE_FLY) == CControl::eMSM_Camera;
if (IsPlayerUsingParachute())
{
// No mouse controls for parachuting; yoke indicator is not necessary
if (ms_bShowingYoke)
{
CMiniMap::ShowYoke(false);
}
}
else if((bMouseFlySteering && !CControlMgr::GetMainPlayerControl().GetDriveCameraToggleOn()) || (bCameraMouseFlySteering && CControlMgr::GetMainPlayerControl().GetDriveCameraToggleOn()))
{
// We've changed to flying
CControl& playerControl = CControlMgr::GetMainPlayerControl();
CVehicle *pVehicle = FindPlayerVehicle(CGameWorld::GetMainPlayerInfo(), true);
float fRoll = playerControl.GetValue(INPUT_VEH_FLY_ROLL_LR).GetNorm();
float fPitch = playerControl.GetValue(INPUT_VEH_FLY_PITCH_UD).GetNorm();
if(pVehicle)
{
if(pVehicle->InheritsFromHeli())
{
CHeli *pHeli = static_cast<CHeli*>(pVehicle);
fRoll = -pHeli->GetRollControl();
fPitch = pHeli->GetPitchControl();
}
else if(pVehicle->InheritsFromPlane())
{
CPlane *pPlane = static_cast<CPlane*>(pVehicle);
fRoll = pPlane->GetRollControl();
fPitch = pPlane->GetPitchControl();
}
}
CMiniMap::ShowYoke(true, fRoll, fPitch, 100);
}
else
{
CMiniMap::ShowYoke(false);
}
}
ms_iPrevAltimeterMode = out_Results.m_AltimeterMode;
#endif
if( bMinNeedsSetting )
{
out_Results.m_fMinAltimeterHeight = CGameWorldHeightMap::GetMinHeightFromWorldHeightMap(vPlayerPos.x-ALTIMETER_HEIGHTMAP_WIGGLE_ROOM, vPlayerPos.y-ALTIMETER_HEIGHTMAP_WIGGLE_ROOM
, vPlayerPos.x+ALTIMETER_HEIGHTMAP_WIGGLE_ROOM, vPlayerPos.y+ALTIMETER_HEIGHTMAP_WIGGLE_ROOM );
}
}
if (ms_bShowingYoke && out_Results.m_AltimeterMode != ALTIMETER_FLYING)
{
// Changed from flying mode to something else
CMiniMap::ShowYoke(false);
}
// there's bugs with this being broken.
// this loose static is probably why
static bool bPreviousPlaneStalling = false;
if (bPlaneIsStalling != bPreviousPlaneStalling)
{
if (CScaleformMgr::BeginMethod(GetMovieId(MINIMAP_MOVIE_FOREGROUND), SF_BASE_CLASS_MINIMAP, "SHOW_STALL_WARNING"))
{
CScaleformMgr::AddParamBool(bPlaneIsStalling);
CScaleformMgr::EndMethod();
}
bPreviousPlaneStalling = bPlaneIsStalling;
}
}
/////////////////////////////////////////////////////////////////////////////////////
// NAME: CMiniMap_RenderThread::GetCurrentMainTile
// PURPOSE: returns the tile the player is currently on
/////////////////////////////////////////////////////////////////////////////////////
Vector2 CMiniMap::GetCurrentMainTile()
{
Vector2 vTile(0,0);
Vector2 vPos;
if (IsInPauseMap())
{
vPos.x = GetPauseMapCursor().x - sm_Tunables.Tiles.vMiniMapWorldStart.x;
vPos.y = sm_Tunables.Tiles.vMiniMapWorldStart.y - GetPauseMapCursor().y;
}
else
{
Vector3 vPlayerPos;
GetCentrePosition(vPlayerPos);
vPos.x = vPlayerPos.x - sm_Tunables.Tiles.vMiniMapWorldStart.x;
vPos.y = sm_Tunables.Tiles.vMiniMapWorldStart.y - vPlayerPos.y;
}
vTile.x = floor( (vPos.x / sm_Tunables.Tiles.vMiniMapWorldSize.x) * MINIMAP_WORLD_TILE_SIZE_X);
vTile.y = floor( (vPos.y / sm_Tunables.Tiles.vMiniMapWorldSize.y) * MINIMAP_WORLD_TILE_SIZE_Y);
//uiDisplayf("CURRENT TILE CHOSEN: %0.2f, %0.2f", vTile.x, vTile.y);
return vTile;
}
/////////////////////////////////////////////////////////////////////////////////////
// NAME: CMiniMap::UpdateTiles
// PURPOSE: switches on/off tiles based on current player position
/////////////////////////////////////////////////////////////////////////////////////
void CMiniMap::UpdateTilesOnUT(bool &bReturnBitmapOnly, Vector2 &vReturnTilesAroundPlayer)
{
if (CSystem::IsThisThreadId(SYS_THREAD_RENDER)) // only on UT
{
uiAssertf(0, "CMiniMap::UpdateTilesOnUT can only be called on the Update Thread!");
return;
}
// Vector2 vTilesAroundPlayer;
// bool bBitmapOnly = false;
vReturnTilesAroundPlayer = Vector2(2.0f, 2.0f);
bReturnBitmapOnly = false;
if ( (!IsInPauseMap()) && (!IsInCustomMap()) )
{
float fTilesAroundPlayer = 2.0f;
#if __BANK
if (s_fDebugForceTilesAroundPlayer != -2.0f)
{
if (s_fDebugForceTilesAroundPlayer == -1.0f)
{
bReturnBitmapOnly = true;
}
fTilesAroundPlayer = s_fDebugForceTilesAroundPlayer;
}
else
#endif // __BANK
if (IsInBigMap() && ms_bBigMapFullScreen)
{
bReturnBitmapOnly = true;
}
else if(IsInBigMap())
{
// calculate the number of tiles based on how much map we're showing
// much more correct than guessing with tuning values, especially since script is involved
Vector2 mapAreaWorld( GetCurrentMiniMapBlurSize() );
Vector2 screenSize((float)VideoResManager::GetUIWidth(), (float)VideoResManager::GetUIHeight());
#if RSG_PC
// handle multi-monitor fun-ness.
const GridMonitor &mon = GRCDEVICE.GetMonitorConfig().getLandscapeMonitor();
screenSize.x = mon.getWidth() * screenSize.x / GRCDEVICE.GetWidth();
screenSize.y = mon.getHeight() * screenSize.y / GRCDEVICE.GetHeight();
#endif
mapAreaWorld.Multiply( screenSize ); // Convert to pixels
mapAreaWorld.Scale( 100.0f / GetRange(true) ); // scale the amount up, adjusting for Scaleform scale (ie, 100 == 1x zoom. 50 == 2x zoom)
Vector2 tileAreaWorld( sm_Tunables.Tiles.vMiniMapWorldSize );
tileAreaWorld.Multiply( Vector2( 1.0f/(MINIMAP_WORLD_TILE_SIZE_X / WIDTH_OF_DWD_SUPERTILE), 1.0f/(MINIMAP_WORLD_TILE_SIZE_Y / HEIGHT_OF_DWD_SUPERTILE) ) ); // each supertile has a number of smaller tiles inside it
Vector2 areaAroundPlayerWorld( mapAreaWorld.x / tileAreaWorld.x, mapAreaWorld.y / tileAreaWorld.y );
areaAroundPlayerWorld.Scale(.5f); // we computed the 'diameter' of tiles, but we need radius
fTilesAroundPlayer = Max(areaAroundPlayerWorld.x, areaAroundPlayerWorld.y); // whichever value is bigger, use that one.
}
else
{
float fRange = GetRange(true);
if (fRange >= sm_Tunables.Camera.fInteriorFootZoom)
{
fTilesAroundPlayer = 1.0f;
}
else if (fRange >= sm_Tunables.Camera.fExteriorFootZoom)
{
fTilesAroundPlayer = 2.0f;
}
else if (fRange >= sm_Tunables.Camera.fVehicleStaticZoom)
{
fTilesAroundPlayer = 2.0f;
}
else if (fwTimer::GetTimeInMilliseconds() <= iMiniMapDpadZoomTimer+TIME_TO_ZOOM_OUT_MINIMAP)
{
fTilesAroundPlayer = 1.0f;
}
else
{
fTilesAroundPlayer = 2.0f;
}
}
if (bReturnBitmapOnly)
{
fTilesAroundPlayer = 0.0f;
}
vReturnTilesAroundPlayer = Vector2(fTilesAroundPlayer, fTilesAroundPlayer);
}
else
{ // We're in the Pause Map // dont stream out when we move off the panes
/* if ( (!CPauseMenu::IsInMapScreen()) && (!CPauseMenu::IsInGalleryScreen()) )
{
bReturnBitmapOnly = true;
vReturnTilesAroundPlayer = Vector2(0.0f, 0.0f);
return;
}*/
#if __BANK
if (s_vDebugForceTilesAroundPlayer.x != -1.0f || s_vDebugForceTilesAroundPlayer.y != -1.0f)
{
bReturnBitmapOnly = false;
vReturnTilesAroundPlayer = s_vDebugForceTilesAroundPlayer;
}
else
#endif // __BANK
{
if (IsInPauseMap() || CPauseMenu::IsInGalleryScreen())
{
vReturnTilesAroundPlayer = CMiniMap_Common::GetTilesFromZoomLevel(CMapMenu::GetCurrentZoomLevel());
bReturnBitmapOnly = (vReturnTilesAroundPlayer.x == 0.0f && vReturnTilesAroundPlayer.y == 0.0f);
}
else // this will be any other screen (ie custom screen). Here we display a set number of tiles or none at all based on a zoom level
{
float fRange = GetRange(true);
#define RANGE_WHERE_MAP_NEEDS_TILES (5.0f)
if (fRange >= RANGE_WHERE_MAP_NEEDS_TILES)
{
vReturnTilesAroundPlayer = Vector2(2.0f, 4.0);
bReturnBitmapOnly = false;
}
else
{
vReturnTilesAroundPlayer = Vector2(0.0f, 0.0);
bReturnBitmapOnly = true;
}
}
}
}
}
void CMiniMap::GetCentrePosition(Vector3 &vReturnVector)
{
#if !__FINAL
if ((!IsInPauseMap()) && (!IsInCustomMap()) &&
( camInterface::GetDebugDirector().IsFreeCamActive() BANK_ONLY( DEBUG_DRAW_ONLY( && !CMiniMap_RenderThread::sm_bDrawCollisionVolumes))))
{
vReturnVector = camInterface::GetPos();
return;
}
#endif // __FINAL
CPed *pLocalPlayer = GetMiniMapPed();
if (uiVerifyf(pLocalPlayer, "CMiniMap::GetCentrePosition - failed to get pointer to local player"))
{
if ( (!CPauseMenu::IsInMapScreen()) && (!CPauseMenu::IsInGalleryScreen()) && (IsPositionLocked()) )
{
vReturnVector.x = GetLockedPosition().x;
vReturnVector.y = GetLockedPosition().y;
vReturnVector.z = 0.0f;
}
else if ( (IsInPauseMap()) || ( (IsInCustomMap()) && (CPauseMenu::IsActive()) ) )
{
vReturnVector.x = GetPauseMapCursor().x;
vReturnVector.y = GetPauseMapCursor().y;
vReturnVector.z = 0.0f;
}
else
{
vReturnVector = VEC3V_TO_VECTOR3(pLocalPlayer->GetTransform().GetPosition());
const CVehicle *pVehicle = pLocalPlayer->GetVehiclePedInside();
if (pVehicle)
{
vReturnVector.z = pVehicle->GetBoundCentre().GetZ();
}
}
}
else
{
vReturnVector.Zero();
}
}
bool CMiniMap::IsPlayerRunning()
{
if (CScriptHud::bDontZoomMiniMapWhenRunningThisFrame)
{
return false;
}
CPed *pLocalPlayer = GetMiniMapPed();
if (uiVerifyf(pLocalPlayer, "CMiniMap::IsPlayerRunning - failed to get pointer to local player"))
{
if (!pLocalPlayer->GetMotionData()->GetIsLessThanRun())
{
return true;
}
}
return false;
}
float CMiniMap::GetSpeedOfPlayersVehicle()
{
float fReturnSpeed = 0.0f;
CPed *pLocalPlayer = GetMiniMapPed();
if (uiVerifyf(pLocalPlayer, "CMiniMap::GetSpeedOfPlayersVehicle - failed to get pointer to local player"))
{
const CVehicle *pVehicle = pLocalPlayer->GetVehiclePedInside();
const CPed *pPedMount = pLocalPlayer->GetMyMount(); // ie horse
if (pVehicle || pPedMount)
{
float fVehicleSpeed = 0.0f;
bool bIsNetworkClone = false;
if (pVehicle)
{
fVehicleSpeed = pVehicle->GetVelocity().Mag();
bIsNetworkClone = pVehicle->IsNetworkClone();
}
else if (pPedMount)
{
fVehicleSpeed = pPedMount->GetVelocity().Mag();
bIsNetworkClone = pPedMount->IsNetworkClone();
}
if (!bIsNetworkClone) // don't scale on network clones as it causes issues like in bug 514578
{
fReturnSpeed = fVehicleSpeed;
}
}
}
return fReturnSpeed;
}
bool CMiniMap::IsPlayerUsingParachute()
{
CPed *pLocalPlayer = GetMiniMapPed();
if (uiVerifyf(pLocalPlayer, "CMiniMap::IsPlayerUsingParachute - failed to get pointer to local player"))
{
// set parachuting flag here in the main update which we can query for the rest of this frame
if (!GetIsInsideInterior())
{
CQueriableInterface* pedQueriableInterface = pLocalPlayer->GetPedIntelligence()->GetQueriableInterface();
if(pedQueriableInterface && pedQueriableInterface->IsTaskCurrentlyRunning(CTaskTypes::TASK_PARACHUTE))
{
s32 taskState = pedQueriableInterface->GetStateForTaskType(CTaskTypes::TASK_PARACHUTE);
if(taskState == CTaskParachute::State_Deploying ||
taskState == CTaskParachute::State_Skydiving ||
taskState == CTaskParachute::State_Parachuting)
{
return true;
}
}
}
}
return false;
}
bool CMiniMap::IsPlayerInPlaneOrHelicopter()
{
CPed *pLocalPlayer = GetMiniMapPed();
if (uiVerifyf(pLocalPlayer, "CMiniMap::IsPlayerInPlaneOrHelicopter - failed to get pointer to local player"))
{
const CVehicle *pVehicle = pLocalPlayer->GetVehiclePedInside();
if (pVehicle)
{
if (pVehicle->GetVehicleType() == VEHICLE_TYPE_PLANE || pVehicle->GetVehicleType() == VEHICLE_TYPE_HELI)
{
return true;
}
}
}
return false;
}
bool CMiniMap::IsPlayerInBikeOrCar()
{
CPed *pLocalPlayer = GetMiniMapPed();
if (uiVerifyf(pLocalPlayer, "CMiniMap::IsPlayerInBikeOrCar - failed to get pointer to local player"))
{
const CVehicle *pVehicle = pLocalPlayer->GetVehiclePedInside();
if (pVehicle)
{
if (pVehicle->GetVehicleType() == VEHICLE_TYPE_BIKE || pVehicle->GetVehicleType() ==VEHICLE_TYPE_BICYCLE || pVehicle->GetVehicleType() == VEHICLE_TYPE_CAR)
{
return true;
}
}
}
return false;
}
bool CMiniMap::IsPlayerOnHorse()
{
CPed *pLocalPlayer = GetMiniMapPed();
if (uiVerifyf(pLocalPlayer, "CMiniMap::IsPlayerOnHorse - failed to get pointer to local player"))
{
return (pLocalPlayer->GetIsOnMount());
}
return false;
}
bool CMiniMap::IsPlayerUnderwaterOrInSub()
{
CPed *pLocalPlayer = GetMiniMapPed();
if (uiVerifyf(pLocalPlayer, "CMiniMap::IsPlayerUnderwaterOrInSub - failed to get pointer to local player"))
{
const CVehicle *pVehicle = pLocalPlayer->GetVehiclePedInside();
if (pVehicle)
{
// Only render sub minimap details if subcar is transformed
if (pVehicle->InheritsFromSubmarine() || (pVehicle->InheritsFromSubmarineCar() && pVehicle->IsInSubmarineMode()))
{
static bool bEverything = true;
if( bEverything )
return pVehicle->m_Buoyancy.GetStatus() != NOT_IN_WATER;
return pVehicle->m_Buoyancy.GetStatus() == FULLY_IN_WATER;
}
return false;
}
// not in a vehicle? are you swimmin'?
const CInWaterEventScanner& waterScanner = pLocalPlayer->GetPedIntelligence()->GetEventScanner()->GetInWaterEventScanner();
float fTimeUnderWater = waterScanner.GetTimeSubmerged();
return fTimeUnderWater > 0.0f;
}
return false;
}
/////////////////////////////////////////////////////////////////////////////////////
// NAME: CMiniMap::UpdateStatesOnUT
// PURPOSE: updates global states on the UT so we can use them later in the RT call
/////////////////////////////////////////////////////////////////////////////////////
void CMiniMap::UpdateStatesOnUT()
{
if (!CSystem::IsThisThreadId(SYS_THREAD_UPDATE)) // only on UT
{
uiAssertf(0, "CMiniMap:: UpdateStatesOnUT can only be called on the UpdateThread!");
return;
}
if (!bActive)
return;
CPed *pLocalPlayer = GetMiniMapPed();
if (!pLocalPlayer)
return;
sMiniMapRenderStateStruct MiniMapUpdateState;
MiniMapUpdateState.bDeadOrArrested = (pLocalPlayer->ShouldBeDead() || pLocalPlayer->GetIsArrested());
GetCentrePosition(MiniMapUpdateState.m_vCentrePosition);
const CVehicle *pVehicle = pLocalPlayer->GetVehiclePedInside();
if (pVehicle)
{
Matrix34 mat = MAT34V_TO_MATRIX34(pVehicle->GetMatrix());
Vector3 eulers;
mat.ToEulersYXZ(eulers); // get the roll
MiniMapUpdateState.fRoll = eulers.y;
}
else
{
Matrix34 mat = MAT34V_TO_MATRIX34(pLocalPlayer->GetMatrix());
Vector3 eulers;
mat.ToEulersYXZ(eulers); // get the roll
MiniMapUpdateState.fRoll = eulers.y;
}
// invert the roll if in first person
{
const camBaseCamera* pDominantRenderedCamera = camInterface::GetDominantRenderedCamera();
if(pDominantRenderedCamera && camInterface::GetDominantRenderedCamera()->GetIsClassId(camCinematicMountedCamera::GetStaticClassId()))
{
const camCinematicMountedCamera* pMountedCamera = static_cast<const camCinematicMountedCamera*>(pDominantRenderedCamera);
if( pMountedCamera && pMountedCamera->IsFirstPersonCamera() )
MiniMapUpdateState.fRoll *= -1.0;
}
}
MiniMapUpdateState.bInPlaneOrHeli = IsPlayerInPlaneOrHelicopter();
MiniMapUpdateState.m_fPlayerVehicleSpeed = GetSpeedOfPlayersVehicle();
u32& iHashOfCurrentInterior = MiniMapUpdateState.m_Interior.uHash;
CPortalTracker* pPT = const_cast<CPortalTracker*>(pLocalPlayer ? pLocalPlayer->GetPortalTracker() : NULL);
if (pPT->IsInsideInterior()) // need to check very basic interior test here to know whether we need to stream in the interior movie
{
iHashOfCurrentInterior = pLocalPlayer->GetPortalTracker()->GetInteriorNameHash();
u32 roomIndex = pLocalPlayer->GetInteriorLocation().GetRoomIndex();
// get current interior rotation and position:
CInteriorInst* pIntInst = pLocalPlayer->GetPortalTracker()->GetInteriorInst();
if (pIntInst)
{
MiniMapUpdateState.m_Interior.iLevel = pIntInst->GetFloorIdInRoom(roomIndex) + pIntInst->GetFloorId();
MiniMapUpdateState.m_Interior.vPos = VEC3V_TO_VECTOR3(pIntInst->GetTransform().GetPosition());
MiniMapUpdateState.m_Interior.vBoundMin = pIntInst->GetBoundingBoxMin();
MiniMapUpdateState.m_Interior.vBoundMax = pIntInst->GetBoundingBoxMax();
MiniMapUpdateState.m_Interior.fRot = -(pIntInst->GetTransform().GetHeading() * RtoD);
}
}
MiniMapUpdateState.bInsideInterior = GetIsInsideInterior();
MiniMapUpdateState.bInCreator = CScriptHud::bUsingMissionCreator;
if (ms_bInPrologue) // fix for 986642
{
iHashOfCurrentInterior = ATSTRINGHASH("V_FakePrologueLand",0xa6410896);
MiniMapUpdateState.m_Interior.vPos.Set(4750.0f, -4500.0f, 0.0f);
MiniMapUpdateState.m_Interior.fRot = 0.0f;
MiniMapUpdateState.m_Interior.iLevel = 0;
}
else if(ms_bOnIslandMap)
{
u32 uIslandVaultHash = ATSTRINGHASH("h4_dlc_island_vault", 0x3D792750);
bool bIsInsideIslandVault = MiniMapUpdateState.bInsideInterior && iHashOfCurrentInterior == uIslandVaultHash;
iHashOfCurrentInterior = ATSTRINGHASH("h4_fake_islandx",0xC0A90510);
MiniMapUpdateState.m_Interior.vPos.Set(4700.0f, -5150.0f, 0.0f);
MiniMapUpdateState.m_Interior.fRot = 0.0f;
// hack to allow the vault interior to display on the island map
if(bIsInsideIslandVault)
{
MiniMapUpdateState.m_Interior.iLevel = 1;
}
else
{
MiniMapUpdateState.m_Interior.iLevel = 0;
}
}
else
{
if (CScriptHud::FakeInterior.bActive && CScriptHud::FakeInterior.iHash != 0)
{
iHashOfCurrentInterior = CScriptHud::FakeInterior.iHash;
if (CScriptHud::FakeInterior.iLevel == sMiniMapInterior::INVALID_LEVEL)
{
MiniMapUpdateState.m_Interior.iLevel = 0;
}
else
{
MiniMapUpdateState.m_Interior.iLevel = CScriptHud::FakeInterior.iLevel;
}
MiniMapUpdateState.m_Interior.vPos.Set(CScriptHud::FakeInterior.vPosition.x, CScriptHud::FakeInterior.vPosition.y, 0.0f);
MiniMapUpdateState.m_Interior.fRot = -(float)CScriptHud::FakeInterior.iRotation;
MiniMapUpdateState.m_Interior.vBoundMin.Zero();
MiniMapUpdateState.m_Interior.vBoundMax.Zero();
}
}
#if __BANK
if (ms_iDebugInteriorHash != 0)
{
iHashOfCurrentInterior = (u32)ms_iDebugInteriorHash;
MiniMapUpdateState.m_bHasDebugInterior = true;
}
else
{
MiniMapUpdateState.m_bHasDebugInterior = false;
}
if (ms_iDebugInteriorLevel != sMiniMapInterior::INVALID_LEVEL)
{
MiniMapUpdateState.m_Interior.iLevel = ms_iDebugInteriorLevel;
}
#endif // __BANK
//
// check whether this is an interior that we want to override with an alternative interior
//
if (iHashOfCurrentInterior != 0)
{
bool bFoundMatchingOverrideInterior = false;
for (s32 i = 0; ( (!bFoundMatchingOverrideInterior) && (i < sm_InteriorInfo.GetCount()) ); i++)
{
if (iHashOfCurrentInterior != sm_InteriorInfo[i].iMainInteriorHash)
{
for (s32 j = 0; ( (!bFoundMatchingOverrideInterior) && (j < sm_InteriorInfo[i].iSubInteriorHash.GetCount()) ); j++)
{
if (iHashOfCurrentInterior == sm_InteriorInfo[i].iSubInteriorHash[j])
{
iHashOfCurrentInterior = sm_InteriorInfo[i].iMainInteriorHash;
MiniMapUpdateState.m_Interior.vPos.Set(sm_InteriorInfo[i].vMainInteriorPos.x, sm_InteriorInfo[i].vMainInteriorPos.y, 0.0f);
MiniMapUpdateState.m_Interior.fRot = sm_InteriorInfo[i].fMainInteriorRot;
MiniMapUpdateState.m_Interior.vBoundMin.Zero();
MiniMapUpdateState.m_Interior.vBoundMax.Zero();
MiniMapUpdateState.m_Interior.iLevel = 0;
bFoundMatchingOverrideInterior = true;
}
}
}
}
}
if ( ms_previousInterior.uHash != 0 &&
ms_previousInterior.ResolveDifferentHash(MiniMapUpdateState.m_Interior) )
{
// We're leaving an interior; stop caching the interior's fake position
CScriptHud::ms_iCurrentFakedInteriorHash = 0;
CScriptHud::vInteriorFakePauseMapPlayerPos.Set(INVALID_FAKE_PLAYER_POS);
}
else
{
// Make sure the previous interior is always cached
ms_previousInterior.ResolveDifferentHash(MiniMapUpdateState.m_Interior);
}
MiniMapUpdateState.bIsInParachute = IsPlayerUsingParachute();
UpdateMapPositionAndScaleOnUT(MiniMapUpdateState.m_fAngle, MiniMapUpdateState.m_fOffset, MiniMapUpdateState.m_vMiniMapPosition, MiniMapUpdateState.m_fMiniMapRange, MiniMapUpdateState.m_iRotation);
MiniMapUpdateState.m_bIsInBigMap = IsInBigMap();
MiniMapUpdateState.m_bBigMapFullZoom = ms_bBigMapFullZoom;
MiniMapUpdateState.m_bIsInPauseMap = IsInPauseMap();
MiniMapUpdateState.bDrawCrosshair = CPauseMenu::IsInMapScreen() && CPauseMenu::IsNavigatingContent();
MiniMapUpdateState.m_bLockedToDistanceZoom = (CScriptHud::ms_fRadarZoomDistanceThisFrame != 0.0f);
MiniMapUpdateState.m_bIsInCustomMap = sMiniMapMenuComponent.IsActive();
MiniMapUpdateState.m_vCurrentMiniMapPosition = GetCurrentMiniMapPosition();
MiniMapUpdateState.m_vCurrentMiniMapSize = GetCurrentMiniMapSize();
MiniMapUpdateState.m_vCurrentMiniMapMaskPosition = GetCurrentMiniMapMaskPosition();
MiniMapUpdateState.m_vCurrentMiniMapMaskSize = GetCurrentMiniMapMaskSize();
MiniMapUpdateState.m_vCurrentMiniMapBlurPosition = GetCurrentMiniMapBlurPosition();
MiniMapUpdateState.m_vCurrentMiniMapBlurSize = GetCurrentMiniMapBlurSize();
MiniMapUpdateState.m_bIsActive = bActive;
#if __BANK
if( s_bRenderMapPositions )
{
grcDebugDraw::RectAxisAligned(MiniMapUpdateState.m_vCurrentMiniMapPosition, MiniMapUpdateState.m_vCurrentMiniMapPosition+MiniMapUpdateState.m_vCurrentMiniMapSize, Color_red, false);
grcDebugDraw::RectAxisAligned(MiniMapUpdateState.m_vCurrentMiniMapMaskPosition, MiniMapUpdateState.m_vCurrentMiniMapMaskPosition+MiniMapUpdateState.m_vCurrentMiniMapMaskSize, Color_orange, false);
grcDebugDraw::RectAxisAligned(MiniMapUpdateState.m_vCurrentMiniMapBlurPosition, MiniMapUpdateState.m_vCurrentMiniMapBlurPosition+MiniMapUpdateState.m_vCurrentMiniMapBlurSize, Color_yellow, false);
}
#endif
// the MinimapModeState gets passed through to RT here, so we need the 'GetCurrentMiniMapPosition' style calls above to
// return sizes based on this value as this if this is set to a transition, it will change the minimap properties, so we
// need latest info to use
MiniMapUpdateState.m_MinimapModeState = MinimapModeState;
#if RSG_PC
// we need to resize after a device loss, but for some reason, if we did this immediately, it disappears
// so instead we gotta wait a frame for the DLC call to make it through.
if( s_iDeviceLostResetCountdown )
{
if( GRCDEVICE.IsReady()
&& MiniMapUpdateState.m_MinimapModeState == MINIMAP_MODE_STATE_NONE
&& --s_iDeviceLostResetCountdown == 0)
{
MiniMapUpdateState.m_MinimapModeState = ms_MiniMapReappearanceState.MinimapModeStateWhenHidden;
}
}
#endif
if (IsInBigMap() || IsInCustomMap())
{
MiniMapUpdateState.m_CurrentGolfMap = GOLF_COURSE_OFF;
}
else
{
#if __BANK
if (ms_iDebugGolfCourseMap != -1)
{
MiniMapUpdateState.m_CurrentGolfMap = (eGOLF_COURSE_HOLES) ms_iDebugGolfCourseMap;
}
else
#endif // __BANK
{
MiniMapUpdateState.m_CurrentGolfMap = GetCurrentGolfMap();
}
}
if( MiniMapUpdateState.m_CurrentGolfMap == GOLF_COURSE_OFF )
{
MiniMapUpdateState.m_CurrentMiniMapFilename[0] = '\0';
}
else
{
safecpy(MiniMapUpdateState.m_CurrentMiniMapFilename, sm_miniMaps[MINIMAP_VALUE_GOLF_COURSE].m_fileName, MAX_LENGTH_OF_MINIMAP_FILENAME);
}
#if __BANK
MiniMapUpdateState.m_bDisplayAllBlipNames = bDisplayAllBlipNames;
// MiniMapUpdateState.m_iDebugGolfCourseMap = ms_iDebugGolfCourseMap;
#endif
UpdateAltimeter(MiniMapUpdateState);
// We want to show a yoke to help with mouse control when driving.
#if RSG_PC
if(ms_iPrevAltimeterMode == ALTIMETER_OFF && ms_bShowingYoke)
{
CMiniMap::ShowYoke(false);
}
#endif
MiniMapUpdateState.m_bShowSonarSweep = ms_bShowSonarSweep;
MiniMapUpdateState.m_bBackgroundMapShouldBeHidden = (CPauseMenu::GetMenuPreference(PREF_RADAR_MODE) == 2 || IsBackgroundMapHidden());
if (IsInPauseMap() || IsInCustomMap())
{
MiniMapUpdateState.m_bBackgroundMapShouldBeHidden = false;
}
if (GetInPrologue())
{
MiniMapUpdateState.m_bShowPrologueMap = true;
MiniMapUpdateState.m_bShowMainMap = false;
MiniMapUpdateState.m_bShowIslandMap = false;
}
else
{
const bool c_bShouldShowMap = (!CScriptHud::ms_bHideMiniMapExteriorMapThisFrame || IsInCustomMap());
MiniMapUpdateState.m_bShowPrologueMap = false;
MiniMapUpdateState.m_bShowMainMap = c_bShouldShowMap && !GetIsOnIslandMap();
MiniMapUpdateState.m_bShowIslandMap = c_bShouldShowMap && GetIsOnIslandMap();
}
MiniMapUpdateState.m_bHideInteriorMap = CScriptHud::ms_bHideMiniMapInteriorMapThisFrame;
#if ENABLE_FOG_OF_WAR
MiniMapUpdateState.m_vPlayerPos = Vector2(pLocalPlayer->GetTransform().GetPosition().GetXf(),pLocalPlayer->GetTransform().GetPosition().GetYf());
MiniMapUpdateState.m_bUpdateFoW = !IsInPauseMap() && !IsInCustomMap() && !MiniMapUpdateState.m_bIsInBigMap && !ms_bInPrologue && ((!NetworkInterface::IsGameInProgress()) || ms_bAllowFoWInMP);
MiniMapUpdateState.m_bUpdateFoW &= !ms_bDoNotUpdateFoW;
MiniMapUpdateState.m_bShowFow = IsInPauseMap() && ((!NetworkInterface::IsGameInProgress()) || ms_bAllowFoWInMP) && !IsInCustomMap() && !ms_bInPrologue && !ms_bHideFoW ;
MiniMapUpdateState.m_numScriptRevealRequested = ms_numScriptRevealRequested;
if( ms_numScriptRevealRequested )
{
sysMemCpy(MiniMapUpdateState.m_ScriptReveal,ms_ScriptReveal,sizeof(MiniMapUpdateState.m_ScriptReveal));
ms_numScriptRevealRequested = 0;
}
MiniMapUpdateState.m_bUpdatePlayerFoW = !CGameWorld::GetMainPlayerInfo()->AreControlsDisabled();
if( ShouldProcessMinimap() )
{
MiniMapUpdateState.m_bClearFoW = ms_bRequestFoWClear;
ms_bRequestFoWClear = false;
ms_bSetFowIsValid = true;
MiniMapUpdateState.m_bRevealFoW = false;
#if !__FINAL
MiniMapUpdateState.m_bRevealFoW |= PARAM_revealmap.Get();
#endif // !__FINAL
MiniMapUpdateState.m_bRevealFoW |= ms_bRequestRevealFoW;
#if __BANK
MiniMapUpdateState.m_bRevealFoW |= CControlMgr::GetKeyboard().GetKeyJustDown(KEY_M, KEYBOARD_MODE_DEBUG_SHIFT, "Reveal Map");
#endif // __BANK
ms_bRequestRevealFoW = false;
#if __D3D11
MiniMapUpdateState.m_bUploadFoWTextureData = ms_bUploadFoWTextureData;
ms_bUploadFoWTextureData = false;
#endif // __D3D11
}
#endif // ENABLE_FOG_OF_WAR
MiniMapUpdateState.m_vCentreTileForPlayer = GetCurrentMainTile();
UpdateTilesOnUT(MiniMapUpdateState.m_bBitmapOnly, MiniMapUpdateState.m_vTilesAroundPlayer);
MiniMapUpdateState.m_bFlashWantedOverlay = ms_bFlashWantedOverlay;
MiniMapUpdateState.m_uFlashStartTime = ms_uFlashStartTime;
MiniMapUpdateState.m_eFlashColour = ms_eFlashColour;
MiniMapUpdateState.m_fPauseMapScale = GetPauseMapScale();
MiniMapUpdateState.m_bShouldProcessMiniMap = ShouldProcessMinimap();
MiniMapUpdateState.m_bInsideReappearance = false;
MiniMapUpdateState.m_bDisplayPlayerNames = CScriptHud::ms_bDisplayPlayerNameBlipTags;
// if the minimap is turned off then the 1st render of it when it comes back has an instant zoom to fix bug 1013874 and similar issues
// this lasts for 2 frames for a reason; to ensure all checks are catered for as we dont know what else may change the zoom and in what
// order. script may pop the player outside before turning on the minimap or they may turn it on beforehand, and we have to deal with
// them doing that in a polished manner
//
// this bit of code is not pretty but at these stage we need to get it looking polished and there are so many things that can effect this stuff
// we want it to appear nicely even if script hide it, show it, someone presses START, unpauses and goes to bigmap.... hence why this has a lot
// of IF checks.
//
u32 uTimeForMiniMapToReappear = 500; // fix for 1893333 without changing too much on how this works...
if (sMiniMapMenuComponent.IsActive()) // quicker time in custom map
{
uTimeForMiniMapToReappear = 100;
}
#if __BANK
bool bOutputDebug = false;
#endif
if (!MiniMapUpdateState.m_bShouldProcessMiniMap)
{
if ( (!ms_MiniMapReappearanceState.bBeenInPauseMenu) && (ms_MiniMapReappearanceState.iMiniMapRenderedTimer == 0) ) // if it was on previously
{
// store position of centre of minimap:
ms_MiniMapReappearanceState.vMiniMapCentrePosWhenHidden = MiniMapUpdateState.m_vCentrePosition;
// store whether inside an interior (note we need to check portal code here rather than the minimap movie, as that wont be setup till minimap is rendered)
const CPed *pLocalPlayer = GetMiniMapPed();
CPortalTracker* pPT = const_cast<CPortalTracker*>(pLocalPlayer ? pLocalPlayer->GetPortalTracker() : NULL);
bool bInsideInteriorFromPortal = ( (CScriptHud::FakeInterior.bActive) || ( (pPT) && (pPT->IsInsideInterior()) && (!pPT->IsAllowedToRunInInterior()) ) );
ms_MiniMapReappearanceState.bMiniMapInteriorWhenHidden = bInsideInteriorFromPortal || MiniMapUpdateState.bInsideInterior;
#if __BANK
bOutputDebug = true;
#endif
}
if (CPauseMenu::IsActive() && !sMiniMapMenuComponent.IsActive())
{
ms_MiniMapReappearanceState.bBeenInPauseMenu = true;
}
if (!CScriptHud::bDisplayRadar)
{
u32 iNewTimer = fwTimer::GetSystemTimeInMilliseconds();
if (iNewTimer > ms_MiniMapReappearanceState.iMiniMapRenderedTimer)
{
ms_MiniMapReappearanceState.iMiniMapRenderedTimer = iNewTimer;
}
}
else
{
u32 iNewTimer = fwTimer::GetSystemTimeInMilliseconds()+uTimeForMiniMapToReappear;
if (iNewTimer > ms_MiniMapReappearanceState.iMiniMapRenderedTimer)
{
ms_MiniMapReappearanceState.iMiniMapRenderedTimer = iNewTimer;
}
}
MiniMapUpdateState.m_bInsideReappearance = true;
ms_MiniMapReappearanceState.MinimapModeStateWhenHidden = MinimapModeState;
}
else if ( (!ms_MiniMapReappearanceState.bBeenInPauseMenu) && (ms_MiniMapReappearanceState.iMiniMapRenderedTimer != 0) )
{
if ( (ms_MiniMapReappearanceState.bMiniMapInteriorWhenHidden == MiniMapUpdateState.bInsideInterior) &&
(ms_MiniMapReappearanceState.MinimapModeStateWhenHidden == MINIMAP_MODE_STATE_NONE) )
{
ms_MiniMapReappearanceState.iMiniMapRenderedTimer = 0; // turn it straight on again
}
}
MiniMapUpdateState.m_bShouldRenderMiniMap = ShouldRenderMinimap();
bool bIsInBigmapThisFrame = IsInBigMap(); // so we can render instantly when switching between minimap and bigmap
static bool bIsInBigmapPreviousFrame = bIsInBigmapThisFrame;
if (MiniMapUpdateState.m_bShouldRenderMiniMap)
{
MiniMapUpdateState.m_bShouldRenderMiniMap = ( (bIsInBigmapThisFrame || bIsInBigmapPreviousFrame) ||
(ms_MiniMapReappearanceState.iMiniMapRenderedTimer == 0) ||
( (IsPositionLocked() && !sMiniMapMenuComponent.IsActive()) && (!IsInGolfMap()) && (!ms_MiniMapReappearanceState.bBeenInPauseMenu) ) || // we are going to use IsPositionLocked to pre-stream the minimap
(fwTimer::GetSystemTimeInMilliseconds() >= ms_MiniMapReappearanceState.iMiniMapRenderedTimer) ||
(ms_MiniMapReappearanceState.iMiniMapRenderedTimer < (fwTimer::GetSystemTimeInMilliseconds() - uTimeForMiniMapToReappear)) );
if (MiniMapUpdateState.m_bShouldRenderMiniMap)
{
if (!CPauseMenu::IsActive())
{
ms_MiniMapReappearanceState.bBeenInPauseMenu = false;
}
ms_MiniMapReappearanceState.iMiniMapRenderedTimer = 0;
}
#if __BANK
else if (bOutputDebug) // only output debug if the timer hasnt been updated this frame (stops it spamming so much)
{
bool bCutsceneRunning = (CutSceneManager::GetInstance() && CutSceneManager::GetInstance()->IsRunning());
if ( (CPauseMenu::GetMenuPreference(PREF_RADAR_MODE) != 0) && (!CPauseMenu::IsActive()) && (!bCutsceneRunning) ) // only want this output when minimap is on and in game
{
uiDisplayf("Minimap not rendered as it is preparing its display (%d/%d)", fwTimer::GetSystemTimeInMilliseconds(), ms_MiniMapReappearanceState.iMiniMapRenderedTimer);
}
}
#endif // #if __BANK
}
if (ms_MiniMapReappearanceState.iMiniMapRenderedTimer == 0)
{
ms_bIsHiddenAfterTransition = false;
}
else
{
ms_bIsHiddenAfterTransition = (ms_MiniMapReappearanceState.iMiniMapRenderedTimer > (fwTimer::GetSystemTimeInMilliseconds() - uTimeForMiniMapToReappear));
}
if (CPauseMenu::IsActive() && !sMiniMapMenuComponent.IsActive()) // if in pausemap, then render anyway, but keep the flags set as above
{
MiniMapUpdateState.m_bShouldRenderMiniMap = true;
}
if ( (IsInBigMap()) && (MiniMapUpdateState.m_bShouldRenderMiniMap) ) // fixes 1563911
{
MiniMapUpdateState.m_bShouldRenderMiniMap = true;//AreAllTexturesActive(ms_eBitmapForMinimap);
}
ms_bIsRendering = (MiniMapUpdateState.m_bShouldProcessMiniMap) && (MiniMapUpdateState.m_bShouldRenderMiniMap);
MiniMapUpdateState.m_iScriptZoomValue = CScriptHud::ms_iRadarZoomValue;
DLC(CMiniMap_RenderState_Setup, (&MiniMapUpdateState) ); // pass through to drawlist
// Moved to CMiniMap::UpdateAtEndOfFrame() to ensure that it's only cleared once the RenderThread has had a chance to process it
// MinimapModeState = MINIMAP_MODE_STATE_NONE; // Graeme - really not sure about this. I'm relying on MinimapModeState only being checked inside CMiniMap_RenderThread::UpdateStatesWithActionScriptOnRT()
bIsInBigmapPreviousFrame = bIsInBigmapThisFrame; // store for next frame
#if DEBUG_DRAW && __BANK
CMiniMap_RenderThread::RenderDebugVolumesOnUT();
#endif
}
/////////////////////////////////////////////////////////////////////////////////////
// NAME: CMiniMap::UpdateDpadDown()
// PURPOSE: certain things in the minimap are triggered when the player pressed DPAD DOWN
// this function deals with that
/////////////////////////////////////////////////////////////////////////////////////
void CMiniMap::UpdateDpadDown()
{
// dont allow dpad down to work in golf course (but still process it if its been set previously)
if ( !IsInGolfMap() && !CPhoneMgr::IsDisplayed() &&
(!NetworkInterface::IsGameInProgress() || CNewHud::IsSniperSightActive()) &&
!GetIsInsideInterior() )
{
CPed * pPlayerPed = FindPlayerPed();
if (pPlayerPed)
{
const CControl* pControl = pPlayerPed->GetControlFromPlayer();
if ( (pControl && pControl->GetHudSpecial().IsDown()) || (CNewHud::IsSniperSightActive() && !CScriptHud::bDontZoomMiniMapWhenSnipingThisFrame) )
{
iMiniMapDpadZoomTimer = fwTimer::GetTimeInMilliseconds();
}
}
}
}
/////////////////////////////////////////////////////////////////////////////////////
// NAME: CMiniMap::UpdateGPS
// PURPOSE: updates the GPS arrows on the minimap
/////////////////////////////////////////////////////////////////////////////////////
void CMiniMap::UpdateGPS()
{
if (!CSystem::IsThisThreadId(SYS_THREAD_UPDATE)) // only on UT
{
uiAssertf(0, "CMiniMap::UpdateGPS can only be called on the UpdateThread!");
return;
}
if (GetMovieId(MINIMAP_MOVIE_FOREGROUND) == -1)
return;
// static bool bPreviousOffsetMiniMapForGPSBar = false;
// bool bOffsetMiniMapForGPSBar = bPreviousOffsetMiniMapForGPSBar;
s32 iLatestGpsInstruction = INVALID_GPS_INSTRUCTION;
CPed *pPlayerPed = GetMiniMapPed();
bool hideDistance = false;
bool bDoSubCheck = false;
if ( (pPlayerPed) && (pPlayerPed->GetIsInVehicle()) && (!IsInBigMap()) )
{
CVehicle* pVehicle = pPlayerPed->GetVehiclePedInside();
bool bInsideSubCarOnRoad = false;
bool bInsideAmphibiousCarOnRoad = false;
if(pVehicle->InheritsFromSubmarineCar()) // fix for 1883240
{
bInsideSubCarOnRoad = (pVehicle->m_Buoyancy.GetStatus() == NOT_IN_WATER); // only considered in the car and not sub if we are not in the water
}
else if (pVehicle->InheritsFromAmphibiousAutomobile())
{
// Check out of water timer to stop this flicking on and off when jumping across waves
CAmphibiousAutomobile* pAmphiVeh = static_cast<CAmphibiousAutomobile*>(pVehicle);
bInsideAmphibiousCarOnRoad = pAmphiVeh->m_Buoyancy.GetStatus() == NOT_IN_WATER && pAmphiVeh->GetBoatHandling()->GetOutOfWaterTime() > 2.0f;
}
bDoSubCheck = pVehicle && pVehicle->GetIsAquatic() && IsPlayerUnderwaterOrInSub();
if(pVehicle && (pVehicle->GetIsAircraft() || (pVehicle->GetIsAquatic() && !bDoSubCheck && !bInsideSubCarOnRoad && !bInsideAmphibiousCarOnRoad)))
{
hideDistance = true;
}
else if (!IsInPauseMap() && !IsInBigMap())
{
s32 iCurrentGPSRouteId = -1;
float fCurrentGPSDistance = -1.0f;
if(bDoSubCheck)
{
Vector3 vSubPos;
spdAABB bounds;
bounds = pVehicle->GetLocalSpaceBoundBox(bounds);
pVehicle->GetBoundCentre(vSubPos);
const float fHalfSubHeight = (bounds.GetMax().GetZf() - bounds.GetMin().GetZf()) * 0.5f;
float fWaterLevel = 0.0f;
pVehicle->m_Buoyancy.GetWaterLevelIncludingRiversNoWaves(vSubPos, &fWaterLevel, POOL_DEPTH, REJECTIONABOVEWATER, NULL);
// Ideally we would do this probe asynchronously, but this is already more efficient than using FindGroundZForCoord().
WorldProbe::CShapeTestHitPoint probeHitPoint;
WorldProbe::CShapeTestResults probeResult(probeHitPoint);
WorldProbe::CShapeTestProbeDesc probeDesc;
// If we hit nothing, assume THE ABYSS.
float fGroundBelowSubLevel = __MIN_HEIGHT_OF_ABYSS;
Vector3 vProbeEnd(vSubPos.x, vSubPos.y, fGroundBelowSubLevel);
probeDesc.SetStartAndEnd(vSubPos, vProbeEnd);
probeDesc.SetResultsStructure(&probeResult);
probeDesc.SetIncludeFlags(ArchetypeFlags::GTA_ALL_MAP_TYPES);
probeDesc.SetContext(WorldProbe::EHud);
probeDesc.SetTypeFlags(ArchetypeFlags::GTA_AI_TEST);
if(WorldProbe::GetShapeTestManager()->SubmitTest(probeDesc))
{
fGroundBelowSubLevel = probeHitPoint.GetHitPosition().z;
}
const float fDistanceToSurface = Max(fWaterLevel - (vSubPos.z + fHalfSubHeight), 0.0f);
const float fDistanceToFloor = Max((vSubPos.z - fHalfSubHeight) - fGroundBelowSubLevel, 0.0f);
if( !ms_bPreviousShowDepthGauge )
{
CScaleformMgr::CallMethod(GetMovieId(MINIMAP_MOVIE_FOREGROUND), SF_BASE_CLASS_MINIMAP, "SHOW_DEPTH");
}
const float fDelta = 0.30f; // because metric, only send if we differ by ~a foot
if( !ms_bPreviousShowDepthGauge || abs(fDistanceToSurface - fPreviousGPSDistance) >= fDelta || abs(fDistanceToFloor - fPreviousMinimapFloor) >= fDelta )
{
// this MAY need some leeway since at the highest level you start taking damage
bool bWarnAboutCrushDepth = false;//pVehicle->GetSubHandling() && pVehicle->GetSubHandling()->IsUnderDesignDepth( pVehicle );
if (CScaleformMgr::BeginMethod(GetMovieId(MINIMAP_MOVIE_FOREGROUND), SF_BASE_CLASS_MINIMAP, "SET_DEPTH"))
{
CScaleformMgr::AddParamFloat(fDistanceToSurface);
CScaleformMgr::AddParamFloat(fDistanceToFloor);
CScaleformMgr::AddParamBool(CFrontendStatsMgr::ShouldUseMetric());
CScaleformMgr::AddParamBool(bWarnAboutCrushDepth);
CScaleformMgr::EndMethod();
}
fPreviousGPSDistance = fDistanceToSurface;
fPreviousMinimapFloor = fDistanceToFloor;
}
iLatestGpsInstruction = 0;
ms_bPreviousShowDepthGauge = true;
}
else if (CGps::GetRouteFound(GPS_SLOT_RADAR_BLIP))
{
iCurrentGPSRouteId = GPS_SLOT_RADAR_BLIP;
}
else if (CGps::GetRouteFound(GPS_SLOT_WAYPOINT))
{
iCurrentGPSRouteId = GPS_SLOT_WAYPOINT;
}
if (iCurrentGPSRouteId != -1 && CGps::ShouldGpsBeVisible(iCurrentGPSRouteId, false))
{
iLatestGpsInstruction = CGps::CalcRouteInstruction(iCurrentGPSRouteId);
if (CUserDisplay::AreaName.IsNewName() && CUserDisplay::AreaName.GetName()[0] != '\0')
{
if (CScaleformMgr::BeginMethod(GetMovieId(MINIMAP_MOVIE_FOREGROUND), SF_BASE_CLASS_MINIMAP, "SET_SATNAV_AREA"))
{
CScaleformMgr::AddParamString(CUserDisplay::AreaName.GetName());
CScaleformMgr::EndMethod();
}
//bOffsetMiniMapForGPSBar = true;
}
if(CGps::GetSlot(iCurrentGPSRouteId).IsWorking())
{
fCurrentGPSDistance = float(CGps::GetRouteLength(iCurrentGPSRouteId));
}
}
if( !bDoSubCheck )
{
if( fCurrentGPSDistance != -1.0f && abs(fCurrentGPSDistance - fPreviousGPSDistance) >= 1.0 ) // if a significant enough delta
{
if (CScaleformMgr::BeginMethod(GetMovieId(MINIMAP_MOVIE_FOREGROUND), SF_BASE_CLASS_MINIMAP, "SET_SATNAV_DISTANCE"))
{
CScaleformMgr::AddParamFloat(fCurrentGPSDistance);
CScaleformMgr::AddParamBool(CFrontendStatsMgr::ShouldUseMetric());
CScaleformMgr::EndMethod();
}
fPreviousGPSDistance = fCurrentGPSDistance;
}
}
}
else
{
// If you're in the pause menu, let's clear the distance so it'll refresh when we unpause.
fPreviousGPSDistance = -1.0f;
}
}
if( !bDoSubCheck && ms_bPreviousShowDepthGauge )
{
CScaleformMgr::CallMethod(GetMovieId(MINIMAP_MOVIE_FOREGROUND), SF_BASE_CLASS_MINIMAP, "HIDE_DEPTH");
ms_bPreviousShowDepthGauge = false;
}
/* // matches enum in Actionscript (bug 377270)
BLANK = 0
FORWARD = 1
BACK = 2
LEFT = 3
RIGHT = 4
SLIPROAD_LEFT = 5
SLIPROAD_RIGHT = 6
DIAGONAL_LEFT = 7
DIAGONAL_RIGHT = 8
MERGE_LEFT = 9
MERGE_RIGHT = 10
U_TURN = 11
*/
s32 iActionScriptValue = 0;
if (!hideDistance && iLatestGpsInstruction != INVALID_GPS_INSTRUCTION)
{
switch (iLatestGpsInstruction)
{
case CGpsSlot::GPS_INSTRUCTION_TURN_LEFT:
{
iActionScriptValue = 3;
break;
}
case CGpsSlot::GPS_INSTRUCTION_TURN_RIGHT:
{
iActionScriptValue = 4;
break;
}
case CGpsSlot::GPS_INSTRUCTION_KEEP_LEFT:
{
iActionScriptValue = 7;
break;
}
case CGpsSlot::GPS_INSTRUCTION_KEEP_RIGHT:
{
iActionScriptValue = 8;
break;
}
case CGpsSlot::GPS_INSTRUCTION_STRAIGHT_AHEAD:
{
iActionScriptValue = 1;
break;
}
case CGpsSlot::GPS_INSTRUCTION_UTURN:
{
iActionScriptValue = 11;
break;
}
case CGpsSlot::GPS_INSTRUCTION_CALCULATING_ROUTE:
case CGpsSlot::GPS_INSTRUCTION_HIGHLIGHTED_ROUTE:
case CGpsSlot::GPS_INSTRUCTION_YOU_HAVE_ARRIVED:
case CGpsSlot::GPS_INSTRUCTION_BONG:
{
iActionScriptValue = -1;
break;
}
case CGpsSlot::GPS_INSTRUCTION_UNKNOWN:
{
iActionScriptValue = -1;
break;
}
default:
{
iActionScriptValue = -1;
break;
}
}
}
if (iActionScriptValue != iPreviousGpsInstruction)
{
if (iActionScriptValue == 0)
{
if (CScaleformMgr::BeginMethod(GetMovieId(MINIMAP_MOVIE_FOREGROUND), SF_BASE_CLASS_MINIMAP, "HIDE_SATNAV"))
{
CScaleformMgr::EndMethod();
}
//bOffsetMiniMapForGPSBar = false;
}
else
if (iActionScriptValue != -1)
{
if (CScaleformMgr::BeginMethod(GetMovieId(MINIMAP_MOVIE_FOREGROUND), SF_BASE_CLASS_MINIMAP, "SET_SATNAV_DIRECTION"))
{
CScaleformMgr::AddParamInt(iActionScriptValue);
CScaleformMgr::EndMethod();
}
//bOffsetMiniMapForGPSBar = true;
}
iPreviousGpsInstruction = iActionScriptValue;
}
// the invokes to turn off the graphical elements of this will take a frame to get flushed, so we also need to wait the same time
// before repositioning the movie and also skip a blip update at this point, so its a smooth transition
/* if (bSkipBlipUpdate)
{
// readjust the position:
Vector2 vPos = GetCurrentMiniMapPosition();
Vector2 vSize = GetCurrentMiniMapSize();
CScaleformMgr::ChangeMovieParams(GetMovieId(), vPos, vSize, GFxMovieView::SM_ExactFit);
bSkipBlipUpdate = false;
}*/
/* if (bOffsetMiniMapForGPSBar != bPreviousOffsetMiniMapForGPSBar)
{
//SetShowingGPSDisplay(bOffsetMiniMapForGPSBar);
// bSkipBlipUpdate = true;
bPreviousOffsetMiniMapForGPSBar = bOffsetMiniMapForGPSBar;
}*/
}
/////////////////////////////////////////////////////////////////////////////////////
// NAME: CMiniMap::ReInit
// PURPOSE: reinits the minimap - shuts it down and restarts it
// this is called between network sessions so the radar fully clears out its
// memory and data
/////////////////////////////////////////////////////////////////////////////////////
void CMiniMap::ReInit()
{
uiDisplayf("MiniMap: REINIT() - Starting to reinitialise minimap...");
gRenderThreadInterface.Flush(); // flush anything in the DL before we shutdown and re-init
uiDisplayf("MiniMap: REINIT() - flushed renderthread OK...");
// ensure queue is empty before we restart
CBlipUpdateQueue::QueueLock lock(CMiniMap_Common::GetBlipUpdateQueue());
CMiniMap_Common::EmptyBlipUpdateQueue();
uiDisplayf("MiniMap: REINIT() - emptied queue OK...");
#if ENABLE_FOG_OF_WAR
CMiniMap::SetIgnoreFowOnInit(true);
#endif
ms_bInsideReInit = true;
CMiniMap::Shutdown(SHUTDOWN_SESSION);
ms_bInsideReInit = false;
CMiniMap::Init(INIT_SESSION);
// Reset FoW states to after reset
#if ENABLE_FOG_OF_WAR
CMiniMap::SetIgnoreFowOnInit(false);
#endif
uiDisplayf("MiniMap: REINIT() - Minimap is now fully reinitialised");
}
/////////////////////////////////////////////////////////////////////////////////////
// NAME: CMiniMap::UpdateMultiplayerInformation
// PURPOSE: updates the minimap with any information from MP
/////////////////////////////////////////////////////////////////////////////////////
void CMiniMap::UpdateMultiplayerInformation()
{
if (!CSystem::IsThisThreadId(SYS_THREAD_UPDATE)) // only on UT
{
uiAssertf(0, "CMiniMap::UpdateMultiplayerInformation can only be called on the UpdateThread!");
return;
}
bool bDisableAbilityBar = NetworkInterface::IsGameInProgress() || CTheScripts::GetIsInDirectorMode();
if (bPreviousMultiplayerStatus != bDisableAbilityBar )
{
bPreviousMultiplayerStatus = bDisableAbilityBar;
if (CScaleformMgr::BeginMethod(GetMovieId(MINIMAP_MOVIE_FOREGROUND), SF_BASE_CLASS_MINIMAP, "MULTIPLAYER_IS_ACTIVE"))
{
CScaleformMgr::AddParamBool(bPreviousMultiplayerStatus);
CScaleformMgr::EndMethod();
}
}
}
/////////////////////////////////////////////////////////////////////////////////////
// NAME: CMiniMap::IsFlagSet
// PURPOSE: returns whether a specific flag is set
/////////////////////////////////////////////////////////////////////////////////////
bool CMiniMap::IsFlagSet(const CMiniMapBlip *pBlip, u32 iQueryFlag)
{
uiAssertf(pBlip, "CMiniMap::IsFlagSet - Blip not valid!");
// optimisation - assume pBlip is valid if passed in, should speed things up
if (pBlip->IsComplex())
{
return ((CBlipComplex*)pBlip)->m_flags.IsSet(iQueryFlag);
}
else
{
return ((CBlipComplex*)blip[iSimpleBlip])->m_flags.IsSet(iQueryFlag);
}
}
void CMiniMap::UnsetFlag(CMiniMapBlip *pBlip, u32 iQueryFlag)
{
if (pBlip->IsComplex())
{
((CBlipComplex*)pBlip)->m_flags.Clear(iQueryFlag);
}
else
{
((CBlipComplex*)blip[iSimpleBlip])->m_flags.Clear(iQueryFlag);
}
}
void CMiniMap::SetFlag(CMiniMapBlip *pBlip, u32 iQueryFlag)
{
if (pBlip->IsComplex())
{
((CBlipComplex*)pBlip)->m_flags.Set(iQueryFlag, true);
}
else
{
((CBlipComplex*)blip[iSimpleBlip])->m_flags.Set(iQueryFlag, true);
}
}
void CMiniMap::ResetFlag(CMiniMapBlip *pBlip)
{
if (pBlip->IsComplex())
((CBlipComplex*)pBlip)->m_flags.Reset();
else
((CBlipComplex*)blip[iSimpleBlip])->m_flags.Reset();
}
void CMiniMap::GetAllFlags(BlipFlagBitset& outBits, CMiniMapBlip* pBlip)
{
if (uiVerifyf(pBlip, "CMiniMap::IsFlagSet - Blip not valid!"))
{
if (pBlip->IsComplex())
{
outBits = ((CBlipComplex*)pBlip)->m_flags;
}
else
{
outBits = ((CBlipComplex*)blip[iSimpleBlip])->m_flags;
}
}
}
void CMiniMap::AddConeColorForBlip(s32 iBlipIndex, eHUD_COLOURS coneColor)
{
m_ConeColors[iBlipIndex] = coneColor;
}
/////////////////////////////////////////////////////////////////////////////////////
// NAME: CMiniMap::GetBlipPositionValue()
// PURPOSE: return the position of the blip
/////////////////////////////////////////////////////////////////////////////////////
Vector3 CMiniMap::GetBlipPositionValue(CMiniMapBlip *pBlip)
{
if (pBlip->IsComplex())
{
return ((CBlipComplex*)pBlip)->vPosition;
}
else
{
return Vector3(((CBlipSimple*)pBlip)->vPosition.x, ((CBlipSimple*)pBlip)->vPosition.y, 0.0f);
}
}
/////////////////////////////////////////////////////////////////////////////////////
// NAME: CMiniMap::ShouldProcessMinimap
// PURPOSE: in certain situations we dont want to update the minimap
/////////////////////////////////////////////////////////////////////////////////////
bool CMiniMap::ShouldProcessMinimap()
{
if (CSystem::IsThisThreadId(SYS_THREAD_RENDER)) // as this method can be called on either thread, we need to check the relevant buffer here
{
uiAssertf(0, "CMiniMap::ShouldProcessMinimap - Graeme - didn't expect this to be called on the RenderThread");
return false;
}
#if __BANK
static s32 iDebugUpdateState = -1;
#endif // __BANK
if (MinimapModeState != MINIMAP_MODE_STATE_NONE)
{
#if __BANK
if (iDebugUpdateState != 1)
{
uiDebugf1("NOT UPDATING MINIMAP BECAUSE: MinimapModeState != MINIMAP_MODE_STATE_NONE (%d)", MinimapModeState);
iDebugUpdateState = 1;
}
#endif // __BANK
return false;
}
if (!IsInPauseMap())
{
#if __BANK
if (TiledScreenCapture::IsEnabled() ||
LightProbe::IsCapturingPanorama())
{
#if __BANK
if (iDebugUpdateState != 2)
{
uiDebugf1("NOT UPDATING MINIMAP BECAUSE: TiledScreenCapture::IsEnabled()");
iDebugUpdateState = 2;
}
#endif //__BANK
return false;
}
if (!ms_g_bDisplayGameMiniMap)
{
#if __BANK
if (iDebugUpdateState != 3)
{
uiDebugf1("NOT UPDATING MINIMAP BECAUSE: !ms_g_bDisplayGameMiniMap");
iDebugUpdateState = 3;
}
#endif //__BANK
return false;
}
#endif // __BANK
#if COMPANION_APP
if (!CCompanionData::GetInstance()->IsConnected())
{
#endif // COMPANION_APP
if (!CPauseMenu::GetMenuPreference(PREF_RADAR_MODE))
{
#if __BANK
if (iDebugUpdateState != 4)
{
uiDebugf1("NOT UPDATING MINIMAP BECAUSE: !CPauseMenu::GetMenuPreference(PREF_RADAR_MODE)");
iDebugUpdateState = 4;
}
#endif //__BANK
return false;
}
#if COMPANION_APP
}
#endif // COMPANION_APP
}
else
{
if (!CPauseMenu::IsInMapScreen()) // if were are in the pausemenu map mode, then check we are actually on the map screen
return false;
}
#if __BANK
if (iDebugUpdateState != 0)
{
uiDebugf1("NOW UPDATING MINIMAP");
iDebugUpdateState = 0;
}
#endif // __BANK
return true; // we should render/update the minimap
}
/////////////////////////////////////////////////////////////////////////////////////
// NAME: CMiniMap::ShouldRenderMinimap
// PURPOSE: in certain situations we dont want to render the minimap
/////////////////////////////////////////////////////////////////////////////////////
bool CMiniMap::ShouldRenderMinimap()
{
if (CSystem::IsThisThreadId(SYS_THREAD_RENDER)) // as this method can be called on either thread, we need to check the relevant buffer here
{
uiAssertf(0, "CMiniMap::ShouldRenderMinimap - Graeme - didn't expect this to be called on the RenderThread");
return false;
}
#if RSG_PC
if (g_rlPc.IsUiShowing())
{
return false;
}
#endif
#if __BANK
static s32 iDebugRenderingState = -1;
#endif // __BANK
if (sMiniMapMenuComponent.IsActive()) // always show minimap if in custom screen so it appears in the menu, regardless of anything else
{
return true;
}
if (!IsInPauseMap())
{
#if __BANK
if (TiledScreenCapture::IsEnabled() ||
LightProbe::IsCapturingPanorama())
{
#if __BANK
if (iDebugRenderingState != 2)
{
uiDebugf1("NOT RENDERING MINIMAP BECAUSE: TiledScreenCapture::IsEnabled() or LightProbe::IsCapturingPanorama()");
iDebugRenderingState = 2;
}
#endif //__BANK
return false;
}
if (!ms_g_bDisplayGameMiniMap)
{
#if __BANK
if (iDebugRenderingState != 3)
{
uiDebugf1("NOT RENDERING MINIMAP BECAUSE: !ms_g_bDisplayGameMiniMap");
iDebugRenderingState = 3;
}
#endif //__BANK
return false;
}
#endif // __BANK
if (!CScriptHud::bDisplayRadar)
{
#if __BANK
if (iDebugRenderingState != 4)
{
uiDebugf1("NOT RENDERING MINIMAP BECAUSE: !CScriptHud::bDisplayRadar");
iDebugRenderingState = 4;
}
#endif //__BANK
return false;
}
if (!bVisible)
{
#if __BANK
if (iDebugRenderingState != 5)
{
uiDebugf1("NOT RENDERING MINIMAP BECAUSE: !bVisible");
iDebugRenderingState = 5;
}
#endif //__BANK
return false;
}
if (CWarningScreen::IsActive())
{
#if __BANK
if (iDebugRenderingState != 6)
{
uiDebugf1("NOT RENDERING MINIMAP BECAUSE: CWarningScreen::IsActive()");
iDebugRenderingState = 6;
}
#endif //__BANK
return false;
}
if (gVpMan.AreWidescreenBordersActive())
{
#if __BANK
if (iDebugRenderingState != 7)
{
uiDebugf1("NOT RENDERING MINIMAP BECAUSE: gVpMan.AreWidescreenBordersActive()");
iDebugRenderingState = 7;
}
#endif //__BANK
return false;
}
if (CScriptHud::bDontDisplayHudOrRadarThisFrame)
{
#if __BANK
if (iDebugRenderingState != 8)
{
uiDebugf1("NOT RENDERING MINIMAP BECAUSE: CScriptHud::bDontDisplayHudOrRadarThisFrame");
iDebugRenderingState = 8;
}
#endif //__BANK
return false;
}
if (!CPauseMenu::GetMenuPreference(PREF_RADAR_MODE))
{
#if __BANK
if (iDebugRenderingState != 9)
{
uiDebugf1("NOT RENDERING MINIMAP BECAUSE: !CPauseMenu::GetMenuPreference(PREF_RADAR_MODE)");
iDebugRenderingState = 9;
}
#endif //__BANK
return false;
}
if (!NetworkInterface::IsGameInProgress()) // keep minimap on in these cases in MP
{
if (!CGameLogic::IsGameStateInPlay())
{
#if __BANK
if (iDebugRenderingState != 10)
{
uiDebugf1("NOT RENDERING MINIMAP BECAUSE: !CGameLogic::IsGameStateInPlay()");
iDebugRenderingState = 10;
}
#endif //__BANK
return false;
}
CPed *pLocalPlayer = GetMiniMapPed();
if (pLocalPlayer && (pLocalPlayer->ShouldBeDead() || pLocalPlayer->GetIsArrested()))
{
#if __BANK
if (iDebugRenderingState != 11)
{
uiDebugf1("NOT RENDERING MINIMAP BECAUSE: (pLocalPlayer && (pLocalPlayer->ShouldBeDead() || pLocalPlayer->GetIsArrested()))");
iDebugRenderingState = 11;
}
#endif //__BANK
return false;
}
}
if (camInterface::IsFadedOut())
{
#if __BANK
if (iDebugRenderingState != 12)
{
uiDebugf1("NOT RENDERING MINIMAP BECAUSE: camInterface::IsFadedOut()");
iDebugRenderingState = 12;
}
#endif //__BANK
return false;
}
if ( (CutSceneManager::GetInstance()) && (CutSceneManager::GetInstance()->IsRunning()) && (!CutSceneManager::GetInstance()->GetDisplayMiniMapThisUpdate()) )
{
#if __BANK
if (iDebugRenderingState != 13)
{
uiDebugf1("NOT RENDERING MINIMAP BECAUSE: cutscene running and it doesnt need to show");
iDebugRenderingState = 13;
}
#endif //__BANK
return( false );
}
}
else
{
if (!CPauseMenu::IsInMapScreen()) // if were are in the pausemenu map mode, then check we are actually on the map screen
return false;
}
#if __BANK
if (iDebugRenderingState != 0)
{
uiDebugf1("NOW RENDERING MINIMAP");
iDebugRenderingState = 0;
}
#endif // __BANK
return true; // we should render/update the minimap
}
/////////////////////////////////////////////////////////////////////////////////////
// NAME: CMiniMap::ShouldAddSonarBlips
// PURPOSE: Determines whether sonar blips should be added
/////////////////////////////////////////////////////////////////////////////////////
bool CMiniMap::ShouldAddSonarBlips()
{
#if __BANK
if (bDebugAlwaysDrawSonarBlips)
{
return true;
}
#endif //__BANK
if (ms_bForceSonarBlipsOn)
{
ResetFlags();
return true;
}
CPed* pLocalPlayer = GetMiniMapPed();
if (!pLocalPlayer)
{
#if __BANK
if (bDebugVisibilityOfSonarBlips)
{
uiDisplayf("MiniMap: SONAR_BLIP - Not adding sonar blip because No Local Player");
}
#endif
return false;
}
#if DEBUG_DRAW
if (bDebugDrawSonarBlipRange)
{
grcDebugDraw::Circle(VEC3V_TO_VECTOR3(pLocalPlayer->GetTransform().GetPosition()), CMiniMap::sm_Tunables.Sonar.fMinListenerRangeToDrawSonarBlips, Color_bisque3, Vector3(1,0,0), Vector3(0,1,0));
}
#endif // DEBUG_DRAW
if (pLocalPlayer->IsUsingStealthMode())
{
return true;
}
CEntityScannerIterator entityList = pLocalPlayer->GetPedIntelligence()->GetNearbyPeds();
for( CEntity* pEnt = entityList.GetFirst(); pEnt; pEnt = entityList.GetNext() )
{
CPed* pNearbyPed = static_cast<CPed*>(pEnt);
if (pNearbyPed)
{
const bool bIncludeDislike = false;
bool bIsThreatenedBy = pNearbyPed->GetPedIntelligence()->IsThreatenedBy(*pLocalPlayer, bIncludeDislike);
bool bIsInCombatWith = false;
if (!bIsThreatenedBy)
{
//Check if the target is the player.
const CEntity* pTarget = pNearbyPed->GetPedIntelligence()->GetQueriableInterface()->GetHostileTarget();
bIsInCombatWith = (pTarget && pTarget == pLocalPlayer);
}
if (bIsThreatenedBy || bIsInCombatWith)
{
// If this is a network game, skip this ped if it isn't another player
if (NetworkInterface::IsGameInProgress() && !pNearbyPed->IsPlayer())
{
continue;
}
Vec3V vNearbyPedPos = pNearbyPed->GetTransform().GetPosition();
ScalarV vDist2 = DistSquared(vNearbyPedPos, pLocalPlayer->GetTransform().GetPosition());
if (IsLessThanAll(vDist2, ScalarV(square(CMiniMap::sm_Tunables.Sonar.fMinListenerRangeToDrawSonarBlips))))
{
#if DEBUG_DRAW
if (bDebugDrawSonarBlipRange)
{
grcDebugDraw::Line(VEC3V_TO_VECTOR3(pLocalPlayer->GetTransform().GetPosition()), VEC3V_TO_VECTOR3(vNearbyPedPos), Color_bisque3);
}
#endif // DEBUG_DRAW
return true;
}
}
}
}
#if __BANK
if (bDebugVisibilityOfSonarBlips)
{
uiDisplayf("MiniMap: SONAR_BLIP - Not adding sonar blip because of nearby ped checks failed");
}
#endif
return false;
}
/////////////////////////////////////////////////////////////////////////////////////
// NAME: CMiniMap::UpdateBlips
// PURPOSE: updates all the blips
/////////////////////////////////////////////////////////////////////////////////////
void CMiniMap::UpdateBlips()
{
if (CSystem::IsThisThreadId(SYS_THREAD_RENDER)) // only on UT
{
uiAssertf(0, "CMiniMap:: UpdateBlips can only be called on the UpdateThread!");
return;
}
CBlipUpdateQueue::QueueLock lock(CMiniMap_Common::GetBlipUpdateQueue());
CMiniMap_Common::EmptyBlipUpdateQueue();
//
// self-destructing sonar blips
//
bool bHasRedBlipActive = false;
// B*1563553 - Don't draw other sonar blips when a red sonar blip is active [7/19/2013 mdawe]
for (s32 i = 0; i < ms_SonarBlips.GetCount(); i++)
{
bHasRedBlipActive |= CHudColour::IsHudColourRed(ms_SonarBlips[i].iHudColour);
}
for (s32 i = 0; i < ms_SonarBlips.GetCount(); i++)
{
// if still set to rendered from the previous frame then it hasnt been re-used, so delete it here. Also check if a red blip is active, as red blips should kill other ones.
if (ms_SonarBlips[i].iFramesAlive > 0 || bHasRedBlipActive)
{
ms_SonarBlips[i].iFramesAlive++;
bool bDeleteSonarBlip = false;
static const s32 iNumFramesToKeepSonarBlipsAlive = 70; // 70 frames should be enough to keep them alive for
bDeleteSonarBlip |= (ms_SonarBlips[i].iFramesAlive > iNumFramesToKeepSonarBlipsAlive);
bDeleteSonarBlip |= (ms_SonarBlips[i].pPed && ms_SonarBlips[i].pPed->IsDead());
bDeleteSonarBlip |= (bHasRedBlipActive && !CHudColour::IsHudColourRed(ms_SonarBlips[i].iHudColour));
if (bDeleteSonarBlip)
{
ms_SonarBlips.DeleteFast(i);
i = 0;
continue;
}
}
}
if (ShouldRenderMinimap() && GetInStealthMode())
{
for (s32 i = 0; i < ms_SonarBlips.GetCount(); i++)
{
if (uiVerifyf(ms_SonarBlips[i].fSize > 0.0f, "Invalid size %f for sonar blip.", ms_SonarBlips[i].fSize))
{
s32 iFrameCheck = (s32)(floor)(ms_SonarBlips[i].fSize / 5.0f); // work out how long to allow the existing sized blip to continue before re-sizing
if (ms_SonarBlips[i].iFramesAlive <= (iFrameCheck-1))
{
// update position based on ped if we have one
if (ms_SonarBlips[i].pPed && ms_SonarBlips[i].bShouldOverridePos)
{
Vector3 vPedPos = (VEC3V_TO_VECTOR3(ms_SonarBlips[i].pPed->GetTransform().GetPosition()));
ms_SonarBlips[i].vPos = Vector2(vPedPos.x, vPedPos.y);
}
DLC(CMiniMap_AddSonarBlipToStage, (ms_SonarBlips[i]));
}
}
if (ms_SonarBlips[i].iFramesAlive == 0) // only send thru if not already rendered
{
ms_SonarBlips[i].iFramesAlive = 1;
}
}
}
//
// standard blips:
//
s32 iRotation = 0;
if (!IsInPauseMap() && !ms_bBigMapFullScreen)
{
if (GetLockedAngle() == -1)
{
iRotation = (s32)(camInterface::ComputeMiniMapHeading() * RtoD);
}
else
{
iRotation = GetLockedAngle();
}
}
DLC(CMiniMap_ResetBlipConeFlags, () );
ms_blipCones.ClearUsedFlagsForAllBlipCones();
#if __DEV
u32 culledBlips = 0;
u32 totalBlips = 0;
#endif
for (s32 iIndex = 0; iIndex < iMaxCreatedBlips; iIndex++)
{
if (iIndex == iSimpleBlip)
continue;
CMiniMapBlip *pBlip = GetBlipFromActualId(iIndex);
if (!pBlip)
continue;
// Prefetch next blip
if(iIndex < (iMaxCreatedBlips-1))
{
int nextIndex = iIndex+1;
if (nextIndex != iSimpleBlip)
{
CMiniMapBlip *pBlip = GetBlipFromActualId(nextIndex);
if (pBlip)
PrefetchObject(pBlip);
}
}
DEV_ONLY(totalBlips++);
//
// update specific blip info based on entity details:
//
CEntity *pEntity = NULL;
bool bBLIP_FLAG_VALUE_REMOVE_FROM_STAGE = IsFlagSet(pBlip, BLIP_FLAG_VALUE_REMOVE_FROM_STAGE);
bool bBLIP_FLAG_VALUE_CHANGED_FLASH = CMiniMap::IsFlagSet(pBlip, BLIP_FLAG_VALUE_CHANGED_FLASH);
if (!bBLIP_FLAG_VALUE_REMOVE_FROM_STAGE)
{
// The blip may have been marked for removal when its entity was deleted so don't try to use the entity
eBLIP_TYPE iBlipType = GetBlipTypeValue(pBlip);
if (iBlipType == BLIP_TYPE_CAR || iBlipType == BLIP_TYPE_CHAR || iBlipType == BLIP_TYPE_OBJECT || iBlipType == BLIP_TYPE_PICKUP_OBJECT || iBlipType == BLIP_TYPE_COP || iBlipType == BLIP_TYPE_STEALTH)
{
pEntity = FindBlipEntity(pBlip);
//
// update the heading indicator if it is attached to an entity
//
if (IsFlagSet(pBlip, BLIP_FLAG_SHOW_HEADING_INDICATOR))
{
if (pEntity)
{
SetBlipDirectionValue(pBlip, (pEntity->GetTransform().GetHeading() * RtoD));
}
}
}
else if (iBlipType == BLIP_TYPE_PICKUP)
{
pEntity = NULL;
CPickupPlacement* pPlacement = GetPickupPlacementFromBlip(pBlip);
Assertf(pPlacement, "CMiniMap: pickup doesn't exist");
if (pPlacement)
{
// Use the pickup position if a pickup has created. So the blip shows its real position.
CPickup* pPickup = pPlacement->GetPickup();
if(pPickup)
{
SetBlipPositionValue(pBlip, VEC3V_TO_VECTOR3(pPickup->GetTransform().GetPosition()));
}
else
{
SetBlipPositionValue(pBlip, pPlacement->GetPickupPosition());
}
}
}
if (CPauseMenu::IsInMapScreen() && GetBlipCategoryValue(pBlip) == BLIP_CATEGORY_WAYPOINT &&
ms_bCentreBlipPosChangedThisFrame)
{
CMapMenu::UpdateLegendDisplayItem(pBlip);
}
}
if (pEntity)
{
Vector3 vEntityPos = (VEC3V_TO_VECTOR3(pEntity->GetTransform().GetPosition()));
if (pEntity->GetIsTypePed())
{
CPed *pPed = static_cast<CPed*>(pEntity);
if (pPed)
{
if (IsFlagSet(pBlip, BLIP_FLAG_SHOW_CONE))
{
SetupConeDetail(pBlip, pPed); // we need to setup the cone data on the UT
}
// Only update BLIP_CATEGORY_PLAYER legend item if local/remote player's positions have changed
if(CPauseMenu::IsInMapScreen() && GetBlipCategoryValue(pBlip) == BLIP_CATEGORY_PLAYER &&
(ms_bCentreBlipPosChangedThisFrame || GetBlipPositionValue(pBlip) != vEntityPos))
{
CMapMenu::UpdateLegendDisplayItem(pBlip);
}
// In MP override the player position via the network position getter. That will provide us with the same position for player blips if two remote players are in the same vehicle
// This runs through network code because vehicle entities don't exist if the local player is viewing two remote players in the same vehicle from across the world
if(pPed->IsAPlayerPed() && NetworkInterface::IsGameInProgress())
{
NetworkInterface::GetPlayerPositionForBlip(*pPed, vEntityPos);
}
}
}
else
{
if (IsFlagSet(pBlip, BLIP_FLAG_SHOW_CONE))
{
SetupFakeConeDetails(pBlip);
}
}
SetBlipPositionValue(pBlip, vEntityPos);
}
else
{
// Update BLIP_CATEGORY_PLAYER legend item if remote player is in a building and local player's position has changed
if (CPauseMenu::IsInMapScreen() && GetBlipCategoryValue(pBlip) == BLIP_CATEGORY_PLAYER && ms_bCentreBlipPosChangedThisFrame)
{
CMapMenu::UpdateLegendDisplayItem(pBlip);
}
}
// test stealth blips
#if __BANK
if (GetBlipTypeValue(pBlip) == BLIP_TYPE_STEALTH && iDebugSonarStyle != SONAR_STYLE_NONE)
{
if (pEntity && pEntity->GetIsTypePed())
{
CPed *pPed = static_cast<CPed*>(pEntity);
if (pPed)
{
Vector3 vCurrentBlipPos(GetBlipPositionValue(pBlip));
#define __MOVEMENT_PRECISION (2.5f)
Vector3 vStartingBlipPos(GetBlipPositionValueOnStage(pBlip));
vStartingBlipPos.x = ceilf(vStartingBlipPos.x * __MOVEMENT_PRECISION) / __MOVEMENT_PRECISION;
vStartingBlipPos.y = ceilf(vStartingBlipPos.y * __MOVEMENT_PRECISION) / __MOVEMENT_PRECISION;
vStartingBlipPos.z = ceilf(vStartingBlipPos.z * __MOVEMENT_PRECISION) / __MOVEMENT_PRECISION;
vCurrentBlipPos.x = ceilf(vCurrentBlipPos.x * __MOVEMENT_PRECISION) / __MOVEMENT_PRECISION;
vCurrentBlipPos.y = ceilf(vCurrentBlipPos.y * __MOVEMENT_PRECISION) / __MOVEMENT_PRECISION;
vCurrentBlipPos.z = ceilf(vCurrentBlipPos.z * __MOVEMENT_PRECISION) / __MOVEMENT_PRECISION;
bool bFiring = false;
const CTaskGun* gunTask = static_cast<CTaskGun*>(pPed->GetPedIntelligence()->FindTaskActiveByType(CTaskTypes::TASK_GUN));
if(gunTask)
{
bFiring = (gunTask->GetIsFiring());
}
bool bActivateVisualStealthDisplay = false;
bActivateVisualStealthDisplay = (vStartingBlipPos != vCurrentBlipPos || bFiring);
if (iDebugSonarStyle == SONAR_STYLE_RED_BLIPS_FLASH_5_SECONDS)
{
if (pPed->IsDead())
{
bActivateVisualStealthDisplay = true;
}
}
if (bActivateVisualStealthDisplay)
{
if (iDebugSonarStyle == SONAR_STYLE_SONAR_ONLY)
{
if (GetBlipDisplayValue(pBlip) != BLIP_DISPLAY_NEITHER)
{
SetBlipDisplayValue(pBlip, BLIP_DISPLAY_NEITHER);
}
}
else
{
if (GetBlipDisplayValue(pBlip) != BLIP_DISPLAY_BOTH)
{
SetBlipDisplayValue(pBlip, BLIP_DISPLAY_BOTH);
}
}
if (iDebugSonarStyle == SONAR_STYLE_RED_BLIPS_SONAR || iDebugSonarStyle == SONAR_STYLE_SONAR_ONLY)
{
CreateSonarBlip(GetBlipPositionValue(pBlip), CMiniMap::sm_Tunables.Sonar.fSoundRange_MostlyAudible, HUD_COLOUR_BLACK);
}
if (iDebugSonarStyle == SONAR_STYLE_RED_BLIPS_FLASH) // flash for 1 second
{
if (!IsFlagSet(pBlip, BLIP_FLAG_FLASHING))
{
SetBlipFlashDuration(pBlip, 1000);
SetBlipFlashInterval(pBlip, 200);
SetFlag(pBlip, BLIP_FLAG_VALUE_CHANGED_FLASH);
bBLIP_FLAG_VALUE_CHANGED_FLASH = true;
}
}
if (iDebugSonarStyle == SONAR_STYLE_RED_BLIPS_FLASH_5_SECONDS) // flash for 1 second
{
if (!IsFlagSet(pBlip, BLIP_FLAG_FLASHING))
{
SetBlipFlashDuration(pBlip, 5000);
SetBlipFlashInterval(pBlip, 200);
SetFlag(pBlip, BLIP_FLAG_VALUE_CHANGED_FLASH);
bBLIP_FLAG_VALUE_CHANGED_FLASH = true;
}
if (pPed->IsDead())
{
SetBlipFlashDuration(pBlip, MAX_UINT16);
}
}
if (iDebugSonarStyle != SONAR_STYLE_RED_BLIPS_FLASH_5_SECONDS && iDebugSonarStyle != SONAR_STYLE_RED_BLIPS_FLASH)
{
if (IsFlagSet(pBlip, BLIP_FLAG_FLASHING))
{
SetBlipFlashInterval(pBlip, DEFAULT_BLIP_FLASH_INTERVAL);
SetBlipFlashDuration(pBlip, MAX_UINT16);
UnsetFlag(pBlip, BLIP_FLAG_FLASHING);
}
}
}
if (iDebugSonarStyle != SONAR_STYLE_RED_BLIPS_FLASH_5_SECONDS && iDebugSonarStyle != SONAR_STYLE_RED_BLIPS_FLASH)
{
if (IsFlagSet(pBlip, BLIP_FLAG_FLASHING))
{
SetBlipFlashInterval(pBlip, DEFAULT_BLIP_FLASH_INTERVAL);
SetBlipFlashDuration(pBlip, MAX_UINT16);
UnsetFlag(pBlip, BLIP_FLAG_FLASHING);
}
}
}
}
}
#endif // #if __BANK
// UpdateIndividualBlip
if ( (GetUniqueBlipUsed(pBlip) != INVALID_BLIP_ID) && (!IsFlagSet(pBlip, BLIP_FLAG_VALUE_DESTROY_BLIP_OBJECT)) )
{
bool dlcBlip = true; // do we want to send the blip to the render thread for additional processing
bool setExecutedLastFrame = true; // do we want to set the flag that we sent the blip to the render thread
bool cullRemoveFromStage = false; // are we removing the blip from the stage because it's being culled, but was sent to the render thread last frame
BANK_ONLY(if(ms_bCullDistantBlips))
{
if(bBLIP_FLAG_VALUE_REMOVE_FROM_STAGE)
{
// do nothing, these blips need to be removed from the stage on the renderthread
}
else
{
bool cullBlip = false;
// use stored map position
bool bRadiusBlip = (GetBlipTypeValue(pBlip) == BLIP_TYPE_RADIUS || GetBlipTypeValue(pBlip) == BLIP_TYPE_AREA);
Vector3 vBlipPos = GetBlipPositionValue(pBlip);
Vector3 ms_vMapPosition2 = ms_vMapPosition;
vBlipPos.z = 0.0f;
ms_vMapPosition2.z = 0.0f;
if( (!bRadiusBlip) && (vBlipPos.Dist2(ms_vMapPosition2) > rage::square(ms_fMaxDistance)) )
{
if (IsInPauseMap())
{
if (GetIsInsideInterior())
{
CPed *pLocalPlayer = CMiniMap::GetMiniMapPed();
CPortalTracker* pPT = const_cast<CPortalTracker*>(pLocalPlayer ? pLocalPlayer->GetPortalTracker() : NULL);
Vector3 vInteriorBoundMin;
Vector3 vInteriorBoundMax;
if (pPT && pPT->IsInsideInterior())
{
CInteriorInst* pIntInst = pLocalPlayer->GetPortalTracker()->GetInteriorInst();
if (pIntInst)
{
vInteriorBoundMin = pIntInst->GetBoundingBoxMin();
vInteriorBoundMax = pIntInst->GetBoundingBoxMax();
}
}
if (GetBlipTypeValue(pBlip) == BLIP_TYPE_COORDS)
{
if (vBlipPos.GetX() < vInteriorBoundMin.x ||
vBlipPos.GetX() > vInteriorBoundMax.x ||
vBlipPos.GetY() < vInteriorBoundMin.y ||
vBlipPos.GetY() > vInteriorBoundMax.y)
{
cullBlip = true;
}
}
}
else
{
cullBlip = true;
}
}
else if (CMiniMap::IsFlagSet(pBlip, BLIP_FLAG_SHORTRANGE) && (!CMiniMap::IsFlagSet(pBlip, BLIP_FLAG_FLASHING)) && (!bBLIP_FLAG_VALUE_CHANGED_FLASH))
{
cullBlip = true;
}
if(cullBlip)
{
if(IsFlagSet(pBlip, BLIP_FLAG_EXECUTED_VIA_DLC_LAST_FRAME))
{
// blip might be on the stage - remove it temporarily so it doesn't become a zombie blip
UnsetFlag(pBlip, BLIP_FLAG_EXECUTED_VIA_DLC_LAST_FRAME);
SetFlag(pBlip, BLIP_FLAG_VALUE_REMOVE_FROM_STAGE);
bBLIP_FLAG_VALUE_REMOVE_FROM_STAGE = true;
cullRemoveFromStage = true;
setExecutedLastFrame = false;
}
else
{
// we don't need this blip
dlcBlip = false;
}
}
}
}
}
if(dlcBlip)
{
CMiniMap_Common::AddBlipToUpdate(*((CBlipComplex*)pBlip));
//DLC(CMiniMap_Blip_Update, ((CBlipComplex*)pBlip, -iRotation) );
if(setExecutedLastFrame)
{
// we sent this blip to the RT this frame, so if we cull it next frame we'll need to remove it from the stage
SetFlag(pBlip, BLIP_FLAG_EXECUTED_VIA_DLC_LAST_FRAME);
}
if(cullRemoveFromStage)
{
// clear our remove flag if we just set it above, to keep from destroying our blips
UnsetFlag(pBlip, BLIP_FLAG_VALUE_REMOVE_FROM_STAGE);
bBLIP_FLAG_VALUE_REMOVE_FROM_STAGE = false;
}
}
#if __DEV
else
{
culledBlips++;
}
#endif
#if __BANK
if(ms_bShowBlipVectorMap)
{
CVectorMap::DrawMarker(GetBlipPositionValue(pBlip), dlcBlip? Color_green : Color_purple, 10.f);
}
#endif
}
if (bBLIP_FLAG_VALUE_REMOVE_FROM_STAGE)
{
UnsetFlag(pBlip, BLIP_FLAG_VALUE_REMOVE_FROM_STAGE);
UnsetFlag(pBlip, BLIP_FLAG_FLASHING); // set as no longer flashing as its been removed from the stage
SetFlag(pBlip, BLIP_FLAG_VALUE_DESTROY_BLIP_OBJECT);
}
if (bBLIP_FLAG_VALUE_CHANGED_FLASH)
{
if (!IsFlagSet(pBlip,BLIP_FLAG_FLASHING))
SetFlag(pBlip, BLIP_FLAG_FLASHING);
else
UnsetFlag(pBlip, BLIP_FLAG_FLASHING);
UnsetFlag(pBlip, BLIP_FLAG_VALUE_CHANGED_FLASH);
}
UnsetFlag(pBlip, BLIP_FLAG_VALUE_CHANGED_COLOUR);
// silly to check for set then force it off anyway
UnsetFlag(pBlip, BLIP_FLAG_UPDATE_STAGE_DEPTH);
//optimization: gate all these low freq checks with one
if (IsFlagSet(pBlip, BLIP_FLAG_UPDATED_LOW_FREQ_FLAGS))
{
UnsetFlag(pBlip, BLIP_FLAG_UPDATED_LOW_FREQ_FLAGS);
UnsetFlag(pBlip, BLIP_FLAG_VALUE_REINIT_STAGE);
UnsetFlag(pBlip, BLIP_FLAG_VALUE_CHANGED_TICK);
UnsetFlag(pBlip, BLIP_FLAG_VALUE_CHANGED_GOLD_TICK);
UnsetFlag(pBlip, BLIP_FLAG_VALUE_CHANGED_FOR_SALE);
UnsetFlag(pBlip, BLIP_FLAG_VALUE_CHANGED_OUTLINE_INDICATOR);
UnsetFlag(pBlip, BLIP_FLAG_VALUE_CHANGED_FRIEND_INDICATOR);
UnsetFlag(pBlip, BLIP_FLAG_VALUE_CHANGED_CREW_INDICATOR);
UnsetFlag(pBlip, BLIP_FLAG_VALUE_CHANGED_PULSE);
UnsetFlag(pBlip, BLIP_FLAG_VALUE_SET_NUMBER);
}
#if __BANK
UnsetFlag(pBlip, BLIP_FLAG_VALUE_SET_LABEL);
UnsetFlag(pBlip, BLIP_FLAG_VALUE_REMOVE_LABEL);
#endif // __BANK
// update any flash durations set on this blip:
UpdateAndAutoSwitchOffFlash(pBlip);
}
ms_blipCones.RemoveUnusedBlipCones();
#if COMPANION_APP
// Call Companion to listen for messages and notifications
CCompanionData::GetInstance()->Update();
// Update blips on Companion App here
SendBlipsToCompanionApp();
#endif // COMPANION_APP
DLC(CMiniMap_UpdateBlips, () );
DLC(CMiniMap_RemoveUnusedBlipConesFromStage, () );
#if __DEV
if(ms_bCullDistantBlips)
grcDebugDraw::AddDebugOutput("Culling %u of %u blips", culledBlips, totalBlips);
#endif
#if __BANK
if(ms_bShowBlipVectorMap)
{
// draw our vector map
CVectorMap::DrawMarker(ms_vMapPosition, Color_green, 10.f);
CVectorMap::DrawCircle(ms_vMapPosition, ms_fMaxDistance, Color_red, false );
}
#endif
}
// #include "profile/element.h"
// #include "profile/group.h"
// #include "profile/page.h"
// Timing stuff
// PF_PAGE(RobM, "AA RobM Stuff");
// PF_GROUP(RobMSend);
// PF_LINK(RobM, RobMSend);
// PF_TIMER(RobMSendCost, RobMSend);
void CMiniMap::SendBlipsToCompanionApp()
{
#if COMPANION_APP
// PF_FUNC(RobMSendCost);
if (CCompanionData::GetInstance()->IsConnected())
{
for (s32 iIndex = 0; iIndex < iMaxCreatedBlips; iIndex++)
{
if (iIndex == iSimpleBlip)
continue;
CMiniMapBlip *pBlip = GetBlipFromActualId(iIndex);
if (!pBlip)
continue;
if (pBlip->IsComplex())
{
// Add the new blip
if (!IsFlagSet(pBlip, BLIP_FLAG_VALUE_REMOVE_FROM_STAGE) && !IsFlagSet(pBlip, BLIP_FLAG_VALUE_DESTROY_BLIP_OBJECT))
{
Color32 colour;
if (GetBlipColourValue(pBlip) != BLIP_COLOUR_USE_COLOUR32)
{
colour = CMiniMap_Common::GetColourFromBlipSettings(GetBlipColourValue(pBlip), IsFlagSet(pBlip, BLIP_FLAG_BRIGHTNESS));
}
else
{
colour = GetBlipColour32Value(pBlip); // use secondary colour
}
CCompanionData::GetInstance()->AddBlip(1, (CBlipComplex*)pBlip, colour);
}
}
}
}
#endif // COMPANION_APP
}
void CMiniMap::ResetFlags()
{
ms_bForceSonarBlipsOn = false;
}
void CMiniMap::SetupConeDetail(CMiniMapBlip *pBlip, CPed *pPed)
{
if (!uiVerifyf(pPed,"[PEDCONES] Blip Actual: %i Unique: %i couldn't update a visibility cone because there was no ped for me", pBlip->m_iActualId, pBlip->m_iUniqueId))
return;
CPedPerception *pPedPerception = &pPed->GetPedIntelligence()->GetPedPerception();
if (!uiVerifyf(pPedPerception, "[PEDCONES] Blip Actual: %i Unique: %i couldn't update a visibility cone because ped %s had no CPedPerception", pBlip->m_iActualId, pBlip->m_iUniqueId, pPed->GetDebugName()))
return;
// work out the coords for the cone:
const float fVisualFieldMinAzimuthAngle = pPedPerception->GetIsHighlyPerceptive() ? -PI : pPedPerception->GetVisualFieldMinAzimuthAngle() * DtoR;
const float fVisualFieldMaxAzimuthAngle = pPedPerception->GetIsHighlyPerceptive() ? PI : pPedPerception->GetVisualFieldMaxAzimuthAngle() * DtoR;
const float fCentreOfGazeMaxAngle = pPedPerception->GetCentreOfGazeMaxAngle() * DtoR;
// Calculate the peripheral and focus ranges to render the debug lines
float fPeripheralRange = pPedPerception->GetSeeingRangePeripheral();
float fFocusRange = pPedPerception->GetSeeingRange();
pPedPerception->CalculatePerceptionDistances(fPeripheralRange, fFocusRange);
// B*2343564: If any of the overriden cop perception parameters have changed, force re-draw the cone (not just the range value).
bool bRedrawIfAnyConeParametersChange = CPedPerception::ms_bCopOverridesSet && pPed->IsCopPed();
bool bForceRedraw = false;
if (ms_blipCones.UpdateBlipConeParameters(GetUniqueBlipUsed(pBlip), fFocusRange, bRedrawIfAnyConeParametersChange, fPeripheralRange, fCentreOfGazeMaxAngle, fVisualFieldMinAzimuthAngle, fVisualFieldMaxAzimuthAngle))
{
bForceRedraw = true;
}
// To calculate rotation of cone
Matrix34 viewMatrix;
pPedPerception->CalculateViewMatrix(viewMatrix);
Vector3 localEuler = viewMatrix.GetEulers();
// To position the cone
Vector3 vBlipPos = CMiniMap::GetBlipPositionValue(pBlip);
eHUD_COLOURS color = HUD_COLOUR_BLUEDARK;
eHUD_COLOURS* pColor = m_ConeColors.Access(pBlip->m_iUniqueId);
if(pColor)
{
color = *pColor;
m_ConeColors.Delete(pBlip->m_iUniqueId);
}
CBlipCone blipCone(GetActualBlipUsed(pBlip),
fVisualFieldMinAzimuthAngle, fVisualFieldMaxAzimuthAngle, fCentreOfGazeMaxAngle,
fFocusRange, fPeripheralRange,
vBlipPos.x, vBlipPos.y, localEuler.z, (u8)CMiniMap::GetBlipAlphaValue(pBlip), bForceRedraw, color);
DLC(CMiniMap_RenderBlipCone, (&blipCone) );
#if __DEV
if (ms_bRenderPedPerceptionCone)
{
// Render just the exterior perception ranges and interior focus boundaries so its simpler to understand
float aAsimuthAngles[MAX_CONE_ANGLES] = {fVisualFieldMinAzimuthAngle, -fCentreOfGazeMaxAngle, fCentreOfGazeMaxAngle, fVisualFieldMaxAzimuthAngle};
for(u32 azimuthIndex=0; azimuthIndex<MAX_CONE_ANGLES; azimuthIndex++)
{
float azimuthAngle = aAsimuthAngles[azimuthIndex];
bool isCentreOfGaze = azimuthIndex == 1 || azimuthIndex == 2;
Vector3 line(0.0f, isCentreOfGaze?fFocusRange:fPeripheralRange, 0.0f);
float elevationAngle = 0.0f;
line.RotateX(elevationAngle);
line.RotateZ(azimuthAngle);
float fNextAzimuthAngle = (azimuthIndex < (MAX_CONE_ANGLES-1))?aAsimuthAngles[azimuthIndex+1]:azimuthAngle;
bool isArcCentreOfGaze = azimuthIndex == 1;
Color32 focusColour = Color_cyan1;
Color32 colour = isCentreOfGaze ? focusColour : Color_cyan2;
Color32 arcColour = (isArcCentreOfGaze) ? focusColour : Color_cyan2;
viewMatrix.Transform(line);
// draw the line in the 3d world
Vector3 startPosition(VEC3V_TO_VECTOR3(pPed->GetTransform().GetPosition()));
grcDebugDraw::Line(startPosition, line, colour, colour);
// Draw an arc towards the next angle
float fAngle = azimuthAngle;
static float ANGLE_RENDER_DIFF = PI/32.0f;
while( fAngle < fNextAzimuthAngle )
{
float fNextAngle = Min(fAngle + ANGLE_RENDER_DIFF, fNextAzimuthAngle);
Vector3 line1(0.0f, isArcCentreOfGaze?fFocusRange:fPeripheralRange, 0.0f);
line1.RotateX(elevationAngle);
line1.RotateZ(fAngle);
viewMatrix.Transform(line1);
Vector3 line2(0.0f, isArcCentreOfGaze?fFocusRange:fPeripheralRange, 0.0f);
line2.RotateX(elevationAngle);
line2.RotateZ(fNextAngle);
viewMatrix.Transform(line2);
grcDebugDraw::Line(line1, line2, arcColour, arcColour);
fAngle = fNextAngle;
}
}
}
#endif // __DEV
}
void CMiniMap::SetupFakeConeDetails(CMiniMapBlip* pBlip)
{
const int INVALID_INDEX = -1;
int iFakeConeInfoIndex = INVALID_INDEX;
for(int i = 0; i < m_FakeCones.GetCount(); ++i)
{
if(m_FakeCones[i].pBlip == pBlip)
{
iFakeConeInfoIndex = i;
break;
}
}
if(iFakeConeInfoIndex == INVALID_INDEX)
{
uiAssertf(0, "CMiniMap::SetupFakeConeDetails - Blip Actual: %i Unique: %i couldn't update a visibility cone because there is no fake cone info.", pBlip->m_iActualId, pBlip->m_iUniqueId);
return;
}
Vector3 vBlipPos = CMiniMap::GetBlipPositionValue(pBlip);
bool bForceRedraw = false;
if (ms_blipCones.UpdateBlipConeParameters(GetUniqueBlipUsed(pBlip),
m_FakeCones[iFakeConeInfoIndex].fFocusRange,
m_FakeCones[iFakeConeInfoIndex].bContinuousUpdate,
m_FakeCones[iFakeConeInfoIndex].fPeripheralRange,
m_FakeCones[iFakeConeInfoIndex].fCentreOfGazeMaxAngle,
m_FakeCones[iFakeConeInfoIndex].fVisualFieldMinAzimuthAngle,
m_FakeCones[iFakeConeInfoIndex].fVisualFieldMaxAzimuthAngle))
{
bForceRedraw = true;
}
CBlipCone blipCone(
GetActualBlipUsed(pBlip),
m_FakeCones[iFakeConeInfoIndex].fVisualFieldMinAzimuthAngle,
m_FakeCones[iFakeConeInfoIndex].fVisualFieldMaxAzimuthAngle,
m_FakeCones[iFakeConeInfoIndex].fCentreOfGazeMaxAngle,
m_FakeCones[iFakeConeInfoIndex].fFocusRange,
m_FakeCones[iFakeConeInfoIndex].fPeripheralRange,
vBlipPos.x, vBlipPos.y,
m_FakeCones[iFakeConeInfoIndex].fRotation,
(u8)CMiniMap::GetBlipAlphaValue(pBlip),
bForceRedraw,
m_FakeCones[iFakeConeInfoIndex].color);
DLC(CMiniMap_RenderBlipCone, (&blipCone) );
// TODO: Debug drawing if wanted
}
void CMiniMap::AddFakeConeData(int iBlipIndex, float fVisualFieldMinAzimuthAngle, float fVisualFieldMaxAzimuthAngle, float fCentreOfGazeMaxAngle, float fPeripheralRange, float fFocusRange, float fRotation, bool bContinuousUpdate, eHUD_COLOURS color)
{
s32 iActualIndex = ConvertUniqueBlipToActualBlip(iBlipIndex);
if (iActualIndex >= MAX_NUM_BLIPS)
{
uiAssertf(0, "CMiniMap::AddFakeConeData - Attempted to make cone data for blip %d (%d) over the max array (%d)!", iBlipIndex, iActualIndex, MAX_NUM_BLIPS);
return;
}
if (iActualIndex < 0)
{
uiAssertf(0, "CMiniMap::AddFakeConeData - Invalid actual index.");
return;
}
CMiniMapBlip *pBlip = GetBlipFromActualId(iActualIndex);
if (!pBlip)
{
uiAssertf(0, "CMiniMap::AddFakeConeData - Invalid blip index used to get blip.");
return;
}
const int INVALID_INDEX = -1;
int iFakeConeInfoIndex = INVALID_INDEX;
for(int i = 0; i < m_FakeCones.GetCount(); ++i)
{
if(m_FakeCones[i].pBlip == pBlip)
{
iFakeConeInfoIndex = i;
break;
}
}
if(iFakeConeInfoIndex != INVALID_INDEX)
{
m_FakeCones[iFakeConeInfoIndex].fVisualFieldMinAzimuthAngle = fVisualFieldMinAzimuthAngle;
m_FakeCones[iFakeConeInfoIndex].fVisualFieldMaxAzimuthAngle = fVisualFieldMaxAzimuthAngle;
m_FakeCones[iFakeConeInfoIndex].fCentreOfGazeMaxAngle = fCentreOfGazeMaxAngle;
m_FakeCones[iFakeConeInfoIndex].fPeripheralRange = fPeripheralRange;
m_FakeCones[iFakeConeInfoIndex].fFocusRange = fFocusRange;
m_FakeCones[iFakeConeInfoIndex].fRotation = fRotation;
m_FakeCones[iFakeConeInfoIndex].bContinuousUpdate = bContinuousUpdate;
m_FakeCones[iFakeConeInfoIndex].color = color;
}
else
{
sMinimapFakeCone fakeCone;
fakeCone.pBlip = pBlip;
fakeCone.fVisualFieldMinAzimuthAngle = fVisualFieldMinAzimuthAngle;
fakeCone.fVisualFieldMaxAzimuthAngle = fVisualFieldMaxAzimuthAngle;
fakeCone.fCentreOfGazeMaxAngle = fCentreOfGazeMaxAngle;
fakeCone.fPeripheralRange = fPeripheralRange;
fakeCone.fFocusRange = fFocusRange;
fakeCone.fRotation = fRotation;
fakeCone.bContinuousUpdate = bContinuousUpdate;
fakeCone.color = color;
m_FakeCones.PushAndGrow(fakeCone);
}
}
void CMiniMap::DestroyFakeConeData(int iBlipIndex)
{
s32 iActualIndex = ConvertUniqueBlipToActualBlip(iBlipIndex);
if (iActualIndex >= MAX_NUM_BLIPS)
{
uiAssertf(0, "CMiniMap::DestroyFakeConeData - Attempted to make cone data for blip %d (%d) over the max array (%d)!", iBlipIndex, iActualIndex, MAX_NUM_BLIPS);
return;
}
if (iActualIndex < 0)
{
uiAssertf(0, "CMiniMap::DestroyFakeConeData - Invalid actual index.");
return;
}
CMiniMapBlip *pBlip = GetBlipFromActualId(iActualIndex);
if (!pBlip)
{
uiAssertf(0, "CMiniMap::DestroyFakeConeData - Invalid blip index used to get blip.");
return;
}
int iFakeConeInfoIndex = -1;
for(int i = 0; i < m_FakeCones.GetCount(); ++i)
{
if(m_FakeCones[i].pBlip == pBlip)
{
iFakeConeInfoIndex = i;
break;
}
}
if (uiVerifyf(iFakeConeInfoIndex != -1, "[PEDCONES] Blip Actual: %i Unique: %i couldn't update a visibility cone because there is no fake cone info.", pBlip->m_iActualId, pBlip->m_iUniqueId))
{
m_FakeCones.Delete(iFakeConeInfoIndex);
}
}
/////////////////////////////////////////////////////////////////////////////////////
// NAME: CMiniMap::UpdateBlipMarkers()
// PURPOSE: updates the blip markers - adds to a list (DOES NOT RENDER THEM HERE!)
/////////////////////////////////////////////////////////////////////////////////////
void CMiniMap::UpdateBlipMarkers()
{
if (IsInPauseMap())
return;
#if __BANK
if (!CMarkers::g_bDisplayMarkers)
return;
#endif
if (gVpMan.AreWidescreenBordersActive()) // dont render world markers if widescreen borders are active
return;
CEntity *pEntity = NULL;
CVehicle* pVehicle = NULL;
CPed* pPed = NULL;
CPed * pLocalPlayer = GetMiniMapPed();
const Vector3 &vPlayerPos = CGameWorld::FindLocalPlayerCentreOfWorld();
float fEntityTop;
Vector3 vecPos;
#define ARROW_OFFSET (0.4f)
#define SIZE_OF_ARROW (0.12f)
#define INTERIOR_HEIGHT_ABOVE_ENTITY (0.1f)
#define MIN_HEIGHT_ADJUST (0.7f)
#define MAX_HEIGHT_OF_MARKER_ABOVE_CAR (0.9f)
#define MAX_HEIGHT_OF_MARKER_ABOVE_OBJ (1.3f)
#define MIN_DISTANCE_TO_ADJUST_FROM (2.0f)
#define MAX_DISTANCE_TO_ADJUST_FROM (6.5f)
#define MAX_DISTANCE_TO_DISPLAY (500.0f) // only display markers on blips X metres around the player - needs to be high as we may be looking thru the sniper rifle
#define DISTANCE_TO_DISPLAY_FROM (40.0f)
#define DISTANCE_TO_DISPLAY_FROM_MULTIPLAYER (60.0f)
#define DISTANCE_TO_DISPLAY_FROM_LONG_DIST (120.0f)
float fDistFromMarker = (MAX_DISTANCE_TO_ADJUST_FROM*MAX_DISTANCE_TO_ADJUST_FROM);
for (s32 nTrace = 0; nTrace < iMaxCreatedBlips; nTrace++)
{
if (nTrace == iSimpleBlip) // dont process the simple blip
continue;
CMiniMapBlip *pBlip = GetBlipFromActualId(nTrace);
if (!pBlip)
continue;
eBLIP_DISPLAY_TYPE displayValue = GetBlipDisplayValue(pBlip);
if (displayValue != BLIP_DISPLAY_NEITHER)
{
Color32 BlipColour;
if (GetBlipColourValue(pBlip) != BLIP_COLOUR_USE_COLOUR32)
{
BlipColour = CMiniMap_Common::GetColourFromBlipSettings(GetBlipColourValue(pBlip), IsFlagSet(pBlip, BLIP_FLAG_BRIGHTNESS));
}
else
{
BlipColour = GetBlipColour32Value(pBlip);
}
bool bPlayerInsideInterior = GetIsInsideInterior();
switch (GetBlipTypeValue(pBlip))
{
case BLIP_TYPE_CONTACT:
{
// Coordinates get a marker on the ground
if(!CTheScripts::GetPlayerIsOnAMission())
{
if ((displayValue == BLIP_DISPLAY_BOTH)
|| (displayValue == BLIP_DISPLAY_MARKERONLY))
{
if ( pLocalPlayer )
{
// all locates that have default colour should be yellow:
if (GetBlipColourValue(pBlip) == BLIP_COLOUR_DEFAULT)
BlipColour = CHudColour::GetRGBA(HUD_COLOUR_YELLOWLIGHT);
Vector3 vBlipPos(GetBlipPositionValue(pBlip));
Vector3 deltaFromTargetXY = vPlayerPos-vBlipPos;
deltaFromTargetXY.z = 0;
fDistFromMarker = deltaFromTargetXY.Mag2();
if (fDistFromMarker < MAX_DISTANCE_TO_DISPLAY*MAX_DISTANCE_TO_DISPLAY)
{
fDistFromMarker = rage::Min(MAX_DISTANCE_TO_ADJUST_FROM*MAX_DISTANCE_TO_ADJUST_FROM, fDistFromMarker);
s32 iAlpha = (u32)MIN(220,rage::Floorf((rage::Max((fDistFromMarker-(MIN_DISTANCE_TO_ADJUST_FROM*MIN_DISTANCE_TO_ADJUST_FROM)),fDistFromMarker)/(MAX_DISTANCE_TO_ADJUST_FROM*MAX_DISTANCE_TO_ADJUST_FROM))*220.0f));
MarkerInfo_t markerInfo;
markerInfo.type = MARKERTYPE_ARROW;
markerInfo.vPos = RCC_VEC3V(vBlipPos);
markerInfo.vScale = Vec3V(V_TWO);
markerInfo.col = BlipColour;
markerInfo.col.SetAlpha(iAlpha);
markerInfo.faceCam = true;
g_markers.Register(markerInfo);
}
}
}
}
break;
}
case BLIP_TYPE_COORDS:
case BLIP_TYPE_RADIUS:
case BLIP_TYPE_AREA:
{
// no 3d markers for this radar blip type
break;
}
case BLIP_TYPE_CAR :
{
pVehicle = static_cast<CVehicle*>(FindBlipEntity(pBlip));
Assert(pVehicle);
if (pVehicle)
{
if ( (displayValue == BLIP_DISPLAY_BOTH) || (displayValue == BLIP_DISPLAY_MARKERONLY) )
{
fEntityTop = pVehicle->GetBaseModelInfo()->GetBoundingBoxMax().z;
if (pVehicle->GetVehicleType() == VEHICLE_TYPE_HELI)
{
fEntityTop -= 1.0f; // little lower down for helicoptors
}
vecPos = VEC3V_TO_VECTOR3(pVehicle->GetTransform().GetPosition());
float fHeightAboveEntity = MIN_HEIGHT_ADJUST;
vecPos.z += fEntityTop + fHeightAboveEntity + SIZE_OF_ARROW + ARROW_OFFSET;
Vector3 deltaFromTargetXY = vPlayerPos-vecPos;
deltaFromTargetXY.z = 0;
fDistFromMarker = deltaFromTargetXY.Mag2();
if (fDistFromMarker < MAX_DISTANCE_TO_DISPLAY*MAX_DISTANCE_TO_DISPLAY)
{
fDistFromMarker = rage::Min(MAX_DISTANCE_TO_ADJUST_FROM*MAX_DISTANCE_TO_ADJUST_FROM, fDistFromMarker);
s32 iAlpha = (u32)MIN(220,rage::Floorf((rage::Max((fDistFromMarker-(MIN_DISTANCE_TO_ADJUST_FROM*MIN_DISTANCE_TO_ADJUST_FROM)),fDistFromMarker)/(MAX_DISTANCE_TO_ADJUST_FROM*MAX_DISTANCE_TO_ADJUST_FROM))*220.0f));
MarkerInfo_t markerInfo;
markerInfo.type = MARKERTYPE_ARROW;
markerInfo.vPos = RCC_VEC3V(vecPos);
markerInfo.vScale = Vec3V(SIZE_OF_ARROW, SIZE_OF_ARROW, SIZE_OF_ARROW);
markerInfo.col = Color32(BlipColour.GetRed(), BlipColour.GetGreen(), BlipColour.GetBlue(), iAlpha);
markerInfo.faceCam = true;
g_markers.Register(markerInfo);
}
}
}
break;
}
case BLIP_TYPE_CHAR :
{
pPed = static_cast<CPed*>(FindBlipEntity(pBlip));
fEntityTop = 0.0f;
if (pPed)
{
if (pPed->GetPedConfigFlag( CPED_CONFIG_FLAG_InVehicle ))
{
if (pPed->GetVehiclePedInside())
{
pEntity = (CEntity*) pPed->GetVehiclePedInside();
fEntityTop = pEntity->GetBaseModelInfo()->GetBoundingBoxMax().z;
if ((pPed->GetVehiclePedInside())->GetVehicleType() == VEHICLE_TYPE_HELI)
{
fEntityTop -= 1.0f; // little lower down for helicoptors
}
}
else
{
pEntity = NULL;
}
}
else
{
pEntity = (CEntity*) pPed;
fEntityTop = pEntity->GetBaseModelInfo()->GetBoundingBoxMax().z * 0.9f;
}
}
else
{
pEntity = NULL;
}
if (pEntity != NULL && ((displayValue == BLIP_DISPLAY_BOTH)
|| (displayValue == BLIP_DISPLAY_MARKERONLY)))
{
bool bEntityInsideInterior = (pPed && pPed->GetPortalTracker()->IsInsideInterior());
// dont display if player is outside and entity is inside
// this may cause other issues but something is needed to stop the markers
// appearing outside celings when the player is standing on a roof
if (!bPlayerInsideInterior && bEntityInsideInterior)
break;
vecPos = VEC3V_TO_VECTOR3(pEntity->GetTransform().GetPosition()); // get the position of the entity
// if entity is dynamic then check that the global matrices have been updated, if so get the position from them
if (pEntity->GetIsDynamic())
{
CDynamicEntity *pDynamicEntity = static_cast<CDynamicEntity*>(pEntity);
Assert(pDynamicEntity);
s32 boneIndex = pDynamicEntity->GetBoneIndexFromBoneTag(BONETAG_ROOT);
Assert(boneIndex != BONETAG_INVALID);
if(boneIndex == BONETAG_INVALID)
boneIndex = 0;
Matrix34 boneMat;
pPed->GetGlobalMtx(boneIndex, boneMat);
vecPos = boneMat.d;
}
float fHeightAboveEntity = 0.0f; // for a ped in an interior, this should be enough for it not to go thru the roof
bool bRender = true;
if (!bPlayerInsideInterior)
{
Vector3 deltaFromTargetXY = vPlayerPos-vecPos;
deltaFromTargetXY.z = 0;
fDistFromMarker = deltaFromTargetXY.Mag2();
if (fDistFromMarker > MAX_DISTANCE_TO_DISPLAY*MAX_DISTANCE_TO_DISPLAY)
{
bRender = false;
}
fDistFromMarker = rage::Min(MAX_DISTANCE_TO_ADJUST_FROM*MAX_DISTANCE_TO_ADJUST_FROM, fDistFromMarker);
fHeightAboveEntity = rage::Max(((((1.0f / (MAX_DISTANCE_TO_ADJUST_FROM*MAX_DISTANCE_TO_ADJUST_FROM))*fDistFromMarker)*(MAX_HEIGHT_OF_MARKER_ABOVE_CAR*MAX_HEIGHT_OF_MARKER_ABOVE_CAR))-MIN_HEIGHT_ADJUST), 0.0f);
}
vecPos.z += fEntityTop + fHeightAboveEntity + SIZE_OF_ARROW + ARROW_OFFSET;
// lets ensure that these markers dont go halfway through buildings etc
const Vector3 vEndPos(vecPos.x, vecPos.y, vecPos.z - SIZE_OF_ARROW);
if (bEntityInsideInterior)
{
WorldProbe::CShapeTestProbeDesc probeDesc;
probeDesc.SetStartAndEnd(vecPos, vEndPos);
probeDesc.SetIncludeFlags(ArchetypeFlags::GTA_ALL_MAP_TYPES);
bRender = (!WorldProbe::GetShapeTestManager()->SubmitTest(probeDesc));
}
if (bRender)
{
s32 iAlpha = (u32)MIN(220,rage::Floorf((rage::Max((fDistFromMarker-(MIN_DISTANCE_TO_ADJUST_FROM*MIN_DISTANCE_TO_ADJUST_FROM)),fDistFromMarker)/(MAX_DISTANCE_TO_ADJUST_FROM*MAX_DISTANCE_TO_ADJUST_FROM))*220.0f));
MarkerInfo_t markerInfo;
markerInfo.type = MARKERTYPE_ARROW;
markerInfo.vPos = RCC_VEC3V(vecPos);
markerInfo.vScale = Vec3V(SIZE_OF_ARROW, SIZE_OF_ARROW, SIZE_OF_ARROW);
markerInfo.col = Color32(BlipColour.GetRed(), BlipColour.GetGreen(), BlipColour.GetBlue(), iAlpha);
markerInfo.faceCam = true;
g_markers.Register(markerInfo);
}
}
break;
}
case BLIP_TYPE_OBJECT :
case BLIP_TYPE_PICKUP_OBJECT :
case BLIP_TYPE_PICKUP :
case BLIP_TYPE_WEAPON_PICKUP:
{
if ((displayValue == BLIP_DISPLAY_BOTH)
|| (displayValue == BLIP_DISPLAY_MARKERONLY))
{
bool bRenderMarker = true;
float fSizeOfArrow = SIZE_OF_ARROW;
vecPos.Set(0.0f, 0.0f, 0.0f);
if (GetBlipTypeValue(pBlip) == BLIP_TYPE_OBJECT)
{
pEntity = FindBlipEntity(pBlip);
Assertf(pEntity, "CRadar::Draw3dMarkers - object doesn't exist");
if(pEntity)
{
fEntityTop = pEntity->GetBaseModelInfo()->GetBoundingBoxMax().z;
vecPos = VEC3V_TO_VECTOR3(pEntity->GetTransform().GetPosition());
}
else
{
fEntityTop = 0.5f;
}
}
else
{
Assert(GetBlipTypeValue(pBlip) == BLIP_TYPE_PICKUP || GetBlipTypeValue(pBlip) == BLIP_TYPE_WEAPON_PICKUP);
CPickupPlacement* pPlacement = GetPickupPlacementFromBlip(pBlip);
Assertf(pPlacement, "Blip exists for non-existing pickup placement");
fEntityTop = 0.5f; // default pickup height
if (pPlacement)
{
vecPos = pPlacement->GetPickupPosition();
}
pEntity = NULL;
}
if (pEntity) // objects
{
Vector3 deltaFromTargetXY = vPlayerPos-vecPos;
deltaFromTargetXY.z = 0;
fDistFromMarker = deltaFromTargetXY.Mag2();
if (fDistFromMarker > MAX_DISTANCE_TO_DISPLAY*MAX_DISTANCE_TO_DISPLAY)
{
bRenderMarker = false;
}
fDistFromMarker = rage::Min(MAX_DISTANCE_TO_ADJUST_FROM*MAX_DISTANCE_TO_ADJUST_FROM, fDistFromMarker);
}
else // pickups
{
Vector3 deltaFromTargetXY = vPlayerPos-vecPos;
deltaFromTargetXY.z = 0;
fDistFromMarker = deltaFromTargetXY.Mag2();
if (fDistFromMarker > MAX_DISTANCE_TO_DISPLAY*MAX_DISTANCE_TO_DISPLAY)
{
bRenderMarker = false;
}
CPickupPlacement* pPlacement = GetPickupPlacementFromBlip(pBlip);
bool bScaled = false;
if (pPlacement)
{
const CPickupData* pPickupData = pPlacement->GetPickupData();
if (pPickupData)
{
bScaled = (pPickupData->GetScale() > 1.0f);
}
}
if (!NetworkInterface::IsGameInProgress())
{
if (((!IsFlagSet(pBlip,BLIP_FLAG_MARKER_LONG_DIST)) && !bScaled) && fDistFromMarker > DISTANCE_TO_DISPLAY_FROM*DISTANCE_TO_DISPLAY_FROM) // skip any pickups that are not close by otherwise the 3dmarkers array will just fill up (shorter distance)
bRenderMarker = false;
}
else
{
if (((!IsFlagSet(pBlip,BLIP_FLAG_MARKER_LONG_DIST)) && !bScaled) && fDistFromMarker > DISTANCE_TO_DISPLAY_FROM_MULTIPLAYER*DISTANCE_TO_DISPLAY_FROM_MULTIPLAYER) // skip any pickups that are not close by otherwise the 3dmarkers array will just fill up (shorter distance)
bRenderMarker = false;
}
if ((bScaled || (IsFlagSet(pBlip,BLIP_FLAG_MARKER_LONG_DIST))) && fDistFromMarker > DISTANCE_TO_DISPLAY_FROM_LONG_DIST*DISTANCE_TO_DISPLAY_FROM_LONG_DIST) // check a longer distance
bRenderMarker = false;
fDistFromMarker = rage::Min(MAX_DISTANCE_TO_ADJUST_FROM*MAX_DISTANCE_TO_ADJUST_FROM, fDistFromMarker);
fSizeOfArrow *= 1.7f; // Les wants this 3 times as big
}
float fHeightAboveEntity = INTERIOR_HEIGHT_ABOVE_ENTITY;
if (!bPlayerInsideInterior)
{
if (GetBlipTypeValue(pBlip) == BLIP_TYPE_WEAPON_PICKUP)
fHeightAboveEntity = 0.2f; // dont scale for weapon pickups
else
fHeightAboveEntity = MIN_HEIGHT_ADJUST;
}
vecPos.z += fEntityTop + fHeightAboveEntity + fSizeOfArrow + ARROW_OFFSET;
/// const Vector3 vEndPos = Vector3(vecPos.x, vecPos.y, vecPos.z - fSizeOfArrow);
if (bRenderMarker)
{
MarkerInfo_t markerInfo;
markerInfo.type = MARKERTYPE_ARROW;
markerInfo.vPos = RCC_VEC3V(vecPos);
markerInfo.vScale = Vec3V(fSizeOfArrow, fSizeOfArrow, fSizeOfArrow);
markerInfo.col = BlipColour;
markerInfo.col.SetAlpha(220);
markerInfo.bounce = GetBlipTypeValue(pBlip) == BLIP_TYPE_WEAPON_PICKUP;
markerInfo.faceCam = true;
g_markers.Register(markerInfo);
}
}
break;
}
case BLIP_TYPE_UNUSED :
{
break;
}
default :
{
Assertf(0, "Blip %d has an invalid type: %d\n", nTrace, (s32)GetBlipTypeValue(pBlip));
break;
}
}
}
}
}
/////////////////////////////////////////////////////////////////////////////////////
// NAME: CMiniMap::CreateMiniMapMovie
// PURPOSE: creates and loads the scaleform radar movie
/////////////////////////////////////////////////////////////////////////////////////
bool CMiniMap::CreateMiniMapMovie()
{
CScaleformMgr::CreateMovieParams params("minimap_main_map");
params.vPos.x = GetCurrentMiniMapPosition().x;
params.vPos.y = GetCurrentMiniMapPosition().y;
params.vPos.z = 0.0f;
params.vSize = GetCurrentMiniMapSize();
params.bRemovable = false; // not removeable at shutdown session in scaleform automatically
params.bInitiallyLocked = true; // don't update until we give these movies the go-ahead
params.bIgnoreSuperWidescreenScaling = true;
iMovieId[MINIMAP_MOVIE_BACKGROUND] = CScaleformMgr::CreateMovieAndWaitForLoad(params);
params.cFilename = GetCurrentMiniMapFilename();
iMovieId[MINIMAP_MOVIE_FOREGROUND] = CScaleformMgr::CreateMovieAndWaitForLoad(params);
if (GetMovieId(MINIMAP_MOVIE_BACKGROUND) != -1 && GetMovieId(MINIMAP_MOVIE_FOREGROUND) != -1)
{
CScaleformMgr::ForceMovieUpdateInstantly(GetMovieId(MINIMAP_MOVIE_BACKGROUND), false);
CScaleformMgr::ForceMovieUpdateInstantly(GetMovieId(MINIMAP_MOVIE_FOREGROUND), false);
CMiniMap_RenderThread::SetMovieId(MINIMAP_MOVIE_BACKGROUND, GetMovieId(MINIMAP_MOVIE_BACKGROUND));
CMiniMap_RenderThread::SetMovieId(MINIMAP_MOVIE_FOREGROUND, GetMovieId(MINIMAP_MOVIE_FOREGROUND));
return true;
}
else
{
return false;
}
}
/////////////////////////////////////////////////////////////////////////////////////
// NAME: CMiniMap::RemoveMiniMapMovie
// PURPOSE: deletes the mini map movie
/////////////////////////////////////////////////////////////////////////////////////
void CMiniMap::RemoveMiniMapMovie()
{
for (s32 i = 0; i < MAX_MINIMAP_MOVIE_LAYERS; i++)
{
if (GetMovieId(i) >= 0)
{
CScaleformMgr::RequestRemoveMovie(GetMovieId(i));
iMovieId[i] = -1;
CMiniMap_RenderThread::SetMovieId(i, -1);
}
}
}
/////////////////////////////////////////////////////////////////////////////////////
// NAME: CMiniMap::SetBlipObjectName
// PURPOSE: sets the actionscript object name to be used for this blip
/////////////////////////////////////////////////////////////////////////////////////
void CMiniMap::SetBlipObjectName(CMiniMapBlip *pBlip, const BlipLinkage& iNameId )
{
if (pBlip && pBlip->IsComplex())
{
((CBlipComplex*)pBlip)->iLinkageId = iNameId;
}
}
/////////////////////////////////////////////////////////////////////////////////////
// NAME: CMiniMap::SetBlipNameValue
// PURPOSE: sets the text name value to be shown on screen
/////////////////////////////////////////////////////////////////////////////////////
void CMiniMap::SetBlipNameValue(CMiniMapBlip *pBlip, const char *cParam, bool bFromTextFile)
{
if (pBlip && pBlip->IsComplex())
{
CBlipComplex* pBlipCmplx = static_cast<CBlipComplex*>(pBlip);
if (bFromTextFile)
{
pBlipCmplx->cLocName.SetKey(cParam);
}
else
{
pBlipCmplx->cLocName.SetLoc(cParam);
}
}
}
/////////////////////////////////////////////////////////////////////////////////////
// NAME: CMiniMap::SetBlipNameValue
// PURPOSE: sets the text name value to be shown on screen
/////////////////////////////////////////////////////////////////////////////////////
void CMiniMap::SetBlipNameValue(CMiniMapBlip *pBlip, const atHashWithStringBank& hash)
{
if (pBlip && pBlip->IsComplex())
{
CBlipComplex* pBlipCmplx = static_cast<CBlipComplex*>(pBlip);
pBlipCmplx->cLocName.SetKey(hash);
}
}
/////////////////////////////////////////////////////////////////////////////////////
// NAME: CMiniMap::SetBlipCategoryValue
// PURPOSE: sets the category the blip is in
/////////////////////////////////////////////////////////////////////////////////////
void CMiniMap::SetBlipCategoryValue(CMiniMapBlip *pBlip, u8 iNewBlipCategory)
{
if (pBlip && pBlip->IsComplex())
{
((CBlipComplex*)pBlip)->iCategory = iNewBlipCategory;
}
}
/////////////////////////////////////////////////////////////////////////////////////
// NAME: CMiniMap::SetBlipDirectionValue
// PURPOSE: sets rotation of a blip in DEGREES
/////////////////////////////////////////////////////////////////////////////////////
void CMiniMap::SetBlipDirectionValue(CMiniMapBlip *pBlip, float fParam, bool bClamp /*= true*/)
{
if (pBlip && pBlip->IsComplex())
{
if (bClamp)
{
// ensure the value is between 0 and 359 degrees
fParam = CMiniMap_Common::WrapBlipRotation(fParam);
}
((CBlipComplex*)pBlip)->fDirection = fParam;
}
}
/////////////////////////////////////////////////////////////////////////////////////
// NAME: CMiniMap::GetBlipPoolIndexValue()
// PURPOSE: return the pool index value
/////////////////////////////////////////////////////////////////////////////////////
CEntityPoolIndexForBlip &CMiniMap::GetBlipPoolIndexValue(CMiniMapBlip *pBlip)
{
static CEntityPoolIndexForBlip invalidPoolIndex;
if (pBlip && pBlip->IsComplex())
return ((CBlipComplex*)pBlip)->m_PoolIndex;
else
return invalidPoolIndex;
}
CPickupPlacement *CMiniMap::GetPickupPlacementFromBlip(CMiniMapBlip *pBlip)
{
if (pBlip && pBlip->IsComplex())
{
CBlipComplex *pComplexBlip = (CBlipComplex*) pBlip;
if (uiVerifyf(pComplexBlip->type == BLIP_TYPE_PICKUP, "CMiniMap::GetPickupPlacementFromBlip - expected this blip to have type BLIP_TYPE_PICKUP"))
{
return pComplexBlip->m_PoolIndex.GetPickupPlacement();
}
}
return NULL;
}
////////////////////////////////////////////////////////////////////////////
// name: GetActualBlipUsed
//
// purpose: gets the actual blip used for this blip
////////////////////////////////////////////////////////////////////////////
s32 CMiniMap::GetActualBlipUsed(const CMiniMapBlip *pBlip)
{
if (pBlip)
{
return (pBlip->m_iActualId);
}
return -1;
}
////////////////////////////////////////////////////////////////////////////
// name: GetUniqueBlipUsed
//
// purpose: gets the unique blip used for this blip
////////////////////////////////////////////////////////////////////////////
// Only used for debug output in MiniMapCommon and MiniMapRenderThread
s32 CMiniMap::GetUniqueBlipUsed(const CMiniMapBlip *pBlip)
{
if (pBlip)
{
return (pBlip->m_iUniqueId);
}
return INVALID_BLIP_ID;
}
/////////////////////////////////////////////////////////////////////////////////////
// NAME: CMiniMap::GetBlipPositionValue()
// PURPOSE: return the position of the blip
/////////////////////////////////////////////////////////////////////////////////////
Vector3 CMiniMap::GetBlipPositionValueOnStage(CMiniMapBlip *pBlip)
{
if (uiVerifyf(pBlip, "Blip doesnt exist!"))
{
if (pBlip->IsComplex())
{
return ((CBlipComplex*)pBlip)->vPosition;
}
else
{
return Vector3(((CBlipSimple*)pBlip)->vPosition.x, ((CBlipSimple*)pBlip)->vPosition.y, 0.0f);
}
}
return ORIGIN;
}
/////////////////////////////////////////////////////////////////////////////////////
// NAME: CMiniMap::GetBlipObjectNameId
// PURPOSE: gets id of the object
/////////////////////////////////////////////////////////////////////////////////////
s32 CMiniMap::GetBlipObjectNameId(CMiniMapBlip *pBlip)
{
CBlipComplex* pCmplxBlip = static_cast<CBlipComplex*>( pBlip && pBlip->IsComplex() ? pBlip : blip[iSimpleBlip] );
#if HASHED_BLIP_IDS
return static_cast<s32>(pCmplxBlip->iLinkageId.GetHash());
#else
return pCmplxBlip->iLinkageId;
#endif
}
/////////////////////////////////////////////////////////////////////////////////////
// NAME: CMiniMap::GetBlipNameValue
// PURPOSE: gets the text name value to be shown on screen
/////////////////////////////////////////////////////////////////////////////////////
const char* CMiniMap::GetBlipNameValue(CMiniMapBlip *pBlip)
{
const CBlipComplex* pBlipCmplex = static_cast<CBlipComplex*>(pBlip->IsComplex() ? pBlip : blip[iSimpleBlip] );
return pBlipCmplex->cLocName.GetStr();
}
/////////////////////////////////////////////////////////////////////////////////////
// NAME: CMiniMap::GetBlipColourValue()
// PURPOSE: return the colour info for this blip
/////////////////////////////////////////////////////////////////////////////////////
eBLIP_COLOURS CMiniMap::GetBlipColourValue(CMiniMapBlip *pBlip)
{
if (pBlip && pBlip->IsComplex())
return (eBLIP_COLOURS)((CBlipComplex*)pBlip)->iColour;
else
return (eBLIP_COLOURS)((CBlipComplex*)blip[iSimpleBlip])->iColour;
}
/////////////////////////////////////////////////////////////////////////////////////
// NAME: CMiniMap::GetBlipAlphaValue()
// PURPOSE: return the alpha for this blip
/////////////////////////////////////////////////////////////////////////////////////
s32 CMiniMap::GetBlipAlphaValue(CMiniMapBlip *pBlip)
{
if (pBlip && pBlip->IsComplex())
return ((CBlipComplex*)pBlip)->iAlpha;
else
return ((CBlipComplex*)blip[iSimpleBlip])->iAlpha;
}
/////////////////////////////////////////////////////////////////////////////////////
// NAME: CMiniMap::GetBlipSecondaryColourValue()
// PURPOSE: return the rgba colour info for this blip
/////////////////////////////////////////////////////////////////////////////////////
Color32 CMiniMap::GetBlipColour32Value(CMiniMapBlip *pBlip)
{
if (pBlip && pBlip->IsComplex())
return ((CBlipComplex*)pBlip)->iColourSecondary;
else
return ((CBlipComplex*)blip[iSimpleBlip])->iColourSecondary;
}
/////////////////////////////////////////////////////////////////////////////////////
// NAME: CMiniMap::GetBlipTypeValue()
// PURPOSE: return the blip type
/////////////////////////////////////////////////////////////////////////////////////
eBLIP_TYPE CMiniMap::GetBlipTypeValue(CMiniMapBlip *pBlip)
{
if (uiVerifyf(pBlip, "Blip doesnt exist!"))
{
if (pBlip->IsComplex())
return (eBLIP_TYPE)((CBlipComplex*)pBlip)->type;
else
return (eBLIP_TYPE)((CBlipComplex*)blip[iSimpleBlip])->type;
}
return BLIP_TYPE_UNUSED;
}
/////////////////////////////////////////////////////////////////////////////////////
// NAME: CMiniMap::GetBlipNumberValue()
// PURPOSE: return the blip display type
/////////////////////////////////////////////////////////////////////////////////////
s8 CMiniMap::GetBlipNumberValue(CMiniMapBlip *pBlip)
{
if (pBlip)
{
if (pBlip->IsComplex())
return ((CBlipComplex*)pBlip)->iNumberToDisplay;
else
return ((CBlipComplex*)blip[iSimpleBlip])->iNumberToDisplay;
}
return -1;
}
/////////////////////////////////////////////////////////////////////////////////////
// NAME: CMiniMap::GetBlipDisplayValue()
// PURPOSE: return the blip display type
/////////////////////////////////////////////////////////////////////////////////////
eBLIP_DISPLAY_TYPE CMiniMap::GetBlipDisplayValue(CMiniMapBlip *pBlip)
{
if (pBlip)
{
if (pBlip->IsComplex())
return (eBLIP_DISPLAY_TYPE)((CBlipComplex*)pBlip)->display;
else
return (eBLIP_DISPLAY_TYPE)((CBlipComplex*)blip[iSimpleBlip])->display;
}
return BLIP_DISPLAY_NEITHER;
}
/////////////////////////////////////////////////////////////////////////////////////
// NAME: CMiniMap::GetBlipDirectionValue()
// PURPOSE: return rotation info of this blip
/////////////////////////////////////////////////////////////////////////////////////
float CMiniMap::GetBlipDirectionValue(CMiniMapBlip *pBlip)
{
if (pBlip && pBlip->IsComplex())
return ((CBlipComplex*)pBlip)->fDirection;
else
return ((CBlipComplex*)blip[iSimpleBlip])->fDirection;
}
/////////////////////////////////////////////////////////////////////////////////////
// NAME: CMiniMap::FindBlipEntity()
// PURPOSE: For a radar trace we identify the entity pointer (if there is one)
/////////////////////////////////////////////////////////////////////////////////////
CEntity *CMiniMap::FindBlipEntity(CMiniMapBlip *pBlip)
{
if (uiVerifyf(pBlip, "CMiniMap::FindBlipEntity - blip doesn't exist"))
{
if (uiVerifyf(pBlip->IsComplex(), "CMiniMap::FindBlipEntity - blip isn't complex"))
{
const eBLIP_TYPE blipType = GetBlipTypeValue(pBlip);
switch(blipType)
{
case BLIP_TYPE_CAR:
case BLIP_TYPE_CHAR:
case BLIP_TYPE_STEALTH:
case BLIP_TYPE_OBJECT:
case BLIP_TYPE_PICKUP_OBJECT :
case BLIP_TYPE_COP:
return ((CBlipComplex*)pBlip)->m_PoolIndex.GetEntity(blipType);
default:
break;
}
}
}
return NULL;
}
/////////////////////////////////////////////////////////////////////////////////////
// NAME: SetBlipParameter()
// PURPOSE: updates a param in the blip structure
/////////////////////////////////////////////////////////////////////////////////////
void CMiniMap::SetBlipParameter(eBLIP_PARAMS iTodo, s32 iIndex, s32 iParam)
{
s32 iActualIndex = ConvertUniqueBlipToActualBlip(iIndex);
if (iActualIndex >= MAX_NUM_BLIPS)
{
uiAssertf(0, "MiniMap: Attempted to update blip %d (%d) over the max array (%d)!", iIndex, iActualIndex, MAX_NUM_BLIPS);
return;
}
if (iActualIndex < 0)
return;
CMiniMapBlip *pBlip = GetBlipFromActualId(iActualIndex);
if (!pBlip)
return;
if (!pBlip->IsComplex())
{
uiAssertf(0, "MiniMap: Attempted to modify a Simple Blip - %d (%d)", iIndex, iActualIndex);
}
switch (iTodo)
{
case BLIP_CHANGE_DEBUG_NUMBER:
{
#if __BANK
SetBlipDebugNumberValue(pBlip, (s8)iParam);
if (iParam != -1)
{
SetFlag(pBlip, BLIP_FLAG_VALUE_SET_LABEL); // on
}
else
{
SetFlag(pBlip, BLIP_FLAG_VALUE_REMOVE_LABEL); // off
}
#endif // __BANK
break;
}
case BLIP_CHANGE_CATEGORY:
{
SetBlipCategoryValue(pBlip, (u8)iParam);
break;
}
case BLIP_CHANGE_PRIORITY:
{
SetBlipPriorityValue(pBlip, (eBLIP_PRIORITY)iParam);
SetFlag(pBlip, BLIP_FLAG_UPDATE_STAGE_DEPTH);
break;
}
case BLIP_CHANGE_DISPLAY:
{
SetBlipDisplayValue(pBlip, (eBLIP_DISPLAY_TYPE)iParam);
if (CPauseMenu::IsActive())
{
if ((eBLIP_DISPLAY_TYPE)iParam != GetBlipDisplayValue(pBlip))
{
uiDebugf1("Updating pausemap legend because '%s' blip changed display value", GetBlipNameValue(pBlip));
CPauseMenu::UpdatePauseMapLegend();
}
}
break;
}
case BLIP_CHANGE_SHOW_NUMBER:
{
SetBlipNumberValue(pBlip, (s8)iParam);
SetFlag(pBlip, BLIP_FLAG_VALUE_SET_NUMBER);
SetFlag(pBlip, BLIP_FLAG_UPDATED_LOW_FREQ_FLAGS);
break;
}
case BLIP_CHANGE_COLOUR:
{
if (GetBlipColourValue(pBlip) != (eBLIP_COLOURS)iParam)
{
if (iIndex == GetUniqueCentreBlipId())
{
uiDebugf1("MiniMap: Centre blip colour changed to BLIP COLOUR=%d", iParam);
}
SetBlipColourValue(pBlip, (eBLIP_COLOURS)iParam);
SetFlag(pBlip, BLIP_FLAG_VALUE_CHANGED_COLOUR);
SetFlag(pBlip, BLIP_FLAG_VALUE_CHANGED_OUTLINE_INDICATOR); // incase alpha changes
SetFlag(pBlip, BLIP_FLAG_VALUE_CHANGED_FRIEND_INDICATOR); // incase alpha changes
SetFlag(pBlip, BLIP_FLAG_VALUE_CHANGED_CREW_INDICATOR); // incase alpha changes
SetFlag(pBlip, BLIP_FLAG_UPDATED_LOW_FREQ_FLAGS);
}
// if its a ped and we change the colour to BLUE ensure we change the blip name to be friend instead of enemy
if (GetBlipTypeValue(pBlip) == BLIP_TYPE_CHAR)
{
if ((eBLIP_COLOURS)iParam == BLIP_COLOUR_BLUE)
SetBlipNameValue(pBlip, "BLIP_FRIEND", true);
}
break;
}
case BLIP_CHANGE_COLOUR_ROUTE:
{
// update the colour of the gps route:
if (IsFlagSet(pBlip,BLIP_FLAG_ROUTE))
{
Color32 colour;
if (iParam != BLIP_COLOUR_USE_COLOUR32)
{
colour = CMiniMap_Common::GetColourFromBlipSettings((eBLIP_COLOURS)iParam, IsFlagSet(pBlip,BLIP_FLAG_BRIGHTNESS));
}
else
{
colour = GetBlipColour32Value(pBlip); // use secondary colour for route
}
CGps::ChangeRadarBlipGpsColour(iIndex, colour);
}
break;
}
case BLIP_CHANGE_ALPHA:
{
if (iParam > 255)
{
uiAssertf(0, "Invalid alpha value for blip %d (%d)", iIndex, iActualIndex);
iParam = 255; // ensure it caps it at 255
}
if (GetBlipAlphaValue(pBlip) != (u8)iParam)
{
if (GetBlipAlphaValue(pBlip) == 0) // if it was 0 then it will need to be recoloured when it gets re-added to the stage
{
if (iIndex == GetUniqueCentreBlipId())
{
uiDebugf1("MiniMap: Centre blip alpha changed to %d", (u8)iParam);
}
SetFlag(pBlip, BLIP_FLAG_VALUE_CHANGED_COLOUR);
}
SetBlipAlphaValue(pBlip, (u8)iParam); // alpha is stored as a u8
SetFlag(pBlip, BLIP_FLAG_UPDATE_ALPHA_ONLY);
SetFlag(pBlip, BLIP_FLAG_VALUE_CHANGED_OUTLINE_INDICATOR); // if alpha changes, we need to change alpha in friend indicator
SetFlag(pBlip, BLIP_FLAG_VALUE_CHANGED_FRIEND_INDICATOR); // if alpha changes, we need to change alpha in friend indicator
SetFlag(pBlip, BLIP_FLAG_VALUE_CHANGED_CREW_INDICATOR); // if alpha changes, we need to change alpha in friend indicator
SetFlag(pBlip, BLIP_FLAG_UPDATED_LOW_FREQ_FLAGS);
}
break;
}
case BLIP_CHANGE_FLASH_DURATION:
{
if (GetBlipFlashDuration(pBlip) != (u16)iParam) // only set the interval if it is different from the currently set flash interval
{
SetBlipFlashDuration(pBlip, (u16)iParam);
SetFlag(pBlip, BLIP_FLAG_VALUE_CHANGED_FLASH);
}
break;
}
case BLIP_CHANGE_FLASH_INTERVAL:
{
if (GetBlipFlashInterval(pBlip) != (u16)iParam) // only set the interval if it is different from the currently set flash interval
{
SetBlipFlashInterval(pBlip, (u16)iParam);
// go through all blips that have been set to flash (inc this one) at the same rate and re-init the flash:
for (s32 i = 0; i < iMaxCreatedBlips; i++)
{
if (i == iSimpleBlip)
continue;
CMiniMapBlip *pFlashingBlip = GetBlipFromActualId(i);
if (!pFlashingBlip)
continue;
if (IsFlagSet(pFlashingBlip,BLIP_FLAG_FLASHING))
{
UnsetFlag(pFlashingBlip, BLIP_FLAG_FLASHING); // unset so it resets the flag on the change
SetFlag(pFlashingBlip, BLIP_FLAG_VALUE_CHANGED_FLASH); // flag so we know its changed
}
}
}
break;
}
case BLIP_CHANGE_BRIGHTNESS:
{
if (IsFlagSet(pBlip, BLIP_FLAG_BRIGHTNESS) != (iParam != 0))
{
if (iParam)
SetFlag(pBlip, BLIP_FLAG_BRIGHTNESS);
else
UnsetFlag(pBlip, BLIP_FLAG_BRIGHTNESS);
SetFlag(pBlip, BLIP_FLAG_VALUE_CHANGED_COLOUR);
}
break;
}
case BLIP_CHANGE_SHOW_HEIGHT:
{
if (iParam)
SetFlag(pBlip, BLIP_FLAG_SHOW_HEIGHT);
else
{
UnsetFlag(pBlip, BLIP_FLAG_SHOW_HEIGHT);
UnsetFlag(pBlip, BLIP_FLAG_USE_EXTENDED_HEIGHT_THRESHOLD);
UnsetFlag(pBlip, BLIP_FLAG_USE_HEIGHT_ON_EDGE);
SetFlag(pBlip, BLIP_FLAG_VALUE_TURNED_OFF_SHOW_HEIGHT);
}
break;
}
case BLIP_CHANGE_HIGH_DETAIL:
{
if (iParam)
SetFlag(pBlip, BLIP_FLAG_HIGH_DETAIL);
else
UnsetFlag(pBlip, BLIP_FLAG_HIGH_DETAIL);
break;
}
case BLIP_CHANGE_SHOW_TICK:
{
if (iParam)
SetFlag(pBlip, BLIP_FLAG_SHOW_TICK);
else
UnsetFlag(pBlip, BLIP_FLAG_SHOW_TICK);
SetFlag(pBlip, BLIP_FLAG_VALUE_CHANGED_TICK);
SetFlag(pBlip, BLIP_FLAG_UPDATED_LOW_FREQ_FLAGS);
break;
}
case BLIP_CHANGE_SHOW_TICK_GOLD:
{
if (iParam)
SetFlag(pBlip, BLIP_FLAG_SHOW_GOLD_TICK);
else
UnsetFlag(pBlip, BLIP_FLAG_SHOW_GOLD_TICK);
SetFlag(pBlip, BLIP_FLAG_VALUE_CHANGED_GOLD_TICK);
SetFlag(pBlip, BLIP_FLAG_UPDATED_LOW_FREQ_FLAGS);
break;
}
case BLIP_CHANGE_SHOW_FOR_SALE:
{
if(iParam)
SetFlag(pBlip, BLIP_FLAG_SHOW_FOR_SALE);
else
UnsetFlag(pBlip, BLIP_FLAG_SHOW_FOR_SALE);
SetFlag(pBlip, BLIP_FLAG_VALUE_CHANGED_FOR_SALE);
SetFlag(pBlip, BLIP_FLAG_UPDATED_LOW_FREQ_FLAGS);
break;
}
case BLIP_CHANGE_SHOW_HEADING_INDICATOR:
{
if (iParam)
{
SetFlag(pBlip, BLIP_FLAG_SHOW_HEADING_INDICATOR);
}
else
{
UnsetFlag(pBlip, BLIP_FLAG_SHOW_HEADING_INDICATOR);
SetBlipDirectionValue(pBlip, DEFAULT_BLIP_ROTATION, false); // reset back to default (no) rotation (fixes bug 1168334)
}
break;
}
case BLIP_CHANGE_SHOW_OUTLINE_INDICATOR:
{
if (iParam)
SetFlag(pBlip, BLIP_FLAG_SHOW_OUTLINE_INDICATOR);
else
UnsetFlag(pBlip, BLIP_FLAG_SHOW_OUTLINE_INDICATOR);
UnsetFlag(pBlip, BLIP_FLAG_SHOW_FRIEND_INDICATOR);
UnsetFlag(pBlip, BLIP_FLAG_SHOW_CREW_INDICATOR);
SetFlag(pBlip, BLIP_FLAG_VALUE_CHANGED_OUTLINE_INDICATOR);
SetFlag(pBlip, BLIP_FLAG_VALUE_CHANGED_FRIEND_INDICATOR);
SetFlag(pBlip, BLIP_FLAG_VALUE_CHANGED_CREW_INDICATOR);
SetFlag(pBlip, BLIP_FLAG_UPDATED_LOW_FREQ_FLAGS);
break;
}
case BLIP_CHANGE_SHOW_FRIEND_INDICATOR:
{
if (iParam)
SetFlag(pBlip, BLIP_FLAG_SHOW_FRIEND_INDICATOR);
else
UnsetFlag(pBlip, BLIP_FLAG_SHOW_FRIEND_INDICATOR);
UnsetFlag(pBlip, BLIP_FLAG_SHOW_OUTLINE_INDICATOR);
SetFlag(pBlip, BLIP_FLAG_VALUE_CHANGED_FRIEND_INDICATOR);
SetFlag(pBlip, BLIP_FLAG_VALUE_CHANGED_OUTLINE_INDICATOR);
SetFlag(pBlip, BLIP_FLAG_UPDATED_LOW_FREQ_FLAGS);
break;
}
case BLIP_CHANGE_SHOW_CREW_INDICATOR:
{
if (iParam)
SetFlag(pBlip, BLIP_FLAG_SHOW_CREW_INDICATOR);
else
UnsetFlag(pBlip, BLIP_FLAG_SHOW_CREW_INDICATOR);
UnsetFlag(pBlip, BLIP_FLAG_SHOW_OUTLINE_INDICATOR);
SetFlag(pBlip, BLIP_FLAG_VALUE_CHANGED_CREW_INDICATOR);
SetFlag(pBlip, BLIP_FLAG_VALUE_CHANGED_OUTLINE_INDICATOR);
SetFlag(pBlip, BLIP_FLAG_UPDATED_LOW_FREQ_FLAGS);
break;
}
case BLIP_CHANGE_SHOW_CONE:
{
if (iParam)
SetFlag(pBlip, BLIP_FLAG_SHOW_CONE);
else
{
UnsetFlag(pBlip, BLIP_FLAG_SHOW_CONE);
}
break;
}
case BLIP_CHANGE_DELETE:
{
CEntity* pEntity = CMiniMap::FindBlipEntity(pBlip);
if(pEntity && pEntity->GetIsPhysical())
{
#if __BANK
//Displayf("BLIP_CHANGE_DELETE RemoveBlip %s for %s:%x i:%d %d from script.", GetBlipNameValue(pBlip), pEntity->GetModelName(), pEntity, iIndex, iActualIndex);
#endif
smart_cast<CPhysical*>(pEntity)->SetCreatedBlip(false);
}
RemoveBlip(pBlip);
break;
}
case BLIP_CHANGE_PULSE:
{
const BlipLinkage& iCurrentBlipId = GetBlipObjectNameId(pBlip);
// only BLIP_LEVEL can pulse at the moment (as this is hard coded into the actionscript)
if (uiVerifyf(iCurrentBlipId == BLIP_LEVEL, "Minimap - PULSE_BLIP called on a blip that is unsupported (%d)", iCurrentBlipId))
{
SetFlag(pBlip, BLIP_FLAG_VALUE_CHANGED_PULSE);
SetFlag(pBlip, BLIP_FLAG_UPDATED_LOW_FREQ_FLAGS);
}
break;
}
case BLIP_CHANGE_MINIMISE_ON_EDGE:
{
if (iParam)
SetFlag(pBlip, BLIP_FLAG_MINIMISE_ON_EDGE);
else
UnsetFlag(pBlip, BLIP_FLAG_MINIMISE_ON_EDGE);
break;
}
case BLIP_CHANGE_MISSION_CREATOR:
{
if (iParam)
SetFlag(pBlip, BLIP_FLAG_MISSION_CREATOR);
else
UnsetFlag(pBlip, BLIP_FLAG_MISSION_CREATOR);
break;
}
case BLIP_CHANGE_FRIENDLY:
{
const BlipLinkage& iCurrentBlipId = GetBlipObjectNameId(pBlip);
if (iCurrentBlipId == BLIP_LEVEL)
{
SetBlipColourValue(pBlip, BLIP_COLOUR_FRIENDLY);
if (iParam)
{
SetFlag(pBlip, BLIP_FLAG_BRIGHTNESS);
if (GetBlipTypeValue(pBlip) == BLIP_TYPE_CHAR)
SetBlipNameValue(pBlip, "BLIP_FRIEND", true);
}
else
{
UnsetFlag(pBlip, BLIP_FLAG_BRIGHTNESS);
if (GetBlipTypeValue(pBlip) == BLIP_TYPE_CHAR)
SetBlipNameValue(pBlip, "BLIP_ENEMY", true);
}
// update the colour of the gps route:
if (IsFlagSet(pBlip, BLIP_FLAG_ROUTE))
{
Color32 colour;
if (GetBlipColourValue(pBlip) != BLIP_COLOUR_USE_COLOUR32)
{
eBLIP_COLOURS blipColour = GetBlipColourValue(pBlip);
if (blipColour == BLIP_COLOUR_DEFAULT) // any "default" coloured sprite blips always have a yellow gps route
{
blipColour = BLIP_COLOUR_YELLOW;
}
colour = CMiniMap_Common::GetColourFromBlipSettings(blipColour, IsFlagSet(pBlip,BLIP_FLAG_BRIGHTNESS));
}
else
{
colour = GetBlipColour32Value(pBlip); // use secondary colour for route
}
CGps::ChangeRadarBlipGpsColour(iIndex, colour);
}
SetFlag(pBlip, BLIP_FLAG_VALUE_CHANGED_COLOUR);
}
break;
}
case BLIP_CHANGE_RADIUS_EDGE:
{
if (uiVerifyf(GetBlipTypeValue(pBlip) == BLIP_TYPE_RADIUS, "Blip %d (%d) is not a radius blip!", iIndex, iActualIndex))
{
if (iParam)
SetBlipObjectName(pBlip, BLIP_RADIUS_OUTLINE);
else
SetBlipObjectName(pBlip, BLIP_RADIUS);
SetFlag(pBlip, BLIP_FLAG_VALUE_REINIT_STAGE); // as the sprite itself changes, it needs to be removed and re-added
SetFlag(pBlip, BLIP_FLAG_UPDATED_LOW_FREQ_FLAGS);
}
break;
}
case BLIP_CHANGE_AREA_EDGE:
{
if (uiVerifyf(GetBlipTypeValue(pBlip) == BLIP_TYPE_AREA, "Blip %d (%d) is not an area blip!", iIndex, iActualIndex))
{
if (iParam)
SetBlipObjectName(pBlip, BLIP_AREA_OUTLINE);
else
SetBlipObjectName(pBlip, BLIP_AREA);
SetFlag(pBlip, BLIP_FLAG_VALUE_REINIT_STAGE); // as the sprite itself changes, it needs to be removed and re-added
SetFlag(pBlip, BLIP_FLAG_UPDATED_LOW_FREQ_FLAGS);
}
break;
}
case BLIP_CHANGE_ROUTE:
{
//
// only 1 route at any one time at the moment:
//
if (iParam) // clear all previous route blips
{
ClearAllBlipRoutes();
}
// set this blip to use a route
if (iParam)
SetFlag(pBlip, BLIP_FLAG_ROUTE);
else
UnsetFlag(pBlip, BLIP_FLAG_ROUTE);
if (IsFlagSet(pBlip,BLIP_FLAG_ROUTE))
{
Color32 colour;
if (GetBlipColourValue(pBlip) != BLIP_COLOUR_USE_COLOUR32)
{
eBLIP_COLOURS blipColour = GetBlipColourValue(pBlip);
if (blipColour == BLIP_COLOUR_DEFAULT) // any "default" coloured sprite blips always have a yellow gps route
{
blipColour = BLIP_COLOUR_YELLOW;
}
colour = CMiniMap_Common::GetColourFromBlipSettings(blipColour, IsFlagSet(pBlip,BLIP_FLAG_BRIGHTNESS));
}
else
{
colour = GetBlipColour32Value(pBlip); // use secondary colour for route
}
Vector3 vBlipPos(GetBlipPositionValue(pBlip));
CGps::StartRadarBlipGps(vBlipPos, FindBlipEntity(pBlip), iIndex, colour);
}
else
{
CGps::StopRadarBlipGps(GetUniqueBlipUsed(pBlip));
}
break;
}
case BLIP_CHANGE_SHORTRANGE:
{
if (iParam)
SetFlag(pBlip, BLIP_FLAG_SHORTRANGE);
else
UnsetFlag(pBlip, BLIP_FLAG_SHORTRANGE);
break;
}
case BLIP_CHANGE_HIDDEN_ON_LEGEND:
{
if (iParam)
SetFlag(pBlip, BLIP_FLAG_HIDDEN_ON_LEGEND);
else
UnsetFlag(pBlip, BLIP_FLAG_HIDDEN_ON_LEGEND);
break;
}
case BLIP_CHANGE_MARKER_LONG_DISTANCE:
{
if (iParam)
SetFlag(pBlip, BLIP_FLAG_MARKER_LONG_DIST);
else
UnsetFlag(pBlip, BLIP_FLAG_MARKER_LONG_DIST);
break;
}
case BLIP_CHANGE_FLASH:
{
if (IsFlagSet(pBlip, BLIP_FLAG_FLASHING) != (iParam != 0))
{
SetFlag(pBlip, BLIP_FLAG_VALUE_CHANGED_FLASH);
SetBlipFlashInterval(pBlip, DEFAULT_BLIP_FLASH_INTERVAL);
SetBlipFlashDuration(pBlip, MAX_UINT16);
}
break;
}
case BLIP_CHANGE_FLASH_ALT:
{
if (IsFlagSet(pBlip, BLIP_FLAG_FLASHING) != (iParam != 0))
{
SetBlipFlashInterval(pBlip, DEFAULT_BLIP_FLASH_INTERVAL * 2);
SetFlag(pBlip, BLIP_FLAG_VALUE_CHANGED_FLASH);
SetBlipFlashInterval(pBlip, DEFAULT_BLIP_FLASH_INTERVAL);
SetBlipFlashDuration(pBlip, MAX_UINT16);
}
break;
}
case BLIP_CHANGE_OBJECT_NAME:
case BLIP_CHANGE_SPRITE: // need to support this until old radar is removed
{
const char* pBlipSpriteName = CMiniMap_Common::GetBlipName(iParam);
if (pBlipSpriteName)
{
// some blips have height indication as default:
if ( (iParam == BLIP_LEVEL) || (iParam >= RADAR_TRACE_NUMBERED_1 && iParam <= RADAR_TRACE_NUMBERED_5) )
{
SetFlag(pBlip, BLIP_FLAG_SHOW_HEIGHT);
}
else
{
UnsetFlag(pBlip, BLIP_FLAG_SHOW_HEIGHT);
}
SetBlipObjectName(pBlip, iParam);
// set the blip name based on the object id:
char cBlipTextLabel[TEXT_KEY_SIZE];
formatf(cBlipTextLabel, "BLIP_%d", iParam, NELEM(cBlipTextLabel));
SetBlipNameValue(pBlip, cBlipTextLabel, true);
SetBlipColourValue(pBlip, BLIP_COLOUR_DEFAULT);
SetFlag(pBlip, BLIP_FLAG_VALUE_CHANGED_COLOUR);
SetFlag(pBlip, BLIP_FLAG_VALUE_REINIT_STAGE); // as the sprite itself changes, it needs to be removed and re-added
SetFlag(pBlip, BLIP_FLAG_UPDATED_LOW_FREQ_FLAGS);
if (CPauseMenu::IsActive())
{
uiDebugf1("Updating pausemap legend because '%s' blip changed sprite", GetBlipNameValue(pBlip));
CPauseMenu::UpdatePauseMapLegend();
}
}
else
{
uiAssertf(0, "MiniMap: Couldn't change blip object name to %d as blip %d (%d) doesnt exist", iParam, iIndex, iActualIndex);
}
break;
}
case BLIP_CHANGE_EXTENDED_HEIGHT_THRESHOLD :
{
if (iParam)
SetFlag(pBlip, BLIP_FLAG_USE_EXTENDED_HEIGHT_THRESHOLD);
else
UnsetFlag(pBlip, BLIP_FLAG_USE_EXTENDED_HEIGHT_THRESHOLD);
break;
}
case BLIP_CHANGE_SHORT_HEIGHT_THRESHOLD :
{
if (iParam)
SetFlag(pBlip, BLIP_FLAG_USE_SHORT_HEIGHT_THRESHOLD);
else
UnsetFlag(pBlip, BLIP_FLAG_USE_SHORT_HEIGHT_THRESHOLD);
break;
}
case BLIP_CHANGE_HEIGHT_ON_EDGE :
{
if (iParam)
SetFlag(pBlip, BLIP_FLAG_USE_HEIGHT_ON_EDGE);
else
UnsetFlag(pBlip, BLIP_FLAG_USE_HEIGHT_ON_EDGE);
break;
}
case BLIP_CHANGE_HOVERED_ON_PAUSEMAP:
{
if (iParam)
SetFlag(pBlip, BLIP_FLAG_HOVERED_ON_PAUSEMAP);
else
UnsetFlag(pBlip, BLIP_FLAG_HOVERED_ON_PAUSEMAP);
SetFlag(pBlip, BLIP_FLAG_UPDATE_STAGE_DEPTH);
break;
}
default:
{
uiAssertf(0, "MiniMap: Trying to update blip %d (%d) with invalid task (%d) - Int %d", iIndex, iActualIndex, iTodo, iParam);
}
}
}
void CMiniMap::ClearAllBlipRoutes()
{
for (s32 i = 0; i < iMaxCreatedBlips; i++)
{
if (i == iSimpleBlip)
continue;
CMiniMapBlip *pRouteBlip = blip[i];
if (!pRouteBlip)
continue;
if (IsFlagSet(pRouteBlip,BLIP_FLAG_ROUTE))
{
CGps::StopRadarBlipGps(GetUniqueBlipUsed(pRouteBlip)); // remove identifier to route in gps code
UnsetFlag(pRouteBlip, BLIP_FLAG_ROUTE); // remove route
}
}
}
void CMiniMap::SetBlipParameter(eBLIP_PARAMS iTodo, s32 iIndex, Color32 iParam)
{
s32 iActualIndex = ConvertUniqueBlipToActualBlip(iIndex);
if (iActualIndex >= MAX_NUM_BLIPS)
{
uiAssertf(0, "MiniMap: Attempted to update blip %d (%d) over the max array (%d)!", iIndex, iActualIndex, MAX_NUM_BLIPS);
return;
}
if (iActualIndex < 0)
return;
CMiniMapBlip *pBlip = GetBlipFromActualId(iActualIndex);
if (!pBlip)
return;
if (!pBlip->IsComplex())
{
uiAssertf(0, "MiniMap: Attempted to modify a Simple Blip %d (%d)", iIndex, iActualIndex);
}
switch (iTodo)
{
case BLIP_CHANGE_COLOUR32:
{
if (GetBlipColour32Value(pBlip) != iParam)
{
SetBlipSecondaryColourValue(pBlip, iParam);
SetFlag(pBlip, BLIP_FLAG_VALUE_CHANGED_COLOUR);
SetFlag(pBlip, BLIP_FLAG_VALUE_CHANGED_OUTLINE_INDICATOR);
SetFlag(pBlip, BLIP_FLAG_VALUE_CHANGED_FRIEND_INDICATOR);
SetFlag(pBlip, BLIP_FLAG_VALUE_CHANGED_CREW_INDICATOR);
SetFlag(pBlip, BLIP_FLAG_UPDATED_LOW_FREQ_FLAGS);
}
break;
}
case BLIP_CHANGE_COLOUR_ROUTE:
{
// update the colour of the gps route:
if (IsFlagSet(pBlip,BLIP_FLAG_ROUTE))
{
CGps::ChangeRadarBlipGpsColour(iIndex, iParam);
}
break;
}
default:
{
uiAssertf(0, "MiniMap: Trying to update blip %d (%d) with invalid task (%d) - Colour %d", iIndex, iActualIndex, iTodo, iParam.GetColor());
}
}
}
void CMiniMap::SetBlipParameter(eBLIP_PARAMS iTodo, s32 iIndex, float fParam)
{
s32 iActualIndex = ConvertUniqueBlipToActualBlip(iIndex);
if (iActualIndex < 0)
return;
CMiniMapBlip *pBlip = GetBlipFromActualId(iActualIndex);
if (!pBlip)
return;
if (!pBlip->IsComplex())
{
uiAssertf(0, "MiniMap: Attempted to modify a Simple Blip %d (%d)", iIndex, iActualIndex);
}
switch (iTodo)
{
case BLIP_CHANGE_SCALE:
{
SetBlipScaleValue(pBlip, fParam);
break;
}
case BLIP_CHANGE_DIRECTION:
{
SetBlipDirectionValue(pBlip, fParam);
break;
}
default:
{
uiAssertf(0, "MiniMap: Trying to update blip %d (%d) with invalid task (%d) - Float %0.2f", iIndex, iActualIndex, iTodo, fParam);
}
}
}
void CMiniMap::SetBlipParameter(eBLIP_PARAMS iTodo, s32 iIndex, const Vector3& vParam)
{
s32 iActualIndex = ConvertUniqueBlipToActualBlip(iIndex);
uiAssertf(iActualIndex >= 0, "SetBlipParameter - blip %d (%d) doesn't exist", iIndex, iActualIndex);
if (iActualIndex < 0)
return;
CMiniMapBlip *pBlip = GetBlipFromActualId(iActualIndex);
if (!pBlip)
return;
if (!pBlip->IsComplex())
{
uiAssertf(0, "MiniMap: Attempted to modify a Simple Blip %d (%d)", iIndex, iActualIndex);
}
switch (iTodo)
{
case BLIP_CHANGE_SCALE:
{
Vector2 vec2;
vParam.GetVector2XY(vec2);
SetBlipScaleValue(pBlip, vec2);
break;
}
case BLIP_CHANGE_POSITION:
{
SetBlipPositionValue(pBlip, vParam);
break;
}
default:
{
uiAssertf(0, "MiniMap: Trying to update blip %d (%d) with invalid task (%d) - Vector %0.2f,%0.2f,%0.2f", iIndex, iActualIndex, iTodo, vParam.x, vParam.y, vParam.z);
}
}
}
void CMiniMap::SetBlipParameter(eBLIP_PARAMS iTodo, s32 iIndex, const char *cParam)
{
s32 iActualIndex = ConvertUniqueBlipToActualBlip(iIndex);
if (iActualIndex < 0)
return;
CMiniMapBlip *pBlip = GetBlipFromActualId(iActualIndex);
if (!pBlip)
return;
if (!pBlip->IsComplex())
{
uiAssertf(0, "MiniMap: Attempted to modify a Simple Blip %d (%d)", iIndex, iActualIndex);
}
switch (iTodo)
{
case BLIP_CHANGE_NAME:
{
if ( static_cast<CBlipComplex*>(pBlip)->cLocName != cParam )
{
SetBlipNameValue(pBlip, cParam, true);
if (CPauseMenu::IsActive())
{
uiDebugf1("Updating pausemap legend because '%s' blip changed name", GetBlipNameValue(pBlip));
CPauseMenu::UpdatePauseMapLegend();
}
}
else
{
uiDebugf1("Blip %d (%s, %d) set with name '%s' when it was already set with it (BLIP_CHANGE_NAME)", GetUniqueBlipUsed(pBlip), GetBlipObjectName(pBlip), GetBlipObjectNameId(pBlip), GetBlipNameValue(pBlip));
}
break;
}
case BLIP_CHANGE_NAME_FROM_ASCII:
{
if ( static_cast<CBlipComplex*>(pBlip)->cLocName != cParam )
{
SetBlipNameValue(pBlip, cParam, false);
if (CPauseMenu::IsActive())
{
uiDebugf1("Updating pausemap legend because '%s' blip changed name", GetBlipNameValue(pBlip));
CPauseMenu::UpdatePauseMapLegend();
}
}
else
{
uiDebugf1("Blip %d (%s, %d) set with name '%s' when it was already set with it (BLIP_CHANGE_NAME_FROM_ASCII)", GetUniqueBlipUsed(pBlip), GetBlipObjectName(pBlip), GetBlipObjectNameId(pBlip), GetBlipNameValue(pBlip));
}
break;
}
default:
{
uiAssertf(0, "MiniMap: Trying to update blip %d (%d) with invalid task (%d) with String %s", iIndex, iActualIndex, iTodo, cParam);
}
}
}
/////////////////////////////////////////////////////////////////////////////////////
// NAME: CMiniMap::SetBlipNumberValue
// PURPOSE:
/////////////////////////////////////////////////////////////////////////////////////
void CMiniMap::SetBlipNumberValue(CMiniMapBlip *pBlip, s8 iParam)
{
if (pBlip && pBlip->IsComplex())
((CBlipComplex*)pBlip)->iNumberToDisplay = iParam;
}
/////////////////////////////////////////////////////////////////////////////////////
// NAME: CMiniMap::SetBlipDisplayValue
// PURPOSE:
/////////////////////////////////////////////////////////////////////////////////////
void CMiniMap::SetBlipDisplayValue(CMiniMapBlip *pBlip, eBLIP_DISPLAY_TYPE iParam)
{
if (pBlip && pBlip->IsComplex())
((CBlipComplex*)pBlip)->display = (u8)iParam;
}
/////////////////////////////////////////////////////////////////////////////////////
// NAME: CMiniMap::GetActualSimpleBlipId
// PURPOSE: returns the id used for the simple blip
/////////////////////////////////////////////////////////////////////////////////////
s32 CMiniMap::GetActualSimpleBlipId()
{
return iSimpleBlip;
}
/////////////////////////////////////////////////////////////////////////////////////
// NAME: CMiniMap::IsBlipIdInUse
// PURPOSE: returns whether this blip is in use
/////////////////////////////////////////////////////////////////////////////////////
bool CMiniMap::IsBlipIdInUse(s32 iUniqueIndex)
{
if (iUniqueIndex == INVALID_BLIP_ID)
{
return false;
}
CMiniMapBlip *pBlip = GetBlip(iUniqueIndex);
if (pBlip)
{
return ((GetUniqueBlipUsed(pBlip) != INVALID_BLIP_ID) &&
(!IsFlagSet(pBlip, BLIP_FLAG_VALUE_REMOVE_FROM_STAGE)) &&
(!IsFlagSet(pBlip, BLIP_FLAG_VALUE_DESTROY_BLIP_OBJECT)));
}
return false;
}
/////////////////////////////////////////////////////////////////////////////////////
// NAME: CMiniMap::IsBlipOnStage
// PURPOSE: returns whether this blip is currently on the stage
/////////////////////////////////////////////////////////////////////////////////////
bool CMiniMap::IsBlipOnStage(CMiniMapBlip *pBlip)
{
if (pBlip)
{
// if (GetBlipGfxValue(pBlip))
if (IsFlagSet(pBlip, BLIP_FLAG_ON_STAGE))
{
return true;
}
}
return false;
}
/////////////////////////////////////////////////////////////////////////////////////
// NAME: CMiniMap::SetVisible
// PURPOSE: sets the minimap to be visible or hidden
/////////////////////////////////////////////////////////////////////////////////////
void CMiniMap::SetVisible(bool bSetVisible)
{
bVisible = bSetVisible;
}
/////////////////////////////////////////////////////////////////////////////////////
// NAME: CMiniMap::GetBlipFromActualId
// PURPOSE: returns the base blip from the actual id
/////////////////////////////////////////////////////////////////////////////////////
CMiniMapBlip *CMiniMap::GetBlipFromActualId(s32 iId)
{
if (iId >= 0 && iId < MAX_NUM_BLIPS)
{
return (blip[iId]);
}
uiAssertf(0, "CMiniMap: Cannot get Blip from actual blip id %d", iId);
return NULL;
}
/////////////////////////////////////////////////////////////////////////////////////
// NAME: CMiniMap::GetBlip
// PURPOSE: returns the base blip from the unique id
// this function needs to fail silently
/////////////////////////////////////////////////////////////////////////////////////
CMiniMapBlip *CMiniMap::GetBlip(s32 iUniqueBlipId)
{
s32 iActualBlipId = ConvertUniqueBlipToActualBlip(iUniqueBlipId);
if (iActualBlipId >= 0 && iActualBlipId < MAX_NUM_BLIPS) // this function needs to fail silently
{
return (GetBlipFromActualId(iActualBlipId));
}
return NULL;
}
/////////////////////////////////////////////////////////////////////////////////////
// NAME: CMiniMap::RemoveBlipAttachedToEntity()
// PURPOSE: removes any blips that are attached to the passed entity index
/////////////////////////////////////////////////////////////////////////////////////
void CMiniMap::RemoveBlipAttachedToEntity(const CEntity *pEntity, eBLIP_TYPE blipType)
{
CEntityPoolIndexForBlip entityIndex(pEntity, blipType);
for (s32 iIndex = 0; iIndex < iMaxCreatedBlips; iIndex++)
{
if (iIndex == iSimpleBlip)
continue;
CMiniMapBlip *pBlip = GetBlipFromActualId(iIndex);
if (!pBlip)
continue;
if ( (GetBlipTypeValue(pBlip) == blipType) && (GetBlipPoolIndexValue(pBlip) == entityIndex) )
{
s32 iUniqueBlipId = GetUniqueBlipUsed(pBlip);
RemoveBlip(pBlip);
// remove any script resources which reference this blip
CTheScripts::GetScriptHandlerMgr().RemoveScriptResource(CGameScriptResource::SCRIPT_RESOURCE_RADAR_BLIP, iUniqueBlipId);
return; // if we removed one we can now return out (dont carry on through the array checking - fixes bug 649817)
}
}
}
CMiniMapBlip *CMiniMap::GetBlipAttachedToEntity(const CEntity *pEntity, eBLIP_TYPE blipType, u32 FlagToCheck, bool bInUseOnly)
{
bool bCheckForRelationshipGroup = false;
if ((FlagToCheck & BLIP_FLAG_CREATED_FOR_RELATIONSHIP_GROUP_PED) != 0)
{
bCheckForRelationshipGroup = true;
}
bool bCheckFlags = bInUseOnly || bCheckForRelationshipGroup;
CEntityPoolIndexForBlip entityIndex(pEntity, blipType);
for (s32 iIndex = 0; iIndex < iMaxCreatedBlips; iIndex++)
{
if (iIndex == iSimpleBlip)
continue;
CMiniMapBlip *pBlip = blip[iIndex];
if (!pBlip)
continue;
if (!bCheckFlags
|| (bCheckForRelationshipGroup && IsFlagSet(pBlip, BLIP_FLAG_CREATED_FOR_RELATIONSHIP_GROUP_PED))
|| (bInUseOnly && IsBlipIdInUse(pBlip->m_iUniqueId)))
{
if ( (GetBlipTypeValue(pBlip) == blipType) && (GetBlipPoolIndexValue(pBlip) == entityIndex) )
{
return pBlip;
}
}
}
return NULL;
}
/////////////////////////////////////////////////////////////////////////////////////
// NAME: CMiniMap::UpdateAndAutoSwitchOffFlash()
// PURPOSE: updates and decides whether to switch off a flash on a blip
// based on the set duration
/////////////////////////////////////////////////////////////////////////////////////
void CMiniMap::UpdateAndAutoSwitchOffFlash(CMiniMapBlip *pBlip)
{
//
// Check whether we need to auto-switch off flashing:
//
if (uiVerifyf(pBlip, "Blip doesnt exist!"))
{
if (IsFlagSet(pBlip,BLIP_FLAG_FLASHING))
{
u16 iFlashValue = GetBlipFlashDuration(pBlip);
if (iFlashValue != MAX_UINT16) // dont switch off the flash on blip value MAX_UINT8 ever
{
s32 iNewFlashValue = iFlashValue - fwTimer::GetTimeStepInMilliseconds();
if (iNewFlashValue > 0) // decrement the timer
{
SetBlipFlashDuration(pBlip, u16(iNewFlashValue));
}
if (iFlashValue == 0 || iNewFlashValue <= 0)
{
// switch off the flash completely
SetBlipFlashDuration(pBlip, MAX_UINT16);
SetFlag(pBlip, BLIP_FLAG_VALUE_CHANGED_FLASH);
}
}
}
}
}
/////////////////////////////////////////////////////////////////////////////////////
// NAME: CMiniMap::ToggleComponent()
// PURPOSE: turns each minimap component on/off
/////////////////////////////////////////////////////////////////////////////////////
void CMiniMap::ToggleComponent(s32 const c_componentId, bool const c_visible, bool const c_immediate, eHUD_COLOURS const c_hudColor)
{
if (CScaleformMgr::BeginMethod(GetMovieId(MINIMAP_MOVIE_BACKGROUND), SF_BASE_CLASS_MINIMAP, "TOGGLE_COMPONENT"))
{
CScaleformMgr::AddParamInt(c_componentId);
CScaleformMgr::AddParamBool(c_visible);
if (c_hudColor != HUD_COLOUR_INVALID)
{
CScaleformMgr::AddParamInt((s32)c_hudColor);
}
CScaleformMgr::EndMethod(c_immediate);
}
}
/////////////////////////////////////////////////////////////////////////////////////
// NAME: CMiniMap::ToggleTerritory()
// PURPOSE: sets up each minimap territory
/////////////////////////////////////////////////////////////////////////////////////
void CMiniMap::ToggleTerritory(s32 iPropertyId, s32 iOwner1, s32 iOwner2, s32 iOwner3, s32 iOwner4)
{
if (CScaleformMgr::BeginMethod(GetMovieId(MINIMAP_MOVIE_FOREGROUND), SF_BASE_CLASS_MINIMAP, "SET_MP_PROPERTY_OWNER"))
{
CScaleformMgr::AddParamInt(iPropertyId);
CScaleformMgr::AddParamInt(iOwner1);
if (iOwner2 != -1)
{
CScaleformMgr::AddParamInt(iOwner2);
}
if (iOwner3 != -1)
{
CScaleformMgr::AddParamInt(iOwner3);
}
if (iOwner4 != -1)
{
CScaleformMgr::AddParamInt(iOwner4);
}
CScaleformMgr::EndMethod();
}
}
/////////////////////////////////////////////////////////////////////////////////////
// NAME: CMiniMap::ShowYoke()
// PURPOSE: calls "show_yoke" on the foreground movie with the passed params
/////////////////////////////////////////////////////////////////////////////////////
void CMiniMap::ShowYoke(const bool bVisible, const float fPosX, const float fPosY, const s32 iAlpha)
{
// Return early if the yoke is continuing to be invisible. If we return early when the yoke is visible, its position won't be updated.
if (!ms_bShowingYoke && !bVisible)
{
return;
}
CMiniMap::ms_bShowingYoke = bVisible;
if (CScaleformMgr::BeginMethod(GetMovieId(MINIMAP_MOVIE_FOREGROUND), SF_BASE_CLASS_MINIMAP, "SHOW_YOKE"))
{
CScaleformMgr::AddParamFloat(fPosX);
CScaleformMgr::AddParamFloat(fPosY);
CScaleformMgr::AddParamBool(bVisible);
CScaleformMgr::AddParamInt(iAlpha);
CScaleformMgr::EndMethod();
}
}
void CMiniMap::ShowSonarSweep(const bool bVisible)
{
if(!bVisible)
{
if (CScaleformMgr::BeginMethod(GetMovieId(MINIMAP_MOVIE_FOREGROUND), SF_BASE_CLASS_MINIMAP, "SHOW_SONAR_SWEEP"))
{
CScaleformMgr::AddParamBool(bVisible);
CScaleformMgr::EndMethod();
}
}
ms_bShowSonarSweep = bVisible;
}
/////////////////////////////////////////////////////////////////////////////////////
// NAME: CMiniMap::GetCurrentMiniMap
// PURPOSE: returns the enum for the current minimap
/////////////////////////////////////////////////////////////////////////////////////
eMINIMAP_VALUES CMiniMap::GetCurrentMiniMap()
{
//
// reworked this function to fix 1797848. Before we could have 1 state pending to be set up but the values used would be the current state, causing a glitch
//
eMINIMAP_VALUES returnValue = MINIMAP_VALUE_MINIMAP;
#if !__FINAL
static eMINIMAP_VALUES prevMiniMapValue = returnValue;
#endif
switch (MinimapModeState) // if we are currently set to move to another state, ensure we use that value
{
case MINIMAP_MODE_STATE_SETUP_FOR_MINIMAP:
case MINIMAP_MODE_STATE_SETUP_FOR_MINIMAP_HAS_BEEN_PROCESSED_BY_RENDER_THREAD:
{
returnValue = MINIMAP_VALUE_MINIMAP;
break;
}
case MINIMAP_MODE_STATE_SETUP_FOR_GOLFMAP:
case MINIMAP_MODE_STATE_SETUP_FOR_GOLFMAP_HAS_BEEN_PROCESSED_BY_RENDER_THREAD:
{
returnValue = MINIMAP_VALUE_GOLF_COURSE;
break;
}
case MINIMAP_MODE_STATE_SETUP_FOR_PAUSEMAP:
case MINIMAP_MODE_STATE_SETUP_FOR_PAUSEMAP_HAS_BEEN_PROCESSED_BY_RENDER_THREAD:
{
returnValue = MINIMAP_VALUE_PAUSEMAP;
break;
}
case MINIMAP_MODE_STATE_SETUP_FOR_BIGMAP:
case MINIMAP_MODE_STATE_SETUP_FOR_BIGMAP_HAS_BEEN_PROCESSED_BY_RENDER_THREAD:
{
if (!ms_bBigMapFullScreen)
{
returnValue = MINIMAP_VALUE_BIGMAP;
}
else
{
returnValue = MINIMAP_VALUE_PAUSEMAP;
}
break;
}
case MINIMAP_MODE_STATE_SETUP_FOR_CUSTOMMAP:
case MINIMAP_MODE_STATE_SETUP_FOR_CUSTOMMAP_HAS_BEEN_PROCESSED_BY_RENDER_THREAD:
{
returnValue = MINIMAP_VALUE_CUSTOM;
break;
}
// otherwise use the standard values:
default:
{
if (IsInPauseMap())
{
returnValue = MINIMAP_VALUE_PAUSEMAP;
}
else
{
if (IsInBigMap())
{
if (!ms_bBigMapFullScreen)
{
returnValue = MINIMAP_VALUE_BIGMAP;
}
else
{
returnValue = MINIMAP_VALUE_PAUSEMAP;
}
}
else if (IsInCustomMap())
{
returnValue = MINIMAP_VALUE_CUSTOM;
}
else
{
if (IsInGolfMap())
{
returnValue = MINIMAP_VALUE_GOLF_COURSE;
}
else
{
returnValue = MINIMAP_VALUE_MINIMAP;
}
}
}
}
}
#if !__FINAL
if (prevMiniMapValue != returnValue)
{
if(CMiniMap_Common::OutputDebugTransitions())
{
uiDisplayf("MINIMAP_TRANSITION: CMiniMap::GetCurrentMiniMap changed from %d to %d (UT)", (s32)prevMiniMapValue, (s32)returnValue);
}
prevMiniMapValue = returnValue;
}
#endif // !__FINAL
return returnValue;
}
/////////////////////////////////////////////////////////////////////////////////////
// NAME: CMiniMap::GetCurrentMiniMapFilename
// PURPOSE: returns the current minimap filename
/////////////////////////////////////////////////////////////////////////////////////
char *CMiniMap::GetCurrentMiniMapFilename()
{
if (IsInPauseMap())
{
return &sm_miniMaps[MINIMAP_VALUE_MINIMAP].m_fileName[0]; // uses MINIMAP_VALUE_STANDARD for pausemap as it shares the same map
}
else
{
if (IsInBigMap())
{
return &sm_miniMaps[MINIMAP_VALUE_MINIMAP].m_fileName[0]; // uses MINIMAP_VALUE_STANDARD for bigmap as it shares the same map
}
else
{
// never return golf course, for it will mess up everything if we attempt to load
//if (IsInGolfMap())
//{
// return &sm_miniMaps[MINIMAP_VALUE_GOLF_COURSE].m_fileName[0];
//}
//else
{
return &sm_miniMaps[MINIMAP_VALUE_MINIMAP].m_fileName[0];
}
}
}
}
eMINIMAP_VALUES GetMaskValue(eMINIMAP_VALUES miniMap)
{
if( miniMap == MINIMAP_VALUE_PAUSEMAP)
{
miniMap = MINIMAP_VALUE_PAUSEMAP_MASK;
}
else if (miniMap == MINIMAP_VALUE_BIGMAP)
{
miniMap = MINIMAP_VALUE_BIGMAP_MASK;
}
else if( miniMap == MINIMAP_VALUE_MINIMAP )
{
miniMap = MINIMAP_VALUE_MINIMAP_MASK;
}
else if( miniMap == MINIMAP_VALUE_CUSTOM )
{
miniMap = MINIMAP_VALUE_CUSTOM_MASK;
}
return miniMap;
}
eMINIMAP_VALUES GetBlurValue(eMINIMAP_VALUES miniMap)
{
if (miniMap == MINIMAP_VALUE_BIGMAP)
{
miniMap = MINIMAP_VALUE_BIGMAP_BLUR;
}
else
{
miniMap = MINIMAP_VALUE_MINIMAP_BLUR;
}
return miniMap;
}
Vector2 CMiniMap::GetCurrentMiniMapMaskPosition()
{
eMINIMAP_VALUES miniMap = GetMaskValue(GetCurrentMiniMap());
Vector2 vPos(sm_miniMaps[miniMap].m_position);
Vector2 vSize(sm_miniMaps[miniMap].m_size);
#if RSG_PC
if(miniMap != MINIMAP_VALUE_PAUSEMAP_MASK)
{
// we need to adjust the map twice to compensate for the extra divisions that happen on the render thread, which work for the pause map
// here we're compensating for rather rubbish tuning values that we don't (?) want to adjust for the consoles...?
CHudTools::AdjustNormalized16_9ValuesForCurrentAspectRatio(CHudTools::GetFormatFromString(sm_miniMaps[miniMap].m_alignX), nullptr, &vSize);
}
CHudTools::AdjustNormalized16_9ValuesForCurrentAspectRatio(CHudTools::GetFormatFromString(sm_miniMaps[miniMap].m_alignX), &vPos, &vSize);
#endif
return CHudTools::CalculateHudPosition(vPos, vSize, sm_miniMaps[miniMap].m_alignX, sm_miniMaps[miniMap].m_alignY);
}
Vector2 CMiniMap::GetCurrentMiniMapMaskSize()
{
eMINIMAP_VALUES miniMap = GetMaskValue(GetCurrentMiniMap());
Vector2 vSize(sm_miniMaps[miniMap].m_size);
#if RSG_PC
if(miniMap != MINIMAP_VALUE_PAUSEMAP_MASK)
{
// we need to adjust the map twice to compensate for the extra divisions that happen on the render thread, which work for the pause map
// here we're compensating for rather rubbish tuning values that we don't (?) want to adjust for the consoles...?
CHudTools::AdjustNormalized16_9ValuesForCurrentAspectRatio(CHudTools::GetFormatFromString(sm_miniMaps[miniMap].m_alignX), nullptr, &vSize);
}
CHudTools::AdjustNormalized16_9ValuesForCurrentAspectRatio(CHudTools::GetFormatFromString(sm_miniMaps[miniMap].m_alignX), nullptr, &vSize);
#endif
return vSize;
}
Vector2 CMiniMap::GetCurrentMiniMapBlurPosition()
{
eMINIMAP_VALUES miniMap = GetBlurValue( GetCurrentMiniMap() );
Vector2 vPos(sm_miniMaps[miniMap].m_position);
Vector2 vSize(sm_miniMaps[miniMap].m_size);
#if RSG_PC
CHudTools::AdjustNormalized16_9ValuesForCurrentAspectRatio(CHudTools::GetFormatFromString(sm_miniMaps[miniMap].m_alignX), &vPos, &vSize);
#endif
return CHudTools::CalculateHudPosition(vPos, vSize, sm_miniMaps[miniMap].m_alignX, sm_miniMaps[miniMap].m_alignY);
}
Vector2 CMiniMap::GetCurrentMiniMapBlurSize()
{
eMINIMAP_VALUES miniMap = GetBlurValue( GetCurrentMiniMap() );
Vector2 vSize(sm_miniMaps[miniMap].m_size);
#if RSG_PC
CHudTools::AdjustNormalized16_9ValuesForCurrentAspectRatio(CHudTools::GetFormatFromString(sm_miniMaps[miniMap].m_alignX), nullptr, &vSize);
#endif
return vSize;
}
/////////////////////////////////////////////////////////////////////////////////////
// NAME: CMiniMap::GetCurrentMiniMapPosition
// PURPOSE: returns the current minimap position
/////////////////////////////////////////////////////////////////////////////////////
// Is it safe for this to be called on the RenderThread?
Vector2 CMiniMap::GetCurrentMiniMapPosition()
{
eMINIMAP_VALUES miniMap = GetCurrentMiniMap();
Vector2 vPos(sm_miniMaps[miniMap].m_position);
Vector2 vSize(sm_miniMaps[miniMap].m_size);
#if RSG_PC
if( miniMap!= MINIMAP_VALUE_PAUSEMAP )
CHudTools::AdjustNormalized16_9ValuesForCurrentAspectRatio(CHudTools::GetFormatFromString(sm_miniMaps[miniMap].m_alignX), &vPos, &vSize);
#endif
return CHudTools::CalculateHudPosition(vPos, vSize, sm_miniMaps[miniMap].m_alignX, sm_miniMaps[miniMap].m_alignY);
}
/////////////////////////////////////////////////////////////////////////////////////
// NAME: CMiniMap::GetCurrentMiniMapSize
// PURPOSE: returns the current minimap size
/////////////////////////////////////////////////////////////////////////////////////
// Is it safe for this to be called on the RenderThread?
Vector2 CMiniMap::GetCurrentMiniMapSize()
{
eMINIMAP_VALUES miniMap = GetCurrentMiniMap();
Vector2 vSize(sm_miniMaps[miniMap].m_size);
#if RSG_PC
if( miniMap!= MINIMAP_VALUE_PAUSEMAP )
CHudTools::AdjustNormalized16_9ValuesForCurrentAspectRatio(CHudTools::GetFormatFromString(sm_miniMaps[miniMap].m_alignX), nullptr, &vSize);
#endif
return vSize;
}
/////////////////////////////////////////////////////////////////////////////////////
// NAME: CMiniMap::SetInPrologue
// PURPOSE: Sets if we should display the prologue map, and clears out any custom
// waypoints if we change maps.
/////////////////////////////////////////////////////////////////////////////////////
void CMiniMap::SetInPrologue(bool bValue)
{
if(ms_bInPrologue != bValue)
{
uiDisplayf("CMiniMap::SetInPrologue - Prologue Clear");
SwitchOffWaypoint();
if (ms_iNorthBlip != INVALID_BLIP_ID)
{
float fNorthPos = CMiniMap::sm_Tunables.Tiles.vMiniMapWorldSize.y*2.0f;
if (bValue)
{
fNorthPos = -fNorthPos; // invert the "north" in prologue - todo 928263
}
Vector3 vNorthPos(0.0f,fNorthPos, 0.0f);
SetBlipParameter(BLIP_CHANGE_POSITION, ms_iNorthBlip, vNorthPos);
}
ms_bInPrologue = bValue;
}
}
void CMiniMap::SetOnIslandMap(bool bValue)
{
if(ms_bOnIslandMap != bValue)
{
uiDisplayf("CMiniMap::SetOnIslandMap - Island X Map Change.");
SwitchOffWaypoint();
// TODO_UI: North blip hack goes here too?
ms_bOnIslandMap = bValue;
}
}
/////////////////////////////////////////////////////////////////////////////////////
// NAME: CMiniMap::FlashMiniMapDisplay
// PURPOSE: a flash for the radar when stuff appears e.g. random events
/////////////////////////////////////////////////////////////////////////////////////
void CMiniMap::FlashMiniMapDisplay(eHUD_COLOURS hudColour)
{
ms_eFlashColour = hudColour;
ms_uFlashStartTime = fwTimer::GetTimeInMilliseconds();
}
/////////////////////////////////////////////////////////////////////////////////////
// NAME: CMiniMap::CreateWaypointBlipAndRoute
// PURPOSE: creates a blip and gps route for the given waypoint
/////////////////////////////////////////////////////////////////////////////////////
void CMiniMap::CreateWaypointBlipAndRoute(sWaypointStruct& Waypoint, eBLIP_DISPLAY_TYPE iDisplayType, eHUD_COLOURS iHudColor)
{
ClearWaypointBlipAndRoute(Waypoint);
CEntity* pEntity = nullptr;
Vector3 vTarget(Waypoint.vPos.x, Waypoint.vPos.y, WorldProbe::FindGroundZForCoord(BOTTOM_SURFACE, Waypoint.vPos.x, Waypoint.vPos.y));
//Entity based waypoint
if (ms_bEntityWaypointAllowed && NetworkInterface::IsGameInProgress())
{
if (netObject* pObj = NetworkInterface::GetObjectManager().GetNetworkObject(Waypoint.ObjectId))
{
pEntity = pObj->GetEntity();
eBLIP_TYPE iBlipType = CEntityPoolIndexForBlip::GetBlipTypeForEntity(pEntity);
CEntityPoolIndexForBlip PoolIndex(pEntity, iBlipType);
Waypoint.iBlipIndex = CreateBlip(true, iBlipType, PoolIndex, iDisplayType, "waypoint");
}
}
//Fall back to coordinate waypoint
if(Waypoint.iBlipIndex == INVALID_BLIP_ID)
{
Waypoint.iBlipIndex = CreateBlip(true, BLIP_TYPE_COORDS, vTarget, iDisplayType, "waypoint");
}
CGpsSlot& GpsSlot = CGps::GetSlot(GPS_SLOT_WAYPOINT);
GpsSlot.m_iGpsFlags = ms_waypointGpsFlags;
if (pEntity == nullptr) //Ignore Z for coordinate only waypoints
{
GpsSlot.m_iGpsFlags |= GPS_FLAG_IGNORE_DESTINATION_Z;
}
GpsSlot.Start(vTarget, pEntity, Waypoint.iBlipIndex, true, GPS_SLOT_WAYPOINT, CHudColour::GetRGB(iHudColor, 255));
if (Waypoint.iBlipIndex != INVALID_BLIP_ID)
{
SetBlipParameter(BLIP_CHANGE_OBJECT_NAME, Waypoint.iBlipIndex, BLIP_WAYPOINT);
SetBlipParameter(BLIP_CHANGE_PRIORITY, Waypoint.iBlipIndex, BLIP_PRIORITY_HIGHEST_SPECIAL);
SetBlipParameter(BLIP_CHANGE_COLOUR, Waypoint.iBlipIndex, BLIP_COLOUR_USE_COLOUR32);
SetBlipParameter(BLIP_CHANGE_COLOUR32, Waypoint.iBlipIndex, CHudColour::GetRGBA(iHudColor));
SetBlipParameter(BLIP_CHANGE_CATEGORY, Waypoint.iBlipIndex, BLIP_CATEGORY_WAYPOINT);
}
}
void CMiniMap::ClearWaypointBlipAndRoute(sWaypointStruct& Waypoint)
{
if (Waypoint.iBlipIndex != INVALID_BLIP_ID)
{
if (IsBlipIdInUse(Waypoint.iBlipIndex))
{
if (CMiniMapBlip *pBlip = GetBlip(Waypoint.iBlipIndex))
{
RemoveBlip(pBlip);
}
}
Waypoint.iBlipIndex = INVALID_BLIP_ID;
Waypoint.ObjectId = NETWORK_INVALID_OBJECT_ID;
Waypoint.iAssociatedBlipId = INVALID_BLIP_ID;
CGps::m_Slots[GPS_SLOT_WAYPOINT].Clear(GPS_SLOT_WAYPOINT, true);
}
}
/////////////////////////////////////////////////////////////////////////////////////
// NAME: CMiniMap::SetInBigMap
// PURPOSE: sets up any params when we enter "big map" mode
/////////////////////////////////////////////////////////////////////////////////////
void CMiniMap::SetInBigMap(bool bBigMap)
{
#if !__FINAL
if(CMiniMap_Common::OutputDebugTransitions())
{
if (ms_bInBigMap != bBigMap) // because script like to spam these things
{
if (bBigMap)
uiDisplayf("MINIMAP_TRANSITION: CMiniMap::SetInBigMap(TRUE) (UT)");
else
uiDisplayf("MINIMAP_TRANSITION: CMiniMap::SetInBigMap(FALSE) (UT)");
}
}
#endif
if (ms_bInBigMap != bBigMap)
{
CScriptHud::ms_iRadarZoomValue = 0; // only alter these zoom values if the bigmap actually is changing state
CScriptHud::ms_fMiniMapForcedZoomPercentage = 0.0f;
ms_bInBigMap = bBigMap;
if (!bBigMap)
{
ms_bBigMapFullZoom = ms_bBigMapFullScreen = false;
}
}
}
/////////////////////////////////////////////////////////////////////////////////////
// NAME: CMiniMap::SetInGolfMap
// PURPOSE:
/////////////////////////////////////////////////////////////////////////////////////
void CMiniMap::SetInGolfMap(bool bGolfMap)
{
#if !__FINAL
if(CMiniMap_Common::OutputDebugTransitions())
{
if (ms_bInGolfMap != bGolfMap) // because script like to spam these things
{
if (bGolfMap)
uiDisplayf("MINIMAP_TRANSITION: CMiniMap::SetInGolfMap(TRUE) (UT)");
else
uiDisplayf("MINIMAP_TRANSITION: CMiniMap::SetInGolfMap(FALSE) (UT)");
}
}
#endif
ms_bInGolfMap = bGolfMap;
if (!bGolfMap)
{
ms_iGolfCourseMap = GOLF_COURSE_OFF;
}
}
/////////////////////////////////////////////////////////////////////////////////////
// NAME: CMiniMap::Init
// PURPOSE: initialises the minimap
/////////////////////////////////////////////////////////////////////////////////////
void CMiniMap::Init(unsigned initMode)
{
if(initMode == INIT_CORE)
{
ms_bXmlDataHasBeenRead = false;
for (s32 i = 0; i < MAX_WAYPOINT_MARKERS; i++)
{
ms_Waypoint[i].iPlayerModelHash = 0;
ms_Waypoint[i].iBlipIndex = INVALID_BLIP_ID;
ms_Waypoint[i].vPos = Vector2(0,0);
}
ms_PointOfInterest.Reset();
REGISTER_FRONTEND_XML(CMiniMap::HandleCoreXML, XML_CORE_NODE_NAME);
REGISTER_FRONTEND_XML(CMiniMap::HandleInteriorXML, "minimap_interiors");
#if COMPANION_APP
// Initialise the Companion App stuff here
CCompanionData::GetInstance()->Initialise();
#endif // COMPANION_APP
}
else if(initMode == INIT_SESSION)
{
ms_BitmapBackground.Reset();
//@@: location CMINIMAP_INIT_RESIZE_MAP
ms_BitmapBackground.Resize(MM_BITMAP_VERSION_NUM_ENUMS, sm_Tunables.Bitmap.iBitmapTilesX, sm_Tunables.Bitmap.iBitmapTilesY);
for (s32 a = 0; a < MM_BITMAP_VERSION_NUM_ENUMS; a++)
{
for (s32 i = 0; i < sm_Tunables.Bitmap.iBitmapTilesX; i++)
{
for (s32 j = 0; j < sm_Tunables.Bitmap.iBitmapTilesY; j++)
{
ms_BitmapBackground(a,i,j).iTxdId = -1;
ms_BitmapBackground(a,i,j).iState = MM_BITMAP_NONE;
}
}
}
//Clear waypoints state
ms_bEntityWaypointAllowed = false;
ms_waypointGpsFlags = 0;
ms_bWaypointClearOnArrivalMode = eWaypointClearOnArrivalMode::Enabled;
for (s32 i = 0; i < MAX_WAYPOINT_MARKERS; i++)
{
ClearWaypointBlipAndRoute(ms_Waypoint[i]);
ms_Waypoint[i].iPlayerModelHash = 0;
}
ms_bBitmapInitialized = true;
ms_bFlashWantedOverlay = false;
ms_iLockedMiniMapAngle = -1;
ms_vLockedMiniMapPosition = Vector2(-9999.0f,-9999.0f);
ms_iCentreBlip = INVALID_BLIP_ID;
ms_iNorthBlip = INVALID_BLIP_ID;
// ms_iBlipHovering = -1;
ms_bInStealthMode = true; // PhilH wants this ON as default
ms_bHideBackgroundMap = false;
ms_bBlockWaypoint = false;
ms_bInPrologue = false;
ms_bOnIslandMap = false;
ms_bInPauseMap = false;
ms_bInCustomMap = false;
ms_bInBigMap = false;
ms_iGolfCourseMap = GOLF_COURSE_OFF;
ms_iLockedMiniMapAngle = -1;
#if __BANK
ms_g_bDisplayGameMiniMap = true;
ms_iDebugGolfCourseMap = -1;
ms_bOverrideConeColour = false;
ms_ConeColourRed = 47;
ms_ConeColourGreen = 92;
ms_ConeColourBlue = 115;
ms_ConeColourAlpha = CMiniMap_Common::ALPHA_OF_POLICE_PERCEPTION_CONES;
ms_fConeFocusRangeMultiplier = 1.05f;
ms_bDrawActualRangeCone = false;
#endif
if (!ms_bXmlDataHasBeenRead) // only create a new minimap movie once - not between sessions (its a waste of time as it removes and re-adds shortly after)
{
LoadXmlData();
ms_bXmlDataHasBeenRead = true;
OldMiniMapConstructor();
}
else
{
// Make sure the movies are locked so the SetActive will unlock them
CScaleformMgr::LockMovie(GetMovieId(MINIMAP_MOVIE_BACKGROUND));
CScaleformMgr::LockMovie(GetMovieId(MINIMAP_MOVIE_FOREGROUND));
}
MinimapModeState = MINIMAP_MODE_STATE_SETUP_FOR_MINIMAP; // fix for 1390231
SetSimpleBlipDefaults();
CreateCentreAndNorthBlips();
SetInPrologue(false);
SetOnIslandMap(false);
// ensure the minimap is set up at init session in order to continue safely:
SetActive();
#if ENABLE_FOG_OF_WAR
if( GetIgnoreFowOnInit() == false )
{
SetRequestFoWClear(true);
SetFoWMapValid(false);
SetHideFow(false);
}
#endif
uiDisplayf("Minimap is now active");
}
ms_MiniMapReappearanceState.iMiniMapRenderedTimer = 0;
ms_MiniMapReappearanceState.MinimapModeStateWhenHidden = MINIMAP_MODE_STATE_NONE;
ms_MiniMapReappearanceState.vMiniMapCentrePosWhenHidden.Zero();
ms_MiniMapReappearanceState.bMiniMapInteriorWhenHidden = false;
ms_MiniMapReappearanceState.bBeenInPauseMenu = false;
ms_previousInterior.Clear();
ms_blipCones.Init(initMode);
m_FakeCones.clear();
m_ConeColors.Reset();
CMiniMap_Common::Init(initMode);
CMiniMap_RenderThread::Init(initMode);
}
/////////////////////////////////////////////////////////////////////////////////////
// NAME: CMiniMap::Shutdown
// PURPOSE: shuts down the minimap
/////////////////////////////////////////////////////////////////////////////////////
void CMiniMap::Shutdown(unsigned shutdownMode)
{
{ // scope for the AutoLocks
CScaleformMgr::AutoLock lockFore(GetMovieId(MINIMAP_MOVIE_FOREGROUND));
CScaleformMgr::AutoLock lockBack(GetMovieId(MINIMAP_MOVIE_BACKGROUND));
if (shutdownMode == SHUTDOWN_CORE)
{
#if __BANK
ShutdownWidgets();
#endif // __BANK
CMiniMap_Common::Shutdown(shutdownMode);
CMiniMap_RenderThread::Shutdown(shutdownMode);
CMiniMap_RenderThread::RemoveContainers();
RemoveMiniMapMovie();
}
else if (shutdownMode == SHUTDOWN_SESSION)
{
CScaleformMgr::ForceMovieUpdateInstantly(GetMovieId(MINIMAP_MOVIE_BACKGROUND), false);
CScaleformMgr::ForceMovieUpdateInstantly(GetMovieId(MINIMAP_MOVIE_FOREGROUND), false);
// ms_bInsideReInit - we don't want to remove all blips when transitioning between MP and SP.
// We should leave it to script to remove their own blips so that the number of SCRIPT_RESOURCE_RADAR_BLIP doesn't report more blips than actually exist
const s32 actualSimpleBlipId = GetActualSimpleBlipId();
const s32 actualNorthBlipId = GetActualNorthBlipId();
const s32 actualCentreBlipId = GetActualCentreBlipId();
for (s32 iIndex = iMaxCreatedBlips-1; iIndex >= 0; iIndex--) // remove them in reverse order so that the iMaxCreatedBlips should also get adjusted
{
CMiniMapBlip *pBlip = GetBlipFromActualId(iIndex);
if (!pBlip)
continue;
if (pBlip->IsComplex())
{ // Not sure what to do if the blip is simple. Ask Derek if it can ever be simple and be on the stage
CMiniMap_RenderThread::RemoveBlipFromStage((CBlipComplex*)pBlip, true);
}
else
{
uiAssertf(0, "CMiniMap::Shutdown - Graeme - just checking if this ever happens for simple blips");
}
if (!ms_bInsideReInit
|| (iIndex == actualSimpleBlipId)
|| (iIndex == actualNorthBlipId)
|| (iIndex == actualCentreBlipId) )
{
RemoveBlip(pBlip);
DestroyBlipObject(pBlip);
}
}
if (!ms_bInsideReInit)
{
iMaxCreatedBlips = 0;
ms_PointOfInterest.Reset();
}
bActive = false;
// at end of each session, we flag to perform garbage collection on the minimap
CScaleformMgr::ForceCollectGarbage(GetMovieId(MINIMAP_MOVIE_BACKGROUND));
CScaleformMgr::ForceCollectGarbage(GetMovieId(MINIMAP_MOVIE_FOREGROUND));
CMiniMap_Common::Shutdown(shutdownMode);
CMiniMap_RenderThread::Shutdown(shutdownMode);
RestartMiniMapMovie();
}
} // scope for the AutoLocks - not sure if gRenderThreadInterface.Flush() is safe to do while the movies are locked. better to be careful.
}
/////////////////////////////////////////////////////////////////////////////////////
// NAME: CMiniMap::RestartMiniMapMovie
// PURPOSE: restarts the minimap movies - removes all stuff thats been setup,
// restarts the movies (removes & re-adds movieview) and re-sets up movies
/////////////////////////////////////////////////////////////////////////////////////
void CMiniMap::RestartMiniMapMovie()
{
CMiniMap_RenderThread::RemoveContainers();
// restart the background movie
if (!CScaleformMgr::RestartMovie(GetMovieId(MINIMAP_MOVIE_BACKGROUND), true, false))
{
uiAssertf(0, "CMiniMap::Init - Couldnt restart the foreground movie");
}
// restart the blips movie
if (!CScaleformMgr::RestartMovie(GetMovieId(MINIMAP_MOVIE_FOREGROUND), true, false))
{
uiAssertf(0, "CMiniMap::Init - Couldnt restart the foreground movie");
}
CMiniMap_RenderThread::SetupContainers();
// turn off all components
for (s32 iComponentId = 0; iComponentId < MAX_MINIMAP_COMPONENTS; iComponentId++)
{
ToggleComponent(iComponentId, false, true);
}
CNewHud::RepopulateHealthInfoDisplay();
CMiniMap_RenderThread::SetupHealthArmourOnStage(false);
CMiniMap_RenderThread::UpdateMapVisibility();
}
void CMiniMap::HandleCoreXML(parTreeNode* pMiniMapNode)
{
#if __ASSERT
parAttribute* pVersion = pMiniMapNode->GetElement().FindAttribute("v");
if( uiVerifyf(pVersion, "CMinimap is expecting a versioned node \"" XML_CORE_NODE_NAME "\" in frontend.xml. Please get latest on it." ))
{
float xmlVersion = static_cast<float>(atof(pVersion->GetStringValue()));
uiAssertf(xmlVersion == XML_VERSION, "CMiniMap expected a version of %f in \"" XML_CORE_NODE_NAME "\" but found %f instead!", XML_VERSION, xmlVersion);
}
#endif // __ASSERT
s32 iCount = MINIMAP_VALUE_MINIMAP; // start at standard style
parTreeNode* pNode = NULL;
while ((pNode = pMiniMapNode->FindChildWithName("data", pNode)) != NULL)
{
safecpy(&sm_miniMaps[iCount].m_fileName[0], pNode->GetElement().FindAttributeAnyCase("name")->GetStringValue(), MAX_LENGTH_OF_MINIMAP_FILENAME);
sm_miniMaps[iCount].m_position.x = (float)atof(pNode->GetElement().FindAttributeAnyCase("posX")->GetStringValue());
sm_miniMaps[iCount].m_position.y = (float)atof(pNode->GetElement().FindAttributeAnyCase("posY")->GetStringValue());
sm_miniMaps[iCount].m_size.x = (float)atof(pNode->GetElement().FindAttributeAnyCase("sizeX")->GetStringValue());
sm_miniMaps[iCount].m_size.y = (float)atof(pNode->GetElement().FindAttributeAnyCase("sizeY")->GetStringValue());
sm_miniMaps[iCount].m_alignX = (pNode->GetElement().FindAttributeAnyCase("alignX")->GetStringValue())[0];
sm_miniMaps[iCount].m_alignY = (pNode->GetElement().FindAttributeAnyCase("alignY")->GetStringValue())[0];
/*
// need to adjust the mask from 16:9 to current aspect ratio in use by the scaleform movies
if (iCount == MINIMAP_VALUE_MINIMAP_MASK_STANDARD_16_9 || iCount == MINIMAP_VALUE_MINIMAP_MASK_BIGMAP_16_9)
{
sm_miniMaps[iCount].m_size.x += CHudTools::GetDifferenceFrom_16_9_ToCurrentAspectRatio() * 0.3f; // use the difference we currently have and scale it for now, needs revising!
}
// only a certain few want to be adjusted for widescreen at load time (probably NONE of these on PC... but that's for later)
if( iCount == MINIMAP_VALUE_STANDARD ||
iCount == MINIMAP_VALUE_GOLF_COURSE ||
iCount == MINIMAP_VALUE_BIGMAP ||
iCount == MINIMAP_VALUE_MINIMAP_BLUR ||
iCount == MINIMAP_VALUE_BIGMAP_BLUR )
{
CHudTools::AdjustForWidescreen(WIDESCREEN_FORMAT_LEFT, &sm_miniMaps[iCount].m_position, &sm_miniMaps[iCount].m_size, NULL);
}
*/
iCount++;
}
}
/////////////////////////////////////////////////////////////////////////////////////
// NAME: CMiniMap::LoadXmlData()
// PURPOSE: reads in the xml data and stores it
/////////////////////////////////////////////////////////////////////////////////////
void CMiniMap::LoadXmlData(bool bForceReload)
{
CFrontendXMLMgr::LoadXML(bForceReload);
}
/////////////////////////////////////////////////////////////////////////////////////
// NAME: CMiniMap::HandleInteriorXML()
// PURPOSE: reads in the xml data and stores it
/////////////////////////////////////////////////////////////////////////////////////
void CMiniMap::HandleInteriorXML(parTreeNode* pMiniMapNode)
{
sm_InteriorInfo.Reset();
parTreeNode* pNode = NULL;
parTreeNode* pNodeContent = NULL;
while ((pNode = pMiniMapNode->FindChildWithName("interior", pNode)) != NULL)
{
sMiniMapInteriorStruct newContentInfo;
newContentInfo.iMainInteriorHash = atStringHash(pNode->GetElement().FindAttributeAnyCase("name")->GetStringValue());
newContentInfo.vMainInteriorPos.x = (float)atof(pNode->GetElement().FindAttributeAnyCase("posX")->GetStringValue());
newContentInfo.vMainInteriorPos.y = (float)atof(pNode->GetElement().FindAttributeAnyCase("posY")->GetStringValue());
newContentInfo.fMainInteriorRot = (float)atof(pNode->GetElement().FindAttributeAnyCase("rot")->GetStringValue());
while ((pNodeContent = pNode->FindChildWithName("content", pNodeContent)) != NULL)
{
u32 iNewSubInteriorHash = atStringHash(pNodeContent->GetElement().FindAttributeAnyCase("name")->GetStringValue());
newContentInfo.iSubInteriorHash.PushAndGrow(iNewSubInteriorHash);
}
sm_InteriorInfo.PushAndGrow(newContentInfo);
}
}
/////////////////////////////////////////////////////////////////////////////////////
// NAME: CMiniMap::UpdateAtEndOfFrame
// PURPOSE: various stuff that needs to be done in the 'safe area' at the end of the
// frame, like removing blips, requesting stream or removal of other movies
// removed any unused blips that have been marked for deletion and already
// removed from the stage in a safe manner
/////////////////////////////////////////////////////////////////////////////////////
void CMiniMap::UpdateAtEndOfFrame()
{
if (!bActive) // if not active yet, then dont update at end of frame
return;
if (!ms_bXmlDataHasBeenRead)
{
uiAssertf(0, "Graeme - CMiniMap::UpdateAtEndOfFrame has been called before MiniMap has been fully initialised");
return;
}
// if (CMiniMap_RenderThread::HasRenderStateStructBeenReceivedByRenderThread())
if (CMiniMap_RenderThread::HasRenderThreadProcessedThisMinimapModeState(MinimapModeState))
{
if (MinimapModeState == MINIMAP_MODE_STATE_SETUP_FOR_MINIMAP) // ensure health and armour are repopulated after the state has been applied on the RT
{
CNewHud::RepopulateHealthInfoDisplay();
}
MinimapModeState = MINIMAP_MODE_STATE_NONE;
// apply any pending transition that has previously been requested here:
if (ms_pendingMinimapModeState != MINIMAP_MODE_STATE_NONE)
{
#if !__FINAL
if(CMiniMap_Common::OutputDebugTransitions())
{
uiDisplayf("MINIMAP_TRANSITION: CMiniMap::UpdateAtEndOfFrame -- Setting pending minimap mode state %d", ms_pendingMinimapModeState);
}
#endif //!__FINAL
SetMinimapModeState(ms_pendingMinimapModeState);
ms_pendingMinimapModeState = MINIMAP_MODE_STATE_NONE;
}
}
//
// removal of any unused blips:
//
for (s32 iIndex = 0; iIndex < iMaxCreatedBlips; iIndex++)
{
if (iIndex == GetActualSimpleBlipId())
continue;
CMiniMapBlip *pBlip = GetBlipFromActualId(iIndex);
if (!pBlip)
continue;
if (IsFlagSet(pBlip, BLIP_FLAG_VALUE_DESTROY_BLIP_OBJECT)) // try and remove the blip if this flag is set but it will only remove it if its no longer on the stage
{
DestroyBlipObject(pBlip); // we may remove this blip here
}
else
{
if (CMiniMap_RenderThread::DoesRenderedBlipExist(iIndex))
{
SetFlag(pBlip, BLIP_FLAG_ON_STAGE);
}
else
{
UnsetFlag(pBlip, BLIP_FLAG_ON_STAGE);
}
}
}
CMiniMap_RenderThread::ProcessAtEndOfFrame();
}
/////////////////////////////////////////////////////////////////////////////////////
// NAME: CMiniMap::Update
// PURPOSE: updates the minimap
/////////////////////////////////////////////////////////////////////////////////////
void CMiniMap::Update()
{
if (CSystem::IsThisThreadId(SYS_THREAD_RENDER)) // only on UT
{
uiAssertf(0, "CMiniMap:: Update can only be called on the UpdateThread!");
return;
}
//
// debug code so we can test the zoom to distance and zoom to blip code
//
#if __BANK
if (s_bZoomToWaypointBlip)
{
s32 iBlipIndex = CMiniMap::GetActiveWaypointId();
if (iBlipIndex != INVALID_BLIP_ID)
{
CMiniMapBlip *pBlip = CMiniMap::GetBlip(iBlipIndex);
if (pBlip)
{
Vector3 vCentrePos;
Vector3 vBlipPos = CMiniMap::GetBlipPositionValue(pBlip);
CMiniMap::GetCentrePosition(vCentrePos);
Vector3 deltaFromTargetXY = vCentrePos-vBlipPos;
deltaFromTargetXY.z = 0.0f;
CScriptHud::ms_fRadarZoomDistanceThisFrame = deltaFromTargetXY.Mag() + s_fRadarZoomDistanceThisFrameWidget;
}
}
}
else
{
if (s_fRadarZoomDistanceThisFrameWidget != 0.0f) // set this every frame if its been set in rag
{
CScriptHud::ms_fRadarZoomDistanceThisFrame = s_fRadarZoomDistanceThisFrameWidget;
}
}
#endif
//
// end of debug code so we can test the zoom to distance and zoom to blip code
//
if ( !ShouldProcessMinimap() ||
( IsInPauseMap() && !CPauseMenu::IsInMapScreen() && !CNetwork::IsGameInProgress()) )
{
// if(cStoreScreenMgr::IsStoreMenuOpen()) // valid "updatestate" needs to be sent all the time to keep things transitioning correctly so flags etc set match what we have sent to AS
// {
// DLC(CMiniMap_RenderState_Setup, ());
// }
// else
// {
UpdateStatesOnUT(); // Graeme - The render thread uses ms_MiniMapRenderState.m_bShouldProcessMiniMap to know whether to render or not. So I'll try calling this in here
// so that the render thread knows not to render. Without this, I was seeing the minimap even when the scripts were calling HIDE_HUD_AND_RADAR_THIS_FRAME
// }
UpdateBlips(); // Graeme - B*1320771 - we were getting a "Cannot find a free blip slot - maximum has been hit" assert if script removed lots of blips and added lots of new ones
// while ShouldProcessMinimap() was returning false. The Update Thread can only remove a blip properly once it has told the Render Thread to remove the blip from the stage.
// For that to happen, we need to call UpdateBlips() even if the rest of UpdateMiniMap() isn't going to get called.
// Maybe as an alternative we could have always processed the minimap fully and just chosen not to render it where we're currently saying not to process it.
return;
}
#if !__FINAL
if (PARAM_nominimap.Get())
{
if (!IsInPauseMap())
return;
}
#endif // !__FINAL
PF_PUSH_TIMEBAR_DETAIL("Scaleform Movie Update (MiniMap)");
UpdateCentreAndNorthBlips();
UpdateWaypoint(); // ensure we always have the correct waypoint in use for the current player in use
UpdateMiniMap();
PF_POP_TIMEBAR_DETAIL();
}
#if RSG_PC
void CMiniMap::DeviceLost()
{
uiDebugf1("Device got lost, but we don't do anything about it for the minimap");
}
void CMiniMap::DeviceReset()
{
if( ms_MiniMapReappearanceState.MinimapModeStateWhenHidden != MINIMAP_MODE_STATE_NONE )
s_iDeviceLostResetCountdown = 2; // we need to wait a bit, otherwise the DLC call gets lost and we don't resize.
}
#endif // RSG_PC
/////////////////////////////////////////////////////////////////////////////////////
// NAME: CMiniMap::SetCurrentGolfMap
// PURPOSE: sets the golf course map (and also turns on/off the sea background)
/////////////////////////////////////////////////////////////////////////////////////
void CMiniMap::SetCurrentGolfMap(eGOLF_COURSE_HOLES iValue)
{
if (ms_iGolfCourseMap != iValue)
{
ms_iGolfCourseMap = iValue; // set the new course map after we setup the state
if (iValue != GOLF_COURSE_OFF)
{
// turn on golf map (or set a new golf map)
if (!CPauseMenu::IsActive()) // dont set new golf map if in pausemenu (pausemap or custom maps)
{
SetMinimapModeState(MINIMAP_MODE_STATE_SETUP_FOR_GOLFMAP); // setup whatever golf map we may need
}
}
else
{
// turn off golf map
SetMinimapModeState(MINIMAP_MODE_STATE_SETUP_FOR_MINIMAP); // back to standard minimap if we turn it off
}
}
}
/////////////////////////////////////////////////////////////////////////////////////
// NAME: CMiniMap::GetActualCentreBlipId
// PURPOSE: returns the actual blip array id for the centre blip
/////////////////////////////////////////////////////////////////////////////////////
s32 CMiniMap::GetActualCentreBlipId()
{
if (!ms_bXmlDataHasBeenRead)
{
uiAssertf(0, "Graeme - CMiniMap::GetActualCentreBlipId has been called before MiniMap has been fully initialised");
return -1;
}
return (ConvertUniqueBlipToActualBlip(ms_iCentreBlip));
}
/////////////////////////////////////////////////////////////////////////////////////
// NAME: CMiniMap::GetActualNorthBlipId
// PURPOSE: returns the actual blip array id for the north blip
/////////////////////////////////////////////////////////////////////////////////////
s32 CMiniMap::GetActualNorthBlipId()
{
if (!ms_bXmlDataHasBeenRead)
{
uiAssertf(0, "Graeme - CMiniMap::GetActualNorthBlipId has been called before MiniMap has been fully initialised");
return -1;
}
return (ConvertUniqueBlipToActualBlip(ms_iNorthBlip));
}
/////////////////////////////////////////////////////////////////////////////////////
// NAME: CMiniMap::RevealCoordinate
// PURPOSE: returns the actual blip array id for the north blip
/////////////////////////////////////////////////////////////////////////////////////
void CMiniMap::RevealCoordinate(const Vector2& coordinates)
{
uiAssertf(ms_numScriptRevealRequested<=8,"Trying to reveal more than 8 coordinates in the FoW map");
if( ms_numScriptRevealRequested < 8 )
{
ms_ScriptReveal[ms_numScriptRevealRequested] = coordinates;
ms_numScriptRevealRequested++;
}
}
/////////////////////////////////////////////////////////////////////////////////////
// NAME: CMiniMap::CreateCentreAndNorthBlips
// PURPOSE: creates the player position and north blips
/////////////////////////////////////////////////////////////////////////////////////
void CMiniMap::CreateCentreAndNorthBlips()
{
if (!ms_bXmlDataHasBeenRead)
{
uiAssertf(0, "Graeme - CMiniMap::CreateCentreAndNorthBlips has been called before MiniMap has been fully initialised");
return;
}
ms_iCentreBlip = CreateBlip(true, BLIP_TYPE_COORDS, Vector3(0,0,1.0f), BLIP_DISPLAY_BLIPONLY, "centre_blip");
SetBlipParameter(BLIP_CHANGE_OBJECT_NAME, ms_iCentreBlip, BLIP_CENTRE);
SetBlipParameter(BLIP_CHANGE_SCALE, ms_iCentreBlip, 0.7f); // slightly smaller
SetBlipParameter(BLIP_CHANGE_PRIORITY, ms_iCentreBlip, BLIP_PRIORITY_ONTOP_OF_EVERYTHING);
SetBlipParameter(BLIP_CHANGE_BRIGHTNESS, ms_iCentreBlip, true);
SetBlipParameter(BLIP_CHANGE_CATEGORY, ms_iCentreBlip, BLIP_CATEGORY_LOCAL_PLAYER);
Vector3 vNorthPos(0.0f,CMiniMap::sm_Tunables.Tiles.vMiniMapWorldSize.y*2.0f, 0.0f);
ms_iNorthBlip = CreateBlip(true, BLIP_TYPE_COORDS, vNorthPos, BLIP_DISPLAY_MINIMAP_OR_BIGMAP, "North_blip");
SetBlipParameter(BLIP_CHANGE_OBJECT_NAME, ms_iNorthBlip, BLIP_NORTH);
SetBlipParameter(BLIP_CHANGE_PRIORITY, ms_iNorthBlip, BLIP_PRIORITY_LOW_SPECIAL); // bug 623249 requests NORTH blip is always ontop of everything - thgen 783144 says otherwise
}
/////////////////////////////////////////////////////////////////////////////////////
// NAME: CMiniMap::UpdateCentreAndNorthBlips
// PURPOSE: updates the player position
/////////////////////////////////////////////////////////////////////////////////////
void CMiniMap::UpdateCentreAndNorthBlips()
{
if (!ms_bXmlDataHasBeenRead)
{
uiAssertf(0, "Graeme - CMiniMap::UpdateCentreAndNorthBlips has been called before MiniMap has been fully initialised");
return;
}
ms_bCentreBlipPosChangedThisFrame = false;
if ((!IsInPauseMap()) && ms_iNorthBlip != INVALID_BLIP_ID)
{
if (!IsInGolfMap())
{
SetBlipParameter(BLIP_CHANGE_DISPLAY, ms_iNorthBlip, BLIP_DISPLAY_MINIMAP_OR_BIGMAP);
}
else
{
SetBlipParameter(BLIP_CHANGE_DISPLAY, ms_iNorthBlip, BLIP_DISPLAY_NEITHER);
}
}
const CPed * pLocalPlayer = GetMiniMapPed();
if (pLocalPlayer && ms_iCentreBlip != INVALID_BLIP_ID)
{
CMiniMapBlip *pBlip = GetBlip(ms_iCentreBlip);
if (!pBlip)
return;
float fHeading = pLocalPlayer->GetTransform().GetHeading() * RtoD;
Vector3 vPosition = GetPlayerBlipPosition();
// Cache whether the player position has changed this frame
ms_bCentreBlipPosChangedThisFrame = (vPosition != GetBlipPositionValue(pBlip));
const CVehicle *pVehicle = pLocalPlayer->GetVehiclePedInside();
if (pVehicle && (pLocalPlayer->GetIsDrivingVehicle() || CNetwork::IsGameInProgress()) )
{
// fix for 1493320 - using this instead of heading means we get the dir regardless of whether upside down or not, works in all vehicles really well
Matrix34 mat = MAT34V_TO_MATRIX34(pVehicle->GetMatrix());
Vector3 eulers;
mat.ToEulersYXZ(eulers);
fHeading = eulers.z * RtoD;
}
if (IsInPauseMap())
{
SetBlipParameter(BLIP_CHANGE_FLASH, ms_iCentreBlip, true);
}
else
{
// use debugcam position/rotation and flash if debug cam is active
#if !__FINAL
if (camInterface::GetDebugDirector().IsFreeCamActive() BANK_ONLY( DEBUG_DRAW_ONLY( && !CMiniMap_RenderThread::sm_bDrawCollisionVolumes)))
{
vPosition = camInterface::GetPos();
fHeading = camInterface::GetHeading() * RtoD;
SetBlipParameter(BLIP_CHANGE_FLASH, ms_iCentreBlip, true);
SetBlipParameter(BLIP_CHANGE_FLASH_INTERVAL, ms_iCentreBlip, 200);
}
else
#endif // __FINAL
{
SetBlipParameter(BLIP_CHANGE_FLASH, ms_iCentreBlip, false);
}
}
SetBlipParameter(BLIP_CHANGE_DIRECTION, ms_iCentreBlip, fHeading);
SetBlipParameter(BLIP_CHANGE_POSITION, ms_iCentreBlip, vPosition);
//
// set the centre blip to the network team colour if we are in a network game:
//
if (NetworkInterface::IsGameInProgress())
{
/* s32 iColour;
if (!NetworkInterface::GetLocalPlayer()->HasTeam() || CScriptHud::bUsePlayerColourInsteadOfTeamColour)
{
iColour = NetworkColours::MapNetworkColourToRadarBlipColour(NetworkInterface::GetLocalPlayer()->GetColour());
}
else
{
iColour = NetworkColours::MapNetworkColourToRadarBlipColour(NetworkColours::GetTeamColour(NetworkInterface::GetLocalPlayer()->GetTeam()));
}
if (GetBlipColourValue(pBlip) != iColour)
{
SetBlipParameter(BLIP_CHANGE_COLOUR, ms_iCentreBlip, iColour);
}*/
}
else
{
if (CScriptHud::m_playerBlipColourOverride != BLIP_COLOUR_DEFAULT)
{
if (GetBlipColourValue(pBlip) != CScriptHud::m_playerBlipColourOverride)
{
SetBlipParameter(BLIP_CHANGE_COLOUR, ms_iCentreBlip, CScriptHud::m_playerBlipColourOverride);
}
}
else
{
if (!IsInPauseMap())
{
/*CWanted *pWanted = CGameWorld::FindLocalPlayerWanted();
if(pWanted)
{
int wantedLevel = CNewHud::GetHudWantedLevel(pWanted);
if (CWanted::GetWantedBlips().GetIsBeingAttacked())
{
// light red when wanted and "hidden to cops"
if (GetBlipColourValue(pBlip) != BLIP_COLOUR_WANTED)
{
SetBlipParameter(BLIP_CHANGE_COLOUR, ms_iCentreBlip, BLIP_COLOUR_WANTED);
}
}
else if(wantedLevel > 0)
{
if(pWanted->CopsAreSearching())
{
// grey when wanted and "hidden to cops"
if (GetBlipColourValue(pBlip) != BLIP_COLOUR_STEALTH_GREY)
{
SetBlipParameter(BLIP_CHANGE_COLOUR, ms_iCentreBlip, BLIP_COLOUR_STEALTH_GREY);
}
}
else
{
// light red when wanted and "hidden to cops"
if (GetBlipColourValue(pBlip) != BLIP_COLOUR_WANTED)
{
SetBlipParameter(BLIP_CHANGE_COLOUR, ms_iCentreBlip, BLIP_COLOUR_WANTED);
}
}
}
else
{
// white at all other times
if (GetBlipColourValue(pBlip) != BLIP_COLOUR_WHITE)
{
SetBlipParameter(BLIP_CHANGE_COLOUR, ms_iCentreBlip, BLIP_COLOUR_WHITE);
}
}
}
else*/
CPed* pPlayerPed = CGameWorld::FindLocalPlayer();
CWanted* pWanted = NULL;
if(pPlayerPed)
pWanted = pPlayerPed->GetPlayerWanted();
bool bStealth = false;
if(pWanted)
{
bool bTemp;
int wantedLevel = CNewHud::GetHudWantedLevel(pWanted, bTemp);
if(wantedLevel > 0 && pWanted->CopsAreSearching())
{
if(CPedGeometryAnalyser::IsPedInBush(*pPlayerPed) ||
CPedGeometryAnalyser::IsPedInUnknownCar(*pPlayerPed) ||
CPedGeometryAnalyser::IsPedInWaterAtDepth(*pPlayerPed, CPedGeometryAnalyser::ms_MaxPedWaterDepthForVisibility))
{
bStealth = true;
}
}
}
if(bStealth)
{
// grey when hidden
if (GetBlipColourValue(pBlip) != BLIP_COLOUR_STEALTH_GREY)
{
SetBlipParameter(BLIP_CHANGE_COLOUR, ms_iCentreBlip, BLIP_COLOUR_STEALTH_GREY);
}
}
else
{
// white at all other times
if (GetBlipColourValue(pBlip) != BLIP_COLOUR_WHITE)
{
SetBlipParameter(BLIP_CHANGE_COLOUR, ms_iCentreBlip, BLIP_COLOUR_WHITE);
}
// keep alpha at 255 at all times in SP
if (GetBlipAlphaValue(pBlip) != 255)
{
SetBlipParameter(BLIP_CHANGE_ALPHA, ms_iCentreBlip, 255);
}
}
}
else
{
// player colour in SP: (1548193)
eHUD_COLOURS hudColour = CNewHud::GetCurrentCharacterColour();
eBLIP_COLOURS blipColour;
switch (hudColour)
{
case HUD_COLOUR_MICHAEL:
{
blipColour = BLIP_COLOUR_MICHAEL;
break;
}
case HUD_COLOUR_FRANKLIN:
{
blipColour = BLIP_COLOUR_FRANKLIN;
break;
}
case HUD_COLOUR_TREVOR:
default:
{
blipColour = BLIP_COLOUR_TREVOR;
break;
}
}
if (GetBlipColourValue(pBlip) != blipColour)
{
SetBlipParameter(BLIP_CHANGE_COLOUR, ms_iCentreBlip, blipColour);
}
}
}
}
}
}
Vector3 CMiniMap::GetPlayerBlipPosition()
{
Vector3 vPosition;
Vector2 vFakePlayerPosition;
if (CScriptHud::GetFakedPauseMapPlayerPos(vFakePlayerPosition))
{
vPosition.Set(vFakePlayerPosition.x, vFakePlayerPosition.y, 0.0f);
}
else
{
const CPed* pLocalPlayer = GetMiniMapPed();
if(pLocalPlayer)
{
vPosition = VEC3V_TO_VECTOR3(pLocalPlayer->GetTransform().GetPosition());
}
}
return vPosition;
}
/////////////////////////////////////////////////////////////////////////////////////
void sPointOfInterestStruct::Delete()
{
CMiniMap::RemoveBlip(GetBlip());
}
CMiniMapBlip* sPointOfInterestStruct::GetBlip() const
{
if(iUniqueBlipId != INVALID_BLIP_ID)
{
return CMiniMap::GetBlip(iUniqueBlipId);
}
return NULL;
}
/////////////////////////////////////////////////////////////////////////////////////
// NAME: CMiniMap::UpdateDisplayConfig()
// PURPOSE: updates safezone info on scaleform
/////////////////////////////////////////////////////////////////////////////////////
void CMiniMap::UpdateDisplayConfig()
{
for (s32 i = 0; i < MAX_MINIMAP_MOVIE_LAYERS; i++)
{
CScaleformMgr::ChangeMovieParams(iMovieId[i], GetCurrentMiniMapPosition(), GetCurrentMiniMapSize(), GFxMovieView::SM_ExactFit);
}
}
/////////////////////////////////////////////////////////////////////////////////////
// NAME: CMiniMap::AddOrRemovePointOfInterest()
// PURPOSE: turns on or off a POI blip - up to 10 (bug 989055)
/////////////////////////////////////////////////////////////////////////////////////
void CMiniMap::AddOrRemovePointOfInterest(float fPosX, float fPosY)
{
if (!CSystem::IsThisThreadId(SYS_THREAD_UPDATE)) // only on UT
{
uiAssertf(0, "CMiniMap::SwitchOnWaypoint can only be called on the UpdateThread!");
return;
}
#define POI_BLIP_OVERLAY_RADIUS (400.0f)
float fBlipOverlayRadius2 = rage::square(POI_BLIP_OVERLAY_RADIUS / CMiniMap::GetPauseMapScale());
float fClosestMatch = POI_BLIP_OVERLAY_RADIUS*POI_BLIP_OVERLAY_RADIUS; // plenty big size
int iClosestIndex = -1;
Vector3 vPos(fPosX, fPosY, 1.0f);
for (s32 iId = 0; iId < ms_PointOfInterest.size(); ++iId)
{
CMiniMapBlip *pBlip = ms_PointOfInterest[iId].GetBlip();
if (pBlip)
{
Vector3 vBlipPos(CMiniMap::GetBlipPositionValue(pBlip));
float fCurDist = vBlipPos.Dist2(vPos);
if ( fCurDist < fBlipOverlayRadius2 && fCurDist < fClosestMatch )
{
fCurDist = fClosestMatch;
iClosestIndex = iId;
}
}
}
if( iClosestIndex != -1 )
{
// turn off this blip
ms_PointOfInterest[iClosestIndex].Delete();
ms_PointOfInterest.Delete(iClosestIndex);
return;
}
if( ms_PointOfInterest.IsFull() )
{
// if full, shift contents and recycle the front's index
// this COULD be implemented as a circular/round-robin/ring buffer, but those add complexity and apparently we don't have any (good) templates for them?
sPointOfInterestStruct temp = ms_PointOfInterest[0];
ms_PointOfInterest.Delete(0);
ms_PointOfInterest.Push( temp );
SetBlipParameter(BLIP_CHANGE_POSITION, temp.iUniqueBlipId, vPos);
return;
}
s32 iNewBlipId = CreateBlip(true, BLIP_TYPE_COORDS, vPos, BLIP_DISPLAY_PAUSEMAP, "poi");
if (iNewBlipId != INVALID_BLIP_ID) // rather rare, but if no room, don't add entries to the array
{
sPointOfInterestStruct& newPoi = ms_PointOfInterest.Append();
newPoi.iUniqueBlipId = iNewBlipId;
SetBlipParameter(BLIP_CHANGE_OBJECT_NAME, newPoi.iUniqueBlipId, RADAR_TRACE_POI);
SetBlipParameter(BLIP_CHANGE_PRIORITY, newPoi.iUniqueBlipId, BLIP_PRIORITY_LOWEST);
}
}
bool CMiniMap::GetPointOfInterestDetails(s32 index, Vector2& vPosition)
{
vPosition.Set(0.0f, 0.0f);
if (!CSystem::IsThisThreadId(SYS_THREAD_UPDATE)) // only on UT
{
uiAssertf(0, "CMiniMap::GetPointOfInterestDetails can only be called on the UpdateThread!");
return false;
}
// because the special POI was unused, it's been optimized away. HOWEVER, the save data can't really be touched
// so we'll do this and let it lie fallow in there
if( index == POI_SPECIAL_ID)
return false;
if( index >= 0 && index < ms_PointOfInterest.GetCount() )
{
CMiniMapBlip *pBlip = ms_PointOfInterest[index].GetBlip();
if (pBlip)
{
Vector3 vBlipPos(CMiniMap::GetBlipPositionValue(pBlip));
vPosition.x = vBlipPos.x;
vPosition.y = vBlipPos.y;
return true;
}
}
return false;
}
/////////////////////////////////////////////////////////////////////////////////////
// NAME: CMiniMap::SwitchOnWaypoint()
// PURPOSE: switches on the waypoint blip - pass in the blip sprite we want to use
// as the waypoint blip
/////////////////////////////////////////////////////////////////////////////////////
void CMiniMap::SwitchOnWaypoint(float fPosX, float fPosY, ObjectId ObjectId, bool bHideWaypointIcon, bool bSetLocalDirty, eHUD_COLOURS color /* = eHUD_COLOURS::HUD_COLOUR_WAYPOINT*/)
{
if (!CSystem::IsThisThreadId(SYS_THREAD_UPDATE)) // only on UT
{
uiAssertf(0, "CMiniMap::SwitchOnWaypoint can only be called on the UpdateThread!");
return;
}
if (!ms_bXmlDataHasBeenRead)
{
uiAssertf(0, "Graeme - CMiniMap::SwitchOnWaypoint has been called before MiniMap has been fully initialised");
return;
}
s32 iWaypointToUse = -1;
if (NetworkInterface::IsGameInProgress())
{
iWaypointToUse = MULTIPLAYER_WAYPOINT_MARKER_ID;
}
else
{
// find a slot that has no blip used:
for (s32 i = 0; i < MAX_WAYPOINT_MARKERS; i++)
{
if (ms_Waypoint[i].iBlipIndex == INVALID_BLIP_ID && ms_Waypoint[i].iPlayerModelHash == 0)
{
iWaypointToUse = i;
break;
}
}
}
if (iWaypointToUse == -1)
{
uiAssertf(0, "MiniMap: Not enough waypoint slots to create new marker, replacing slot 0");
iWaypointToUse = 0; // if not enough free slots, then use the 1st to ensure we can always create a new route.
}
sWaypointStruct& Waypoint = ms_Waypoint[iWaypointToUse];
ClearWaypointBlipAndRoute(Waypoint);
// if we have a free slot, create the blip and store the info:
Waypoint.iPlayerModelHash = 0;
CPed *pPlayerPed = FindPlayerPed();
if (pPlayerPed)
{
Waypoint.iPlayerModelHash = pPlayerPed->GetPedModelInfo()->GetHashKey(); // store player model index used
}
//Set waypoint location
Waypoint.vPos.Set(fPosX, fPosY);
//Search for best Blip
float MinBlipDistanceSq = 0.1f;
s32 ClosestBlip = INVALID_BLIP_ID;
if (NetworkInterface::IsGameInProgress())
{
if (netObject* pObj = NetworkInterface::GetObjectManager().GetNetworkObject(ObjectId))
{
if (CEntity* pWaypointEntity = pObj->GetEntity())
{
const Vector3 WaypointLocation(Waypoint.vPos.x, Waypoint.vPos.y, 0.0f);
for (s32 iIndex = 0; iIndex < iMaxCreatedBlips; iIndex++)
{
CMiniMapBlip *pBlip = blip[iIndex];
if (pBlip && pBlip->IsComplex() && IsBlipIdInUse(pBlip->m_iUniqueId))
{
//Find blip associated with this entity
if (pWaypointEntity == FindBlipEntity(pBlip))
{
//Entity found! Assign ObjectID and cache the blip ID so we can validate it later
Waypoint.ObjectId = ObjectId;
Waypoint.iAssociatedBlipId = pBlip->m_iUniqueId;
break;
}
//Calculate closest blip
else
{
const float BlipDistanceSq = (WaypointLocation - GetBlipPositionValue(pBlip)).Mag2();
if (BlipDistanceSq < MinBlipDistanceSq)
{
MinBlipDistanceSq = BlipDistanceSq;
ClosestBlip = pBlip->m_iUniqueId;
}
}
}
}
}
}
}
//Fall back to closest coordinate lookup
if (Waypoint.iAssociatedBlipId == INVALID_BLIP_ID && ClosestBlip != INVALID_BLIP_ID)
{
Waypoint.iAssociatedBlipId = ClosestBlip;
}
eBLIP_DISPLAY_TYPE iDisplayType;
if (bHideWaypointIcon)
{
iDisplayType = BLIP_DISPLAY_NEITHER;
}
else
{
iDisplayType = BLIP_DISPLAY_BLIPONLY;
}
CreateWaypointBlipAndRoute(Waypoint, iDisplayType, color);
uiDebugf1("MiniMap: Waypoint added in slot %d for player %d", iWaypointToUse, Waypoint.iPlayerModelHash);
if(bSetLocalDirty)
{
// update local dirty time
ms_WaypointLocalDirtyTimestamp = NetworkInterface::IsNetworkOpen() ? NetworkInterface::GetNetworkTime() : sysTimer::GetSystemMsTime();
MarkLocallyOwned(true);
}
}
/////////////////////////////////////////////////////////////////////////////////////
// NAME: CMiniMap::SwitchOffWaypoint()
// PURPOSE: switches off the waypoint blip
/////////////////////////////////////////////////////////////////////////////////////
void CMiniMap::SwitchOffWaypoint(bool bSetLocalDirty)
{
if (!CSystem::IsThisThreadId(SYS_THREAD_UPDATE)) // only on UT
{
uiAssertf(0, "CMiniMap::SwitchOffWaypoint can only be called on the UpdateThread!");
return;
}
if (!ms_bXmlDataHasBeenRead)
{
uiAssertf(0, "Graeme - CMiniMap::SwitchOffWaypoint has been called before MiniMap has been fully initialised");
return;
}
#if __BANK
sysStack::PrintStackTrace();
#endif // #if __BANK
s32 iWaypointToUse = -1;
if (NetworkInterface::IsGameInProgress())
{
iWaypointToUse = MULTIPLAYER_WAYPOINT_MARKER_ID;
}
else
{
u32 iCurrentPlayerModelHash = 0;
CPed *pPlayerPed = FindPlayerPed();
if (pPlayerPed)
{
iCurrentPlayerModelHash = pPlayerPed->GetPedModelInfo()->GetHashKey();
}
for (s32 i = 0; i < MAX_WAYPOINT_MARKERS; i++)
{
if (ms_Waypoint[i].iPlayerModelHash == iCurrentPlayerModelHash && ms_Waypoint[i].iBlipIndex != INVALID_BLIP_ID)
{
iWaypointToUse = i;
break;
}
}
}
if (iWaypointToUse != -1)
{
sWaypointStruct& Waypoint = ms_Waypoint[iWaypointToUse];
ClearWaypointBlipAndRoute(Waypoint);
Waypoint.iPlayerModelHash = 0;
Waypoint.vPos = Vector2(0,0);
uiDebugf1("MiniMap: Waypoint removed from slot %d for player %d", iWaypointToUse, Waypoint.iPlayerModelHash);
}
MarkLocallyOwned(false);
if(bSetLocalDirty)
{
// update local dirty time
ms_WaypointLocalDirtyTimestamp = NetworkInterface::IsNetworkOpen() ? NetworkInterface::GetNetworkTime() : sysTimer::GetSystemMsTime();
}
}
/////////////////////////////////////////////////////////////////////////////////////
// NAME: CMiniMap::UpdateWaypoint()
// PURPOSE: replaces the waypoint - removes any old waypoint and uses the one
// current to the local player and creates a gps route for it
/////////////////////////////////////////////////////////////////////////////////////
void CMiniMap::UpdateWaypoint()
{
if (!CSystem::IsThisThreadId(SYS_THREAD_UPDATE)) // only on UT
{
uiAssertf(0, "CMiniMap::UpdateWaypoint can only be called on the UpdateThread!");
return;
}
if (!ms_bXmlDataHasBeenRead)
{
uiAssertf(0, "Graeme - CMiniMap::UpdateWaypoint has been called before MiniMap has been fully initialised");
return;
}
s32 iWaypointToUse = -1;
u32 iCurrentPlayerModelHash = 0;
CPed *pPlayerPed = FindPlayerPed();
if (pPlayerPed)
{
iCurrentPlayerModelHash = pPlayerPed->GetPedModelInfo()->GetHashKey();
}
//
// get current waypoint in use
//
for (s32 i = 0; i < MAX_WAYPOINT_MARKERS; i++)
{
if (ms_Waypoint[i].iBlipIndex != INVALID_BLIP_ID)
{
iWaypointToUse = i;
break;
}
}
//
// remove any current waypoint blip and GPS: (but leave any other info in place to reuse later)
//
if (iWaypointToUse != -1)
{
sWaypointStruct& Waypoint = ms_Waypoint[iWaypointToUse];
// if the waypoint that is already valid is the correct one for the current player, then it doesnt need to
// be refreshed (note if we refresh anyway this causes the blip tracking for taxi missions to get out of sync and end)
// fixes bug 273305
bool ClearWaypoint = Waypoint.iPlayerModelHash != iCurrentPlayerModelHash;
//Validate waypoint object blip still exists
if (Waypoint.ObjectId != NETWORK_INVALID_OBJECT_ID && !IsBlipIdInUse(Waypoint.iAssociatedBlipId))
{
uiDebugf1("MiniMap: Waypoint ObjectID has no associated blip");
ClearWaypoint = true;
}
if (ClearWaypoint)
{
ClearWaypointBlipAndRoute(Waypoint);
uiDebugf1("MiniMap: Waypoint cleared from slot %d for player %d", iWaypointToUse, Waypoint.iPlayerModelHash);
}
else //No refresh required
{
return;
}
}
if (NetworkInterface::IsGameInProgress()) // we dont want to re-create the waypoint in MP, as it always uses the same slot (3). This is the cause of 364289, which caused another bug (-1/INVALID in blip code) to happen in the minimap code.
{
return;
}
iWaypointToUse = -1;
for (s32 i = 0; i < MAX_WAYPOINT_MARKERS; i++)
{
if (ms_Waypoint[i].iPlayerModelHash == iCurrentPlayerModelHash)
{
iWaypointToUse = i;
break;
}
}
//
// if a blip exists still which is valid for this player, then create it:
//
if (iWaypointToUse != -1)
{
if (ms_Waypoint[iWaypointToUse].iPlayerModelHash != 0)
{
CreateWaypointBlipAndRoute(ms_Waypoint[iWaypointToUse], BLIP_DISPLAY_BLIPONLY);
uiDebugf1("MiniMap: Waypoint refreshed in slot %d for player %d", iWaypointToUse, ms_Waypoint[iWaypointToUse].iPlayerModelHash);
}
}
}
/////////////////////////////////////////////////////////////////////////////////////
// NAME: CMiniMap::GetActiveWaypointId()
// PURPOSE: returns the ID of the active waypoint blip
/////////////////////////////////////////////////////////////////////////////////////
bool CMiniMap::IsAnyWaypointIdActive()
{
for (s32 i = 0; i < MAX_WAYPOINT_MARKERS; i++)
{
if (ms_Waypoint[i].iPlayerModelHash != 0)
{
return true;
}
}
return false;
}
/////////////////////////////////////////////////////////////////////////////////////
// NAME: CMiniMap::IsPlayerWaypointActive()
// PURPOSE: returns the ID of the active waypoint blip
/////////////////////////////////////////////////////////////////////////////////////
bool CMiniMap::IsPlayerWaypointActive(u32 iPlayerHash)
{
for (s32 i = 0; i < MAX_WAYPOINT_MARKERS; i++)
{
if (ms_Waypoint[i].iPlayerModelHash == iPlayerHash)
{
return true;
}
}
return false;
}
/////////////////////////////////////////////////////////////////////////////////////
// NAME: CMiniMap::GetActiveWaypointId()
// PURPOSE: returns the ID of the active waypoint blip
/////////////////////////////////////////////////////////////////////////////////////
s32 CMiniMap::GetActiveWaypointId()
{
if (!CSystem::IsThisThreadId(SYS_THREAD_UPDATE)) // only on UT
{
uiAssertf(0, "CMiniMap::GetActiveWaypointId can only be called on the UpdateThread!");
return INVALID_BLIP_ID;
}
sWaypointStruct Waypoint;
if (GetActiveWaypoint(Waypoint))
{
return Waypoint.iBlipIndex;
}
return INVALID_BLIP_ID;
}
/////////////////////////////////////////////////////////////////////////////////////
// NAME: CMiniMap::GetActiveWaypointPosition
// PURPOSE: retrieves waypoint position
/////////////////////////////////////////////////////////////////////////////////////
bool CMiniMap::GetActiveWaypoint(sWaypointStruct& Waypoint)
{
if (!CSystem::IsThisThreadId(SYS_THREAD_UPDATE)) // only on UT
{
uiAssertf(0, "CMiniMap::GetActiveWaypointPosition can only be called on the UpdateThread!");
return false;
}
s32 iWaypointToUse = -1;
u32 iCurrentPlayerModelHash = 0;
CPed *pPlayerPed = FindPlayerPed();
if (pPlayerPed)
{
iCurrentPlayerModelHash = pPlayerPed->GetPedModelInfo()->GetHashKey();
}
if (NetworkInterface::IsGameInProgress())
{
iWaypointToUse = MULTIPLAYER_WAYPOINT_MARKER_ID;
}
else
{
for (s32 i = 0; i < MAX_WAYPOINT_MARKERS; i++)
{
if (ms_Waypoint[i].iPlayerModelHash == iCurrentPlayerModelHash)
{
iWaypointToUse = i;
break;
}
}
}
if (iWaypointToUse != -1 && ms_Waypoint[iWaypointToUse].iBlipIndex != INVALID_BLIP_ID)
{
Waypoint = ms_Waypoint[iWaypointToUse];
return true;
}
// no active waypoint
return false;
}
bool CMiniMap::SetActiveWaypoint(const Vector2& vPosition, ObjectId ObjectId)
{
s32 iWaypointToUse = -1;
if (NetworkInterface::IsGameInProgress())
{
iWaypointToUse = MULTIPLAYER_WAYPOINT_MARKER_ID;
}
else
{
u32 iCurrentPlayerModelHash = 0;
CPed *pPlayerPed = FindPlayerPed();
if (pPlayerPed)
{
iCurrentPlayerModelHash = pPlayerPed->GetPedModelInfo()->GetHashKey();
for (s32 i = 0; i < MAX_WAYPOINT_MARKERS; i++)
{
if (ms_Waypoint[i].iPlayerModelHash == iCurrentPlayerModelHash)
{
iWaypointToUse = i;
break;
}
}
}
}
if (iWaypointToUse != -1 && ms_Waypoint[iWaypointToUse].iBlipIndex != INVALID_BLIP_ID)
{
ms_Waypoint[iWaypointToUse].vPos = vPosition;
ms_Waypoint[iWaypointToUse].ObjectId = ObjectId;
CreateWaypointBlipAndRoute(ms_Waypoint[iWaypointToUse]);
return true;
}
return false;
}
/////////////////////////////////////////////////////////////////////////////////////
// NAME: CMiniMap::GetActiveWaypointPosition
// PURPOSE: retrieves waypoint position
/////////////////////////////////////////////////////////////////////////////////////
bool CMiniMap::IsActiveWaypoint(Vector2 vPosition, ObjectId ObjectId)
{
if(IsWaypointActive())
{
sWaypointStruct vCurrentWaypoint;
GetActiveWaypoint(vCurrentWaypoint);
bool bMatchingPosition = ABS(vPosition.x - vCurrentWaypoint.vPos.x) < VERY_SMALL_FLOAT && ABS(vPosition.y - vCurrentWaypoint.vPos.y) < VERY_SMALL_FLOAT;
bool bMatchingObjectId = ObjectId == vCurrentWaypoint.ObjectId;
if(bMatchingPosition && bMatchingObjectId)
{
return true;
}
}
return false;
}
void CMiniMap::SetEntityWaypointAllowed(bool Value)
{
if (Value != ms_bEntityWaypointAllowed)
{
uiDisplayf("CMiniMap::SetEntityWaypointAllowed(%s)", Value? "true":"false");
ms_bEntityWaypointAllowed = Value;
}
}
void CMiniMap::SetWaypointClearOnArrivalMode(eWaypointClearOnArrivalMode Value)
{
if (Value != ms_bWaypointClearOnArrivalMode)
{
uiDisplayf("CMiniMap::SetWaypointClearOnArrivalMode(%d)", (int)Value);
ms_bWaypointClearOnArrivalMode = Value;
}
}
void CMiniMap::SetWaypointGpsFlags(u16 Value)
{
if (Value != ms_waypointGpsFlags)
{
uiDisplayf("CMiniMap::SetWaypointGPSFlags(%d)", Value);
ms_waypointGpsFlags = Value;
}
}
void CMiniMap::GetWaypointData(u32 WaypointIndex, u32 &PlayerHash, Vector2 &vPosition)
{
if (uiVerifyf(WaypointIndex < MAX_WAYPOINT_MARKERS, "CMiniMap::GetWaypointData - waypoint index is too large"))
{
PlayerHash = ms_Waypoint[WaypointIndex].iPlayerModelHash;
vPosition = ms_Waypoint[WaypointIndex].vPos;
}
}
void CMiniMap::SetWaypointData(u32 WaypointIndex, u32 PlayerHash, const Vector2 &vPosition)
{
if (uiVerifyf(WaypointIndex < MAX_WAYPOINT_MARKERS, "CMiniMap::SetWaypointData - waypoint index is too large"))
{
ms_Waypoint[WaypointIndex].iPlayerModelHash = PlayerHash;
ms_Waypoint[WaypointIndex].vPos = vPosition;
}
}
/////////////////////////////////////////////////////////////////////////////////////
// NAME: CMiniMap::MarkLocallyOwned
// PURPOSE: indicates whether the custom waypoint is locally owned or not
/////////////////////////////////////////////////////////////////////////////////////
void CMiniMap::MarkLocallyOwned(bool isLocallyOwned)
{
ms_bIsWaypointLocal = isLocallyOwned;
}
/////////////////////////////////////////////////////////////////////////////////////
// NAME: CMiniMap::IsWaypointLocallyOwned
// PURPOSE: retrieves locally owned status
/////////////////////////////////////////////////////////////////////////////////////
bool CMiniMap::IsWaypointLocallyOwned()
{
return ms_bIsWaypointLocal;
}
/////////////////////////////////////////////////////////////////////////////////////
// NAME: CMiniMap::GetWaypointLocalDirtyTimestamp
// PURPOSE: retrieves local dirty timestamp
/////////////////////////////////////////////////////////////////////////////////////
unsigned CMiniMap::GetWaypointLocalDirtyTimestamp()
{
return ms_WaypointLocalDirtyTimestamp;
}
/////////////////////////////////////////////////////////////////////////////////////
// NAME: CMiniMap::SetFlashWantedOverlay
// PURPOSE: because minimap now has faded out sides, we need to do the wanted flash
// in code so we can colour the whole map instead of being limited to the
// edge of the movie itself
/////////////////////////////////////////////////////////////////////////////////////
void CMiniMap::SetFlashWantedOverlay(const bool bFlashOn)
{
if(CScriptHud::bWantsToBlockWantedFlash)
{
ms_bFlashWantedOverlay = false;
}
else
{
ms_bFlashWantedOverlay = bFlashOn;
}
}
/////////////////////////////////////////////////////////////////////////////////////
// NAME: CMiniMap::GetNearestWantedCriminalActualBlipId
// PURPOSE: goes through all wanted criminal blips and returns the one that is the
// nearest to the player blip
/////////////////////////////////////////////////////////////////////////////////////
s32 CMiniMap::GetNearestWantedCriminalActualBlipId()
{
s32 iNearestBlipId = -1;
if (!CNetwork::IsGameInProgress())
return iNearestBlipId;
float fShortestDistance = (CMiniMap::sm_Tunables.Tiles.vMiniMapWorldSize.x + CMiniMap::sm_Tunables.Tiles.vMiniMapWorldSize.y); // seems a good starting max value
CMiniMapBlip *pPlayerBlip = GetBlipFromActualId(GetActualCentreBlipId());
if (!pPlayerBlip)
return iNearestBlipId;
Vector3 vPlayerPos = GetBlipPositionValue(pPlayerBlip);
for (s32 iIndex = 0; iIndex < iMaxCreatedBlips; iIndex++)
{
if (iIndex == iSimpleBlip)
continue;
CMiniMapBlip *pBlip = GetBlipFromActualId(iIndex);
if (!pBlip)
continue;
#define CRIM_BLIP_NAME ("radar_gang_wanted_") // i need to make these exposed to code really instead of this hack, but it will do for now since the bug is well overdue!
if (!strncmp(CRIM_BLIP_NAME, GetBlipObjectName(pBlip), NELEM(CRIM_BLIP_NAME)-1))
{
Vector3 vCriminalPos = GetBlipPositionValue(pBlip);
Vector2 vTestForDistance(Vector2(vCriminalPos.x, vCriminalPos.y)-Vector2(vPlayerPos.x, vPlayerPos.y));
float fDistance = vTestForDistance.Mag();
//Displayf("DISTANCE TO CRIM BLIP IS %0.2f (%0.2f)", fDistance, fShortestDistance);
if (fDistance < fShortestDistance)
{
fShortestDistance = fDistance;
iNearestBlipId = iIndex;
}
}
}
return iNearestBlipId;
}
/////////////////////////////////////////////////////////////////////////////////////
// NAME: CMiniMap::CheckIncomingFunctions
// PURPOSE: checks for incoming functions from ActionScript
/////////////////////////////////////////////////////////////////////////////////////
void CMiniMap::CheckIncomingFunctions(atHashWithStringBank /*methodName*/, const GFxValue* args)
{
if ((eSCALEFORM_BASE_CLASS)(s32)args[0].GetNumber() != SF_BASE_CLASS_MINIMAP)
return;
if (!ms_bXmlDataHasBeenRead)
{
uiAssertf(0, "Graeme - CMiniMap::CheckIncomingFunctions has been called before MiniMap has been fully initialised");
return;
}
}
/////////////////////////////////////////////////////////////////////////////////////
// NAME: CMiniMap::GetRevisedMiniMapRangeFromPercentage
// PURPOSE: returns the range of the radar based on the current minimap setting and
// the value passed from script
/////////////////////////////////////////////////////////////////////////////////////
float CMiniMap::GetRevisedMiniMapRangeFromPercentage(float fPercentage)
{
#define ZOOM_RANGE (500.0f)
float fNewRange = (ZOOM_RANGE / 100.0f) * fPercentage;
if (fNewRange > ZOOM_RANGE)
fNewRange = ZOOM_RANGE;
if (fNewRange < 0.0f)
fNewRange = 0.0f;
fNewRange = ((ZOOM_RANGE+1)-fNewRange);
if (IsInBigMap())
{
fNewRange *= __EXTRA_BIGMAP_SCALER; // scale for bug 1624415
}
return fNewRange;
}
/////////////////////////////////////////////////////////////////////////////////////
// NAME: CMiniMap::GetRevisedMiniMapRangeFromScript
// PURPOSE: returns the range of the radar based on the current minimap setting and
// the value passed from script
/////////////////////////////////////////////////////////////////////////////////////
float CMiniMap::GetRevisedMiniMapRangeFromScript(float fCurrentRange, s32 iScriptZoomValue)
{
float fRange = fCurrentRange;
if (iScriptZoomValue < 100)
{
return fRange;
}
if (IsInBigMap())
{
if (iScriptZoomValue <= MAX_SCRIPT_SCALE_AMOUNT_BIGMAP)
{
float fNewScriptRange = (float)MAX_SCRIPT_SCALE_AMOUNT_BIGMAP - (float)iScriptZoomValue;
float fMinAmount = 1.0f;
fNewScriptRange = ( (fNewScriptRange / ((float)MAX_SCRIPT_SCALE_AMOUNT_BIGMAP * 5.0f)) * (40.0f-fMinAmount) ) + fMinAmount;
fRange = (fNewScriptRange * 0.64f); // minimap has changed size so instead of script re-adjusting their values, we rescale here
fRange *= __EXTRA_BIGMAP_SCALER; // scale for bug 1624415
}
}
else
{
if (iScriptZoomValue <= MAX_SCRIPT_SCALE_AMOUNT_STANDARD)
{
float fNewScriptRange = (float)MAX_SCRIPT_SCALE_AMOUNT_STANDARD - (float)iScriptZoomValue;
float fMinAmount = 7.0f;
fNewScriptRange = ( (fNewScriptRange / (float)MAX_SCRIPT_SCALE_AMOUNT_STANDARD) * (200.0f-fMinAmount) ) + fMinAmount;
fRange = fNewScriptRange;
}
if (IsInGolfMap())
{
fRange *= 0.62f; // minimap has changed size so instead of script re-adjusting their values, we rescale here
}
}
return fRange;
}
/////////////////////////////////////////////////////////////////////////////////////
// NAME: CMiniMap::GetRange
// PURPOSE: returns the range of the radar as it should be based on player speed etc
/////////////////////////////////////////////////////////////////////////////////////
float CMiniMap::GetRange(bool bGetTrueRange)
{
// Use adjusted values when the player is wanted
CPed *pLocalPlayer = GetMiniMapPed();
const bool bWanted = ( pLocalPlayer && pLocalPlayer->GetPlayerWanted() && pLocalPlayer->GetPlayerWanted()->GetWantedLevel() > WANTED_CLEAN );
const float fVehicleStaticZoom = bWanted ? sm_Tunables.Camera.fVehicleStaticWantedZoom: sm_Tunables.Camera.fVehicleStaticZoom;
const float fVehicleMovingZoom = bWanted ? sm_Tunables.Camera.fVehicleMovingWantedZoom: sm_Tunables.Camera.fVehicleMovingZoom;
const float fExteriorZoom = bWanted ? sm_Tunables.Camera.fExteriorFootZoomWanted: sm_Tunables.Camera.fExteriorFootZoom;
// const float fExteriorZoomRunning = bWanted ? sm_Tunables.Camera.fExteriorFootZoomWantedRunning: sm_Tunables.Camera.fExteriorFootZoomRunning;
float fRange = fExteriorZoom;
if (CSystem::IsThisThreadId(SYS_THREAD_RENDER)) // only on UT
{
uiAssertf(0, "CMiniMap::GetRange can only be called on the UpdateThread!");
return fRange;
}
if (!IsInBigMap())
{
if ( (GetIsInsideInterior()) && (pLocalPlayer && !pLocalPlayer->IsInOrAttachedToCar()) )
{
if(CScriptHud::ms_bUseVerySmallInteriorZoom)
{
fRange = sm_Tunables.Camera.fInteriorVerySmall;
}
else if(CScriptHud::ms_bUseVeryLargeInteriorZoom)
{
fRange = sm_Tunables.Camera.fInteriorVeryLarge;
}
else
{
fRange = sm_Tunables.Camera.fInteriorFootZoom;
}
}
else
{
float fVehicleSpeed = GetSpeedOfPlayersVehicle();
if (fVehicleSpeed != 0.0f)
{
fRange = fVehicleStaticZoom - (fVehicleSpeed * sm_Tunables.Camera.fVehicleSpeedZoomScalar);
fRange = rage::Max(fRange, fVehicleMovingZoom);
}
else
{
const CVehicle *pVehicle = CGameWorld::FindLocalPlayerVehicle();
if(pVehicle)
{
// B* 526555: When in a car that someone else is driving, the speed is assumed to be 0, but lets force the minimap to be bigger,
// so that the player can actually see stuff.
if(pVehicle->IsNetworkClone())
{
fRange = fVehicleMovingZoom;
}
else // If not a network clone, then we're actually idle.
{
fRange = fVehicleStaticZoom;
}
}
else if(CGameWorld::FindLocalPlayerMount())
{
fRange = fVehicleStaticZoom;
}
else if (IsPlayerUsingParachute())
{
fRange = sm_Tunables.Camera.fParachutingZoom;
}
else
{
fRange = fExteriorZoom;
}
}
/* // not wanted now 1270882
if (fRange == fExteriorZoom) // no scaling when in an interior for 784769
{
if (IsPlayerRunning())
{
fRange = fExteriorZoomRunning;
}
}*/
}
if (pLocalPlayer && pLocalPlayer->IsUsingActionMode())
{
fRange *= 1.2f; // for 1130713
}
}
else
{
if (ms_bBigMapFullZoom)
{
fRange = BIGMAP_SCALE_FULL;
}
else
{
fRange = BIGMAP_SCALE;
}
}
bool bZoomForced = false;
if (CScriptHud::ms_fRadarZoomDistanceThisFrame != 0.0f)
{
float fScaler = ( 100.0f / (CScriptHud::ms_fRadarZoomDistanceThisFrame * 2.0f) );
fRange = 100.0f * fScaler;
return fRange; // return here so we use whatever distance script has set, regardless of any other options - its capped earlier
}
else
{
//
// script can set the value of the zoom between 100 and MAX_SCRIPT_SCALE_AMOUNT.
//
if (CScriptHud::ms_fMiniMapForcedZoomPercentage != 0.0f)
{
fRange = GetRevisedMiniMapRangeFromPercentage(CScriptHud::ms_fMiniMapForcedZoomPercentage);
bZoomForced = true;
}
else if ( (CScriptHud::ms_iRadarZoomValue != 0) && (!ms_bBigMapFullZoom) ) // fix for 510690
{
fRange = GetRevisedMiniMapRangeFromScript(fRange, CScriptHud::ms_iRadarZoomValue);
bZoomForced = true;
}
}
// apply debug widget range
#if __BANK
if (ms_fDebugRange != 2.0f)
fRange = ms_fDebugRange;
#endif // __BANK
if (!IsInBigMap())
{
if (!bZoomForced)
{
// cap:
fRange = rage::Max(fRange, MIN_MINIMAP_RANGE);
fRange = rage::Min(fRange, MAX_MINIMAP_RANGE);
}
if (IsPlayerInPlaneOrHelicopter())
{
fRange /= 1.8f; // zoom out a little extra when in a plane (bug 1121704)
}
if ( (!bGetTrueRange) && (fwTimer::GetTimeInMilliseconds() <= iMiniMapDpadZoomTimer+TIME_TO_ZOOM_OUT_MINIMAP) )
{
if (IsPlayerInPlaneOrHelicopter())
{
fRange /= sm_Tunables.Camera.fRangeZoomedScalarPlane;
}
else
{
fRange /= sm_Tunables.Camera.fRangeZoomedScalarStandard;
}
}
#if !__FINAL
if (camInterface::GetDebugDirector().IsFreeCamActive() BANK_ONLY( DEBUG_DRAW_ONLY( && !CMiniMap_RenderThread::sm_bDrawCollisionVolumes)))
{
if (!GetIsInsideInterior())
{
fRange /= 1.8f;
}
}
#endif // __FINAL
}
else
{
if ( (ms_bBigMapFullZoom) && (!bZoomForced) )
{
fRange = rage::Max(fRange, BIGMAP_SCALE_FULL);
}
}
return fRange;
}
void CMiniMap::UpdateBitmapState( sBitmapStruct& bitmap, bool bStreamThisFrame, bool bDrawThisFrame, const char * cBitmapString)
{
switch (bitmap.iState)
{
case MM_BITMAP_NONE:
{
if (bStreamThisFrame)
{
strLocalIndex iTxdId = g_TxdStore.FindSlot(cBitmapString);
if (iTxdId != -1)
{
g_TxdStore.StreamingRequest(iTxdId, (STRFLAG_FORCE_LOAD | STRFLAG_PRIORITY_LOAD | STRFLAG_DONTDELETE));
bitmap.iTxdId = iTxdId;
bitmap.iState = MM_BITMAP_LOADING;
}
}
break;
}
case MM_BITMAP_LOADING:
{
if (uiVerifyf(bitmap.iTxdId != -1, "txd id is -1"))
{
if (g_TxdStore.HasObjectLoaded(bitmap.iTxdId))
{
g_TxdStore.AddRef(bitmap.iTxdId, REF_OTHER);
g_TxdStore.ClearRequiredFlag(bitmap.iTxdId.Get(), STRFLAG_DONTDELETE);
bitmap.iState = MM_BITMAP_ATTACH;
}
}
break;
}
case MM_BITMAP_ACTIVE:
{
if (!bStreamThisFrame)
{
bitmap.iState = MM_BITMAP_DETACH;
}
break;
}
case MM_BITMAP_SHUTDOWN:
{
strLocalIndex iTxdId = bitmap.iTxdId;
if ( iTxdId != -1)
{
g_TxdStore.AddRef(iTxdId, REF_RENDER); // Make sure the reference sticks around for a few more frames
gDrawListMgr->AddRefCountedModuleIndex(iTxdId.Get(), &g_TxdStore);
g_TxdStore.RemoveRef(iTxdId, REF_OTHER);
}
bitmap.iTxdId = -1;
bitmap.iState = MM_BITMAP_NONE;
break;
}
case MM_BITMAP_ATTACH:
{
bitmap.iState = MM_BITMAP_ACTIVE;
break;
}
case MM_BITMAP_DETACH:
{
bitmap.iState = MM_BITMAP_SHUTDOWN;
break;
}
default:
{
// sweet F.A.
break;
}
}
if (bDrawThisFrame && (bitmap.iState == MM_BITMAP_ACTIVE ||
bitmap.iState == MM_BITMAP_ATTACH))
{
bitmap.iDrawIdx.GetWriteBuf() = bitmap.iTxdId.Get();
}
else
{
bitmap.iDrawIdx.GetWriteBuf() = -1;
}
}
/////////////////////////////////////////////////////////////////////////////////////
// __BANK - all debug stuff shown appear under here
/////////////////////////////////////////////////////////////////////////////////////
#if __BANK
void CalculateFogOfWarMinMaxXAndY()
{
u8 ignoreValue = 0;
if (bIgnoreFogOfWarValueOf255)
{
ignoreValue = 255;
}
fogOfWarMinX = FOG_OF_WAR_RT_SIZE;
fogOfWarMinY = FOG_OF_WAR_RT_SIZE;
fogOfWarMaxX = -1;
fogOfWarMaxY = -1;
u8 *FoW = CMiniMap_Common::GetFogOfWarLockPtr();
if(FoW)
{
for (s32 row = 0; row < FOG_OF_WAR_RT_SIZE; row++)
{
for (s32 column = 0; column < FOG_OF_WAR_RT_SIZE; column++)
{
if (FoW[(row*FOG_OF_WAR_RT_SIZE)+column] != ignoreValue)
{
if (column < fogOfWarMinX) { fogOfWarMinX = column; }
if (column > fogOfWarMaxX) { fogOfWarMaxX = column; }
if (row < fogOfWarMinY) { fogOfWarMinY = row; }
if (row > fogOfWarMaxY) { fogOfWarMaxY = row; }
}
}
}
}
}
/////////////////////////////////////////////////////////////////////////////////////
// NAME: CMiniMap::InitWidgets()
// PURPOSE: inits the ui bank widget and "Create" button
/////////////////////////////////////////////////////////////////////////////////////
void CMiniMap::InitWidgets()
{
bkBank *pBank = BANKMGR.FindBank(UI_DEBUG_BANK_NAME);
if (!pBank) // create the bank if not found
{
pBank = &BANKMGR.CreateBank(UI_DEBUG_BANK_NAME);
}
if (pBank)
{
pBank->AddButton("Create MiniMap widgets", &CreateBankWidgets);
}
}
/////////////////////////////////////////////////////////////////////////////////////
// NAME: CMiniMap::CreateBankWidgets()
// PURPOSE: creates the bank widget
/////////////////////////////////////////////////////////////////////////////////////
void CMiniMap::CreateBankWidgets()
{
static bool bBankCreated = false;
bkBank *bank = BANKMGR.FindBank(UI_DEBUG_BANK_NAME);
if ((!bBankCreated) && (bank))
{
bank->PushGroup("MiniMap");
bank->AddButton("Set Bigmap Active", &SetBigMapActiveDebug);
//bank->AddToggle("Bigmap Full Zoom", &ms_bBigMapFullZoom);
bank->AddButton("Reload XML", &ReloadXmlData);
bank->AddButton("Flash Minimap", datCallback(CFA1(CMiniMap::FlashMiniMapDisplay), reinterpret_cast<CallbackData>(HUD_COLOUR_WHITE) ) );
bank->AddToggle("Display Masks (requires toggling map view)", &CMiniMap_RenderThread::sm_bDebugMaskDisplay);
bank->AddSlider("Mask Display Alpha", &CMiniMap_RenderThread::sm_uDebugMaskAlpha, 0, 100, 5);
bank->AddSeparator();
bank->AddSlider("Multihead Feather Pct", &CMiniMap_RenderThread::sm_fMultiheadEdgeFeatherPct, 0.f, 1.0f, 0.001f);
bank->AddToggle("Draw map sizes (not all drawn are used)", &s_bRenderMapPositions);
for (s32 i = 0; i < MAX_MINIMAP_VALUES; i++)
{
bank->PushGroup(strupr(sm_miniMaps[i].m_fileName));
bank->AddTitle("'L'=left, 'R'=right, 'C'=center or 'I'=ignore");
bank->AddText("AlignX", (char*)&sm_miniMaps[i].m_alignX, 2);
bank->AddTitle("'T'=top, 'B'=bottom, 'C'=center or 'I'=ignore");
bank->AddText("AlignY", (char*)&sm_miniMaps[i].m_alignY, 2);
bank->AddSlider("Position", &sm_miniMaps[i].m_position, -1.0f, 1.0f, 0.001f, &UpdateMiniMapDebug);
bank->AddSlider("Size", &sm_miniMaps[i].m_size, 0.0f, 1.0f, 0.001f, &UpdateMiniMapDebug);
bank->PopGroup();
}
bank->AddSeparator();
bank->PushGroup("Waypoints");
bank->AddToggle("Entity Waypoint Allowed", &ms_bEntityWaypointAllowed);
bank->AddToggle("GPS_FLAG_IGNORE_ONE_WAY", &ms_waypointGpsFlags, GPS_FLAG_IGNORE_ONE_WAY);
bank->AddToggle("GPS_FLAG_FOLLOW_RULES", &ms_waypointGpsFlags, GPS_FLAG_FOLLOW_RULES);
bank->AddToggle("GPS_FLAG_AVOID_HIGHWAY", &ms_waypointGpsFlags, GPS_FLAG_AVOID_HIGHWAY);
bank->AddToggle("GPS_FLAG_NO_ROUTE_SHIFT", &ms_waypointGpsFlags, GPS_FLAG_NO_ROUTE_SHIFT);
bank->AddToggle("GPS_FLAG_NO_PULL_PATH_TO_RIGHT_LANE", &ms_waypointGpsFlags, GPS_FLAG_NO_PULL_PATH_TO_RIGHT_LANE);
bank->AddToggle("GPS_FLAG_AVOID_OFF_ROAD", &ms_waypointGpsFlags, GPS_FLAG_AVOID_OFF_ROAD);
bank->AddToggle("GPS_FLAG_IGNORE_DESTINATION_Z", &ms_waypointGpsFlags, GPS_FLAG_IGNORE_DESTINATION_Z);
bank->PopGroup();
bank->AddSeparator();
bank->PushGroup("Pause Map");
{
bank->AddSlider("Pause Menu Map Scale", &ms_fPauseMenuMapScale, 0, 10000.0, 2.0f);
bank->AddSlider("Pause Menu Cursor", &ms_vPauseMenuMapCursor, -10000.0f, 10000.0, 50.0f);
}
bank->PopGroup();
bank->AddButton("Create/Remove Debug Blip", &CreateRemoveDebugBlip);
bank->AddToggle("CullDistant Blips", &ms_bCullDistantBlips);
bank->AddToggle("Display Blip Vector Map", &ms_bShowBlipVectorMap);
bank->AddSlider("MiniMap Zoom Forced Percentage", &CScriptHud::ms_fMiniMapForcedZoomPercentage, -100.0f, 100.0f, 0.01f);
bank->AddSlider("MiniMap Distance Zoom", &s_fRadarZoomDistanceThisFrameWidget, 0.0f, 5000.0f, 1.0f);
bank->AddToggle("Zoom To Active Waypoint Blip", &s_bZoomToWaypointBlip);
bank->AddSlider("Tilt adjuster", &fDebugTiltValue, -1.0f, 140.0f, 1.0f);
bank->AddSlider("Offset adjuster", &fDebugOffsetValue, -1.0f, 300.0f, 5.0f);
bank->AddSlider("Debug Minimap Zoom", &ms_fDebugRange, 2.0f, 500.0f, 0.001f);
bank->AddSlider("Script Minimap Zoom", &CScriptHud::ms_iRadarZoomValue, 0, MAX_SCRIPT_SCALE_AMOUNT_BIGMAP, 1);
bank->AddToggle("Output current interior info to log", &bDisplayInteriorInfoToLog);
bank->AddSlider("Select Interior", &ms_iDebugInteriorHash, -MAX_INT32, MAX_INT32, 1);
bank->AddSlider("Select Interior Level", &ms_iDebugInteriorLevel, sMiniMapInterior::INVALID_LEVEL, 50, 1);
bank->AddSlider("Debug Golf Course", &ms_iDebugGolfCourseMap, -1, 10, 1);
bank->AddToggle("Always Draw Sonar Blips", &bDebugAlwaysDrawSonarBlips);
bank->AddToggle("Debug visibility of Sonar Blips", &bDebugVisibilityOfSonarBlips);
bank->AddToggle("Debug draw ped range for sonar blips", &bDebugDrawSonarBlipRange);
bank->AddToggle("Use weapon range for MP weapon sonar", &CMiniMap::ms_bUseWeaponRangeForMPSonarDistance);
bank->AddSeparator();
bank->AddToggle("Render Background Movie", &ms_bRenderMiniMapBackground);
bank->AddToggle("Render Foreground Movie", &ms_bRenderMiniMapForeground);
bank->AddToggle("Use Textured Alpha On All Movies", &CMiniMap_RenderThread::ms_bUseTexturedAlphaAllMovies);
bank->AddToggle("Use Textured Alpha On Background Movie", &CMiniMap_RenderThread::ms_bUseTextureAlphaBaseMovie);
bank->AddSeparator();
bank->AddSlider("Locked MiniMap Pos", &ms_vLockedMiniMapPosition, -9999.0f, 9999.0f, 1.0f);
bank->AddSlider("Locked MiniMap Angle", &ms_iLockedMiniMapAngle, -1, 360, 1);
bank->AddSeparator();
bank->PushGroup("Altimeter");
{
bank->AddToggle("New Awesome Mode", &ms_bUseNewAwesomeAltimeter);
bank->AddSlider("Script: Fake Ceiling", &CScriptHud::fFakeMinimapAltimeterHeight, -1000.0f, 2000.0f, 5.0f);
bank->AddToggle("Script: Use Colour", &CScriptHud::ms_bColourMinimapAltimeter);
bank->AddSlider("Altimeter Tick Movie Height", &ALTIMETER_TICK_PIXEL_HEIGHT, -1000.0f, 1000.0f, 1.0f);
bank->AddSlider("Altimeter Ground Level", &ALTIMETER_GROUND_LEVEL_FUDGE_FACTOR, -1000.0f, 1000.0f, 0.5f);
bank->AddSlider("Height Map Wiggle Room", &ALTIMETER_HEIGHTMAP_WIGGLE_ROOM, -100.0f, 100.0f, 5.0f);
bank->PopGroup();
}
bank->AddSeparator();
bank->AddToggle("Hide Background Map", &ms_bHideBackgroundMap);
bank->AddToggle("Block waypoint", &ms_bBlockWaypoint);
bank->AddToggle("Prologue Map", &ms_bInPrologue);
bank->AddToggle("Island X Map", &ms_bOnIslandMap);
// bank->AddToggle("Debug 3D Blips", &bDebug3DBlips);
bank->AddSeparator();
bank->AddToggle("No UI AA on Minimap", &noUIAA);
bank->AddToggle("No UI AA on Bitmap Minimap", &noUIAAOnBitMap);
bank->AddSeparator();
bank->AddSlider("Tiles MiniMap", &s_fDebugForceTilesAroundPlayer, -2.0f, 1000.0f, 1.0f);
bank->AddSlider("Tiles PauseMap", &s_vDebugForceTilesAroundPlayer, -1.0f, 1000.0f, 1.0f);
bank->AddToggle("Debug draw tiles", &ms_bDebugDrawTiles);
bank->AddToggle("Debug draw area/radius blip debug volumes", &CMiniMap_RenderThread::sm_bDrawCollisionVolumes);
bank->AddSeparator();
// bank->AddSlider("Square Limit Range", &vMax2dRadarDistanceSquareTest, 0.0f, 1.0f, 0.001f);
bank->AddToggle("Old Stealth Mode", &ms_bInStealthMode);
bank->AddSlider("Sonar Style", &iDebugSonarStyle, 0, MAX_SONAR_STYLES, 1);
bank->AddToggle("All ped blips as stealth blips", &bAllPedBlipsAsStealth, &ToggleAllPedToStealth);
bank->AddToggle("Override Cone Colour", &ms_bOverrideConeColour);
bank->AddSlider("Cone Colour Red", &ms_ConeColourRed, 0, 255, 1);
bank->AddSlider("Cone Colour Green", &ms_ConeColourGreen, 0, 255, 1);
bank->AddSlider("Cone Colour Blue", &ms_ConeColourBlue, 0, 255, 1);
bank->AddSlider("Cone Colour Alpha", &ms_ConeColourAlpha, 0, 100, 1);
bank->AddSlider("Cone Focus Range Multiplier", &ms_fConeFocusRangeMultiplier, 0.5f, 2.0f, 0.01f);
bank->AddToggle("Draw Actual Range Cone", &ms_bDrawActualRangeCone);
#if ENABLE_FOG_OF_WAR
bank->PushGroup("FoW");
{
bank->AddToggle("Display reveal ratio",&displayRevealFoWRatio);
bank->AddToggle("Test reveal Coord",&testRevealFoWCoord);
bank->AddSlider("Test reveal Coord X",&testRevealX, -10000.0f, 10000.0f, 1.0f);
bank->AddSlider("Test reveal Coord X",&testRevealY, -10000.0f, 10000.0f, 1.0f);
bank->AddToggle("Reveal Map",&ms_bRequestRevealFoW);
bank->AddToggle("Debug Draw Fog Of War Map", &DebugDrawFOW);
bank->AddSlider("Debug Draw X1", &DebugFOWX1, 0.0f, 1.0f, 0.1f);
bank->AddSlider("Debug Draw Y1", &DebugFOWY1, 0.0f, 1.0f, 0.1f);
bank->AddSlider("Debug Draw X2", &DebugFOWX2, 0.0f, 1.0f, 0.1f);
bank->AddSlider("Debug Draw Y2", &DebugFOWY2, 0.0f, 1.0f, 0.1f);
bank->AddButton("Calculate Fog of War Min/Max X/Y", CalculateFogOfWarMinMaxXAndY);
bank->AddToggle("Ignore FoW value of 255", &bIgnoreFogOfWarValueOf255);
bank->AddText("fogOfWarMinX",&fogOfWarMinX,true);
bank->AddText("fogOfWarMinY",&fogOfWarMinY,true);
bank->AddText("fogOfWarMaxX",&fogOfWarMaxX,true);
bank->AddText("fogOfWarMaxY",&fogOfWarMaxY,true);
}
CMiniMap_Common::CreateWidgets(bank);
bank->PopGroup();
#endif // ENABLE_FOG_OF_WAR
bank->PopGroup();
bBankCreated = true;
}
}
/////////////////////////////////////////////////////////////////////////////////////
// NAME: CMiniMap::ShutdownWidgets()
// PURPOSE: removes the bank widget
/////////////////////////////////////////////////////////////////////////////////////
void CMiniMap::ShutdownWidgets()
{
bkBank *pBank = BANKMGR.FindBank(UI_DEBUG_BANK_NAME);
if (pBank)
{
pBank->Destroy();
}
}
void CMiniMap::SetBigMapActiveDebug()
{
// revised this debug to match script command (CommandSetBigMapActive)
bool bActive = !CMiniMap::WasInBigMap();
if (sMiniMapMenuComponent.IsActive() ||
SocialClubMenu::IsActive() ||
cStoreScreenMgr::IsStoreMenuOpen())
{
return;
}
if (bActive)
{
if (!CMiniMap::IsInBigMap())
{
if (!CMiniMap::IsInPauseMap())
{
CMiniMap::SetMinimapModeState(MINIMAP_MODE_STATE_SETUP_FOR_BIGMAP);
}
}
CMiniMap::SetBigMapFullZoom(false);
}
else
{
if (CMiniMap::WasInBigMap()) // want to check it regardless of whether in the pausemenu or not
{
if (!CPauseMenu::IsActive())
{
CMiniMap::SetMinimapModeState(MINIMAP_MODE_STATE_SETUP_FOR_MINIMAP);
}
}
}
};
void CMiniMap::CreateRemoveDebugBlip()
{
if (ms_iDebugBlip == INVALID_BLIP_ID)
{
ms_iDebugBlip = CMiniMap::CreateBlip(true, BLIP_TYPE_COORDS, Vector3(10,10, 10), BLIP_DISPLAY_BOTH, "test debug blip");
SetBlipParameter(BLIP_CHANGE_OBJECT_NAME, ms_iDebugBlip, BLIP_POLICE_PLANE_MOVE);
SetBlipParameter(BLIP_CHANGE_NAME_FROM_ASCII, ms_iDebugBlip, "FKNG_DEBUG_BLIP");
}
else
{
CMiniMapBlip *pBlip = CMiniMap::GetBlip(ms_iDebugBlip);
if (pBlip)
{
RemoveBlip(pBlip);
ms_iDebugBlip = INVALID_BLIP_ID;
}
}
}
/////////////////////////////////////////////////////////////////////////////////////
// NAME: CMiniMap::ReloadXmlData()
// PURPOSE: reloads the xml and updates the values so we see the changes instantly
// in game
/////////////////////////////////////////////////////////////////////////////////////
void CMiniMap::ReloadXmlData()
{
LoadXmlData(true);
UpdateMiniMapDebug();
}
void CMiniMap::UpdateMiniMapDebug()
{
// decide in what we set the new changes:
if (IsInPauseMap())
{
SetMinimapModeState(MINIMAP_MODE_STATE_SETUP_FOR_PAUSEMAP);
}
else if (IsInCustomMap())
{
SetMinimapModeState( MINIMAP_MODE_STATE_SETUP_FOR_CUSTOMMAP);
}
else if (IsInBigMap())
{
SetMinimapModeState(MINIMAP_MODE_STATE_SETUP_FOR_BIGMAP);
}
else if (IsInGolfMap())
{
SetMinimapModeState(MINIMAP_MODE_STATE_SETUP_FOR_GOLFMAP);
}
else
{
SetMinimapModeState(MINIMAP_MODE_STATE_SETUP_FOR_MINIMAP);
}
}
/////////////////////////////////////////////////////////////////////////////////////
// NAME: CMiniMap::ToggleAllPedToStealth()
// PURPOSE: debug function to toggle all normal ped blips into stealth blips
/////////////////////////////////////////////////////////////////////////////////////
void CMiniMap::ToggleAllPedToStealth()
{
if (!ms_bXmlDataHasBeenRead)
{
uiAssertf(0, "Graeme - CMiniMap::ToggleAllPedToStealth has been called before MiniMap has been fully initialised");
return;
}
for (s32 iIndex = 0; iIndex < iMaxCreatedBlips; iIndex++)
{
if (iIndex == iSimpleBlip)
continue;
CMiniMapBlip *pBlip = GetBlipFromActualId(iIndex);
if (!pBlip)
continue;
if (bAllPedBlipsAsStealth)
{
if (GetBlipTypeValue(pBlip) == BLIP_TYPE_CHAR)
{
SetBlipTypeValue(pBlip, BLIP_TYPE_STEALTH);
}
}
else
{
if (GetBlipTypeValue(pBlip) == BLIP_TYPE_STEALTH)
{
SetBlipTypeValue(pBlip, BLIP_TYPE_CHAR);
}
}
}
if (bAllPedBlipsAsStealth)
{
uiDisplayf("MiniMap: ALL PED BLIPS ARE NOW STEALTH BLIPS");
}
else
{
uiDisplayf("MiniMap: ALL STEALTH BLIPS ARE NOW PED BLIPS");
}
}
/////////////////////////////////////////////////////////////////////////////////////
// NAME: CMiniMap::ModifyLabelsToAllActiveBlips()
// PURPOSE: switches on/off labels for all active blips
/////////////////////////////////////////////////////////////////////////////////////
void CMiniMap::ModifyLabelsToAllActiveBlips(bool bSwitchOn, bool bDebugNumbersOnly)
{
for (s32 iId = 0; iId < iMaxCreatedBlips; iId++)
{
if (iId == iSimpleBlip)
continue;
CMiniMapBlip *pBlip = GetBlipFromActualId(iId);
if (!pBlip)
continue;
if ( (bDebugNumbersOnly) && (CMiniMap::GetBlipDebugNumberValue(pBlip) == -1) )
{
continue;
}
if (bSwitchOn)
SetFlag(pBlip, BLIP_FLAG_VALUE_SET_LABEL); // on
else
SetFlag(pBlip, BLIP_FLAG_VALUE_REMOVE_LABEL); // off
}
}
#endif // __BANK
// eof