3222 lines
103 KiB
C++
3222 lines
103 KiB
C++
/////////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// FILE : CMapMenu.cpp
|
|
// PURPOSE : code to control the pausemap in the pausemenu
|
|
// AUTHOR : Derek Payne
|
|
// STARTED : 24/10/2012
|
|
//
|
|
/////////////////////////////////////////////////////////////////////////////////
|
|
|
|
#include "Frontend/CMapMenu.h"
|
|
#include "audio/frontendaudioentity.h"
|
|
#include "camera/viewports/ViewportManager.h"
|
|
#include "event/EventGroup.h"
|
|
#include "event/EventNetwork.h"
|
|
#include "frontend/ButtonEnum.h"
|
|
#include "frontend/FrontendStatsMgr.h" // for checking whether we need metric measurements or not
|
|
#include "frontend/MapZoomData_parser.h"
|
|
#include "frontend/MiniMap.h"
|
|
#include "frontend/MiniMapRenderThread.h"
|
|
#include "frontend/PauseMenu.h"
|
|
#include "frontend/ScaleformMenuHelper.h"
|
|
#include "frontend/ui_channel.h"
|
|
#include "frontend/Map/BlipEnums.h"
|
|
#include "frontend/MousePointer.h"
|
|
#include "Game/User.h"
|
|
#include "Game/Wanted.h"
|
|
#include "Renderer/sprite2d.h"
|
|
#include "scene/streamer/SceneStreamer.h"
|
|
#include "scene/streamer/SceneStreamerMgr.h"
|
|
#include "scene/world/GameWorld.h"
|
|
#include "scene/world/GameWorldHeightMap.h"
|
|
#include "scene/WarpManager.h"
|
|
#include "script/script_hud.h"
|
|
#include "Stats/StatsTypes.h"
|
|
#include "text/TextConversion.h"
|
|
#include "text/TextFile.h"
|
|
#include "System/controlMgr.h"
|
|
#include "Scaleform/tweenstar.h"
|
|
#include "control/gps.h"
|
|
|
|
|
|
// dev
|
|
#if !__FINAL
|
|
#include "audio/northaudioengine.h"
|
|
#include "physics/physics.h"
|
|
#include "system/bootmgr.h"
|
|
#endif
|
|
|
|
FRONTEND_OPTIMISATIONS()
|
|
|
|
#define INVALID_ACTUAL_ID -1
|
|
|
|
//
|
|
// extremes of the pausemap movement
|
|
//
|
|
#define MAP_LIMIT_WEST (-3747.0f) // added an extra 300m onto this for 1443279
|
|
#define MAP_LIMIT_EAST (4500.0f)
|
|
#define MAP_LIMIT_NORTH (8022.0f)
|
|
#define MAP_LIMIT_SOUTH (-4400.0f)
|
|
|
|
#define MAP_LIMIT_WEST_PROLOGUE (1935.0f)
|
|
#define MAP_LIMIT_EAST_PROLOGUE (7850.0f)
|
|
#define MAP_LIMIT_NORTH_PROLOGUE (-3561.0f)
|
|
#define MAP_LIMIT_SOUTH_PROLOGUE (-5295.0f)
|
|
|
|
#define MAP_LIMIT_WEST_ISLAND (3400.0f)
|
|
#define MAP_LIMIT_EAST_ISLAND (5750.0f)
|
|
#define MAP_LIMIT_NORTH_ISLAND (-4100.0f)
|
|
#define MAP_LIMIT_SOUTH_ISLAND (-6200.0f)
|
|
|
|
#define MAX_NUMBER_OF_LEGEND_ITEMS (100)
|
|
|
|
atArray<sMapLegendList> CMapMenu::sm_LegendList;
|
|
s32 CMapMenu::sm_iPreviousHoverActualId = INVALID_ACTUAL_ID;
|
|
s32 CMapMenu::sm_iCurrentSelectedMissionCreatorUniqueId = INVALID_BLIP_ID;
|
|
bool CMapMenu::sm_bCanStartMission = false;
|
|
bool CMapMenu::sm_bShowStartMissionButton = false;
|
|
bool CMapMenu::sm_bCanContact = false;
|
|
bool CMapMenu::sm_bShowContactButton = false;
|
|
bool CMapMenu::sm_bUpdateLegend = false;
|
|
bool CMapMenu::sm_bHideLegend = false;
|
|
bool CMapMenu::sm_bPauseMapInInterior = false;
|
|
bool CMapMenu::sm_bPauseMapInGolf = false;
|
|
Vector2 CMapMenu::sm_vPauseMapLastZoomedPos;
|
|
Vector2 CMapMenu::sm_vPauseMapOriginalPos;
|
|
s32 CMapMenu::sm_iCurrentZoomLevel;
|
|
bool CMapMenu::sm_bCurrentlyZooming;
|
|
float CMapMenu::sm_fPrevZoomLevel = -1;
|
|
bool CMapMenu::sm_bIsRenderingMask = false;
|
|
bool CMapMenu::sm_bWasReloaded = false;
|
|
|
|
#define __INTERVAL_BETWEEN_LEGEND_UPDATES (1000)
|
|
#define __TIME_TO_WAIT_FOR_RESPONSE_TO_SCRIPT_FOR_BLIP_HOVER (1000)
|
|
u32 CMapMenu::sm_iUpdateLegendTimer;
|
|
u32 CMapMenu::sm_iMissionCreatorHoverQueryTimer;
|
|
bool CMapMenu::sm_bHasQueried = false;
|
|
Vector2 CMapMenu::sm_vPreviousCursorPos = Vector2(0,0);
|
|
|
|
#if KEYBOARD_MOUSE_SUPPORT
|
|
BankFloat CMapMenu::MOUSE_WHEEL_DECAY_RATE = 2.5f;
|
|
BankFloat CMapMenu::MOUSE_WHEEL_SCALAR = 0.75f;
|
|
BankFloat CMapMenu::MOUSE_FLICK_DECAY_RATE = 7.f;
|
|
BankFloat CMapMenu::MOUSE_ZOOM_SPEED_FAR = 10.f;
|
|
BankFloat CMapMenu::MOUSE_ZOOM_SPEED_NEAR = 100.0f;
|
|
BankFloat CMapMenu::MOUSE_DRAG_DIST_SQRD = 25.0f;
|
|
BankFloat CMapMenu::MOUSE_DRAG_SOUND_SCREEN_PIXELS_SQRD = 25.f;
|
|
BankFloat CMapMenu::MAX_SOUNDVAR_VALUE = 5.0f;
|
|
BankUInt32 CMapMenu::MOUSE_DBL_CLICK_TIME = 400;
|
|
BankInt32 CMapMenu::MAP_SNAP_PAN_SPEED = 350;
|
|
BankUInt32 MAP_FIRST_PAN_DELAY = 150;
|
|
BankUInt32 MAP_SPAM_PAN_DELAY = 250;
|
|
BankFloat MOUSE_PUSH_GUTTER_PCT = .05f;
|
|
int s_LERP_METHOD = rage::TweenStar::EASE_quadratic_EI;
|
|
|
|
|
|
bool s_bMapMovesOnWaypoint = true;
|
|
bool s_bCenterOnSingleClick = true;
|
|
|
|
PARAM(mapStaysOnWaypoints, "Whether the Pause Map moves on waypoints");
|
|
PARAM(mapCentersOnClick, "If the map centers on a single click and waypoints on a double");
|
|
|
|
#endif // KEYBOARD_MOUSE_SUPPORT
|
|
|
|
atArray<HoveredBlipUniqueId*> HoveredBlipUniqueId::sm_pAllElements;
|
|
|
|
HoveredBlipUniqueId::HoveredBlipUniqueId()
|
|
: m_iUniqueId(INVALID_BLIP_ID)
|
|
{
|
|
sm_pAllElements.PushAndGrow(this);
|
|
};
|
|
|
|
HoveredBlipUniqueId::~HoveredBlipUniqueId()
|
|
{
|
|
Reset();
|
|
sm_pAllElements.DeleteMatches(this);
|
|
}
|
|
|
|
void HoveredBlipUniqueId::Set(s32 newIndex)
|
|
{
|
|
// do nothing if it's already the same
|
|
if( newIndex == m_iUniqueId )
|
|
return;
|
|
|
|
// because multiple things may point to the same blip, check if it's safe to turn it off
|
|
if( m_iUniqueId != INVALID_BLIP_ID && IsMyBlipUniqueToMe())
|
|
{
|
|
CMiniMap::SetBlipParameter(BLIP_CHANGE_HOVERED_ON_PAUSEMAP, m_iUniqueId, false);
|
|
}
|
|
|
|
m_iUniqueId = newIndex;
|
|
|
|
if( m_iUniqueId != INVALID_BLIP_ID )
|
|
{
|
|
CMiniMap::SetBlipParameter(BLIP_CHANGE_HOVERED_ON_PAUSEMAP, m_iUniqueId, true);
|
|
}
|
|
}
|
|
|
|
void HoveredBlipUniqueId::Reset()
|
|
{
|
|
Set( INVALID_BLIP_ID );
|
|
}
|
|
|
|
bool HoveredBlipUniqueId::IsValid() const
|
|
{
|
|
return m_iUniqueId != INVALID_BLIP_ID;
|
|
}
|
|
|
|
bool HoveredBlipUniqueId::IsMyBlipUniqueToMe() const
|
|
{
|
|
for(const auto& p : sm_pAllElements)
|
|
{
|
|
if(p!=this && p->m_iUniqueId == m_iUniqueId )
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////////////
|
|
// NAME: CMapMenu::CMapMenu
|
|
// PURPOSE: init mapscreen
|
|
/////////////////////////////////////////////////////////////////////////////////////
|
|
CMapMenu::CMapMenu(CMenuScreen& owner) : CScriptMenu(owner)
|
|
, m_vBGPos(0.162f, 0.221f)
|
|
, m_vBGSize(0.677f, 0.597f)
|
|
, m_bLastClearedTitle(false)
|
|
, m_bAtLeastOneLowDetailBlip(false)
|
|
, m_bCheckFakedPauseMapPosForCursor(false)
|
|
, m_bCheckGPSPauseMapPosForCursor(false)
|
|
, m_iCurrentLegendItem(0)
|
|
, m_iCurrentLegendItemIndex(0)
|
|
#if KEYBOARD_MOUSE_SUPPORT
|
|
, m_vwrldMouseMovement(0.f, 0.f)
|
|
, m_vscrLastMousePos(0.f, 0.f)
|
|
, m_vscrMousePosOnClick(0.f, 0.f)
|
|
, m_uFirstClickTime(0u)
|
|
, m_fMouseWheelMovement(0.0f)
|
|
, m_bClickedWithoutDragging(false)
|
|
, m_bWasBlipDragging(false)
|
|
, m_iBlipClickedOnUniqueId(INVALID_BLIP_ID)
|
|
#endif
|
|
#if RSG_PC
|
|
, m_iRenderDelay(0)
|
|
#endif
|
|
#if __BANK
|
|
, m_pMyGroup(NULL)
|
|
#endif
|
|
{
|
|
#if KEYBOARD_MOUSE_SUPPORT && !__FINAL
|
|
// only set this bool once
|
|
if( PARAM_mapStaysOnWaypoints.Get() )
|
|
{
|
|
s_bMapMovesOnWaypoint = !PARAM_mapStaysOnWaypoints.Get();
|
|
PARAM_mapStaysOnWaypoints.Set(NULL);
|
|
}
|
|
|
|
// only set this bool once
|
|
if( PARAM_mapCentersOnClick.Get() )
|
|
{
|
|
s_bCenterOnSingleClick = !PARAM_mapCentersOnClick.Get();
|
|
PARAM_mapCentersOnClick.Set(NULL);
|
|
}
|
|
#endif
|
|
|
|
owner.FindDynamicData("sp_path", m_SPPath);
|
|
|
|
sm_iPreviousHoverActualId = INVALID_ACTUAL_ID;
|
|
sm_iCurrentSelectedMissionCreatorUniqueId = INVALID_BLIP_ID;
|
|
|
|
InitStartingValues();
|
|
|
|
sm_vPauseMapOriginalPos = CMiniMap::GetPauseMapCursor();
|
|
SetCursorActual(CMiniMap::GetPauseMapCursor());
|
|
|
|
if (CMiniMap::GetIsInsideInterior(true))
|
|
{
|
|
sm_bPauseMapInInterior = true;
|
|
sm_vPauseMapLastZoomedPos = CMiniMap::GetPauseMapCursor();
|
|
}
|
|
else
|
|
{
|
|
sm_bPauseMapInInterior = false;
|
|
sm_vPauseMapLastZoomedPos.Set(0,0);
|
|
}
|
|
|
|
if (CMiniMap::IsInGolfMap())
|
|
{
|
|
sm_bPauseMapInGolf = true;
|
|
sm_vPauseMapLastZoomedPos = CMiniMap::GetPauseMapCursor();
|
|
}
|
|
else
|
|
{
|
|
sm_bPauseMapInGolf = false;
|
|
sm_vPauseMapLastZoomedPos.Set(0,0);
|
|
}
|
|
|
|
InitStartingValues();
|
|
|
|
// we need the centre and north blips to be set up for pausemap as soon as the pausemap starts updating, so force through and update of
|
|
// these particular blips here
|
|
CMiniMap::UpdateCentreAndNorthBlips();
|
|
|
|
sm_iUpdateLegendTimer = fwTimer::GetSystemTimeInMilliseconds() - __INTERVAL_BETWEEN_LEGEND_UPDATES;
|
|
sm_iMissionCreatorHoverQueryTimer = fwTimer::GetSystemTimeInMilliseconds();
|
|
|
|
sm_bCurrentlyZooming = true;
|
|
}
|
|
|
|
atString& CMapMenu::GetScriptPath()
|
|
{
|
|
if(NetworkInterface::IsNetworkOpen())
|
|
return m_ScriptPath;
|
|
return m_SPPath;
|
|
}
|
|
|
|
void CMapMenu::Init()
|
|
{
|
|
CScriptMenu::Init();
|
|
|
|
CMiniMap::SetMinimapModeState(MINIMAP_MODE_STATE_SETUP_FOR_PAUSEMAP);
|
|
|
|
if(const SGeneralPauseDataConfig* pData = CPauseMenu::GetMenuArray().GeneralData.MovieSettings.Access("MinimapBG"))
|
|
{
|
|
m_vBGPos = pData->vPos;
|
|
m_vBGSize = pData->vSize;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////////////
|
|
// NAME: CMapMenu::~CMapMenu()
|
|
// PURPOSE: clears the legend
|
|
/////////////////////////////////////////////////////////////////////////////////////
|
|
CMapMenu::~CMapMenu()
|
|
{
|
|
if (sm_bCurrentlyZooming)
|
|
{
|
|
g_FrontendAudioEntity.StopSoundMapZoom();
|
|
sm_bCurrentlyZooming = false;
|
|
}
|
|
|
|
#if __BANK
|
|
if( m_pMyGroup )
|
|
m_pMyGroup->Destroy();
|
|
#endif
|
|
|
|
CMiniMap::ExitPauseMapState();
|
|
|
|
m_bCheckFakedPauseMapPosForCursor = false;
|
|
m_bCheckGPSPauseMapPosForCursor = false;
|
|
}
|
|
|
|
bool CMapMenu::IsDoneLoading() const
|
|
{
|
|
return CMiniMap::AreAllTexturesActive(CMiniMap::GetBitmapForMinimap());
|
|
}
|
|
|
|
|
|
void CMapMenu::LoseFocus()
|
|
{
|
|
uiDebugf3("CMapMenu::LoseFocus");
|
|
|
|
//@@: location AHOOK_0067_CHK_LOCATION_D
|
|
if (sm_bCurrentlyZooming)
|
|
{
|
|
g_FrontendAudioEntity.StopSoundMapZoom();
|
|
sm_bCurrentlyZooming = false;
|
|
}
|
|
EmptyLegend(false);
|
|
|
|
g_FrontendAudioEntity.StopSoundMapMovement();
|
|
g_FrontendAudioEntity.StopSoundMapZoom();
|
|
|
|
|
|
CScriptMenu::LoseFocus();
|
|
|
|
#if KEYBOARD_MOUSE_SUPPORT
|
|
CMousePointer::SetMouseCursorVisible(true);
|
|
|
|
m_fMouseWheelMovement = 0.0f;
|
|
m_vwrldMouseMovement.Zero();
|
|
m_iBlipMouseCurrentlyHoverOverUniqueId.Reset();
|
|
#endif // KEYBOARD_MOUSE_SUPPORT
|
|
|
|
CPauseMenu::ScaleContentMovie(false);
|
|
|
|
// prevent leaky blipping
|
|
m_iBlipCurrentlyHoveredOverUniqueId.Reset();
|
|
}
|
|
|
|
|
|
void CMapMenu::InitStartingValues()
|
|
{
|
|
sm_bCanStartMission = false;
|
|
sm_bShowStartMissionButton = false;
|
|
|
|
sm_bCanContact = false;
|
|
sm_bShowContactButton = false;
|
|
|
|
//
|
|
// initial positions:
|
|
//
|
|
//setup starting positions:
|
|
// But not if we're in an interior
|
|
Vector2 vFakePlayerPos;
|
|
if (!sm_bPauseMapInInterior && CScriptHud::GetFakedPauseMapPlayerPos(vFakePlayerPos))
|
|
{
|
|
CMiniMap::SetPauseMapCursor(vFakePlayerPos);
|
|
}
|
|
else
|
|
{
|
|
CPed *pLocalPlayer = CMiniMap::GetMiniMapPed();
|
|
if (uiVerifyf(pLocalPlayer, "CMiniMap::SetMinimapModeState - failed to get a pointer to the local player"))
|
|
{
|
|
Vector3 vPlayerPos = VEC3V_TO_VECTOR3(pLocalPlayer->GetTransform().GetPosition());
|
|
CMiniMap::SetPauseMapCursor(Vector2(vPlayerPos.x, vPlayerPos.y));
|
|
}
|
|
}
|
|
|
|
//
|
|
// initial zoom levels as we go into the map menu
|
|
//
|
|
if (sm_bPauseMapInInterior)
|
|
{
|
|
SetMapZoom(ZOOM_LEVEL_INTERIOR, true);
|
|
}
|
|
else if (sm_bPauseMapInGolf)
|
|
{
|
|
SetMapZoom(ZOOM_LEVEL_GOLF_COURSE, true);
|
|
}
|
|
else if (CMiniMap::GetInPrologue())
|
|
{
|
|
SetMapZoom(ZOOM_LEVEL_START_PROLOGUE, true);
|
|
}
|
|
else if (!NetworkInterface::IsGameInProgress())
|
|
{
|
|
SetMapZoom(ZOOM_LEVEL_START, true);
|
|
}
|
|
else
|
|
{
|
|
SetMapZoom(ZOOM_LEVEL_START_MP, true);
|
|
}
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////////////
|
|
// NAME: CPauseMenu::UpdateInput
|
|
// PURPOSE: updates the map screen input if navigating content
|
|
/////////////////////////////////////////////////////////////////////////////////////
|
|
bool CMapMenu::UpdateInput(s32 eInput)
|
|
{
|
|
bool bResult = false;
|
|
if (CPauseMenu::IsNavigatingContent())
|
|
{
|
|
if ( eInput == PAD_CIRCLE &&
|
|
(SUIContexts::IsActive("CORONA_BIGMAP_CLOSE") || SUIContexts::IsActive("CORONA_BIGMAP_CLOSE_KM")) )
|
|
{
|
|
// Override the map exit input while we're in full-screen race corona map
|
|
return true;
|
|
}
|
|
|
|
bResult = UpdateMapScreenInput(false, eInput);
|
|
}
|
|
else
|
|
{
|
|
UpdateZooming(0.0f, 0.0f, false);
|
|
#if KEYBOARD_MOUSE_SUPPORT
|
|
CMousePointer::SetMouseCursorVisible(true);
|
|
#endif // KEYBOARD_MOUSE_SUPPORT
|
|
}
|
|
|
|
bResult = CScriptMenu::UpdateInput(eInput) || bResult;
|
|
|
|
return bResult;
|
|
}
|
|
|
|
|
|
void CMapMenu::SetMapZoom(s32 iNewZoomLevel, bool bInstant)
|
|
{
|
|
sm_iCurrentZoomLevel = iNewZoomLevel;
|
|
|
|
if (bInstant)
|
|
{
|
|
CMiniMap::SetPauseMapScale(CMiniMap_Common::GetScaleFromZoomLevel(sm_iCurrentZoomLevel));
|
|
}
|
|
}
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////////////
|
|
// NAME: CPauseMenu::GetCurrentSelectedMissionCreatorBlip
|
|
// PURPOSE: returns and resets the script flag
|
|
/////////////////////////////////////////////////////////////////////////////////////
|
|
s32 CMapMenu::GetCurrentSelectedMissionCreatorBlip()
|
|
{
|
|
s32 iReturnValue = INVALID_BLIP_ID;
|
|
|
|
if (sm_iCurrentSelectedMissionCreatorUniqueId != INVALID_BLIP_ID)
|
|
{
|
|
if (sm_bHasQueried)
|
|
{
|
|
if (fwTimer::GetSystemTimeInMilliseconds() > sm_iMissionCreatorHoverQueryTimer + __TIME_TO_WAIT_FOR_RESPONSE_TO_SCRIPT_FOR_BLIP_HOVER)
|
|
{
|
|
sm_iMissionCreatorHoverQueryTimer = fwTimer::GetSystemTimeInMilliseconds();
|
|
iReturnValue = sm_iCurrentSelectedMissionCreatorUniqueId;
|
|
sm_iCurrentSelectedMissionCreatorUniqueId = INVALID_BLIP_ID;
|
|
|
|
//ResetCornerBlipInfo(true);
|
|
sm_bHasQueried = false;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (sm_iMissionCreatorHoverQueryTimer != 0)
|
|
{
|
|
sm_iMissionCreatorHoverQueryTimer = fwTimer::GetSystemTimeInMilliseconds(); // start timer on 1st check
|
|
}
|
|
else
|
|
{
|
|
sm_iMissionCreatorHoverQueryTimer = (fwTimer::GetSystemTimeInMilliseconds() - (s32)(floor(__TIME_TO_WAIT_FOR_RESPONSE_TO_SCRIPT_FOR_BLIP_HOVER * 0.5f)));
|
|
}
|
|
|
|
sm_bHasQueried = true;
|
|
}
|
|
}
|
|
|
|
return iReturnValue;
|
|
}
|
|
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////////////
|
|
// NAME: CPauseMenu::UpdateZooming
|
|
// PURPOSE: updates the zoom to the required level. Needs to be called outside
|
|
// navigating content to allow the map to finish its zoom if the user
|
|
// backs out mid-zoom
|
|
/////////////////////////////////////////////////////////////////////////////////////
|
|
void CMapMenu::UpdateZooming(float fLeftShoulder, float fRightShoulder, bool bInitialEntry)
|
|
{
|
|
bool bUpdateZoomDisplay = false;
|
|
|
|
if (!(fRightShoulder > 0.0f && fLeftShoulder > 0.0f) && (sm_bCurrentlyZooming || fLeftShoulder > 0.0f || fRightShoulder > 0.0f))
|
|
{
|
|
if ( (!sm_bCurrentlyZooming) && (!sm_bPauseMapInInterior) && (!sm_bPauseMapInGolf) )
|
|
{
|
|
g_FrontendAudioEntity.PlaySoundMapZoom();
|
|
|
|
sm_bCurrentlyZooming = true;
|
|
}
|
|
|
|
bUpdateZoomDisplay = (fLeftShoulder > 0.0f || fRightShoulder > 0.0f);
|
|
|
|
if (fRightShoulder > 0.0f && CMiniMap::GetPauseMapScale() < CMiniMap_Common::GetScaleFromZoomLevel(sm_iCurrentZoomLevel))
|
|
{
|
|
s32 iZoomLevelToUse = sm_iCurrentZoomLevel-1;
|
|
|
|
s32 iMaxZoomLevel = MAX_ZOOMED_OUT;
|
|
|
|
if (CMiniMap::GetInPrologue())
|
|
{
|
|
iMaxZoomLevel = MAX_ZOOMED_OUT_PROLOGUE;
|
|
}
|
|
|
|
if (iZoomLevelToUse < iMaxZoomLevel)
|
|
{
|
|
iZoomLevelToUse = iMaxZoomLevel;
|
|
}
|
|
#if RSG_PC || RDR_VERSION
|
|
// on PC, we'll just use these more properly tuned, better-feeling values
|
|
float fPercentZoomed = Range(CMiniMap::GetPauseMapScale(), CMiniMap_Common::GetScaleFromZoomLevel(MAX_ZOOMED_OUT), CMiniMap_Common::GetScaleFromZoomLevel(MAX_ZOOMED_IN) );
|
|
float fScaleIncrease = fRightShoulder * Lerp(SlowOut(fPercentZoomed), MOUSE_ZOOM_SPEED_FAR, MOUSE_ZOOM_SPEED_NEAR) * fwTimer::GetTimeStep_NonPausedNonScaledClipped();
|
|
#else
|
|
float fScaleIncrease = CMiniMap_Common::GetZoomSpeedFromZoomLevel(iZoomLevelToUse, fRightShoulder);
|
|
#endif
|
|
|
|
CMiniMap::SetPauseMapScale(CMiniMap::GetPauseMapScale() + fScaleIncrease);
|
|
|
|
if ((sm_iCurrentZoomLevel == MAX_ZOOMED_IN && CMiniMap::GetPauseMapScale() > CMiniMap_Common::GetScaleFromZoomLevel(sm_iCurrentZoomLevel)) || fRightShoulder > 1.0f)
|
|
{
|
|
CMiniMap::SetPauseMapScale(CMiniMap_Common::GetScaleFromZoomLevel(sm_iCurrentZoomLevel));
|
|
if(fRightShoulder > 1.0f)
|
|
{
|
|
bUpdateZoomDisplay = false;
|
|
}
|
|
}
|
|
}
|
|
else if (fLeftShoulder > 0.0f && CMiniMap::GetPauseMapScale() > CMiniMap_Common::GetScaleFromZoomLevel(sm_iCurrentZoomLevel))
|
|
{
|
|
s32 iZoomLevelToUse = sm_iCurrentZoomLevel+1;
|
|
|
|
if (iZoomLevelToUse > MAX_ZOOMED_IN)
|
|
{
|
|
iZoomLevelToUse = MAX_ZOOMED_IN;
|
|
}
|
|
|
|
#if RSG_PC || RDR_VERSION
|
|
// on PC, we'll just use these more properly tuned, better-feeling values
|
|
float fPercentZoomed = Range(CMiniMap::GetPauseMapScale(), CMiniMap_Common::GetScaleFromZoomLevel(MAX_ZOOMED_OUT), CMiniMap_Common::GetScaleFromZoomLevel(MAX_ZOOMED_IN) );
|
|
float fScaleDecrease = fLeftShoulder * Lerp(SlowOut(fPercentZoomed), MOUSE_ZOOM_SPEED_FAR, MOUSE_ZOOM_SPEED_NEAR) * fwTimer::GetTimeStep_NonPausedNonScaledClipped();
|
|
#else
|
|
float fScaleDecrease = CMiniMap_Common::GetZoomSpeedFromZoomLevel(iZoomLevelToUse, fLeftShoulder);
|
|
#endif
|
|
|
|
CMiniMap::SetPauseMapScale(CMiniMap::GetPauseMapScale() - fScaleDecrease);
|
|
|
|
if ((sm_iCurrentZoomLevel == MAX_ZOOMED_OUT && CMiniMap::GetPauseMapScale() < CMiniMap_Common::GetScaleFromZoomLevel(sm_iCurrentZoomLevel)) || fLeftShoulder > 1.0f)
|
|
{
|
|
CMiniMap::SetPauseMapScale(CMiniMap_Common::GetScaleFromZoomLevel(sm_iCurrentZoomLevel));
|
|
if(fLeftShoulder > 1.0f)
|
|
{
|
|
bUpdateZoomDisplay = false;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
sm_bCurrentlyZooming = false;
|
|
}
|
|
}
|
|
|
|
if (bUpdateZoomDisplay || bInitialEntry)
|
|
{
|
|
if (CPauseMenu::IsNavigatingContent())
|
|
{
|
|
const float scaleMeterSize = 2750.0f;
|
|
float fFinalZoomValue = scaleMeterSize/CMiniMap::GetPauseMapScale();
|
|
if(fFinalZoomValue != sm_fPrevZoomLevel || bInitialEntry)
|
|
{
|
|
char cZoomString[32];
|
|
|
|
if (CFrontendStatsMgr::ShouldUseMetric()) // the conversion is already done at entry of menu
|
|
{
|
|
formatf(cZoomString, "%0.0fm", fFinalZoomValue);
|
|
}
|
|
else
|
|
{
|
|
formatf(cZoomString, "%0.0fft", METERS_TO_FEET(fFinalZoomValue));
|
|
}
|
|
|
|
// comment out the line below to debug the scale values!
|
|
// formatf(cZoomString, "%0.0fm (%0.2f %0.2f)", fFinalZoomValue, fCurrentScaleValue, CMiniMap::GetPauseMapScale(), NELEM(cZoomString));
|
|
|
|
CPauseMenu::GetMovieWrapper(PAUSE_MENU_MOVIE_CONTENT).CallMethod( "SET_DESCRIPTION", 0,0, cZoomString);
|
|
|
|
sm_fPrevZoomLevel = fFinalZoomValue;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!sm_bCurrentlyZooming)
|
|
{
|
|
g_FrontendAudioEntity.StopSoundMapZoom();
|
|
}
|
|
}
|
|
|
|
|
|
void CMapMenu::DisplayAreaName(bool bForceUpdate)
|
|
{
|
|
if ((sm_bPauseMapInInterior) || (sm_bPauseMapInGolf) || CMiniMap::GetInPrologue())
|
|
{
|
|
if( !m_bLastClearedTitle )
|
|
CScaleformMenuHelper::SET_COLUMN_TITLE(PM_COLUMN_LEFT, "");
|
|
m_bLastClearedTitle = true;
|
|
}
|
|
else
|
|
{
|
|
m_bLastClearedTitle = false;
|
|
if (bForceUpdate || CUserDisplay::AreaName.IsNewName() || CUserDisplay::StreetName.IsNewName())
|
|
{
|
|
char GxtLocationName[MAX_ZONE_NAME_CHARS * 3];
|
|
|
|
char const *pStreetName = &CUserDisplay::StreetName.GetForMap(CMiniMap::GetPauseMapCursor().x, CMiniMap::GetPauseMapCursor().y)[0];
|
|
|
|
if (pStreetName[0] != '\0')
|
|
{
|
|
formatf(GxtLocationName, "%s / %s", &CUserDisplay::AreaName.GetForMap(CMiniMap::GetPauseMapCursor().x, CMiniMap::GetPauseMapCursor().y)[0], pStreetName, NELEM(GxtLocationName));
|
|
}
|
|
else
|
|
{
|
|
const Vector2 c_vMapCursor(CMiniMap::GetPauseMapCursor().x, CMiniMap::GetPauseMapCursor().y);
|
|
const bool c_bCursorInIslandLocation = c_vMapCursor.x >= MAP_LIMIT_WEST_ISLAND || c_vMapCursor.y <= MAP_LIMIT_NORTH_ISLAND;
|
|
const bool c_bIsOnIsland = CMiniMap::GetIsOnIslandMap();
|
|
|
|
if(!c_bCursorInIslandLocation || c_bIsOnIsland)
|
|
{
|
|
formatf(GxtLocationName, "%s", &CUserDisplay::AreaName.GetForMap(CMiniMap::GetPauseMapCursor().x, CMiniMap::GetPauseMapCursor().y)[0], NELEM(GxtLocationName));
|
|
}
|
|
else
|
|
{
|
|
formatf(GxtLocationName, "%s", TheText.Get("Oceana"));
|
|
}
|
|
}
|
|
|
|
CScaleformMenuHelper::SET_COLUMN_TITLE(PM_COLUMN_LEFT, GxtLocationName);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////////////
|
|
// NAME: CPauseMenu::UpdateMapScreenInput
|
|
// PURPOSE: updates the map screen input
|
|
/////////////////////////////////////////////////////////////////////////////////////
|
|
bool CMapMenu::UpdateMapScreenInput(bool bInitialEntry, s32 eInput /* = PAD_NO_BUTTON_PRESSED */)
|
|
{
|
|
#define __STICK_THRESHOLD (0.1f)
|
|
|
|
bool bScaleChanged = bInitialEntry;
|
|
float fMapCrosshairMultiplier = 0.0f;
|
|
bool bChangeZoomStyle = false;
|
|
|
|
|
|
if( eInput == PAD_R3 )
|
|
{
|
|
if( SUIContexts::IsActive("MAP_VisHigh") || SUIContexts::IsActive("MAP_VisLow") )
|
|
{
|
|
// toggle it as we press the button:
|
|
CMiniMap::SetBlipVisibilityHighDetail(!CMiniMap::GetBlipVisibilityHighDetail());
|
|
|
|
g_FrontendAudioEntity.PlaySound("SELECT","HUD_FRONTEND_DEFAULT_SOUNDSET"); // fix for 1877020
|
|
|
|
uiDebugf1("Updating pausemap legend because player toggled HIGH/LOW detail");
|
|
|
|
CPauseMenu::UpdatePauseMapLegend();
|
|
|
|
CPauseMenu::RedrawInstructionalButtons(MENU_UNIQUE_ID_MAP);
|
|
return true;
|
|
}
|
|
}
|
|
|
|
if (!sm_bPauseMapInInterior && !sm_bPauseMapInGolf)
|
|
{
|
|
if (CPauseMenu::CheckInput(FRONTEND_INPUT_SELECT, false, CHECK_INPUT_OVERRIDE_FLAG_STORAGE_DEVICE)) // RB / R1
|
|
{
|
|
bChangeZoomStyle = true;
|
|
|
|
if (CMiniMap::GetIsInsideInterior(true))
|
|
{
|
|
SetCursorActual(sm_vPauseMapLastZoomedPos);
|
|
ResetCornerBlipInfo(false, false);
|
|
SetMapZoom(ZOOM_LEVEL_INTERIOR, true);
|
|
|
|
sm_bPauseMapInInterior = true;
|
|
bScaleChanged = true;
|
|
|
|
CPauseMenu::PlaySound("TOGGLE_ON");
|
|
}
|
|
|
|
if (CMiniMap::IsInGolfMap())
|
|
{
|
|
SetCursorActual(sm_vPauseMapLastZoomedPos);
|
|
ResetCornerBlipInfo(false, false);
|
|
SetMapZoom(ZOOM_LEVEL_GOLF_COURSE, true);
|
|
|
|
sm_bPauseMapInGolf = true;
|
|
bScaleChanged = true;
|
|
|
|
CPauseMenu::PlaySound("TOGGLE_ON");
|
|
}
|
|
|
|
CPauseMenu::RedrawInstructionalButtons(MENU_UNIQUE_ID_MAP); // repopulate any instructional buttons
|
|
UpdatePauseMapLegend(true);
|
|
|
|
// If you've toggled back to interior, ensure this flag is cleared
|
|
m_bCheckFakedPauseMapPosForCursor = false;
|
|
m_bCheckGPSPauseMapPosForCursor = false;
|
|
}
|
|
}
|
|
|
|
const CControl& controls = CControlMgr::GetMainFrontendControl();
|
|
|
|
float fLeftShoulder = controls.GetFrontendLT().GetNorm();
|
|
float fRightShoulder = controls.GetFrontendRT().GetNorm();
|
|
|
|
#if KEYBOARD_MOUSE_SUPPORT
|
|
UpdateMouseWheelZoom(fLeftShoulder, fRightShoulder);
|
|
#endif // KEYBOARD_MOUSE_SUPPORT
|
|
|
|
if (!bScaleChanged)
|
|
{
|
|
if ( (!bChangeZoomStyle) && (sm_bPauseMapInInterior || sm_bPauseMapInGolf) )
|
|
{
|
|
fMapCrosshairMultiplier = CMiniMap_Common::GetScrollSpeedFromZoomLevel(sm_iCurrentZoomLevel);
|
|
|
|
if (CPauseMenu::CheckInput(FRONTEND_INPUT_SELECT, false, CHECK_INPUT_OVERRIDE_FLAG_STORAGE_DEVICE)) // RT / R1
|
|
{
|
|
CPauseMenu::PlaySound("TOGGLE_ON");
|
|
|
|
if (CMiniMap::GetInPrologue())
|
|
{
|
|
SetMapZoom(ZOOM_LEVEL_START_PROLOGUE, true);
|
|
}
|
|
else
|
|
{
|
|
SetMapZoom(ZOOM_LEVEL_START, true);
|
|
}
|
|
|
|
sm_bPauseMapInInterior = false;
|
|
sm_bPauseMapInGolf = false;
|
|
bScaleChanged = true;
|
|
|
|
sm_vPauseMapLastZoomedPos = CMiniMap::GetPauseMapCursor();
|
|
|
|
Vector2 vFakePlayerPos;
|
|
if (CScriptHud::GetFakedPauseMapPlayerPos(vFakePlayerPos))
|
|
{
|
|
SetCursorActual(vFakePlayerPos);
|
|
}
|
|
|
|
// If the player is in an interior where the real player position should be used but the location of the interior is in a faked area of the game-world (e.g. garage),
|
|
// we need to toggle whether we're faking the player position depending on if we're viewing the interior or exterior. This requires script to query when we've switched
|
|
// back to the exterior map and causes a delay before we know to set the cursor position to the newly faked player position. This flag allows us to query the faked position
|
|
// and set the map cursor the first frame script begins faking the player position
|
|
m_bCheckFakedPauseMapPosForCursor = true;
|
|
m_bCheckGPSPauseMapPosForCursor = true;
|
|
|
|
CPauseMenu::RedrawInstructionalButtons(MENU_UNIQUE_ID_MAP); // repopulate any instructional buttons
|
|
UpdatePauseMapLegend(true);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
fMapCrosshairMultiplier = CMiniMap_Common::GetScrollSpeedFromZoomLevel(sm_iCurrentZoomLevel);
|
|
|
|
if (fLeftShoulder > __STICK_THRESHOLD && fRightShoulder == 0.0f)
|
|
{
|
|
s32 iMaxZoomLevel = MAX_ZOOMED_OUT;
|
|
|
|
if (CMiniMap::GetInPrologue())
|
|
{
|
|
iMaxZoomLevel = MAX_ZOOMED_OUT_PROLOGUE;
|
|
}
|
|
|
|
if (sm_iCurrentZoomLevel > iMaxZoomLevel)
|
|
{
|
|
if (CMiniMap_Common::GetScaleFromZoomLevel(sm_iCurrentZoomLevel) >= CMiniMap::GetPauseMapScale())
|
|
{
|
|
SetMapZoom(sm_iCurrentZoomLevel - 1, false);
|
|
}
|
|
}
|
|
}
|
|
if (fRightShoulder > __STICK_THRESHOLD && fLeftShoulder == 0.0f)
|
|
{
|
|
if (sm_iCurrentZoomLevel < MAX_ZOOMED_IN)
|
|
{
|
|
if (CMiniMap_Common::GetScaleFromZoomLevel(sm_iCurrentZoomLevel) <= CMiniMap::GetPauseMapScale())
|
|
{
|
|
SetMapZoom(sm_iCurrentZoomLevel + 1, false);
|
|
|
|
if (sm_iPreviousHoverActualId != INVALID_ACTUAL_ID)
|
|
{
|
|
CMiniMapBlip *pBlip = CMiniMap::GetBlipFromActualId(sm_iPreviousHoverActualId);
|
|
if (pBlip)
|
|
{
|
|
Vector3 vBlipPos(CMiniMap::GetBlipPositionValue(pBlip));
|
|
SetCursorActual(vBlipPos.x, vBlipPos.y);
|
|
sm_vPreviousCursorPos = CMiniMap::GetPauseMapCursor();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// #if __DEV
|
|
// uiDebugf1("Current Map Scale: Level %d %0.2f Pos: (%0.2f, %0.2f) LR: %0.2f %0.2f", sm_iCurrentZoomLevel, CMiniMap::GetPauseMapScale(), CMiniMap::GetPauseMapCursor().x, CMiniMap::GetPauseMapCursor().y, iLeftShoulder, iRightShoulder);
|
|
// #endif // __DEV
|
|
}
|
|
}
|
|
|
|
UpdateZooming(fLeftShoulder, fRightShoulder, bInitialEntry);
|
|
|
|
Vector2 vOldPos = CMiniMap::GetPauseMapCursor();
|
|
Vector2 vNewPos = vOldPos;
|
|
|
|
#if KEYBOARD_MOUSE_SUPPORT
|
|
bool bUsedMouse = true;
|
|
if( UpdateMouseClicksAndPosition(vNewPos) )
|
|
#endif // KEYBOARD_MOUSE_SUPPORT
|
|
{
|
|
KEYBOARD_MOUSE_ONLY( bUsedMouse = false; )
|
|
|
|
Vector2 movement( controls.GetFrontendLeftRight().GetUnboundNorm()
|
|
, controls.GetFrontendUpDown().GetUnboundNorm() );
|
|
|
|
if( movement.Mag2() >= (__STICK_THRESHOLD * __STICK_THRESHOLD) )
|
|
{
|
|
vNewPos.x += (fMapCrosshairMultiplier) * movement.x;
|
|
vNewPos.y -= (fMapCrosshairMultiplier) * movement.y;
|
|
}
|
|
}
|
|
|
|
static Vector2 vInteriorBoundMin(0,0);
|
|
static Vector2 vInteriorBoundMax(0,0);
|
|
|
|
if ( (bScaleChanged) || (vInteriorBoundMin.IsZero() || vInteriorBoundMax.IsZero()) || (GetCurrentZoomLevel() > MAX_ZOOMED_IN) )
|
|
{
|
|
GetMapExtents(vInteriorBoundMin, vInteriorBoundMax, !bInitialEntry);
|
|
}
|
|
|
|
if(sm_bWasReloaded)
|
|
{
|
|
GetMapExtents(vInteriorBoundMin, vInteriorBoundMax, !bInitialEntry);
|
|
sm_bWasReloaded = false;
|
|
}
|
|
|
|
vNewPos.x = Clamp( vNewPos.x, vInteriorBoundMin.x, vInteriorBoundMax.x );
|
|
vNewPos.y = Clamp( vNewPos.y, vInteriorBoundMax.y, vInteriorBoundMin.y ); // min/max reversed because y is reversed
|
|
|
|
if (vOldPos != vNewPos)
|
|
{
|
|
#if KEYBOARD_MOUSE_SUPPORT
|
|
if( bUsedMouse )
|
|
{
|
|
Vector2 vScreenSpace( GetScreenPosFromWorld(vOldPos.x - vNewPos.x, vOldPos.y - vNewPos.y, false) );
|
|
float fSoundScalar = rage::RampValue(vScreenSpace.Mag2(), 0.0f, MOUSE_DRAG_SOUND_SCREEN_PIXELS_SQRD, 0.0f, MAX_SOUNDVAR_VALUE);
|
|
g_FrontendAudioEntity.PlaySoundMapMovement(fSoundScalar);
|
|
uiWarningf("MOVE: %f (%f)", fSoundScalar, vScreenSpace.Mag2());
|
|
}
|
|
else
|
|
#endif
|
|
{
|
|
g_FrontendAudioEntity.PlaySoundMapMovement(-1.0f);
|
|
}
|
|
SetCursorActual(vNewPos);
|
|
}
|
|
else
|
|
{
|
|
g_FrontendAudioEntity.StopSoundMapMovement();
|
|
}
|
|
|
|
if (!bInitialEntry)
|
|
{
|
|
#define __STREET_NAME_BOUNDING_BOX_RANGE (20.0f)
|
|
ThePaths.AddNodesRequiredRegionThisFrame( CPathFind::CPathNodeRequiredArea::CONTEXT_MAP, Vector3(vNewPos.x-__STREET_NAME_BOUNDING_BOX_RANGE, vNewPos.y-__STREET_NAME_BOUNDING_BOX_RANGE, -__STREET_NAME_BOUNDING_BOX_RANGE), Vector3(vNewPos.x+__STREET_NAME_BOUNDING_BOX_RANGE, vNewPos.y+__STREET_NAME_BOUNDING_BOX_RANGE, __STREET_NAME_BOUNDING_BOX_RANGE), "CMapMenu" );
|
|
}
|
|
|
|
//
|
|
// placing a waypoint
|
|
//
|
|
if (!CScriptHud::bHideFrontendMapBlips)
|
|
{
|
|
if ( SUIContexts::IsActive("MAP_CanDropPOI") )
|
|
{
|
|
|
|
const ioValue& poiInput = CControlMgr::GetMainFrontendControl().GetValue(INPUT_MAP_POI);
|
|
if(poiInput.IsReleased() || CPauseMenu::CheckInput(FRONTEND_INPUT_Y, false, CHECK_INPUT_OVERRIDE_FLAG_STORAGE_DEVICE) )// Y/TRIANGLE button
|
|
{
|
|
bool bPlaySound = true;
|
|
#if KEYBOARD_MOUSE_SUPPORT
|
|
// if you click the mouse button, place it where the mouse is
|
|
if(poiInput.IsReleased() && poiInput.GetLastSource().m_Device == IOMS_MOUSE_BUTTON )
|
|
{
|
|
// only do the thing if you're over the map. Otherwise... don't
|
|
if( IsMouseOverMap() )
|
|
{
|
|
Vector2 vWorldPos( GetWorldPosFromScreen((float)ioMouse::GetX(), (float)ioMouse::GetY()) );
|
|
CMiniMap::AddOrRemovePointOfInterest(vWorldPos.x, vWorldPos.y);
|
|
}
|
|
else
|
|
{
|
|
bPlaySound = false;
|
|
}
|
|
}
|
|
else
|
|
#endif
|
|
{
|
|
CMiniMap::AddOrRemovePointOfInterest(CMiniMap::GetPauseMapCursor().x, CMiniMap::GetPauseMapCursor().y);
|
|
CheckCursorOverBlip(CMiniMap::GetPauseMapCursor(), true, false, true);
|
|
sm_vPreviousCursorPos = -CMiniMap::GetPauseMapCursor();
|
|
}
|
|
|
|
if( bPlaySound )
|
|
{
|
|
g_FrontendAudioEntity.PlaySound("WAYPOINT_SET", "HUD_FRONTEND_DEFAULT_SOUNDSET"); // 1503220
|
|
ResetCornerBlipInfo(true, false);
|
|
}
|
|
}
|
|
}
|
|
|
|
// place a waypoint GPS blip on the radar or warp if in mission creator:
|
|
if (CPauseMenu::CheckInput(FRONTEND_INPUT_ACCEPT, false, CHECK_INPUT_OVERRIDE_FLAG_STORAGE_DEVICE)) // SQUARE/X button
|
|
{
|
|
PlaceWaypoint();
|
|
}
|
|
}
|
|
|
|
static bool bLastInteriorFlagSentToActionscript = !(sm_bPauseMapInInterior || sm_bPauseMapInGolf);
|
|
|
|
if (bLastInteriorFlagSentToActionscript != (sm_bPauseMapInInterior || sm_bPauseMapInGolf))
|
|
{
|
|
CPauseMenu::GetMovieWrapper(PAUSE_MENU_MOVIE_CONTENT).CallMethod( "SET_FULL_MAP_SCREEN_CONTROL", !(sm_bPauseMapInInterior || sm_bPauseMapInGolf) );
|
|
|
|
bLastInteriorFlagSentToActionscript = (sm_bPauseMapInInterior || sm_bPauseMapInGolf);
|
|
}
|
|
|
|
// debug stuff:
|
|
#if !__FINAL
|
|
#define DEBUG_WARP_BUTTON_TIME_TO_HOLD (1000)
|
|
|
|
static u32 sDebugWarpButtonPressedTimer = fwTimer::GetSystemTimeInMilliseconds();
|
|
static bool bDebugWarpButtonPressed = false;
|
|
|
|
// useful debug stuff to drop the player in the current cursor position:
|
|
if (CControlMgr::GetPlayerPad() && (CControlMgr::GetPlayerPad()->GetRightShoulder2() && CControlMgr::GetPlayerPad()->GetLeftShoulder2()))
|
|
{
|
|
if (!bDebugWarpButtonPressed)
|
|
{
|
|
CPed* pPed = CGameWorld::FindLocalPlayer();
|
|
if (pPed && (!pPed->GetIsInVehicle() || pPed->GetIsDrivingVehicle())) // don't warp if player is a passenger
|
|
{
|
|
sDebugWarpButtonPressedTimer = fwTimer::GetSystemTimeInMilliseconds();
|
|
bDebugWarpButtonPressed = true;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
bDebugWarpButtonPressed = false;
|
|
}
|
|
|
|
XPARAM(nocheats);
|
|
if (bDebugWarpButtonPressed && !PARAM_nocheats.Get() && fwTimer::GetSystemTimeInMilliseconds() > sDebugWarpButtonPressedTimer + DEBUG_WARP_BUTTON_TIME_TO_HOLD)
|
|
{
|
|
g_FrontendAudioEntity.PlaySound("WAYPOINT_SET", "HUD_FRONTEND_DEFAULT_SOUNDSET");
|
|
|
|
if(!NetworkInterface::IsGameInProgress())
|
|
{
|
|
audNorthAudioEngine::MinimalUpdate();
|
|
}
|
|
CHelpMessage::ClearAll();
|
|
|
|
sDebugWarpButtonPressedTimer = fwTimer::GetSystemTimeInMilliseconds();
|
|
bDebugWarpButtonPressed = false;
|
|
|
|
HANG_DETECT_SAVEZONE_ENTER();
|
|
|
|
float fX = CMiniMap::GetPauseMapCursor().x;
|
|
float fY = CMiniMap::GetPauseMapCursor().y;
|
|
float fZ = CGameWorldHeightMap::GetMaxHeightFromWorldHeightMap(fX, fY);
|
|
Vector3 NewPlayerPos(fX, fY, fZ);
|
|
|
|
// Warp there
|
|
gRenderThreadInterface.Flush();
|
|
CWarpManager::SetWarp( NewPlayerPos, Vector3(0,0,0), 0.0f, true, true, -1.0f, true );
|
|
|
|
if (NetworkInterface::IsGameInProgress())
|
|
{
|
|
GetEventScriptNetworkGroup()->Add(CEventNetworkCheatTriggered(CEventNetworkCheatTriggered::CHEAT_WARP));
|
|
}
|
|
|
|
HANG_DETECT_SAVEZONE_EXIT("CMapMenu::UpdateMapScreenInput");
|
|
|
|
CPauseMenu::Close();
|
|
}
|
|
#endif // !__FINAL
|
|
|
|
return false;
|
|
}
|
|
|
|
void CMapMenu::ReloadMap()
|
|
{
|
|
#if KEYBOARD_MOUSE_SUPPORT && !__FINAL
|
|
// only set this bool once
|
|
if( PARAM_mapStaysOnWaypoints.Get() )
|
|
{
|
|
s_bMapMovesOnWaypoint = !PARAM_mapStaysOnWaypoints.Get();
|
|
PARAM_mapStaysOnWaypoints.Set(NULL);
|
|
}
|
|
|
|
// only set this bool once
|
|
if( PARAM_mapCentersOnClick.Get() )
|
|
{
|
|
s_bCenterOnSingleClick = !PARAM_mapCentersOnClick.Get();
|
|
PARAM_mapCentersOnClick.Set(NULL);
|
|
}
|
|
#endif
|
|
|
|
sm_iPreviousHoverActualId = INVALID_ACTUAL_ID;
|
|
sm_iCurrentSelectedMissionCreatorUniqueId = INVALID_BLIP_ID;
|
|
|
|
InitStartingValues();
|
|
SetMapZoom(ZOOM_LEVEL_0, true);
|
|
sm_bWasReloaded = true;
|
|
|
|
if (CMiniMap::GetIsInsideInterior(true))
|
|
{
|
|
sm_bPauseMapInInterior = true;
|
|
sm_vPauseMapLastZoomedPos = CMiniMap::GetPauseMapCursor();
|
|
}
|
|
else
|
|
{
|
|
sm_bPauseMapInInterior = false;
|
|
sm_vPauseMapLastZoomedPos.Set(0,0);
|
|
}
|
|
|
|
if (CMiniMap::IsInGolfMap())
|
|
{
|
|
sm_bPauseMapInGolf = true;
|
|
sm_vPauseMapLastZoomedPos = CMiniMap::GetPauseMapCursor();
|
|
}
|
|
else
|
|
{
|
|
sm_bPauseMapInGolf = false;
|
|
sm_vPauseMapLastZoomedPos.Set(0,0);
|
|
}
|
|
|
|
InitStartingValues();
|
|
CMiniMap::UpdateCentreAndNorthBlips();
|
|
|
|
sm_iUpdateLegendTimer = fwTimer::GetSystemTimeInMilliseconds() - __INTERVAL_BETWEEN_LEGEND_UPDATES;
|
|
sm_iMissionCreatorHoverQueryTimer = fwTimer::GetSystemTimeInMilliseconds();
|
|
|
|
sm_bCurrentlyZooming = true;
|
|
|
|
CPauseMenu::GenerateMenuData(MENU_UNIQUE_ID_MAP);
|
|
}
|
|
|
|
#if RSG_PC
|
|
void CMapMenu::DeviceReset()
|
|
{
|
|
m_iRenderDelay = 3; // can't simply reset sm_bIsRenderingMask because the map itself has a delay it's going to smack us with
|
|
}
|
|
#endif
|
|
|
|
void CMapMenu::Render(const PauseMenuRenderDataExtra* renderData)
|
|
{
|
|
if (CPauseMenu::IsNavigatingContent())
|
|
{
|
|
if (sm_bIsRenderingMask WIN32PC_ONLY( || (m_iRenderDelay && --m_iRenderDelay==0)) )
|
|
{
|
|
CMiniMap_RenderThread::SetMask(false);
|
|
|
|
sm_bIsRenderingMask = false;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (!sm_bIsRenderingMask WIN32PC_ONLY( || (m_iRenderDelay && --m_iRenderDelay==0)) )
|
|
{
|
|
CMiniMap_RenderThread::SetMask(true);
|
|
|
|
sm_bIsRenderingMask = true;
|
|
}
|
|
}
|
|
|
|
//
|
|
// render actual map:
|
|
//
|
|
Vector2 vBackgroundPos = m_vBGPos;
|
|
Vector2 vBackgroundSize = m_vBGSize;
|
|
if (CPauseMenu::IsNavigatingContent())
|
|
{
|
|
vBackgroundPos.Zero();
|
|
vBackgroundSize.Set(1.0f, 1.0f);
|
|
}
|
|
else
|
|
CHudTools::AdjustNormalized16_9ValuesForCurrentAspectRatio(WIDESCREEN_FORMAT_CENTRE, &vBackgroundPos, &vBackgroundSize);
|
|
|
|
CMiniMap_RenderThread::RenderPauseMap(vBackgroundPos, vBackgroundSize, renderData->fAlphaFader, renderData->fBlipAlphaFader, renderData->fSizeScalar);
|
|
|
|
CScriptMenu::Render(renderData);
|
|
}
|
|
|
|
|
|
|
|
void CMapMenu::RenderPauseMapTint(const Vector2& vBackgroundPos, const Vector2& vBackgroundSize, float fAlpha, bool bBrightTint) // 1354721
|
|
{
|
|
eHUD_COLOURS hudColour = HUD_COLOUR_PAUSEMAP_TINT;
|
|
|
|
// alternative shade of tint if navigating content (fixes 1481452)
|
|
if (bBrightTint)
|
|
{
|
|
hudColour = HUD_COLOUR_PAUSEMAP_TINT_HALF;
|
|
}
|
|
|
|
Color32 adjColor(CHudColour::GetRGBA(hudColour));
|
|
|
|
// the color is stored 'inverted', so reverse it
|
|
adjColor.SetAlpha( Clamp( int(float(255 - adjColor.GetAlpha()) * fAlpha), 0, 255) );
|
|
|
|
CSprite2d::DrawRectGUI(fwRect( vBackgroundPos.x, vBackgroundPos.y,
|
|
vBackgroundPos.x+vBackgroundSize.x, vBackgroundPos.y+vBackgroundSize.y),
|
|
adjColor);
|
|
}
|
|
|
|
bool CMapMenu::Populate(MenuScreenId newScreenId)
|
|
{
|
|
CMiniMap::SetMinimapModeState(MINIMAP_MODE_STATE_SETUP_FOR_PAUSEMAP WIN32PC_ONLY(, true)); // on PC, just always force this because of resolution changes
|
|
|
|
m_iCurrentLegendItem = 0;
|
|
m_iCurrentLegendItemIndex = 0;
|
|
|
|
CScriptMenu::Populate(newScreenId);
|
|
|
|
return true;
|
|
}
|
|
|
|
|
|
|
|
/*void CMapMenu::ShowNextMissionObjective(bool bShow)
|
|
{
|
|
CScaleformMovieWrapper& pauseContent = CPauseMenu::GetMovieWrapper(PAUSE_MENU_MOVIE_CONTENT); // 948328
|
|
|
|
if (bShow)
|
|
{
|
|
for (s32 iMessageNum = CMessages::GetMaxNumberOfPreviousMessages(CMessages::PREV_MESSAGE_TYPE_MISSION)-1; iMessageNum >= 0; iMessageNum--)
|
|
{
|
|
char GxtBriefMessage[MAX_CHARS_IN_MESSAGE];
|
|
if (iMessageNum >= 0 && CMessages::FillStringWithPreviousMessage(CMessages::PREV_MESSAGE_TYPE_MISSION, iMessageNum, GxtBriefMessage, NELEM(GxtBriefMessage)))
|
|
{
|
|
if( pauseContent.BeginMethod("SET_COLUMN_SCROLL") )
|
|
{
|
|
pauseContent.AddParam(0);
|
|
pauseContent.AddParam(0);
|
|
pauseContent.AddParam(0);
|
|
pauseContent.AddParam(0);
|
|
pauseContent.AddParam(GxtBriefMessage);
|
|
pauseContent.EndMethod();
|
|
}
|
|
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
if( pauseContent.BeginMethod("SET_COLUMN_SCROLL") )
|
|
{
|
|
pauseContent.AddParam(0);
|
|
pauseContent.AddParam(-1);
|
|
pauseContent.AddParam(-1);
|
|
pauseContent.AddParam(-1);
|
|
pauseContent.EndMethod();
|
|
}
|
|
}*/
|
|
|
|
|
|
|
|
void CMapMenu::OnNavigatingContent(bool bAreWe)
|
|
{
|
|
#define __ZOOM_WHEN_ACTIVE_INACTIVE (0.975f) // 2.5% // 1496410
|
|
|
|
// if on map screen and going out of navigating content, then clear the legend in the actionscript
|
|
CMenuScreen& LegendData = CPauseMenu::GetScreenData(MENU_UNIQUE_ID_MAP_LEGEND);
|
|
if (bAreWe)
|
|
{
|
|
CUserDisplay::AreaName.ForceSetToDisplay();
|
|
CUserDisplay::DistrictName.ForceSetToDisplay();
|
|
UpdateMapScreenInput(true);
|
|
UpdatePauseMapLegend(false, true); // want to restart the timer
|
|
|
|
CMiniMap::SetPauseMapScale(CMiniMap::GetPauseMapScale() / __ZOOM_WHEN_ACTIVE_INACTIVE);
|
|
CheckCursorOverBlip(CMiniMap::GetPauseMapCursor(), false, true, true);
|
|
|
|
#if KEYBOARD_MOUSE_SUPPORT
|
|
m_vscrLastMousePos.Set(-1.0f, -1.0f); // adjust the mouse position so we'll refresh on enter
|
|
Vector2 vNewPos( CMiniMap::GetPauseMapCursor() );
|
|
UpdateMouseClicksAndPosition(vNewPos);
|
|
#endif
|
|
}
|
|
else
|
|
{
|
|
g_FrontendAudioEntity.StopSoundMapMovement();
|
|
g_FrontendAudioEntity.StopSoundMapZoom();
|
|
|
|
CScaleformMenuHelper::SET_COLUMN_TITLE(PM_COLUMN_LEFT, "");
|
|
m_bLastClearedTitle = true;
|
|
|
|
CMiniMap::SetPauseMapScale(CMiniMap::GetPauseMapScale() * __ZOOM_WHEN_ACTIVE_INACTIVE);
|
|
|
|
CScaleformMenuHelper::HIDE_COLUMN_SCROLL( static_cast<PM_COLUMNS>(LegendData.depth-1));
|
|
ClearMapOverlays();
|
|
|
|
#if KEYBOARD_MOUSE_SUPPORT
|
|
m_fMouseWheelMovement = 0.0f;
|
|
m_vwrldMouseMovement.Zero();
|
|
CMousePointer::SetMouseCursorStyle(MOUSE_CURSOR_STYLE_ARROW);
|
|
m_uFirstClickTime = 0u;
|
|
m_bClickedWithoutDragging = false;
|
|
m_bWasBlipDragging = false;
|
|
m_iBlipMouseCurrentlyHoverOverUniqueId.Reset();
|
|
#endif
|
|
m_iBlipCurrentlyHoveredOverUniqueId.Reset();
|
|
sm_iPreviousHoverActualId = -1;
|
|
}
|
|
CPauseMenu::ScaleContentMovie(bAreWe);
|
|
}
|
|
|
|
bool CMapMenu::CanSetWaypoint()
|
|
{
|
|
return (NetworkInterface::CanSetWaypoint(CGameWorld::FindLocalPlayer()) && (!CScriptHud::bUsingMissionCreator) && (!CMiniMap::IsInGolfMap()) && (!sm_bPauseMapInInterior) && !CMiniMap::GetInPrologue() && !CMiniMap::GetBlockWaypoint());
|
|
}
|
|
|
|
void CMapMenu::PlaceWaypoint(bool bAtMousePosition)
|
|
{
|
|
if (!CScriptHud::bUsingMissionCreator) // standard waypoint
|
|
{
|
|
SetWaypoint( bAtMousePosition );
|
|
}
|
|
else
|
|
{
|
|
if (CScriptHud::bAllowMissionCreatorWarp)
|
|
{
|
|
CPed* pPed = CGameWorld::FindLocalPlayer();
|
|
if (pPed && (!pPed->GetIsInVehicle() || pPed->GetIsDrivingVehicle())) // don't warp if player is a passenger
|
|
{
|
|
CPauseMenu::CloseAndWarp();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
void CMapMenu::PrepareInstructionalButtons( MenuScreenId UNUSED_PARAM(MenuId), s32 UNUSED_PARAM(iUniqueId) )
|
|
{
|
|
// hide instructional buttons when certain categories in the legend are highlighted:
|
|
bool bOnOffDisabled = false;
|
|
if (m_iCurrentLegendItem >= 0 && m_iCurrentLegendItem < sm_LegendList.GetCount())
|
|
{
|
|
if (sm_LegendList[m_iCurrentLegendItem].iBlipCategory == BLIP_CATEGORY_WAYPOINT || sm_LegendList[m_iCurrentLegendItem].iBlipCategory == BLIP_CATEGORY_LOCAL_PLAYER)
|
|
{
|
|
bOnOffDisabled = true;
|
|
}
|
|
}
|
|
|
|
bool bShowBlipDetailButtons = m_bAtLeastOneLowDetailBlip &&
|
|
!CScriptHud::bUsingMissionCreator &&
|
|
!CMapMenu::GetIsInInteriorMode() &&
|
|
!CMiniMap::GetIsOnIslandMap() &&
|
|
!CMapMenu::GetIsInGolfMode();
|
|
|
|
SUIContexts::SetActive("MAP_CanWarp", CScriptHud::bUsingMissionCreator && CScriptHud::bAllowMissionCreatorWarp );
|
|
|
|
SUIContexts::SetActive("MAP_Waypoint", CanSetWaypoint());
|
|
SUIContexts::SetActive("MAP_Destination", CScriptHud::bSetDestinationInMapMenu);
|
|
SUIContexts::SetActive("MAP_CanZoom", !sm_bPauseMapInInterior && !sm_bPauseMapInGolf); // fix for 1809749
|
|
SUIContexts::SetActive("MAP_CanStartMiss", sm_bShowStartMissionButton);
|
|
SUIContexts::SetActive("MAP_CanContact", sm_bShowContactButton);
|
|
// SUIContexts::SetActive("MAP_Criminal", NetworkInterface::IsGameInProgress() && !NetworkInterface::IsInFreeMode() );
|
|
SUIContexts::SetActive("MAP_Interior", CMiniMap::GetIsInsideInterior(true));
|
|
SUIContexts::SetActive("MAP_Golf", CMiniMap::IsInGolfMap());
|
|
SUIContexts::SetActive("MAP_VisHigh", bShowBlipDetailButtons && !CMiniMap::GetBlipVisibilityHighDetail() );
|
|
SUIContexts::SetActive("MAP_VisLow", bShowBlipDetailButtons && CMiniMap::GetBlipVisibilityHighDetail() );
|
|
|
|
const bool bCanDropPOI = !CScriptHud::bUsingMissionCreator &&
|
|
!sm_bPauseMapInInterior &&
|
|
!sm_bPauseMapInGolf &&
|
|
!CMiniMap::GetInPrologue() &&
|
|
!CMiniMap::IsInGolfMap() &&
|
|
!CMiniMap::GetIsOnIslandMap() &&
|
|
!SUIContexts::IsActive("CORONA_BIGMAP_CLOSE") &&
|
|
!SUIContexts::IsActive("CORONA_BIGMAP_CLOSE_KM");
|
|
SUIContexts::SetActive("MAP_CanDropPOI", bCanDropPOI);
|
|
}
|
|
|
|
bool CMapMenu::TriggerEvent(MenuScreenId MenuId, s32 iUniqueId)
|
|
{
|
|
if (MenuId == MENU_UNIQUE_ID_MAP_LEGEND)
|
|
{
|
|
// CMapMenu::ProcessLegend(iUniqueId);
|
|
return true;
|
|
}
|
|
|
|
return CScriptMenu::TriggerEvent(MenuId,iUniqueId);
|
|
}
|
|
|
|
void CMapMenu::LayoutChanged( MenuScreenId iPreviousLayout, MenuScreenId iNewLayout, s32 iUniqueId, eLAYOUT_CHANGED_DIR eDir )
|
|
{
|
|
if (CPauseMenu::IsNavigatingContent())
|
|
{
|
|
if (iNewLayout == MENU_UNIQUE_ID_MAP_LEGEND)
|
|
{
|
|
if (iUniqueId != -1)
|
|
{
|
|
ProcessLegend(iUniqueId, -1);
|
|
}
|
|
}
|
|
|
|
CScriptMenu::LayoutChanged(iPreviousLayout, iNewLayout, iUniqueId, eDir);
|
|
}
|
|
|
|
CPauseMenu::RedrawInstructionalButtons(MENU_UNIQUE_ID_MAP); // repopulate any instructional buttons as we need to check against legend items
|
|
}
|
|
|
|
bool CMapMenu::CheckIncomingFunctions(atHashWithStringBank methodName, const GFxValue* args)
|
|
{
|
|
if (methodName == ATSTRINGHASH("SET_MAP_LOCATION",0x3800d093))
|
|
{
|
|
if (uiVerifyf(args[1].IsNumber() && args[2].IsNumber(), "SET_MAP_LOCATION params not compatible: %s %s", sfScaleformManager::GetTypeName(args[1]), sfScaleformManager::GetTypeName(args[2])))
|
|
{
|
|
s32 iUniqueId = (s32)args[1].GetNumber();
|
|
s32 iSelectedValue = (s32)args[2].GetNumber();
|
|
|
|
uiDebugf3("PauseMenu: Actionscript SET_MAP_LOCATION iUniqueId=%d iSelectedValue=%d", iUniqueId, iSelectedValue);
|
|
|
|
ProcessLegend(iUniqueId, iSelectedValue);
|
|
|
|
CPauseMenu::PlaySound("NAV_LEFT_RIGHT");
|
|
}
|
|
|
|
return true;
|
|
}
|
|
// normally occurs RIGHT after a layout changed, so we can use this to know if they've clicked the mouse on an item and can skip the delay
|
|
else if(methodName == ATSTRINGHASH("SET_MOUSE_OVER_PARAMS",0x32e8715f))
|
|
{
|
|
SetCursorTarget(m_vCursorTarget, true);
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
void CMapMenu::Update()
|
|
{
|
|
CWanted *pWanted = CGameWorld::FindLocalPlayerWanted(); // we want to flash the wanted blips even if we are paused
|
|
if (pWanted)
|
|
{
|
|
CWanted::GetWantedBlips().CreateAndUpdateRadarBlips(pWanted);
|
|
}
|
|
|
|
// For now, we only care about catching the case where we go from non-faked player position interior, to faked-player position exterior
|
|
if (!sm_bPauseMapInInterior)
|
|
{
|
|
if(m_bCheckFakedPauseMapPosForCursor)
|
|
{
|
|
Vector2 vFakePlayerPos;
|
|
if(CScriptHud::GetFakedPauseMapPlayerPos(vFakePlayerPos))
|
|
{
|
|
CMiniMap::SetPauseMapCursor(vFakePlayerPos);
|
|
m_bCheckFakedPauseMapPosForCursor = false;
|
|
}
|
|
}
|
|
|
|
if(m_bCheckGPSPauseMapPosForCursor)
|
|
{
|
|
Vector3 vFakeGPSPos;
|
|
if(CScriptHud::GetFakedGPSPlayerPos(vFakeGPSPos))
|
|
{
|
|
for(int i = 0; i < GPS_NUM_SLOTS; ++i)
|
|
{
|
|
if(CGps::m_Slots[i].IsOn())
|
|
{
|
|
CGps::m_Slots[i].SetStatus(CGpsSlot::eStatus::STATUS_CALCULATING_ROUTE);
|
|
}
|
|
}
|
|
m_bCheckGPSPauseMapPosForCursor = false;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
m_bCheckFakedPauseMapPosForCursor = false;
|
|
m_bCheckGPSPauseMapPosForCursor = false;
|
|
}
|
|
|
|
if (sm_bUpdateLegend)
|
|
{
|
|
// we ensure the legend doesnt update every frame if blips are added/removed as it will jump about and look
|
|
// shit and also slow down the map because of all the invokes
|
|
if (fwTimer::GetSystemTimeInMilliseconds() > sm_iUpdateLegendTimer + __INTERVAL_BETWEEN_LEGEND_UPDATES)
|
|
{
|
|
UpdateLegend(false, false);
|
|
sm_bUpdateLegend = false;
|
|
|
|
sm_iUpdateLegendTimer = fwTimer::GetSystemTimeInMilliseconds();
|
|
}
|
|
}
|
|
#if KEYBOARD_MOUSE_SUPPORT
|
|
// Handle Lerping pan position
|
|
if( m_uCursorTargetTime )
|
|
{
|
|
Vector2 curPos = CMiniMap::GetPauseMapCursor();
|
|
s32 timePassed = s32(fwTimer::GetSystemTimeInMilliseconds() - m_uCursorTargetTime);
|
|
if( timePassed < MAP_SNAP_PAN_SPEED )
|
|
{
|
|
// timePassed may be negative, because the time is in a delay, so just clamp to 0 and hang out there for a bit
|
|
float percentComplete = rage::Clamp(float(timePassed)/MAP_SNAP_PAN_SPEED, 0.0f, 1.0f);
|
|
float percentThere = rage::TweenStar::ComputeEasedValue(percentComplete, static_cast<rage::TweenStar::EaseType>(s_LERP_METHOD) );
|
|
CMiniMap::SetPauseMapCursor( Lerp(percentThere, curPos, m_vCursorTarget) );
|
|
}
|
|
else
|
|
{
|
|
SetCursorActual(m_vCursorTarget);
|
|
DisplayAreaName(true);
|
|
}
|
|
}
|
|
else
|
|
#endif
|
|
if(CPauseMenu::IsNavigatingContent())
|
|
{
|
|
//
|
|
// go through all the blips and see if we are hovering ontop of one
|
|
//
|
|
if ( WIN32PC_ONLY( CControlMgr::GetMainFrontendControl().GetCursorAccept().IsUp() && ) !CheckCursorOverBlip(CMiniMap::GetPauseMapCursor(), false, false, true))
|
|
{
|
|
DisplayAreaName(false);
|
|
}
|
|
}
|
|
|
|
CScriptMenu::Update();
|
|
}
|
|
|
|
void CMapMenu::SetCursorTarget(const Vector2& vPosToLerpTo, bool KEYBOARD_MOUSE_ONLY(bSkipDelay))
|
|
{
|
|
#if KEYBOARD_MOUSE_SUPPORT
|
|
m_vCursorTarget = vPosToLerpTo;
|
|
|
|
// if the time is already set, dial it back a bit so we don't go anywhere for a bit
|
|
// prevent bad-looking spamming
|
|
int iDelay = bSkipDelay ? 0 : (m_uCursorTargetTime == 0 ? MAP_FIRST_PAN_DELAY : MAP_SPAM_PAN_DELAY);
|
|
|
|
m_uCursorTargetTime = fwTimer::GetSystemTimeInMilliseconds() + iDelay;
|
|
#else
|
|
// no lerping on console (for now)
|
|
SetCursorActual(vPosToLerpTo);
|
|
#endif
|
|
}
|
|
|
|
void CMapMenu::SetCursorActual(const Vector2& vPosToSnapTo)
|
|
{
|
|
CMiniMap::SetPauseMapCursor(vPosToSnapTo);
|
|
m_vCursorTarget = vPosToSnapTo;
|
|
m_uCursorTargetTime = 0u;
|
|
}
|
|
|
|
bool CMapMenu::ShouldBlipBeShownOnLegend(CMiniMapBlip *pBlip)
|
|
{
|
|
if (!pBlip)
|
|
return false;
|
|
|
|
if(CMiniMap::IsFlagSet(pBlip, BLIP_FLAG_HIDDEN_ON_LEGEND))
|
|
{
|
|
return false;
|
|
}
|
|
|
|
if (CMiniMap::GetBlipVisibilityHighDetail() && !CMiniMap::IsFlagSet(pBlip, BLIP_FLAG_HIGH_DETAIL))
|
|
{
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
Vector2 CMapMenu::GetWorldPosFromScreen(float x, float y, bool bIncludeTranslation) const
|
|
{
|
|
GPointF screenSpace( x, y );
|
|
GPointF worldSpace2D;
|
|
if(bIncludeTranslation)
|
|
{
|
|
worldSpace2D = CMiniMap_RenderThread::GetLocalToScreenMatrix_UT().TransformByInverse(screenSpace);
|
|
}
|
|
else
|
|
{
|
|
GMatrix3D cloneMatrix;
|
|
cloneMatrix.SetInverse( CMiniMap_RenderThread::GetLocalToScreenMatrix_UT() );
|
|
// odd there's no SetTranslation
|
|
cloneMatrix.SetX(0.f);
|
|
cloneMatrix.SetY(0.f);
|
|
cloneMatrix.SetZ(0.f);
|
|
worldSpace2D = cloneMatrix.Transform(screenSpace);
|
|
}
|
|
|
|
return Vector2(worldSpace2D.x, -worldSpace2D.y); // -y because screen space and world space have different handedness
|
|
}
|
|
|
|
Vector2 CMapMenu::GetScreenPosFromWorld(float x, float y, bool bIncludeTranslation) const
|
|
{
|
|
GPointF screenSpace( x, y );
|
|
GPointF worldSpace2D;
|
|
if(bIncludeTranslation)
|
|
{
|
|
worldSpace2D = CMiniMap_RenderThread::GetLocalToScreenMatrix_UT().Transform(screenSpace);
|
|
}
|
|
else
|
|
{
|
|
GMatrix3D cloneMatrix( CMiniMap_RenderThread::GetLocalToScreenMatrix_UT() );
|
|
// odd there's no SetTranslation
|
|
cloneMatrix.SetX(0.f);
|
|
cloneMatrix.SetY(0.f);
|
|
cloneMatrix.SetZ(0.f);
|
|
worldSpace2D = cloneMatrix.Transform(screenSpace);
|
|
}
|
|
|
|
return Vector2(worldSpace2D.x, -worldSpace2D.y); // -y because screen space and world space have different handedness
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////////////
|
|
// NAME: CPauseMenu::CheckCursorOverBlip()
|
|
// PURPOSE: checks whether we are hovering over a blip
|
|
/////////////////////////////////////////////////////////////////////////////////////
|
|
bool CMapMenu::CheckCursorOverBlip(Vector2 vCursorPos, bool bSnapToBlip, bool bForce, bool bHighlightOnLegend)
|
|
{
|
|
s32 iCurrentBlipHoverActualId = INVALID_ACTUAL_ID;
|
|
if (vCursorPos != sm_vPreviousCursorPos || bForce)
|
|
{
|
|
iCurrentBlipHoverActualId = FindActualBlipIdNearPos(vCursorPos);
|
|
|
|
SetCurrentBlipHover(iCurrentBlipHoverActualId, bSnapToBlip, bHighlightOnLegend);
|
|
|
|
sm_vPreviousCursorPos = vCursorPos;
|
|
|
|
return (iCurrentBlipHoverActualId != INVALID_ACTUAL_ID);
|
|
}
|
|
|
|
return (sm_iPreviousHoverActualId != INVALID_ACTUAL_ID);
|
|
}
|
|
|
|
void CMapMenu::SetCurrentBlipHover(s32 iCurrentBlipHoverActualId, bool bSnapToBlip, bool bHighlightOnLegend)
|
|
{
|
|
if (iCurrentBlipHoverActualId == INVALID_ACTUAL_ID) // we didnt find any blip this time
|
|
{
|
|
if (sm_iPreviousHoverActualId != INVALID_ACTUAL_ID)
|
|
{
|
|
ResetCornerBlipInfo(sm_bCanStartMission || sm_bCanContact, false);
|
|
sm_iPreviousHoverActualId = INVALID_ACTUAL_ID;
|
|
}
|
|
|
|
m_iBlipCurrentlyHoveredOverUniqueId.Reset();
|
|
}
|
|
else
|
|
{
|
|
if (iCurrentBlipHoverActualId != sm_iPreviousHoverActualId) // we have a valid new current blip
|
|
{
|
|
CMiniMapBlip *pBlip = CMiniMap::GetBlipFromActualId(iCurrentBlipHoverActualId);
|
|
if (pBlip)
|
|
{
|
|
m_iBlipCurrentlyHoveredOverUniqueId = CMiniMap::GetUniqueBlipUsed(pBlip);
|
|
|
|
if (bSnapToBlip)
|
|
{
|
|
// if a new blip then snap to the centre of the blip: This aids zooming into blips and general positioning of the cursor
|
|
Vector3 vBlipPos(CMiniMap::GetBlipPositionValue(pBlip));
|
|
SetCursorTarget(vBlipPos.x, vBlipPos.y, false);
|
|
}
|
|
|
|
if ( (CMiniMap::IsFlagSet(pBlip,BLIP_FLAG_MISSION_CREATOR)) && (ShouldBlipBeShownOnLegend(pBlip)) )
|
|
{
|
|
if (sm_iPreviousHoverActualId == INVALID_ACTUAL_ID)
|
|
{
|
|
sm_iMissionCreatorHoverQueryTimer = fwTimer::GetSystemTimeInMilliseconds();
|
|
}
|
|
else
|
|
{
|
|
sm_iMissionCreatorHoverQueryTimer = 0;
|
|
}
|
|
|
|
sm_iCurrentSelectedMissionCreatorUniqueId = CMiniMap::GetUniqueBlipUsed(pBlip);
|
|
|
|
if(NetworkInterface::IsGameInProgress())
|
|
{
|
|
sm_bCanStartMission = true;
|
|
sm_bCanContact = true;
|
|
}
|
|
|
|
CPauseMenu::RedrawInstructionalButtons(MENU_UNIQUE_ID_MAP);
|
|
|
|
sm_bHasQueried = false;
|
|
// column 1 will now get populated by scripted based on the content of sm_iCurrentSelectedMissionCreatorBlipIndex;
|
|
}
|
|
else
|
|
{
|
|
sm_iCurrentSelectedMissionCreatorUniqueId = INVALID_BLIP_ID;
|
|
sm_bCanStartMission = false;
|
|
sm_bShowStartMissionButton = false;
|
|
|
|
sm_bCanContact = false;
|
|
sm_bShowContactButton = false;
|
|
|
|
CPauseMenu::RedrawInstructionalButtons(MENU_UNIQUE_ID_MAP);
|
|
|
|
ResetCornerBlipInfo(false, false);
|
|
}
|
|
|
|
if ( bHighlightOnLegend )
|
|
{
|
|
HighlightLegendItem(pBlip);
|
|
}
|
|
}
|
|
|
|
#if __BANK
|
|
if (sm_iPreviousHoverActualId != INVALID_ACTUAL_ID)
|
|
{
|
|
CMiniMapBlip *pBlip = CMiniMap::GetBlipFromActualId(sm_iPreviousHoverActualId);
|
|
if (pBlip)
|
|
{
|
|
if (CMiniMap::GetBlipDebugNumberValue(pBlip) == -1)
|
|
{
|
|
CMiniMap::SetFlag(pBlip, BLIP_FLAG_VALUE_REMOVE_LABEL); // toggle it off
|
|
}
|
|
}
|
|
}
|
|
#endif // __BANK
|
|
|
|
sm_iPreviousHoverActualId = iCurrentBlipHoverActualId;
|
|
}
|
|
}
|
|
}
|
|
|
|
s32 CMapMenu::FindActualBlipIdNearPos(const Vector2& vCursorPos, bool bTightenRadius) const
|
|
{
|
|
#define BLIP_OVERLAY_RADIUS (250.0f)
|
|
float fBlipOverlayRadius = (BLIP_OVERLAY_RADIUS / CMiniMap::GetPauseMapScale());
|
|
|
|
if (bTightenRadius)
|
|
{
|
|
fBlipOverlayRadius = 1.0f;
|
|
}
|
|
|
|
float fClosestMatch = (fBlipOverlayRadius*fBlipOverlayRadius); // plenty big size
|
|
int iClosestIndex = INVALID_ACTUAL_ID;
|
|
eBLIP_PRIORITY closestPriority = static_cast<eBLIP_PRIORITY>(BLIP_PRIORITY_LOW_SPECIAL-1);
|
|
|
|
for (s32 iId = 0; iId < CMiniMap::GetMaxCreatedBlips(); ++iId)
|
|
{
|
|
if (iId == CMiniMap::GetActualSimpleBlipId())
|
|
continue;
|
|
|
|
CMiniMapBlip *pBlip = CMiniMap::GetBlipFromActualId(iId);
|
|
if (!pBlip)
|
|
continue;
|
|
|
|
switch(CMiniMap::GetBlipDisplayValue(pBlip))
|
|
{
|
|
case BLIP_DISPLAY_PAUSEMAP:
|
|
case BLIP_DISPLAY_PAUSEMAP_ZOOMED:
|
|
case BLIP_DISPLAY_BOTH:
|
|
case BLIP_DISPLAY_BLIPONLY:
|
|
{
|
|
if (ShouldBlipBeShownOnLegend(pBlip))
|
|
{
|
|
Vector2 vBlipPos;
|
|
CMiniMap::GetBlipPositionValue(pBlip).GetVector2XY(vBlipPos);
|
|
float fCurDist2 = vCursorPos.Dist2(vBlipPos);
|
|
eBLIP_PRIORITY curPriority = CMiniMap::GetBlipPriorityValue(pBlip);
|
|
// prefer higher priority blips if we can
|
|
// equals so that later added blips of closer distance will win
|
|
if( fCurDist2 < fClosestMatch || (fCurDist2 == fClosestMatch && curPriority >= closestPriority))
|
|
{
|
|
fClosestMatch = fCurDist2;
|
|
iClosestIndex = iId;
|
|
closestPriority = curPriority;
|
|
// if the blip is the hovered blip, it ALWAYS wins ties (this fixes issues with scrolling along the list and losing highlight)
|
|
if( pBlip->m_iUniqueId == m_iBlipCurrentlyHoveredOverUniqueId.Get())
|
|
closestPriority = BLIP_PRIORITY_MAX;
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
default:
|
|
// nothing happens
|
|
break;
|
|
}
|
|
}
|
|
|
|
return iClosestIndex;
|
|
}
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////////////
|
|
// NAME: CPauseMenu::SnapToBlip
|
|
// PURPOSE: snaps to any passed in blip
|
|
/////////////////////////////////////////////////////////////////////////////////////
|
|
void CMapMenu::SnapToBlip(CMiniMapBlip *pBlip, bool bAllowedToLerp, bool bSetLegend)
|
|
{
|
|
if (!pBlip)
|
|
return;
|
|
|
|
Vector3 vBlipPos = CMiniMap::GetBlipPositionValue(pBlip);
|
|
// s32 iCategory = CMiniMap::GetBlipCategoryValue(pBlip);
|
|
|
|
// work for 1595527...
|
|
// work out how far this new blip is from the current map cursor position, as if over a certain distance we have to zoom out to avoid LOD being shown
|
|
Vector2 deltaFromTargetXY = CMiniMap::GetPauseMapCursor()-Vector2(vBlipPos.x, vBlipPos.y);
|
|
float fDistanceToNewBlip = deltaFromTargetXY.Mag2();
|
|
|
|
//CMiniMap::SetPauseMapCursor(Vector2(vBlipPos.x, vBlipPos.y));
|
|
if ( !CMiniMap::GetInPrologue() && !CMiniMap::GetIsOnIslandMap()
|
|
&& !sm_bPauseMapInInterior && !sm_bPauseMapInGolf )
|
|
{
|
|
#define __DISTANCE_TO_AUTO_ZOOM_OUT (800)
|
|
|
|
// fix for 1720660 - even non-player blips will not auto-zoom out if they are close by, they only zoom the map out if far away
|
|
if (fDistanceToNewBlip > __DISTANCE_TO_AUTO_ZOOM_OUT*__DISTANCE_TO_AUTO_ZOOM_OUT)
|
|
{
|
|
bAllowedToLerp = bAllowedToLerp && (sm_iCurrentZoomLevel == ZOOM_LEVEL_START);
|
|
SetMapZoom(ZOOM_LEVEL_START, true);
|
|
}
|
|
sm_bPauseMapInInterior = false;
|
|
sm_bPauseMapInGolf = false;
|
|
}
|
|
|
|
ResetCornerBlipInfo(false, true);
|
|
|
|
if( bAllowedToLerp )
|
|
{
|
|
SetCursorTarget(vBlipPos.x, vBlipPos.y, false);
|
|
SetCurrentBlipHover(CMiniMap::GetActualBlipUsed(pBlip), false, bSetLegend);
|
|
}
|
|
else
|
|
{
|
|
SetCurrentBlipHover(CMiniMap::GetActualBlipUsed(pBlip), true, bSetLegend);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////////////
|
|
// NAME: CPauseMenu::UpdatePauseMapLegend
|
|
// PURPOSE: requests an update of the pausemap legend, either in the next update
|
|
// based on a timer, or instantly
|
|
/////////////////////////////////////////////////////////////////////////////////////
|
|
void CMapMenu::UpdatePauseMapLegend(bool bInstant, bool bRestartTimer)
|
|
{
|
|
if (!CPauseMenu::IsActive())
|
|
return;
|
|
|
|
if (!CPauseMenu::IsNavigatingContent() || sm_bHideLegend)
|
|
return;
|
|
|
|
sm_bUpdateLegend = true;
|
|
|
|
if (bInstant)
|
|
{
|
|
// reduce the timer by half to speed up the update, but not instant as otherwise we wont catch changes in the next
|
|
// couple of frames, which we will want to catch
|
|
s32 iAlmostCompleteLegendUpdateTime = (s32)floor(__INTERVAL_BETWEEN_LEGEND_UPDATES * 0.5f);
|
|
sm_iUpdateLegendTimer = fwTimer::GetSystemTimeInMilliseconds() - iAlmostCompleteLegendUpdateTime;
|
|
}
|
|
|
|
if (bRestartTimer)
|
|
{
|
|
sm_iUpdateLegendTimer = fwTimer::GetSystemTimeInMilliseconds() - __INTERVAL_BETWEEN_LEGEND_UPDATES;
|
|
}
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////////////
|
|
// NAME: CPauseMenu::UpdateLegendDisplayItem
|
|
// PURPOSE: Updates the SF display item associated with the current blip
|
|
/////////////////////////////////////////////////////////////////////////////////////
|
|
void CMapMenu::UpdateLegendDisplayItem(CMiniMapBlip* pBlip)
|
|
{
|
|
s32 iLegendItem, iBlipIndex;
|
|
|
|
if(GetLegendItemData(pBlip, iLegendItem, iBlipIndex))
|
|
{
|
|
// Only update the legend display item if the currently showing item is the blip index that has changed
|
|
if(sm_LegendList[iLegendItem].iCurrentSelected == iBlipIndex)
|
|
{
|
|
UpdateLegendDisplayItem(iLegendItem, iBlipIndex, false);
|
|
}
|
|
}
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////////////
|
|
// NAME: CPauseMenu::SetCurrentLegendItem
|
|
// PURPOSE: Sets the current legend item and updates the SF display item at the specified legend and blip index
|
|
/////////////////////////////////////////////////////////////////////////////////////
|
|
void CMapMenu::SetCurrentLegendItem(s32 iLegendItem, s32 iBlipIndex, bool bUpdateCurrent)
|
|
{
|
|
if (sm_bHideLegend)
|
|
{
|
|
return;
|
|
}
|
|
|
|
m_iCurrentLegendItem = iLegendItem;
|
|
m_iCurrentLegendItemIndex = iBlipIndex;
|
|
UpdateLegendDisplayItem(iLegendItem, iBlipIndex, bUpdateCurrent);
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////////////
|
|
// NAME: CPauseMenu::UpdateLegendDisplayItem
|
|
// PURPOSE: Updates the SF display item at the specified legend and blip index
|
|
/////////////////////////////////////////////////////////////////////////////////////
|
|
void CMapMenu::UpdateLegendDisplayItem(s32 iLegendItem, s32 iActualId, bool bUpdateCurrent)
|
|
{
|
|
if (iActualId != INVALID_ACTUAL_ID)
|
|
{
|
|
if (iLegendItem >= 0 && iLegendItem < sm_LegendList.GetCount())
|
|
{
|
|
if (uiVerifyf(iActualId < sm_LegendList[iLegendItem].blip.GetCount(), "PauseMap Legend: UpdateLegendDisplayItem tried to access a blip that is not in the list inside item %d (%s)", iLegendItem, sm_LegendList[iLegendItem].cBlipName))
|
|
{
|
|
s32 iUniqueBlipId = sm_LegendList[iLegendItem].blip[iActualId].iUniqueBlipId;
|
|
|
|
CMiniMapBlip *pBlip = CMiniMap::GetBlip(iUniqueBlipId);
|
|
|
|
if (pBlip)
|
|
{
|
|
uiDebugf1("PAUSEMAP: Updating slot in legend to Actionscript...");
|
|
|
|
eOPTION_DISPLAY_STYLE blipStyle = static_cast<eOPTION_DISPLAY_STYLE>(sm_LegendList[iLegendItem].iBlipObjectId);
|
|
|
|
if (sm_LegendList[iLegendItem].blip.GetCount() > 0)
|
|
{
|
|
if (pBlip)
|
|
{
|
|
if (bUpdateCurrent)
|
|
{
|
|
sm_LegendList[iLegendItem].iCurrentSelected = iActualId;
|
|
}
|
|
|
|
UpdateLegendSlotWithNameAndColour(&sm_LegendList[iLegendItem], pBlip, CMiniMap::GetBlipCategoryValue(pBlip));
|
|
|
|
if( CScaleformMenuHelper::SET_DATA_SLOT(PM_COLUMN_LEFT, iLegendItem, MENU_UNIQUE_ID_MAP_LEGEND + PREF_OPTIONS_THRESHOLD, iLegendItem, blipStyle, sm_LegendList[iLegendItem].iCurrentSelected, true, sm_LegendList[iLegendItem].cBlipName, false, true))
|
|
{
|
|
CScaleformMgr::AddParamInt(sm_LegendList[iLegendItem].blipColour.GetRed());
|
|
CScaleformMgr::AddParamInt(sm_LegendList[iLegendItem].blipColour.GetGreen());
|
|
CScaleformMgr::AddParamInt(sm_LegendList[iLegendItem].blipColour.GetBlue());
|
|
|
|
CScaleformMgr::AddParamString(sm_LegendList[iLegendItem].cBlipObjectName, false);
|
|
CScaleformMgr::AddParamInt(sm_LegendList[iLegendItem].blip.GetCount());
|
|
CScaleformMgr::AddParamBool(sm_LegendList[iLegendItem].bActive);
|
|
CScaleformMgr::EndMethod();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
bool CMapMenu::GetLegendItemData(CMiniMapBlip *pBlip, int& iLegendItem, int& iBlipIndex)
|
|
{
|
|
if(uiVerify(pBlip))
|
|
{
|
|
s32 iUniqueBlipId = CMiniMap::GetUniqueBlipUsed(pBlip);
|
|
|
|
if (iUniqueBlipId != INVALID_BLIP_ID)
|
|
{
|
|
u8 iBlipCategory = CMiniMap::GetBlipCategoryValue(pBlip);
|
|
|
|
// find blip in legend
|
|
for (s32 iItemCount = 0; iItemCount < sm_LegendList.GetCount(); iItemCount++)
|
|
{
|
|
if (sm_LegendList[iItemCount].iBlipCategory == iBlipCategory) // only bother to check blips that are in the same category
|
|
{
|
|
for (s32 iBlipCount = 0; iBlipCount < sm_LegendList[iItemCount].blip.GetCount(); iBlipCount++)
|
|
{
|
|
if (sm_LegendList[iItemCount].blip[iBlipCount].iUniqueBlipId == iUniqueBlipId)
|
|
{
|
|
iLegendItem = iItemCount;
|
|
iBlipIndex = iBlipCount;
|
|
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////////////
|
|
// NAME: CPauseMenu::HighlightLegendItem
|
|
// PURPOSE: highlights a blip in the legend list
|
|
/////////////////////////////////////////////////////////////////////////////////////
|
|
void CMapMenu::HighlightLegendItem(CMiniMapBlip *pBlip)
|
|
{
|
|
if (!pBlip)
|
|
return;
|
|
|
|
s32 iLegendItem, iBlipIndex;
|
|
|
|
if(GetLegendItemData(pBlip, iLegendItem, iBlipIndex))
|
|
{
|
|
SetCurrentLegendItem(iLegendItem, iBlipIndex, true);
|
|
CScaleformMenuHelper::SET_COLUMN_HIGHLIGHT(PM_COLUMN_LEFT, iLegendItem);
|
|
}
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////////////
|
|
/////////////////////////////////////////////////////////////////////////////////////
|
|
void CMapMenu::ResetCornerBlipInfo(bool bClear, bool bForceUpdateName)
|
|
{
|
|
if (sm_iCurrentSelectedMissionCreatorUniqueId != INVALID_BLIP_ID || !CPauseMenu::IsNavigatingContent() || sm_bHideLegend)
|
|
{
|
|
bClear = true;
|
|
}
|
|
|
|
sm_iCurrentSelectedMissionCreatorUniqueId = INVALID_BLIP_ID;
|
|
|
|
if (sm_bCanStartMission) // 1587734 - only redraw the buttons if we were on a mission blip
|
|
{
|
|
sm_bCanStartMission = false;
|
|
sm_bShowStartMissionButton = false;
|
|
|
|
CPauseMenu::RedrawInstructionalButtons(MENU_UNIQUE_ID_MAP);
|
|
}
|
|
|
|
if(sm_bCanContact)
|
|
{
|
|
sm_bCanContact = false;
|
|
sm_bShowContactButton = false;
|
|
|
|
CPauseMenu::RedrawInstructionalButtons(MENU_UNIQUE_ID_MAP);
|
|
}
|
|
|
|
if ( (bClear) || (sm_bPauseMapInInterior) || (sm_bPauseMapInGolf) || CMiniMap::GetInPrologue())
|
|
{
|
|
CPauseMenu::GetMovieWrapper(PAUSE_MENU_MOVIE_CONTENT).CallMethod( "SHOW_COLUMN", 1, false );
|
|
}
|
|
|
|
if (bForceUpdateName || !bClear)
|
|
{
|
|
DisplayAreaName(bForceUpdateName);
|
|
UpdateZooming(0.0f, 0.0f, true);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////////////
|
|
// NAME: CPauseMenu::ProcessLegend
|
|
// PURPOSE: processes what blip to highlight from clicking on the legend
|
|
/////////////////////////////////////////////////////////////////////////////////////
|
|
void CMapMenu::ProcessLegend(s32 iLegendItem, s32 iSelectedValue)
|
|
{
|
|
if (CSystem::IsThisThreadId(SYS_THREAD_RENDER)) // only on UT
|
|
{
|
|
sfAssertf(0, "CMapMenu::ProcessLegend can only be called on the UpdateThread!");
|
|
return;
|
|
}
|
|
|
|
if (sm_bHideLegend)
|
|
{
|
|
return; // Don't bother if we're set to not show the legend
|
|
}
|
|
|
|
// using the -1 to know when we change categories, and thus it's fine to lerp there
|
|
bool bAllowedToLerp = (iSelectedValue == -1);
|
|
|
|
if (sm_LegendList.GetCount() > 1 && iLegendItem >= 0 && iLegendItem < sm_LegendList.GetCount()) // check we have more than 1 item in the legend to move to (fixes) 1450856
|
|
{
|
|
if (sm_LegendList[iLegendItem].bActive) // snap to the blip if its active
|
|
{
|
|
if (iSelectedValue >= 0 && iSelectedValue < sm_LegendList[iLegendItem].blip.GetCount())
|
|
{
|
|
sm_LegendList[iLegendItem].iCurrentSelected = iSelectedValue;
|
|
}
|
|
else
|
|
{
|
|
if (sm_LegendList[iLegendItem].iCurrentSelected >= 0 && sm_LegendList[iLegendItem].iCurrentSelected < sm_LegendList[iLegendItem].blip.GetCount())
|
|
{
|
|
iSelectedValue = sm_LegendList[iLegendItem].iCurrentSelected;
|
|
}
|
|
else
|
|
{
|
|
iSelectedValue = 0; // this have gone bad so set it to 0
|
|
}
|
|
}
|
|
|
|
if (uiVerifyf(iSelectedValue >= 0 && iSelectedValue < sm_LegendList[iLegendItem].blip.GetCount(), "PauseMap Legend: SET_MAP_LOCATION tried to access a blip that is not in the list inside item %d (%s)", iLegendItem, sm_LegendList[iLegendItem].cBlipName))
|
|
{
|
|
s32 iUniqueBlipId = sm_LegendList[iLegendItem].blip[iSelectedValue].iUniqueBlipId;
|
|
|
|
CMiniMapBlip *pBlip = CMiniMap::GetBlip(iUniqueBlipId);
|
|
|
|
if (pBlip) // reposition and zoom out
|
|
{
|
|
SetCurrentLegendItem(iLegendItem, iSelectedValue, false);
|
|
|
|
SnapToBlip(pBlip, bAllowedToLerp, false);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////////////
|
|
// NAME: CPauseMenu::RemoveLegend
|
|
// PURPOSE: clears and inits the legend ready for new data or removing old data
|
|
/////////////////////////////////////////////////////////////////////////////////////
|
|
void CMapMenu::RemoveLegend()
|
|
{
|
|
EmptyLegend(true);
|
|
|
|
sm_LegendList.Reset();
|
|
}
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////////////
|
|
// NAME: CPauseMenu::EmptyLegend
|
|
// PURPOSE: empties the legend of all blips but keeps its basic values there to
|
|
// refill with updated blip info
|
|
/////////////////////////////////////////////////////////////////////////////////////
|
|
void CMapMenu::EmptyLegend(bool bForceRemove)
|
|
{
|
|
for (s32 iItemCount = 0; iItemCount < sm_LegendList.GetCount(); iItemCount++)
|
|
{
|
|
if (sm_LegendList[iItemCount].bActive || bForceRemove)
|
|
{
|
|
sm_LegendList[iItemCount].blip.Reset(); // empty all stored blips from this item
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
int CompareBlipLegendSortFunc(const sMapLegendList* candidateA, const sMapLegendList* candidateB)
|
|
{
|
|
// first compare categories
|
|
if( candidateA->iBlipCategory != candidateB->iBlipCategory )
|
|
{
|
|
return ( (candidateA->iBlipCategory < candidateB->iBlipCategory) ? -1 : 1 );
|
|
}
|
|
|
|
// then label
|
|
|
|
// the cast works here since we are just comparing strings and will work with Japanese type languages
|
|
// since all we are interested in here is keeping the order correct rather than a diff check itself
|
|
return strcmpi((char*)candidateA->cBlipName, (char*)candidateB->cBlipName) < 0 ? -1 : 1;
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////////////
|
|
// NAME: CPauseMenu::ClearMapOverlays
|
|
// PURPOSE: clears the legend from actionscript
|
|
/////////////////////////////////////////////////////////////////////////////////////
|
|
void CMapMenu::ClearMapOverlays()
|
|
{
|
|
EmptyLegend(false);
|
|
CScaleformMenuHelper::SET_DATA_SLOT_EMPTY(PM_COLUMN_LEFT);
|
|
ResetCornerBlipInfo(true, false);
|
|
}
|
|
|
|
|
|
|
|
void CMapMenu::GetMapExtents(Vector2 &vMin, Vector2 &vMax, bool bUseLegendList)
|
|
{
|
|
#define __AMOUNT_AROUND_EXTENTS (20.0f)
|
|
#define __AMOUNT_AROUND_EXTENTS_GOLF (300.0f)
|
|
|
|
bool bOverridingInterior = CMiniMap::IsOverridingInterior();
|
|
|
|
if (!bOverridingInterior)
|
|
{
|
|
CPed *pLocalPlayer = CMiniMap::GetMiniMapPed();
|
|
CPortalTracker* pPT = const_cast<CPortalTracker*>(pLocalPlayer ? pLocalPlayer->GetPortalTracker() : NULL);
|
|
|
|
Vector3 vInteriorMin(0,0,0);
|
|
Vector3 vInteriorMax(0,0,0);
|
|
|
|
if (pPT && pPT->IsInsideInterior()) // need to check very basic interior test here to know whether we need to stream in the interior movie
|
|
{
|
|
CInteriorInst* pIntInst = pLocalPlayer->GetPortalTracker()->GetInteriorInst();
|
|
if (pIntInst)
|
|
{
|
|
vInteriorMin = pIntInst->GetBoundingBoxMin();
|
|
vInteriorMax = pIntInst->GetBoundingBoxMax();
|
|
}
|
|
}
|
|
|
|
if (sm_bPauseMapInInterior)
|
|
{
|
|
if (vInteriorMin.IsNonZero() && vInteriorMax.IsNonZero())
|
|
{
|
|
vMin.y = vInteriorMax.y;
|
|
vMax.y = vInteriorMin.y;
|
|
vMax.x = vInteriorMax.x;
|
|
vMin.x = vInteriorMin.x;
|
|
}
|
|
else
|
|
{
|
|
vMin.y = sm_vPauseMapOriginalPos.y + __AMOUNT_AROUND_EXTENTS;
|
|
vMax.y = sm_vPauseMapOriginalPos.y - __AMOUNT_AROUND_EXTENTS;
|
|
vMax.x = sm_vPauseMapOriginalPos.x + __AMOUNT_AROUND_EXTENTS;
|
|
vMin.x = sm_vPauseMapOriginalPos.x - __AMOUNT_AROUND_EXTENTS;
|
|
}
|
|
}
|
|
else if (sm_bPauseMapInGolf)
|
|
{
|
|
vMin.y = sm_vPauseMapOriginalPos.y + __AMOUNT_AROUND_EXTENTS_GOLF;
|
|
vMax.y = sm_vPauseMapOriginalPos.y - __AMOUNT_AROUND_EXTENTS_GOLF;
|
|
vMax.x = sm_vPauseMapOriginalPos.x + __AMOUNT_AROUND_EXTENTS_GOLF;
|
|
vMin.x = sm_vPauseMapOriginalPos.x - __AMOUNT_AROUND_EXTENTS_GOLF;
|
|
}
|
|
else
|
|
{
|
|
if (CMiniMap::GetInPrologue())
|
|
{
|
|
vMin.y = MAP_LIMIT_NORTH_PROLOGUE;
|
|
vMax.y = MAP_LIMIT_SOUTH_PROLOGUE;
|
|
vMax.x = MAP_LIMIT_EAST_PROLOGUE;
|
|
vMin.x = MAP_LIMIT_WEST_PROLOGUE;
|
|
}
|
|
else
|
|
{
|
|
if(CMiniMap::GetIsOnIslandMap())
|
|
{
|
|
vMin.y = MAP_LIMIT_NORTH_ISLAND;
|
|
vMax.y = MAP_LIMIT_SOUTH_ISLAND;
|
|
vMax.x = MAP_LIMIT_EAST_ISLAND;
|
|
vMin.x = MAP_LIMIT_WEST_ISLAND;
|
|
}
|
|
else
|
|
{
|
|
vMin.y = MAP_LIMIT_NORTH;
|
|
vMax.y = MAP_LIMIT_SOUTH;
|
|
vMax.x = MAP_LIMIT_EAST;
|
|
vMin.x = MAP_LIMIT_WEST;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
vMin.y = sm_vPauseMapOriginalPos.y + __AMOUNT_AROUND_EXTENTS;
|
|
vMax.y = sm_vPauseMapOriginalPos.y - __AMOUNT_AROUND_EXTENTS;
|
|
vMax.x = sm_vPauseMapOriginalPos.x + __AMOUNT_AROUND_EXTENTS;
|
|
vMin.x = sm_vPauseMapOriginalPos.x - __AMOUNT_AROUND_EXTENTS;
|
|
}
|
|
|
|
if (bUseLegendList) // use items in the legend list:
|
|
{
|
|
for (s32 iItemCount = 0; iItemCount < sm_LegendList.GetCount(); iItemCount++)
|
|
{
|
|
CMiniMapBlip *pBlip = NULL;
|
|
for (s32 iBlipCount = 0; iBlipCount < sm_LegendList[iItemCount].blip.GetCount(); iBlipCount++)
|
|
{
|
|
pBlip = CMiniMap::GetBlip(sm_LegendList[iItemCount].blip[iBlipCount].iUniqueBlipId);
|
|
|
|
if (!pBlip)
|
|
continue;
|
|
|
|
Vector3 vBlipPos = CMiniMap::GetBlipPositionValue(pBlip);
|
|
|
|
if (vBlipPos.x > vMax.x)
|
|
{
|
|
vMax.x = vBlipPos.x;
|
|
}
|
|
|
|
if (vBlipPos.x < vMin.x)
|
|
{
|
|
vMin.x = vBlipPos.x;
|
|
}
|
|
|
|
if (vBlipPos.y > vMin.y)
|
|
{
|
|
vMin.y = vBlipPos.y;
|
|
}
|
|
|
|
if (vBlipPos.y < vMax.y)
|
|
{
|
|
vMax.y = vBlipPos.y;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else // use blips that are
|
|
{
|
|
if ( ( (!sm_bPauseMapInInterior) && (!sm_bPauseMapInGolf) ) || (bOverridingInterior) )
|
|
{
|
|
// go through all active blips and extend the limits if a blip is outwith the standard limits:
|
|
for (s32 iId = 0; iId < CMiniMap::GetMaxCreatedBlips(); iId++)
|
|
{
|
|
if (iId == CMiniMap::GetActualSimpleBlipId())
|
|
continue;
|
|
|
|
CMiniMapBlip *pBlip = CMiniMap::GetBlipFromActualId(iId);
|
|
|
|
if (!pBlip)
|
|
continue;
|
|
|
|
if ((CMiniMap::GetBlipDisplayValue(pBlip) == BLIP_DISPLAY_PAUSEMAP || CMiniMap::GetBlipDisplayValue(pBlip) == BLIP_DISPLAY_PAUSEMAP_ZOOMED || CMiniMap::GetBlipDisplayValue(pBlip) == BLIP_DISPLAY_BOTH || CMiniMap::GetBlipDisplayValue(pBlip) == BLIP_DISPLAY_BLIPONLY))
|
|
{
|
|
if (ShouldBlipBeShownOnLegend(pBlip))
|
|
{
|
|
Vector3 vBlipPos = CMiniMap::GetBlipPositionValue(pBlip);
|
|
|
|
if (vBlipPos.x > vMax.x)
|
|
{
|
|
vMax.x = vBlipPos.x;
|
|
}
|
|
|
|
if (vBlipPos.x < vMin.x)
|
|
{
|
|
vMin.x = vBlipPos.x;
|
|
}
|
|
|
|
if (vBlipPos.y > vMin.y)
|
|
{
|
|
vMin.y = vBlipPos.y;
|
|
}
|
|
|
|
if (vBlipPos.y < vMax.y)
|
|
{
|
|
vMax.y = vBlipPos.y;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void CMapMenu::OnBlipDelete(CMiniMapBlip* pBlip)
|
|
{
|
|
// clear all static things if it's a blip we care about.
|
|
if( pBlip->m_iActualId == sm_iPreviousHoverActualId )
|
|
sm_iPreviousHoverActualId = INVALID_ACTUAL_ID;
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////////////
|
|
// NAME: CPauseMenu::UpdateLegend
|
|
// PURPOSE: updates the legend list in code with latest blip info
|
|
/////////////////////////////////////////////////////////////////////////////////////
|
|
void CMapMenu::UpdateLegend(bool bClear, bool bForceSendToActionScript)
|
|
{
|
|
if (!CPauseMenu::IsActive() || sm_bHideLegend)
|
|
return;
|
|
|
|
if ( (!bForceSendToActionScript) && (!CPauseMenu::IsNavigatingContent()) )
|
|
return;
|
|
|
|
if (!CPauseMenu::IsInMapScreen())
|
|
{
|
|
return;
|
|
}
|
|
|
|
if (!CPauseMenu::HasProcessedContent())
|
|
return;
|
|
|
|
atArray<sMapLegendList> PrevLegendList;
|
|
|
|
if (!bForceSendToActionScript)
|
|
{
|
|
// make a copy of the legend array:
|
|
for (s32 iItemCount = 0; iItemCount < sm_LegendList.GetCount(); iItemCount++)
|
|
{
|
|
sMapLegendList newLegendItem;
|
|
newLegendItem = sm_LegendList[iItemCount];
|
|
PrevLegendList.PushAndGrow(newLegendItem);
|
|
}
|
|
}
|
|
|
|
if (bClear)
|
|
{
|
|
RemoveLegend();
|
|
uiDebugf1("PAUSEMAP: Legend fully cleared - ready to populate");
|
|
}
|
|
else
|
|
{
|
|
EmptyLegend(false);
|
|
uiDebugf1("PAUSEMAP: Legend emptied of its blips - ready to populate");
|
|
}
|
|
|
|
m_bAtLeastOneLowDetailBlip = false;
|
|
|
|
Vector2 vInteriorBoundMin(0,0);
|
|
Vector2 vInteriorBoundMax(0,0);
|
|
|
|
GetMapExtents(vInteriorBoundMin, vInteriorBoundMax, false);
|
|
|
|
for (s32 iBlipIndex = 0; iBlipIndex < CMiniMap::GetMaxCreatedBlips(); iBlipIndex++)
|
|
{
|
|
if (iBlipIndex == CMiniMap::GetActualSimpleBlipId())
|
|
continue;
|
|
|
|
CMiniMapBlip *pBlip = CMiniMap::GetBlipFromActualId(iBlipIndex);
|
|
|
|
if (pBlip)
|
|
{
|
|
// because not all blips may be shown on the legend, but may be toggled on/off, query this way up here.
|
|
|
|
m_bAtLeastOneLowDetailBlip = m_bAtLeastOneLowDetailBlip || !CMiniMap::IsFlagSet(pBlip, BLIP_FLAG_HIGH_DETAIL);
|
|
|
|
s32 iThisBlipObjectId = CMiniMap::GetBlipObjectNameId(pBlip);
|
|
s32 iThisBlipCategory = CMiniMap::GetBlipCategoryValue(pBlip);
|
|
eBLIP_DISPLAY_TYPE iDisplayValue = CMiniMap::GetBlipDisplayValue(pBlip);
|
|
|
|
// no POI when in golf (bug 1319054) or creator (1702753)
|
|
if (CMiniMap::GetBlipObjectNameId(pBlip) == RADAR_TRACE_POI)
|
|
{
|
|
if ( (sm_bPauseMapInGolf) ||
|
|
(CScriptHud::bUsingMissionCreator) )
|
|
{
|
|
continue; // skip this blip
|
|
}
|
|
}
|
|
|
|
if (sm_bPauseMapInInterior || sm_bPauseMapInGolf)
|
|
{
|
|
bool bCheckBounds = (!vInteriorBoundMin.IsZero()) && (!vInteriorBoundMax.IsZero());
|
|
|
|
if (bCheckBounds)
|
|
{
|
|
if (CMiniMap::IsFlagSet(pBlip, BLIP_FLAG_MISSION_CREATOR)) // fix for 1690613 - do not show any mission creator blips when inside interiors
|
|
{
|
|
continue; // skip this blip
|
|
}
|
|
|
|
switch (CMiniMap::GetBlipTypeValue(pBlip))
|
|
{
|
|
case BLIP_TYPE_COORDS: // FIX for 1463558 - want to show coord blips when fake interiors are active as these are probably "destinations" we still want to see
|
|
{
|
|
if (CScriptHud::FakeInterior.bActive && CMiniMap::GetBlipObjectNameId(pBlip) == BLIP_LEVEL)
|
|
{
|
|
bCheckBounds = false;
|
|
}
|
|
break;
|
|
}
|
|
|
|
case BLIP_TYPE_CHAR: // allow any chars so we see them outside the interior
|
|
{
|
|
bCheckBounds = false;
|
|
break;
|
|
}
|
|
|
|
default:
|
|
{
|
|
bCheckBounds = true;
|
|
}
|
|
}
|
|
|
|
if (bCheckBounds)
|
|
{
|
|
float fAdditionalRangeForCertainBlipTypes = 0.0f; // cull all other blips (apart from some below which have larger range)
|
|
|
|
if (CMiniMap::GetBlipTypeValue(pBlip) == BLIP_TYPE_CAR) // extend the range of where we show car blips
|
|
{
|
|
fAdditionalRangeForCertainBlipTypes = 30.0f;
|
|
}
|
|
|
|
Vector3 vBlipPos = CMiniMap::GetBlipPositionValue(pBlip); // Stay out of the vector registers
|
|
if (vBlipPos.GetX() < (vInteriorBoundMin.x-fAdditionalRangeForCertainBlipTypes) ||
|
|
vBlipPos.GetX() > (vInteriorBoundMax.x+fAdditionalRangeForCertainBlipTypes) ||
|
|
vBlipPos.GetY() < (vInteriorBoundMax.y-fAdditionalRangeForCertainBlipTypes) ||
|
|
vBlipPos.GetY() > (vInteriorBoundMin.y+fAdditionalRangeForCertainBlipTypes))
|
|
{
|
|
continue;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if ( (ShouldBlipBeShownOnLegend(pBlip) && (CMiniMap::GetBlipAlphaValue(pBlip) != 0) && (iDisplayValue != BLIP_DISPLAY_NEITHER) ) )
|
|
{
|
|
if (iDisplayValue == BLIP_DISPLAY_BLIPONLY || iDisplayValue == BLIP_DISPLAY_PAUSEMAP || iDisplayValue == BLIP_DISPLAY_BOTH || iDisplayValue == BLIP_DISPLAY_PAUSEMAP_ZOOMED)
|
|
{
|
|
bool bFound = false;
|
|
|
|
for (s32 iItemCount = 0; ((!bFound) && (iItemCount < sm_LegendList.GetCount())); iItemCount++)
|
|
{
|
|
Color32 newBlipColour;
|
|
if (CMiniMap::GetBlipColourValue(pBlip) != BLIP_COLOUR_USE_COLOUR32)
|
|
{
|
|
newBlipColour = CMiniMap_Common::GetColourFromBlipSettings(CMiniMap::GetBlipColourValue(pBlip), CMiniMap::IsFlagSet(pBlip,BLIP_FLAG_BRIGHTNESS));
|
|
}
|
|
else
|
|
{
|
|
newBlipColour = CMiniMap::GetBlipColour32Value(pBlip);
|
|
}
|
|
|
|
// if same blip id AND same colour AND same name then use in same place (treat different coloured blips as different items, but only check RGB - ignore different alphas)
|
|
if ( (((!bFound) && (((IsBlipInGroupedCategory(iThisBlipCategory)) && sm_LegendList[iItemCount].iBlipCategory == iThisBlipCategory))) || ((!strcmp((char*)sm_LegendList[iItemCount].cBlipName, (char*)CMiniMap::GetBlipNameValue(pBlip))) && (sm_LegendList[iItemCount].iBlipObjectId == iThisBlipObjectId) && (VEC3V_TO_VECTOR3(sm_LegendList[iItemCount].blipColour.GetRGB()) == VEC3V_TO_VECTOR3(newBlipColour.GetRGB())))) )
|
|
{
|
|
// remove any dead blips in this list:
|
|
for (s32 i = 0; i < sm_LegendList[iItemCount].blip.GetCount(); i++)
|
|
{
|
|
if (!CMiniMap::GetBlip(sm_LegendList[iItemCount].blip[i].iUniqueBlipId))
|
|
{
|
|
sm_LegendList[iItemCount].blip.DeleteFast(i);
|
|
}
|
|
}
|
|
|
|
if (sm_LegendList[iItemCount].bActive) // only actually add it if its an active item - if its inactive, we skip it and when its flagged as active again the legend is re-populated
|
|
{
|
|
sMapLegendItem newLegendBlipItem;
|
|
newLegendBlipItem.iUniqueBlipId = CMiniMap::GetUniqueBlipUsed(pBlip);
|
|
|
|
if (sm_LegendList[iItemCount].iCurrentSelected != 0 || sm_LegendList[iItemCount].blip.GetCount() == 0) // fix for 1476383 - only re-update this legend slot if the item is not 0 - also fix for 1693594
|
|
{
|
|
UpdateLegendSlotWithNameAndColour(&sm_LegendList[iItemCount], pBlip, iThisBlipCategory);
|
|
}
|
|
|
|
uiDebugf1("PAUSEMAP: Adding blip %d (%d) to %d %s (colour %d,%d,%d) on legend (x%d)", iBlipIndex, newLegendBlipItem.iUniqueBlipId, iItemCount, sm_LegendList[iItemCount].cBlipName, sm_LegendList[iItemCount].blipColour.GetRed(), sm_LegendList[iItemCount].blipColour.GetGreen(), sm_LegendList[iItemCount].blipColour.GetBlue(), sm_LegendList[iItemCount].blip.GetCount()+1);
|
|
|
|
sm_LegendList[iItemCount].blip.PushAndGrow(newLegendBlipItem);
|
|
}
|
|
|
|
bFound = true;
|
|
}
|
|
}
|
|
|
|
if (!bFound) // not added to a previous item, so create a new one
|
|
{
|
|
sMapLegendList *newLegendItem = &sm_LegendList.Grow();
|
|
|
|
newLegendItem->bActive = true;
|
|
|
|
sMapLegendItem newLegendBlipItem;
|
|
newLegendBlipItem.iUniqueBlipId = CMiniMap::GetUniqueBlipUsed(pBlip);
|
|
|
|
newLegendItem->blip.Reset();
|
|
newLegendItem->blip.PushAndGrow(newLegendBlipItem);
|
|
|
|
UpdateLegendSlotWithNameAndColour(newLegendItem, pBlip, iThisBlipCategory);
|
|
|
|
newLegendItem->iBlipCategory = CMiniMap::GetBlipCategoryValue(pBlip);
|
|
newLegendItem->iCurrentSelected = 0;
|
|
|
|
uiDebugf1("PAUSEMAP: Creating blip %d (%d) to %d %s (colour %d,%d,%d) on legend in category %u", iBlipIndex, newLegendBlipItem.iUniqueBlipId, sm_LegendList.GetCount()-1, newLegendItem->cBlipName, newLegendItem->blipColour.GetRed(), newLegendItem->blipColour.GetGreen(), newLegendItem->blipColour.GetBlue(), newLegendItem->iBlipCategory);
|
|
}
|
|
|
|
if (sm_LegendList.GetCount() >= MAX_NUMBER_OF_LEGEND_ITEMS) // ensure we cap this list at a reasonable amount
|
|
{
|
|
uiAssertf(0, "Max number of unique legend items added (%d)", MAX_NUMBER_OF_LEGEND_ITEMS);
|
|
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// remove any dupes
|
|
for (s32 iItemCount = 0; iItemCount < sm_LegendList.GetCount(); iItemCount++)
|
|
{
|
|
if (sm_LegendList[iItemCount].blip.GetCount() > 0)
|
|
{
|
|
for (s32 iItemCount2 = 0; iItemCount2 < sm_LegendList.GetCount(); iItemCount2++)
|
|
{
|
|
if (iItemCount == iItemCount2)
|
|
continue;
|
|
|
|
if (sm_LegendList[iItemCount2].blip.GetCount() > 0)
|
|
{
|
|
if (sm_LegendList[iItemCount].blip[0].iUniqueBlipId == sm_LegendList[iItemCount2].blip[0].iUniqueBlipId)
|
|
{
|
|
uiDebugf1("PAUSEMAP: Removing item %d %s - unique %d as it is a dupe of item %d %s - unique %d", iItemCount2, sm_LegendList[iItemCount2].cBlipName, sm_LegendList[iItemCount2].blip[0].iUniqueBlipId, iItemCount, sm_LegendList[iItemCount].cBlipName, sm_LegendList[iItemCount].blip[0].iUniqueBlipId);
|
|
sm_LegendList.DeleteFast(iItemCount2);
|
|
iItemCount2 = 0;
|
|
|
|
// update the name of the 1st item again
|
|
s32 iUniqueBlipId = sm_LegendList[iItemCount].blip[0].iUniqueBlipId;
|
|
CMiniMapBlip *pBlip = CMiniMap::GetBlip(iUniqueBlipId);
|
|
UpdateLegendSlotWithNameAndColour(&sm_LegendList[iItemCount], pBlip, CMiniMap::GetBlipCategoryValue(pBlip));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// finally remove any blips that are no longer there
|
|
for (s32 iItemCount = 0; iItemCount < sm_LegendList.GetCount(); iItemCount++)
|
|
{
|
|
// bool bHideInactiveBlips = false;
|
|
CMiniMapBlip *pBlip = NULL;
|
|
if (sm_LegendList[iItemCount].blip.GetCount() > 0)
|
|
{
|
|
pBlip = CMiniMap::GetBlip(sm_LegendList[iItemCount].blip[0].iUniqueBlipId);
|
|
// bHideInactiveBlips = ( (CMiniMap::IsFlagSet(pBlip, BLIP_FLAG_HIDDEN_BY_LEGEND)) && (sm_bPauseMapInGolf || sm_bPauseMapInInterior) );
|
|
}
|
|
|
|
if ( (sm_LegendList[iItemCount].blip.GetCount() <= 0) || (!pBlip)/* || bHideInactiveBlips*/)
|
|
{
|
|
#if !__NO_OUTPUT
|
|
s32 iCurrentArraySize = sm_LegendList.GetCount();
|
|
#endif // #if !__NO_OUTPUT
|
|
|
|
sm_LegendList[iItemCount].blip.Reset();
|
|
sm_LegendList.DeleteFast(iItemCount);
|
|
|
|
#if !__NO_OUTPUT
|
|
s32 iNewArraySize = sm_LegendList.GetCount();
|
|
uiDebugf1("PAUSEMAP: Deleting item %d from legend as it no longer has any blips in the slot (size %d now %d)", iItemCount, iCurrentArraySize, iNewArraySize);
|
|
#endif // #if !__NO_OUTPUT
|
|
|
|
iItemCount = 0;
|
|
}
|
|
}
|
|
|
|
// sort the list in alphabetical order: - this is important as we need to keep the correct
|
|
if (sm_LegendList.GetCount() > 1)
|
|
{
|
|
sm_LegendList.QSort(0, -1, CompareBlipLegendSortFunc);
|
|
}
|
|
|
|
// ensure current selected is not higher than the count
|
|
for (s32 iItemCount = 0; iItemCount < sm_LegendList.GetCount(); iItemCount++)
|
|
{
|
|
if (sm_LegendList[iItemCount].iCurrentSelected >= sm_LegendList[iItemCount].blip.GetCount())
|
|
sm_LegendList[iItemCount].iCurrentSelected = sm_LegendList[iItemCount].blip.GetCount()-1;
|
|
}
|
|
|
|
uiDebugf1("PAUSEMAP: FINAL LEGEND ITEMS...");
|
|
for (s32 iItemCount = 0; iItemCount < sm_LegendList.GetCount(); iItemCount++)
|
|
{
|
|
uiDebugf1("PAUSEMAP: Legend item: %d - %d %s (number of blips %d) Selected: %d Category: %d", iItemCount, sm_LegendList[iItemCount].iBlipObjectId, sm_LegendList[iItemCount].cBlipName, sm_LegendList[iItemCount].blip.GetCount(), sm_LegendList[iItemCount].iCurrentSelected, sm_LegendList[iItemCount].iBlipCategory);
|
|
}
|
|
uiDebugf1("PAUSEMAP: ...END FINAL LEGEND ITEMS");
|
|
|
|
uiDebugf1("PAUSEMAP: legend fully populated");
|
|
|
|
|
|
// attempt to find new index close to where we were
|
|
while(m_iCurrentLegendItem > 0) // no point checking if we're at the 0th element already
|
|
{
|
|
const sMapLegendList& prevLegendList = PrevLegendList[m_iCurrentLegendItem];
|
|
for (s32 iPrevItemIndex = 0; iPrevItemIndex < prevLegendList.blip.GetCount(); iPrevItemIndex++)
|
|
{
|
|
// doing this the first time so we can use the same loop and check if the exact same blip still exists
|
|
// failing that, we'll just check the rest in that same blip legend
|
|
s32 iCheckItemIndex = (iPrevItemIndex + m_iCurrentLegendItemIndex) % prevLegendList.blip.GetCount();
|
|
|
|
if( CMiniMapBlip* pBlip = CMiniMap::GetBlip(prevLegendList.blip[iCheckItemIndex].iUniqueBlipId) )
|
|
{
|
|
// see if that blip is in the new legend somewhere
|
|
if( GetLegendItemData( pBlip, m_iCurrentLegendItem, m_iCurrentLegendItemIndex) )
|
|
{
|
|
uiDebugf1("PAUSEMAP: New current legend item changed to %d[%d]", m_iCurrentLegendItem, m_iCurrentLegendItemIndex);
|
|
goto OutOfTheNestedLoop;
|
|
}
|
|
}
|
|
// failed the first iteration--this is invalid now.
|
|
sm_iPreviousHoverActualId = INVALID_ACTUAL_ID;
|
|
}
|
|
--m_iCurrentLegendItem;
|
|
m_iCurrentLegendItemIndex = 0;
|
|
}
|
|
|
|
uiAssertf(m_iCurrentLegendItem==0, "Not sure how the loop failed... we should've iterated all the way back to 0");
|
|
OutOfTheNestedLoop:
|
|
|
|
// if current legend item is now over the total amount of items in the legend after any deletion, then reduce by 1
|
|
// Pretty sure with the new loops above, we'll never encounter this
|
|
if (m_iCurrentLegendItem > 0 && m_iCurrentLegendItem >= sm_LegendList.GetCount())
|
|
{
|
|
m_iCurrentLegendItem = sm_LegendList.GetCount()-1;
|
|
m_iCurrentLegendItemIndex = 0;
|
|
}
|
|
|
|
bool bSendLegendContentsToActionScript = true;
|
|
|
|
if (!bForceSendToActionScript)
|
|
{
|
|
if ( (sm_LegendList.GetCount() == PrevLegendList.GetCount()) && (PrevLegendList.GetCount() > 0) )
|
|
{
|
|
bool bFoundDiff = false;
|
|
|
|
for (s32 iItemCount = 0; (!bFoundDiff) && iItemCount < sm_LegendList.GetCount() && iItemCount < PrevLegendList.GetCount(); iItemCount++)
|
|
{
|
|
if ( (sm_LegendList[iItemCount].blip.GetCount() != PrevLegendList[iItemCount].blip.GetCount()) ||
|
|
(sm_LegendList[iItemCount].iBlipObjectId != PrevLegendList[iItemCount].iBlipObjectId) )
|
|
{
|
|
bFoundDiff = true;
|
|
}
|
|
}
|
|
|
|
if (!bFoundDiff)
|
|
{
|
|
uiDebugf1("PAUSEMAP: Legend repopulated but detected no change, so will not update actionscript this time");
|
|
bSendLegendContentsToActionScript = false;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (bSendLegendContentsToActionScript)
|
|
{
|
|
SendLegendToActionscript();
|
|
|
|
if (bForceSendToActionScript)
|
|
{
|
|
CheckCursorOverBlip(CMiniMap::GetPauseMapCursor(), true, true, true);
|
|
}
|
|
}
|
|
|
|
if (sm_LegendList.GetCount() == 0) // reset it to 0 so we start afresh if/when new blips appear
|
|
{
|
|
m_iCurrentLegendItem = 0;
|
|
m_iCurrentLegendItemIndex = 0;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////////////
|
|
// NAME: CPauseMenu::IsBlipInGroupedCategory
|
|
// PURPOSE: returns whether this is a category where all blips are grouped together
|
|
// in the legend
|
|
/////////////////////////////////////////////////////////////////////////////////////
|
|
bool CMapMenu::IsBlipInGroupedCategory(s32 iThisBlipCategory)
|
|
{
|
|
return (iThisBlipCategory == BLIP_CATEGORY_PLAYER || iThisBlipCategory == BLIP_CATEGORY_PROPERTY || iThisBlipCategory == BLIP_CATEGORY_APARTMENT);
|
|
}
|
|
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////////////
|
|
// NAME: CPauseMenu::SendLegendToActionscript
|
|
// PURPOSE: sends the legend to actionscript
|
|
/////////////////////////////////////////////////////////////////////////////////////
|
|
void CMapMenu::SendLegendToActionscript()
|
|
{
|
|
uiDebugf1("PAUSEMAP: Sending Legend to Actionscript...");
|
|
|
|
CMiniMapBlip *pBlip = NULL;
|
|
|
|
CScaleformMenuHelper::SET_DATA_SLOT_EMPTY(PM_COLUMN_LEFT);
|
|
|
|
if (sm_LegendList.GetCount() > 0)
|
|
{
|
|
s32 iItemIndex = 0; // ensures index remains intact even if we assert and ignore (so assert becomes ignorable)
|
|
for (s32 iItemCount = 0; iItemCount < sm_LegendList.GetCount(); iItemCount++)
|
|
{
|
|
/*#define __SHOW_CATEGORY (0)
|
|
#if __SHOW_CATEGORY
|
|
char cCategoryTemp[6];
|
|
|
|
formatf(cCategoryTemp, " [%d]", sm_LegendList[iItemCount].iBlipCategory, NELEM(cCategoryTemp));
|
|
cGxtLegendName = CTextConversion::charStrcat(cGxtLegendName, (char*)cCategoryTemp);
|
|
#endif // __SHOW_CATEGORY*/
|
|
|
|
eOPTION_DISPLAY_STYLE blipStyle = static_cast<eOPTION_DISPLAY_STYLE>(sm_LegendList[iItemCount].iBlipObjectId);
|
|
|
|
pBlip = NULL;
|
|
|
|
if (sm_LegendList[iItemCount].blip.GetCount() > 0)
|
|
{
|
|
int iUniqueBlipID = sm_LegendList[iItemCount].blip[0].iUniqueBlipId;
|
|
pBlip = CMiniMap::GetBlip(iUniqueBlipID);
|
|
|
|
if (uiVerifyf(pBlip, "sm_LegendList has invalid blip entry. Index: %d, ID: %d", iItemCount, iUniqueBlipID))
|
|
{
|
|
if( CScaleformMenuHelper::SET_DATA_SLOT(PM_COLUMN_LEFT, iItemIndex, MENU_UNIQUE_ID_MAP_LEGEND + PREF_OPTIONS_THRESHOLD, iItemIndex, blipStyle, sm_LegendList[iItemCount].iCurrentSelected, true, sm_LegendList[iItemCount].cBlipName, false))
|
|
{
|
|
CScaleformMgr::AddParamInt(sm_LegendList[iItemCount].blipColour.GetRed());
|
|
CScaleformMgr::AddParamInt(sm_LegendList[iItemCount].blipColour.GetGreen());
|
|
CScaleformMgr::AddParamInt(sm_LegendList[iItemCount].blipColour.GetBlue());
|
|
CScaleformMgr::AddParamString(sm_LegendList[iItemCount].cBlipObjectName, false);
|
|
CScaleformMgr::AddParamInt(sm_LegendList[iItemCount].blip.GetCount());
|
|
CScaleformMgr::AddParamBool(sm_LegendList[iItemCount].bActive);
|
|
CScaleformMgr::EndMethod();
|
|
|
|
iItemIndex++;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
if (uiVerifyf(m_iCurrentLegendItem < sm_LegendList.GetCount(), "CMiniMap::SendLegendToActionscript - sm_iCurrentLegendItem is higher than sm_LegendList.GetCount()"))
|
|
{
|
|
if (sm_LegendList[m_iCurrentLegendItem].blip.GetCount() > 0
|
|
&& uiVerifyf(m_iCurrentLegendItemIndex < sm_LegendList[m_iCurrentLegendItem].blip.GetCount(), "CMiniMap::SendLegendToActionscript - m_iCurrentLegendItemIndex is higher than sm_LegendList[].blip.GetCount()" )
|
|
)
|
|
{
|
|
pBlip = CMiniMap::GetBlip(sm_LegendList[m_iCurrentLegendItem].blip[m_iCurrentLegendItemIndex].iUniqueBlipId);
|
|
}
|
|
}
|
|
}
|
|
|
|
CScaleformMenuHelper::DISPLAY_DATA_SLOT(PM_COLUMN_LEFT);
|
|
|
|
if (sm_LegendList.GetCount() > 0 && pBlip)
|
|
{
|
|
HighlightLegendItem(pBlip);
|
|
}
|
|
|
|
uiDebugf1("PAUSEMAP: ...Finished sending Legend to Actionscript");
|
|
}
|
|
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////////////
|
|
// NAME: CPauseMenu::UpdateLegendSlotWithNameAndColour
|
|
// PURPOSE: sets up colour and blip name to the legend item passed in
|
|
/////////////////////////////////////////////////////////////////////////////////////
|
|
void CMapMenu::UpdateLegendSlotWithNameAndColour(sMapLegendList *pLegendItem, CMiniMapBlip *pBlip, s32 iThisBlipCategory)
|
|
{
|
|
if (!pLegendItem)
|
|
return;
|
|
|
|
if (!pBlip)
|
|
return;
|
|
|
|
bool bCentreBlip = (CMiniMap::GetUniqueBlipUsed(pBlip) == CMiniMap::GetUniqueCentreBlipId());
|
|
|
|
if (pLegendItem->bActive) // only actually add it if its an active item - if its inactive, we skip it and when its flagged as active again the legend is re-populated
|
|
{
|
|
char cUpdatedString[MAX_BLIP_NAME_SIZE * 2];
|
|
|
|
switch (iThisBlipCategory)
|
|
{
|
|
case BLIP_CATEGORY_PLAYER:
|
|
{
|
|
s32 iDistToOtherPlayer = 0;
|
|
|
|
CEntity* pEntity = CMiniMap::FindBlipEntity(pBlip);
|
|
CVehicle* pLocalPlayerVehicle = CGameWorld::FindLocalPlayerVehicle();
|
|
|
|
// If we're in the same vehicle, keep distance 0
|
|
bool bInSameVehicle = pLocalPlayerVehicle != NULL && pEntity && pEntity->GetIsTypePed() && static_cast<CPed*>(pEntity)->GetVehiclePedInside() == pLocalPlayerVehicle;
|
|
if (!bInSameVehicle)
|
|
{
|
|
|
|
|
|
Vector3 vPlayerBlipPos = CMiniMap::GetPlayerBlipPosition();
|
|
Vector3 vOtherBlipPos = CMiniMap::GetBlipPositionValue(pBlip);
|
|
|
|
iDistToOtherPlayer = (s32)rage::round(vPlayerBlipPos.Dist(vOtherBlipPos));
|
|
}
|
|
|
|
bool bBlipNameContainsHtml = false;
|
|
if (strstr(CMiniMap::GetBlipNameValue(pBlip), "<FONT")
|
|
&& strstr(CMiniMap::GetBlipNameValue(pBlip), "</FONT>"))
|
|
{ // Lowrider Bug 2534692 - the Beast blip name passed from script looks like this
|
|
// <FONT FACE='$Font2_cond_NOT_GAMERNAME' SIZE='15'>~a~</FONT> with the translated word Beast inserted where the ~a~ is.
|
|
// The ActionScript doesn't try to parse HTML within <C>...</C> so don't add those tags if the string already contains the FONT tags.
|
|
bBlipNameContainsHtml = true;
|
|
}
|
|
|
|
if (CFrontendStatsMgr::ShouldUseMetric())
|
|
{
|
|
formatf(cUpdatedString, "%s: %s%s%s (%dm)", TheText.Get("BLIP_OTHPLYR"), bBlipNameContainsHtml?"":"<C>", CMiniMap::GetBlipNameValue(pBlip), bBlipNameContainsHtml?"":"</C>", iDistToOtherPlayer);
|
|
}
|
|
else
|
|
{
|
|
formatf(cUpdatedString, "%s: %s%s%s (%.0fft)", TheText.Get("BLIP_OTHPLYR"), bBlipNameContainsHtml?"":"<C>", CMiniMap::GetBlipNameValue(pBlip), bBlipNameContainsHtml?"":"</C>", METERS_TO_FEET(iDistToOtherPlayer));
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
case BLIP_CATEGORY_PROPERTY:
|
|
{
|
|
formatf(cUpdatedString, "%s: %s", TheText.Get("BLIP_PROPCAT"), CMiniMap::GetBlipNameValue(pBlip));
|
|
break;
|
|
}
|
|
|
|
case BLIP_CATEGORY_APARTMENT:
|
|
{
|
|
formatf(cUpdatedString, "%s: %s", TheText.Get("BLIP_APARTCAT"), CMiniMap::GetBlipNameValue(pBlip));
|
|
break;
|
|
}
|
|
|
|
case BLIP_CATEGORY_WAYPOINT:
|
|
{
|
|
Vector3 vPlayerBlipPos = CMiniMap::GetPlayerBlipPosition();
|
|
Vector3 vWaypointBlipPos = CMiniMap::GetBlipPositionValue(pBlip);
|
|
s32 iDistToWaypoint = (s32)rage::round(vPlayerBlipPos.Dist(vWaypointBlipPos));
|
|
if (CFrontendStatsMgr::ShouldUseMetric())
|
|
{
|
|
formatf(cUpdatedString, "%s (%dm)", CMiniMap::GetBlipNameValue(pBlip), iDistToWaypoint);
|
|
}
|
|
else
|
|
{
|
|
formatf(cUpdatedString, "%s (%.0fft)", CMiniMap::GetBlipNameValue(pBlip), METERS_TO_FEET(iDistToWaypoint));
|
|
}
|
|
break;
|
|
}
|
|
|
|
default:
|
|
{
|
|
if (bCentreBlip)
|
|
{
|
|
if (!NetworkInterface::IsGameInProgress())
|
|
{
|
|
formatf(cUpdatedString, "%s", TheText.Get("BLIP_PLAYER"));
|
|
}
|
|
else
|
|
{
|
|
formatf(cUpdatedString, "<C>%s</C>", CMiniMap::GetBlipNameValue(pBlip), NELEM(cUpdatedString));
|
|
}
|
|
}
|
|
else
|
|
{
|
|
formatf(cUpdatedString, "%s", CMiniMap::GetBlipNameValue(pBlip));
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
CTextConversion::TextToHtml(cUpdatedString, pLegendItem->cBlipName, NELEM(pLegendItem->cBlipName));
|
|
|
|
if (CMiniMap::GetBlipColourValue(pBlip) != BLIP_COLOUR_USE_COLOUR32)
|
|
{
|
|
pLegendItem->blipColour = CMiniMap_Common::GetColourFromBlipSettings(CMiniMap::GetBlipColourValue(pBlip), CMiniMap::IsFlagSet(pBlip,BLIP_FLAG_BRIGHTNESS));
|
|
}
|
|
else
|
|
{
|
|
pLegendItem->blipColour = CMiniMap::GetBlipColour32Value(pBlip);
|
|
}
|
|
|
|
if (CMiniMap::GetBlipTypeValue(pBlip) == BLIP_TYPE_RADIUS || CMiniMap::GetBlipTypeValue(pBlip) == BLIP_TYPE_AREA) // 1531781 - if it is a radius blip then send actionscript the radar_level blip instead
|
|
{
|
|
safecpy(pLegendItem->cBlipObjectName, "radar_level", NELEM(pLegendItem->cBlipObjectName));
|
|
}
|
|
else
|
|
{
|
|
safecpy(pLegendItem->cBlipObjectName, CMiniMap::GetBlipObjectName(pBlip), NELEM(pLegendItem->cBlipObjectName));
|
|
}
|
|
|
|
pLegendItem->iBlipObjectId = CMiniMap::GetBlipObjectNameId(pBlip);
|
|
}
|
|
}
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////////////
|
|
// NAME: CPauseMenu::SetWaypoint
|
|
// PURPOSE: sets a waypoint
|
|
/////////////////////////////////////////////////////////////////////////////////////
|
|
void CMapMenu::SetWaypoint(bool KEYBOARD_MOUSE_ONLY(bUseMousePos) /* = false */)
|
|
{
|
|
if (CanSetWaypoint())
|
|
{
|
|
Vector2 CursorPos( CMiniMap::GetPauseMapCursor() );
|
|
#if KEYBOARD_MOUSE_SUPPORT
|
|
if( bUseMousePos )
|
|
{
|
|
CursorPos = GetWorldPosFromScreen(m_vscrMousePosOnClick.x, m_vscrMousePosOnClick.y);
|
|
}
|
|
#endif
|
|
|
|
ObjectId BlipObjectId = NETWORK_INVALID_OBJECT_ID;
|
|
|
|
s32 IdToUse = KEYBOARD_MOUSE_ONLY(bUseMousePos ? m_iBlipMouseCurrentlyHoverOverUniqueId.Get() : ) m_iBlipCurrentlyHoveredOverUniqueId.Get();
|
|
if (IdToUse!=INVALID_BLIP_ID) // if we are already locked to a selected blip, then do not toggle on/off, set the new waypoint direct to this blip,
|
|
{
|
|
// prefer the blip's actual locked position if it's currently hovered over.
|
|
if( CMiniMapBlip* pHoverBlip = CMiniMap::GetBlip(IdToUse) )
|
|
{
|
|
Vector3 hoverBlipPos(CMiniMap::GetBlipPositionValue(pHoverBlip));
|
|
CursorPos.Set(hoverBlipPos.x, hoverBlipPos.y);
|
|
|
|
if (netObject* pNetObj = NetworkUtils::GetNetworkObjectFromEntity(CMiniMap::FindBlipEntity(pHoverBlip)))
|
|
{
|
|
BlipObjectId = pNetObj->GetObjectID();
|
|
}
|
|
}
|
|
|
|
if (CMiniMap::IsWaypointActive())
|
|
{
|
|
CMiniMapBlip *pWaypointBlip = CMiniMap::GetBlip(CMiniMap::GetActiveWaypointId());
|
|
Vector3 vCurrentWaypointPos(CMiniMap::GetBlipPositionValue(pWaypointBlip));
|
|
|
|
if (CursorPos.x != vCurrentWaypointPos.x || CursorPos.y != vCurrentWaypointPos.y) // unless its the same blip as the waypoint is currently set on
|
|
{
|
|
uiDisplayf("CMapMenu::SetWaypoint - Clearing Waypoint from the place I can never make it hit.");
|
|
CMiniMap::SwitchOffWaypoint();
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!CMiniMap::IsWaypointActive())
|
|
{
|
|
Vector3 vCentreBlipPos(CMiniMap::GetBlipPositionValue(CMiniMap::GetBlipFromActualId(CMiniMap::GetActualCentreBlipId())));
|
|
if (CursorPos.x != vCentreBlipPos.x || CursorPos.y != vCentreBlipPos.y) // ensure a waypoint is never placed ontop of the player icon
|
|
{
|
|
g_FrontendAudioEntity.PlaySound("WAYPOINT_SET", "HUD_FRONTEND_DEFAULT_SOUNDSET");
|
|
|
|
CMiniMap::SwitchOnWaypoint(CursorPos.x, CursorPos.y, BlipObjectId, false); // AdamF wants the waypoint to be visible
|
|
ResetCornerBlipInfo(true, false);
|
|
KEYBOARD_MOUSE_ONLY( if(!bUseMousePos || s_bMapMovesOnWaypoint ) )
|
|
{
|
|
CheckCursorOverBlip(CursorPos, true, false, true);
|
|
}
|
|
sm_vPreviousCursorPos = -CursorPos;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
uiDisplayf("CMapMenu::SetWaypoint - Clearing Waypoint normally");
|
|
CMiniMap::SwitchOffWaypoint();
|
|
}
|
|
}
|
|
else
|
|
{
|
|
uiDisplayf("PAUSEMAP: Tried to set a waypoint but couldn't due to CMapMenu::CanSetWaypoint() returning false");
|
|
}
|
|
}
|
|
|
|
#if KEYBOARD_MOUSE_SUPPORT
|
|
bool CMapMenu::IsMouseOverMap() const
|
|
{
|
|
if( CPauseMenu::GetMouseHoverIndex() != -1 || CMousePointer::IsMouseRolledOverInstructionalButtons() )
|
|
return false;
|
|
|
|
Vector2 mousePosNorm( m_vscrLastMousePos.x / GRCDEVICE.GetWidth(), m_vscrLastMousePos.y / GRCDEVICE.GetHeight() );
|
|
fwRect mon = GRCDEVICE.GetMonitorConfig().getLandscapeMonitor().getArea();
|
|
return mon.IsInside(mousePosNorm);
|
|
}
|
|
|
|
bool CMapMenu::UpdateMouseClicksAndPosition(Vector2& vNewMapPos)
|
|
{
|
|
const CControl& controls = CControlMgr::GetMainFrontendControl();
|
|
|
|
bool bAllowControllerPanning = true;
|
|
|
|
Vector2 vscrMousePos((float)ioMouse::GetX(), (float)ioMouse::GetY());
|
|
|
|
// check for hovering state
|
|
if( m_vscrLastMousePos != vscrMousePos )
|
|
{
|
|
s32 iUnderMouseActualId = FindActualBlipIdNearPos(GetWorldPosFromScreen(vscrMousePos.x, vscrMousePos.y));
|
|
if( iUnderMouseActualId != INVALID_ACTUAL_ID )
|
|
{
|
|
if( CMiniMapBlip* pBlip = CMiniMap::GetBlipFromActualId(iUnderMouseActualId) )
|
|
{
|
|
m_iBlipMouseCurrentlyHoverOverUniqueId = CMiniMap::GetUniqueBlipUsed(pBlip);
|
|
}
|
|
else
|
|
{
|
|
m_iBlipMouseCurrentlyHoverOverUniqueId.Reset();
|
|
}
|
|
}
|
|
else
|
|
{
|
|
m_iBlipMouseCurrentlyHoverOverUniqueId.Reset();
|
|
}
|
|
}
|
|
|
|
|
|
if( controls.GetCursorAccept().IsDown() && IsMouseOverMap() )
|
|
{
|
|
bAllowControllerPanning = false;
|
|
|
|
if( controls.GetCursorAccept().WasUp() )
|
|
{
|
|
m_bClickedWithoutDragging = true;
|
|
m_iBlipClickedOnUniqueId = m_iBlipMouseCurrentlyHoverOverUniqueId.Get();
|
|
|
|
// first click or we've clicked further away from the last time
|
|
if( m_uFirstClickTime == 0 || vscrMousePos.Dist2(m_vscrMousePosOnClick) >= MOUSE_DRAG_DIST_SQRD )
|
|
{
|
|
m_uFirstClickTime = fwTimer::GetSystemTimeInMilliseconds();
|
|
m_vscrMousePosOnClick = vscrMousePos;
|
|
}
|
|
// second click and we're within the window for a proper double click
|
|
else if( (fwTimer::GetSystemTimeInMilliseconds() - m_uFirstClickTime) <= MOUSE_DBL_CLICK_TIME)
|
|
{
|
|
// double click time!
|
|
HandleClickAction(true);
|
|
|
|
}
|
|
m_vwrldMouseMovement.Zero();
|
|
}
|
|
|
|
// check if they've moved the mouse outside of our wiggle room for clicks
|
|
if( !m_bClickedWithoutDragging || vscrMousePos.Dist2(m_vscrMousePosOnClick) >= MOUSE_DRAG_DIST_SQRD )
|
|
{
|
|
m_bClickedWithoutDragging = false;
|
|
// once they've moved the mouse, we can switch to grab
|
|
CMousePointer::SetMouseCursorStyle(MOUSE_CURSOR_STYLE_HAND_GRAB);
|
|
// we can't trust ioMouse's GetDX() for this because it ends up not matching the cursor's live display
|
|
|
|
|
|
// check for ability to drag a blip
|
|
|
|
bool bBlipDragged = false;
|
|
if( m_iBlipClickedOnUniqueId != INVALID_BLIP_ID )
|
|
{
|
|
if( CMiniMapBlip* pHoveredBlip = CMiniMap::GetBlip(m_iBlipClickedOnUniqueId) )
|
|
{
|
|
Vector2 vWorldPos( GetWorldPosFromScreen((float)ioMouse::GetX(), (float)ioMouse::GetY() ));
|
|
// dragging waypoint
|
|
if( m_iBlipClickedOnUniqueId == CMiniMap::GetActiveWaypointId() )
|
|
{
|
|
bBlipDragged = CMiniMap::SetActiveWaypoint(vWorldPos);
|
|
}
|
|
// dragging POI
|
|
else if(CMiniMap::GetBlipObjectNameId(pHoveredBlip) == RADAR_TRACE_POI)
|
|
{
|
|
bBlipDragged = true;
|
|
CMiniMap::SetBlipParameter(BLIP_CHANGE_POSITION, m_iBlipClickedOnUniqueId, Vector3(vWorldPos.x, vWorldPos.y, 1.0f));
|
|
}
|
|
}
|
|
|
|
if( bBlipDragged && !m_bWasBlipDragging )
|
|
{
|
|
g_FrontendAudioEntity.PlaySound("WAYPOINT_MOUSE_CLICK", "HUD_FRONTEND_DEFAULT_SOUNDSET");
|
|
m_bWasBlipDragging = true;
|
|
}
|
|
}
|
|
|
|
// if dragging a blip, check for push scrolling
|
|
if( bBlipDragged )
|
|
{
|
|
bAllowControllerPanning = true;
|
|
Vector2 vpctMousePos( vscrMousePos.x / SCREEN_WIDTH, vscrMousePos.y / SCREEN_HEIGHT);
|
|
float fSafeZone = 1.0f-CHudTools::GetSafeZoneSize();
|
|
// divide by the aspect ratio so that it's the same pixel size for the edges of the screen
|
|
if( vpctMousePos.x <= fSafeZone + (MOUSE_PUSH_GUTTER_PCT / CHudTools::GetAspectRatio() )) vNewMapPos.x -= CMiniMap_Common::GetScrollSpeedFromZoomLevel(sm_iCurrentZoomLevel);
|
|
else if( vpctMousePos.x >= 1.0f-(fSafeZone + (MOUSE_PUSH_GUTTER_PCT / CHudTools::GetAspectRatio() ))) vNewMapPos.x += CMiniMap_Common::GetScrollSpeedFromZoomLevel(sm_iCurrentZoomLevel);
|
|
|
|
if( vpctMousePos.y <= fSafeZone + MOUSE_PUSH_GUTTER_PCT ) vNewMapPos.y += CMiniMap_Common::GetScrollSpeedFromZoomLevel(sm_iCurrentZoomLevel);
|
|
else if( vpctMousePos.y >= 1.0f-(fSafeZone + MOUSE_PUSH_GUTTER_PCT )) vNewMapPos.y -= CMiniMap_Common::GetScrollSpeedFromZoomLevel(sm_iCurrentZoomLevel);
|
|
}
|
|
else
|
|
{
|
|
GPointF mouseDelta( vscrMousePos.x - m_vscrLastMousePos.x, vscrMousePos.y - m_vscrLastMousePos.y);
|
|
m_vwrldMouseMovement = GetWorldPosFromScreen(mouseDelta.x, mouseDelta.y, false);
|
|
|
|
vNewMapPos -= m_vwrldMouseMovement;
|
|
}
|
|
}
|
|
}
|
|
else // not holding or over buttons
|
|
{
|
|
CMousePointer::SetMouseCursorStyle(MOUSE_CURSOR_STYLE_ARROW);
|
|
|
|
if( m_bWasBlipDragging )
|
|
{
|
|
g_FrontendAudioEntity.PlaySound("WAYPOINT_MOUSE_DROP", "HUD_FRONTEND_DEFAULT_SOUNDSET");
|
|
m_bWasBlipDragging = false;
|
|
}
|
|
|
|
// time out a single click
|
|
if( m_bClickedWithoutDragging &&
|
|
m_uFirstClickTime && (fwTimer::GetSystemTimeInMilliseconds() - m_uFirstClickTime) > MOUSE_DBL_CLICK_TIME)
|
|
{
|
|
HandleClickAction(false);
|
|
}
|
|
|
|
|
|
// not dragging, check if we have any momentum
|
|
if(m_vwrldMouseMovement.Mag2() > (__STICK_THRESHOLD*__STICK_THRESHOLD))
|
|
{
|
|
bAllowControllerPanning = false;
|
|
|
|
m_vwrldMouseMovement = Lerp( MOUSE_FLICK_DECAY_RATE * fwTimer::GetTimeStep_NonPausedNonScaledClipped(), m_vwrldMouseMovement, Vector2(0.0f, 0.0f));
|
|
vNewMapPos -= m_vwrldMouseMovement;
|
|
}
|
|
else
|
|
{
|
|
m_vwrldMouseMovement.Zero();
|
|
}
|
|
}
|
|
|
|
m_vscrLastMousePos = vscrMousePos;
|
|
|
|
return bAllowControllerPanning;
|
|
}
|
|
|
|
void CMapMenu::HandleClickAction(bool bIsDoubleClick)
|
|
{
|
|
m_uFirstClickTime = 0u;
|
|
|
|
if( bIsDoubleClick == s_bCenterOnSingleClick )
|
|
{
|
|
PlaceWaypoint(true);
|
|
}
|
|
else if( m_iBlipClickedOnUniqueId != INVALID_BLIP_ID )
|
|
{
|
|
if( CMiniMapBlip* pBlip = CMiniMap::GetBlip(m_iBlipClickedOnUniqueId) )
|
|
{
|
|
SetCurrentBlipHover( CMiniMap::GetActualBlipUsed(pBlip), true, true);
|
|
g_FrontendAudioEntity.PlaySound("TOGGLE_ON","HUD_FRONTEND_DEFAULT_SOUNDSET");
|
|
}
|
|
}
|
|
}
|
|
|
|
void CMapMenu::UpdateMouseWheelZoom(float& fLeftShoulder, float& fRightShoulder)
|
|
{
|
|
const s32 sMouseWheel = ioMouse::GetDZ();
|
|
m_fMouseWheelMovement = Clamp( m_fMouseWheelMovement + sMouseWheel * MOUSE_WHEEL_SCALAR, -1.0f, 1.0f);
|
|
|
|
if( IsMouseOverMap()
|
|
&& !Approach(m_fMouseWheelMovement, 0.0f, MOUSE_WHEEL_DECAY_RATE, fwTimer::GetTimeStep_NonPausedNonScaledClipped())
|
|
&& fabsf(m_fMouseWheelMovement) >= __STICK_THRESHOLD ) // this is here because the zoom function gates on it
|
|
{
|
|
// mouse wheel zooming in
|
|
if(m_fMouseWheelMovement > 0.0f)
|
|
{
|
|
fLeftShoulder = 0.0f;
|
|
fRightShoulder = QuarticEaseInOut(m_fMouseWheelMovement); // easing to make it feel good
|
|
}
|
|
else
|
|
{
|
|
// zooming out
|
|
fLeftShoulder = QuarticEaseInOut(-m_fMouseWheelMovement);
|
|
fRightShoulder = 0.0f;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
m_fMouseWheelMovement = 0.0f;
|
|
// if the mouse is hovering over the legend, allow mouse scrolling
|
|
if( CPauseMenu::GetMouseHoverIndex() != -1 )
|
|
{
|
|
if( CMousePointer::IsMouseWheelUp() )
|
|
CPauseMenu::GetMovieWrapper(PAUSE_MENU_MOVIE_CONTENT).CallMethod( "SET_INPUT_EVENT", PAD_DPADUP );
|
|
|
|
else if( CMousePointer::IsMouseWheelDown() )
|
|
CPauseMenu::GetMovieWrapper(PAUSE_MENU_MOVIE_CONTENT).CallMethod( "SET_INPUT_EVENT", PAD_DPADDOWN );
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
#endif // KEYBOARD_MOUSE_SUPPORT
|
|
|
|
#if __BANK
|
|
void CMapMenu::AddWidgets(bkBank* pBank)
|
|
{
|
|
atString name("PauseMap Bank: ");
|
|
name += m_Owner.MenuScreen.GetParserName();
|
|
m_pMyGroup = pBank->PushGroup(name);
|
|
{
|
|
|
|
pBank->AddSlider("CURRENT ZOOM LEVEL", &sm_iCurrentZoomLevel, ZOOM_LEVEL_START, MAX_ZOOM_LEVELS, 0);
|
|
pBank->AddText("Blip Previous Hovering", &sm_iPreviousHoverActualId);
|
|
pBank->AddText("Blip For Mission Creator", &sm_iCurrentSelectedMissionCreatorUniqueId);
|
|
pBank->AddButton("Reinit Menu", datCallback(CFA(CMapMenu::ReloadMap)));
|
|
#if KEYBOARD_MOUSE_SUPPORT
|
|
pBank->AddText("Blip Clicked On", &m_iBlipClickedOnUniqueId);
|
|
pBank->AddText("Blip Hovering", m_iBlipMouseCurrentlyHoverOverUniqueId.GetPtr());
|
|
pBank->PushGroup("PC Tune");
|
|
{
|
|
const char* pszaEaseNames[] = {
|
|
"Linear",
|
|
"Quadratic In",
|
|
"Quadratic Out",
|
|
"Quadratic InOut",
|
|
"Cubic In",
|
|
"Cubic Out",
|
|
"Cubic InOut",
|
|
"Quartic In",
|
|
"Quartic Out",
|
|
"Quartic InOut",
|
|
"Sine In",
|
|
"Sine Out",
|
|
"Sine InOut",
|
|
"Back In",
|
|
"Back Out",
|
|
"Back InOut",
|
|
"Circular In",
|
|
"Circular Out",
|
|
"Circular InOut"
|
|
};
|
|
|
|
pBank->AddToggle("Map Moves on Waypoint Creation", &s_bMapMovesOnWaypoint);
|
|
pBank->AddToggle("Switch Single Click (Focus) and Double Click (Waypoint) actions", &s_bCenterOnSingleClick);
|
|
pBank->AddSlider("MOUSE_WHEEL_DECAY_RATE", &MOUSE_WHEEL_DECAY_RATE, 0.f, 10.f, 0.1f);
|
|
pBank->AddSlider("MOUSE_WHEEL_SCALAR", &MOUSE_WHEEL_SCALAR, 0.f, 10.f, 0.1f);
|
|
pBank->AddSlider("MOUSE_FLICK_DECAY_RATE", &MOUSE_FLICK_DECAY_RATE, 0.f, 1000.f, 0.1f);
|
|
pBank->AddSlider("MOUSE_ZOOM_SPEED_FAR", &MOUSE_ZOOM_SPEED_FAR, 0.f, 1000.f, 0.1f);
|
|
pBank->AddSlider("MOUSE_ZOOM_SPEED_NEAR", &MOUSE_ZOOM_SPEED_NEAR, 0.f, 1000.f, 0.1f);
|
|
pBank->AddSlider("MOUSE_DRAG_DIST_SQRD (Pixels^2)", &MOUSE_DRAG_DIST_SQRD, 0.f, 5000.f, 5.0f);
|
|
pBank->AddSlider("MOUSE_DRAG_SOUND_SCREEN_PIXELS_SQRD (Pixels^2)", &MOUSE_DRAG_SOUND_SCREEN_PIXELS_SQRD, 0.f, 5000.f, 5.0f);
|
|
pBank->AddSlider("MAX_SOUNDVAR_VALUE", &MAX_SOUNDVAR_VALUE, 0.f, 500.f, 5.0f);
|
|
|
|
pBank->AddSlider("MOUSE_DBL_CLICK_TIME (ms)", &MOUSE_DBL_CLICK_TIME, 0, 1000, 25);
|
|
pBank->AddSlider("MAP_SNAP_PAN_SPEED (ms)", &MAP_SNAP_PAN_SPEED, 0, 5000, 25);
|
|
pBank->AddSlider("MAP_FIRST_PAN_DELAY (ms)",&MAP_FIRST_PAN_DELAY, 0, 5000, 25);
|
|
pBank->AddSlider("MAP_SPAM_PAN_DELAY (ms)", &MAP_SPAM_PAN_DELAY, 0, 5000, 25);
|
|
pBank->AddSlider("MOUSE_PUSH_GUTTER_PCT", &MOUSE_PUSH_GUTTER_PCT, 0.0f, 1.0f, 0.01f);
|
|
pBank->AddCombo("LERP TYPE", &s_LERP_METHOD, COUNTOF(pszaEaseNames), pszaEaseNames);
|
|
}
|
|
pBank->PopGroup();
|
|
#endif
|
|
}
|
|
pBank->PopGroup();
|
|
}
|
|
|
|
#endif
|
|
|
|
|