etqw-sdk/source/game/Waypoints/LocationMarker.cpp

483 lines
13 KiB
C++

// Copyright (C) 2007 Id Software, Inc.
//
#include "../precompiled.h"
#pragma hdrstop
#if defined( _DEBUG ) && !defined( ID_REDIRECT_NEWDELETE )
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
#include "LocationMarker.h"
#include "../Player.h"
#include "../CommandMapInfo.h"
#include "../WorldSpawn.h"
#include "../roles/WayPointManager.h"
/*
===============================================================================
sdLocationMarker
===============================================================================
*/
idCVar g_showCommandMapNames( "g_showCommandMapNames", "0", CVAR_BOOL | CVAR_GAME, "Show/hide location text on the commandmap" );
idCVar g_showLocationWayPoints( "g_showLocationWayPoints", "2", CVAR_INTEGER | CVAR_GAME, "Show/hide location waypoints in the world" );
CLASS_DECLARATION( idEntity, sdLocationMarker )
END_CLASS
idStaticList< locationInfo_t, sdLocationMarker::MAX_LOCATIONS > sdLocationMarker::s_locations;
idStaticList< locationInfo_t*, sdLocationMarker::MAX_LOCATIONS > sdLocationMarker::s_exteriorLocations;
idStaticList< locationInfo_t*, sdLocationMarker::MAX_LOCATIONS > sdLocationMarker::s_interiorLocations;
idList< int > sdLocationMarker::s_areaCollapse;
idList< locationInfo_t* > sdLocationMarker::s_areaLocations;
const sdDeclLocStr* sdLocationMarker::s_locationTextMissing;
const sdDeclLocStr* sdLocationMarker::s_locationTextRange;
sdLocationMarker::sdLocationCVarCallback sdLocationMarker::s_callback;
sdLocationMarker::sdWayPointCVarCallback sdLocationMarker::s_callback2;
compassDirection_t sdLocationMarker::s_compassDirections[ 8 ];
/*
==============
sdLocationMarker::sdLocationMarker
==============
*/
sdLocationMarker::sdLocationMarker( void ) {
}
/*
==============
sdLocationMarker::Spawn
==============
*/
void sdLocationMarker::Spawn( void ) {
locationInfo_t& info = *s_locations.Alloc();
if ( &info == NULL ) {
gameLocal.Error( "sdLocationMarker::Spawn No Free Locations" );
}
info.origin = GetPhysics()->GetOrigin();
if ( spawnArgs.GetBool( "interior" ) ) {
s_interiorLocations.Append( &info );
} else {
s_exteriorLocations.Append( &info );
}
if ( spawnArgs.GetBool( "commandmap" ) ) {
info.commandMapName = declHolder.declLocStrType.LocalFind( spawnArgs.GetString( "commandmap_name" ) );
} else {
info.commandMapName = NULL;
}
if ( spawnArgs.GetBool( "waypoint" ) ) {
info.waypointMaterial = gameLocal.declMaterialType[ spawnArgs.GetString( "mtr_waypoint" ) ];
} else {
info.waypointMaterial = NULL;
}
info.locationName = declHolder.declLocStrType.LocalFind( spawnArgs.GetString( "location_name" ) );
info.minRange = spawnArgs.GetFloat( "range_min" );
info.maxRange = spawnArgs.GetFloat( "range_max" );
info.nextInArea = NULL;
info.commandMapHandle = -1;
info.font = spawnArgs.GetString( "font" );
info.textScale = spawnArgs.GetFloat( "text_scale" );
info.wayPoint = NULL;
PostEventMS( &EV_Remove, 0 );
}
/*
==============
sdLocationMarker::OnNewMapLoad
==============
*/
void sdLocationMarker::OnNewMapLoad( void ) {
Clear();
g_showCommandMapNames.RegisterCallback( &s_callback );
g_showLocationWayPoints.RegisterCallback( &s_callback2 );
}
/*
==============
sdLocationMarker::OnMapClear
==============
*/
void sdLocationMarker::OnMapClear( bool all ) {
Clear();
if ( !all ) {
g_showCommandMapNames.RegisterCallback( &s_callback );
g_showLocationWayPoints.RegisterCallback( &s_callback2 );
}
}
/*
==============
sdLocationMarker::Clear
==============
*/
void sdLocationMarker::Clear( void ) {
g_showCommandMapNames.UnRegisterCallback( &s_callback );
g_showLocationWayPoints.UnRegisterCallback( &s_callback2 );
FreeCommandMapIcons();
FreeWayPoints();
s_locations.SetNum( 0 );
s_exteriorLocations.SetNum( 0 );
s_interiorLocations.SetNum( 0 );
s_areaCollapse.SetNum( 0, false );
s_areaLocations.SetNum( 0, false );
}
/*
==============
sdLocationMarker::FreeCommandMapIcon
==============
*/
void sdLocationMarker::FreeCommandMapIcon( locationInfo_t& info ) {
if ( info.commandMapHandle == -1 ) {
return;
}
sdCommandMapInfoManager::GetInstance().Free( info.commandMapHandle );
info.commandMapHandle = -1;
}
/*
==============
sdLocationMarker::CreateCommandMapIcon
==============
*/
void sdLocationMarker::CreateCommandMapIcon( locationInfo_t& info ) {
if ( info.commandMapHandle != -1 ) {
return;
}
if ( info.commandMapName == NULL ) {
return;
}
info.commandMapHandle = sdCommandMapInfoManager::GetInstance().Alloc( gameLocal.world, 100 );
sdCommandMapInfo* cm = sdCommandMapInfoManager::GetInstance().GetInfo( info.commandMapHandle );
if ( cm != NULL ) {
cm->SetOrigin( info.origin.ToVec2() );
cm->SetDrawMode( sdCommandMapInfo::DM_TEXT );
cm->SetColor( colorWhite );
cm->SetFlag( sdCommandMapInfo::CMF_ALWAYSKNOWN | sdCommandMapInfo::CMF_ONLYSHOWONFULLVIEW );
cm->SetPositionMode( sdCommandMapInfo::PM_FIXED );
cm->SetColorMode( sdCommandMapInfo::CM_NORMAL );
cm->SetFont( info.font.c_str() );
cm->SetTextScale( info.textScale );
cm->SetText( info.commandMapName->GetText() );
}
}
/*
==============
sdLocationMarker::OnMapStart
==============
*/
void sdLocationMarker::OnMapStart( void ) {
int numAreas = gameRenderWorld->NumAreas();
s_areaCollapse.SetNum( numAreas, false );
for ( int i = 0; i < numAreas; i++ ) {
int j;
for ( j = 0; j < i; j++ ) {
if ( gameRenderWorld->AreasAreConnected( j, i, PORTAL_OUTSIDE ) ) {
s_areaCollapse[ i ] = s_areaCollapse[ j ];
break;
}
}
if ( j == i ) {
s_areaCollapse[ i ] = s_areaLocations.Num();
s_areaLocations.Alloc() = NULL;
}
}
for ( int i = 0; i < s_interiorLocations.Num(); i++ ) {
locationInfo_t& loc = *s_interiorLocations[ i ];
int baseArea = gameRenderWorld->PointInArea( loc.origin );
if ( baseArea == -1 ) {
gameLocal.Warning( "sdLocationMarker::OnMapStart Interior Location '%ls' Is Not in an Area", loc.locationName->GetText() );
continue;
}
int indirect = s_areaCollapse[ baseArea ];
loc.nextInArea = s_areaLocations[ indirect ];
s_areaLocations[ indirect ] = &loc;
}
OnShowMarkersChanged();
OnShowWayPointsChanged();
s_locationTextMissing = declHolder.declLocStrType.LocalFind( "game/location/missing" );
s_locationTextRange = declHolder.declLocStrType.LocalFind( "game/location/range" );
float angle = idMath::Sqrt( 0.5f );
s_compassDirections[ 0 ].dir = idVec2( 0.f, 1.f );
s_compassDirections[ 0 ].name = declHolder.declLocStrType.LocalFind( "game/location/direction/N" );
s_compassDirections[ 1 ].dir = idVec2( angle, angle );
s_compassDirections[ 1 ].name = declHolder.declLocStrType.LocalFind( "game/location/direction/NE" );
s_compassDirections[ 2 ].dir = idVec2( 1.f, 0.f );
s_compassDirections[ 2 ].name = declHolder.declLocStrType.LocalFind( "game/location/direction/E" );
s_compassDirections[ 3 ].dir = idVec2( angle, -angle );
s_compassDirections[ 3 ].name = declHolder.declLocStrType.LocalFind( "game/location/direction/SE" );
s_compassDirections[ 4 ].dir = idVec2( 0.f, -1.f );
s_compassDirections[ 4 ].name = declHolder.declLocStrType.LocalFind( "game/location/direction/S" );
s_compassDirections[ 5 ].dir = idVec2( -angle, -angle );
s_compassDirections[ 5 ].name = declHolder.declLocStrType.LocalFind( "game/location/direction/SW" );
s_compassDirections[ 6 ].dir = idVec2( -1.f, 0.f );
s_compassDirections[ 6 ].name = declHolder.declLocStrType.LocalFind( "game/location/direction/W" );
s_compassDirections[ 7 ].dir = idVec2( -angle, angle );
s_compassDirections[ 7 ].name = declHolder.declLocStrType.LocalFind( "game/location/direction/NW" );
}
/*
==============
sdLocationMarker::LocationForPosition
==============
*/
locationInfo_t* sdLocationMarker::LocationForPosition( const idVec3& position ) {
int baseArea = gameRenderWorld->PointInArea( position );
if ( baseArea != -1 ) {
int indirect = s_areaCollapse[ baseArea ];
locationInfo_t* loc = s_areaLocations[ indirect ];
if ( loc != NULL ) {
locationInfo_t* bestLoc = NULL;
float bestDist = -1;
for ( locationInfo_t* testLoc = loc; testLoc != NULL; testLoc = testLoc->nextInArea ) {
float dist = ( testLoc->origin - position ).LengthSqr();
if ( dist > Square( testLoc->maxRange ) ) {
continue;
}
if ( dist < bestDist || bestLoc == NULL ) {
bestLoc = testLoc;
bestDist = dist;
}
}
if ( bestLoc != NULL ) {
return bestLoc;
}
}
}
locationInfo_t* bestLoc = NULL;
float bestDist = -1;
for ( int i = 0; i < s_exteriorLocations.Num(); i++ ) {
locationInfo_t* testLoc = s_exteriorLocations[ i ];
float dist = ( testLoc->origin - position ).LengthSqr();
if ( dist > Square( testLoc->maxRange ) ) {
continue;
}
if ( dist < bestDist || bestLoc == NULL ) {
bestLoc = testLoc;
bestDist = dist;
}
}
return bestLoc;
}
/*
==============
sdLocationMarker::DebugDraw
==============
*/
void sdLocationMarker::DebugDraw( const idVec3& position ) {
locationInfo_t* loc = LocationForPosition( position );
for ( int i = 0; i < s_locations.Num(); i++ ) {
gameRenderWorld->DebugBounds( loc == &s_locations[ i ] ? colorGreen : colorRed, idBounds( idSphere( s_locations[ i ].origin, 16 ) ) );
}
idPlayer* localPlayer = gameLocal.GetLocalPlayer();
if ( localPlayer != NULL ) {
if ( loc != NULL ) {
idWStr text;
GetLocationText( position, text );
gameRenderWorld->DrawText( va( "%ls", text.c_str() ), loc->origin, 0.25f, colorWhite, localPlayer->renderView.viewaxis );
}
}
}
/*
==============
sdLocationMarker::GetLocationText
==============
*/
void sdLocationMarker::GetLocationText( const idVec3& position, idWStr& text ) {
locationInfo_t* info = LocationForPosition( position );
if ( info == NULL ) {
text = s_locationTextMissing->GetText();
return;
}
idVec3 diff = position - info->origin;
float range = diff.LengthFast();
if ( range < info->minRange ) {
text = info->locationName->GetText();
} else {
idVec2 diff2D = diff.ToVec2();
int best = -1;
float bestDist = 0.f;
for ( int i = 0; i < 8; i++ ) {
float temp = diff2D * s_compassDirections[ i ].dir;
if ( temp > bestDist || best == -1 ) {
bestDist = temp;
best = i;
}
}
idWStrList list;
list.Append( va( L"%d", ( int )InchesToMetres( bestDist ) ) );
list.Append( s_compassDirections[ best ].name->GetText() );
list.Append( info->locationName->GetText() );
text = common->LocalizeText( s_locationTextRange, list );
}
}
/*
==============
sdLocationMarker::OnShowMarkersChanged
==============
*/
void sdLocationMarker::OnShowMarkersChanged( void ) {
if ( g_showCommandMapNames.GetBool() ) {
CreateCommandMapIcons();
} else {
FreeCommandMapIcons();
}
}
/*
==============
sdLocationMarker::OnShowWayPointsChanged
==============
*/
void sdLocationMarker::OnShowWayPointsChanged( void ) {
if ( g_showLocationWayPoints.GetInteger() == 1 ) {
CreateWayPoints();
} else {
FreeWayPoints();
}
}
/*
==============
sdLocationMarker::CreateWayPoint
==============
*/
void sdLocationMarker::CreateWayPoint( locationInfo_t& info ) {
if ( info.wayPoint != NULL ) {
return;
}
if ( info.waypointMaterial == NULL ) {
return;
}
info.wayPoint = sdWayPointManager::GetInstance().AllocWayPoint();
info.wayPoint->SetBracketed( false );
info.wayPoint->SetMinRange( info.minRange );
info.wayPoint->SetRange( info.maxRange );
info.wayPoint->SetMaterial( info.waypointMaterial );
info.wayPoint->SetOrigin( info.origin );
info.wayPoint->SetText( info.locationName->GetText() );
}
/*
==============
sdLocationMarker::FreeWayPoint
==============
*/
void sdLocationMarker::FreeWayPoint( locationInfo_t& info ) {
if ( info.wayPoint == NULL ) {
return;
}
sdWayPointManager::GetInstance().FreeWayPoint( info.wayPoint );
info.wayPoint = NULL;
}
/*
==============
sdLocationMarker::FreeCommandMapIcons
==============
*/
void sdLocationMarker::FreeCommandMapIcons( void ) {
for ( int i = 0; i < s_locations.Num(); i++ ) {
FreeCommandMapIcon( s_locations[ i ] );
}
}
/*
==============
sdLocationMarker::FreeWayPoints
==============
*/
void sdLocationMarker::FreeWayPoints( void ) {
for ( int i = 0; i < s_locations.Num(); i++ ) {
FreeWayPoint( s_locations[ i ] );
}
}
/*
==============
sdLocationMarker::CreateCommandMapIcons
==============
*/
void sdLocationMarker::CreateCommandMapIcons( void ) {
for ( int i = 0; i < s_locations.Num(); i++ ) {
CreateCommandMapIcon( s_locations[ i ] );
}
}
/*
==============
sdLocationMarker::CreateWayPoints
==============
*/
void sdLocationMarker::CreateWayPoints( void ) {
for ( int i = 0; i < s_locations.Num(); i++ ) {
CreateWayPoint( s_locations[ i ] );
}
}
/*
==============
sdLocationMarker::ShowLocations
==============
*/
void sdLocationMarker::ShowLocations( bool value ) {
if ( g_showLocationWayPoints.GetInteger() == 2 ) {
if ( value ) {
CreateWayPoints();
} else {
FreeWayPoints();
}
}
}