You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
640 lines
18 KiB
640 lines
18 KiB
#include "MapLayout.h" |
|
#include "Room.h" |
|
#include "ChunkFile.h" |
|
#include "RoomTemplate.h" |
|
#include "KeyValues.h" |
|
#include "LevelTheme.h" |
|
#include "asw_spawn_selection.h" |
|
#include "asw_mission_chooser.h" |
|
|
|
// memdbgon must be the last include file in a .cpp file!!! |
|
#include <tier0/memdbgon.h> |
|
|
|
CInstanceSpawn::CInstanceSpawn() : |
|
m_InstanceSpawningMethod( ISM_INVALID ), |
|
m_nPlacedRoomIndex( -1 ) |
|
{ |
|
m_InstanceFilename[0] = '\0'; |
|
} |
|
|
|
void CInstanceSpawn::FixupValues( const char *pFindValue, const char *pReplaceValue ) |
|
{ |
|
for ( int i = 0; i < m_AdditionalKeyValues.Count(); ++ i ) |
|
{ |
|
if ( Q_stristr( m_AdditionalKeyValues[i].m_Value, pFindValue ) != NULL ) |
|
{ |
|
char outputString[MAX_TILEGEN_IDENTIFIER_LENGTH]; |
|
Q_StrSubst( m_AdditionalKeyValues[i].m_Value, pFindValue, pReplaceValue, outputString, MAX_TILEGEN_IDENTIFIER_LENGTH ); |
|
Q_strncpy( m_AdditionalKeyValues[i].m_Value, outputString, MAX_TILEGEN_IDENTIFIER_LENGTH ); |
|
} |
|
} |
|
} |
|
|
|
bool CInstanceSpawn::LoadFromKeyValues( KeyValues *pKeyValues ) |
|
{ |
|
const char *pFilename = pKeyValues->GetString( "filename", NULL ); |
|
if ( pFilename == NULL ) |
|
{ |
|
Log_Warning( LOG_TilegenLayoutSystem, "No 'filename' specified in CInstanceSpawn block.\n" ); |
|
return false; |
|
} |
|
Q_strncpy( m_InstanceFilename, pFilename, _countof( m_InstanceFilename ) ); |
|
|
|
const char *pType = pKeyValues->GetString( "type", NULL ); |
|
if ( pType == NULL ) |
|
{ |
|
Log_Warning( LOG_TilegenLayoutSystem, "No 'type' specified in CInstanceSpawn block.\n" ); |
|
return false; |
|
} |
|
else |
|
{ |
|
if ( Q_stricmp( pType, "add_at_random_node" ) == 0 ) |
|
{ |
|
m_InstanceSpawningMethod = ISM_ADD_AT_RANDOM_NODE; |
|
} |
|
else |
|
{ |
|
Log_Warning( LOG_TilegenLayoutSystem, "Invalid 'type' specified in CInstanceSpaw block.\n" ); |
|
return false; |
|
} |
|
} |
|
|
|
m_nPlacedRoomIndex = pKeyValues->GetInt( "room_index", -1 ); |
|
m_nRandomSeed = pKeyValues->GetInt( "random_seed", 0 ); |
|
|
|
for ( KeyValues *pReplaceKV = pKeyValues->GetFirstSubKey(); pReplaceKV != NULL; pReplaceKV = pReplaceKV->GetNextKey() ) |
|
{ |
|
if ( Q_stricmp( pReplaceKV->GetName(), "key_value" ) == 0 ) |
|
{ |
|
const char *pKey = pReplaceKV->GetString( "key", "" ); |
|
const char *pValue = pReplaceKV->GetString( "value", "" ); |
|
|
|
int nIndex = m_AdditionalKeyValues.AddToTail(); |
|
Q_strncpy( m_AdditionalKeyValues[nIndex].m_Key, pKey, MAX_TILEGEN_IDENTIFIER_LENGTH ); |
|
Q_strncpy( m_AdditionalKeyValues[nIndex].m_Value, pValue, MAX_TILEGEN_IDENTIFIER_LENGTH ); |
|
} |
|
} |
|
|
|
return true; |
|
} |
|
|
|
void CInstanceSpawn::SaveToKeyValues( KeyValues *pKeyValues ) const |
|
{ |
|
pKeyValues->SetString( "filename", m_InstanceFilename ); |
|
switch ( m_InstanceSpawningMethod ) |
|
{ |
|
case ISM_ADD_AT_RANDOM_NODE: |
|
pKeyValues->SetString( "type", "add_at_random_node" ); |
|
break; |
|
default: |
|
Log_Warning( LOG_TilegenLayoutSystem, "Invalid instance spawning method (%d).\n", m_InstanceSpawningMethod ); |
|
} |
|
|
|
pKeyValues->SetInt( "room_index", m_nPlacedRoomIndex ); |
|
pKeyValues->SetInt( "random_seed", m_nRandomSeed ); |
|
|
|
for ( int i = 0; i < m_AdditionalKeyValues.Count(); ++ i ) |
|
{ |
|
KeyValues *pNewReplacement = new KeyValues( "key_value" ); |
|
pNewReplacement->SetString( "key", m_AdditionalKeyValues[i].m_Key ); |
|
pNewReplacement->SetString( "value", m_AdditionalKeyValues[i].m_Value ); |
|
pKeyValues->AddSubKey( pNewReplacement ); |
|
} |
|
} |
|
|
|
CMapLayout::CMapLayout( KeyValues *pGenerationOptions ) : |
|
m_pGenerationOptions( pGenerationOptions ) |
|
{ |
|
SetCurrentFilename(""); |
|
|
|
m_iPlayerStartTileX = MAP_LAYOUT_TILES_WIDE * 0.5f; |
|
m_iPlayerStartTileY = MAP_LAYOUT_TILES_WIDE * 0.5f; |
|
|
|
// clear our pointer grid |
|
for (int y=0;y<MAP_LAYOUT_TILES_WIDE;y++) |
|
{ |
|
for (int x=0;x<MAP_LAYOUT_TILES_WIDE;x++) |
|
{ |
|
m_pRoomGrid[x][y] = NULL; |
|
} |
|
} |
|
} |
|
|
|
CMapLayout::~CMapLayout() |
|
{ |
|
// todo: clear any 'currently selected rooms', etc |
|
Clear(); |
|
|
|
if ( m_pGenerationOptions != NULL ) |
|
{ |
|
m_pGenerationOptions->deleteThis(); |
|
} |
|
} |
|
|
|
void CMapLayout::Clear() |
|
{ |
|
// delete all placed rooms |
|
int iRooms = m_PlacedRooms.Count(); |
|
for (int i=iRooms-1;i>=0;i--) |
|
{ |
|
CRoom *pRoom = m_PlacedRooms[i]; |
|
delete pRoom; // destructor removes it from the list |
|
} |
|
m_LogicalRooms.RemoveAll(); |
|
m_InstanceSpawns.RemoveAll(); |
|
m_Encounters.PurgeAndDeleteElements(); |
|
|
|
// wipe the grid |
|
for (int x=0;x<MAP_LAYOUT_TILES_WIDE;x++) |
|
{ |
|
for (int y=0;y<MAP_LAYOUT_TILES_WIDE;y++) |
|
{ |
|
m_pRoomGrid[x][y] = NULL; |
|
} |
|
} |
|
|
|
m_iPlayerStartTileX = MAP_LAYOUT_TILES_WIDE * 0.5f; |
|
m_iPlayerStartTileY = MAP_LAYOUT_TILES_WIDE * 0.5f; |
|
} |
|
|
|
void CMapLayout::SetGenerationOptions( KeyValues *pNewGenerationOptions ) |
|
{ |
|
if ( m_pGenerationOptions ) |
|
{ |
|
m_pGenerationOptions->deleteThis(); |
|
} |
|
|
|
m_pGenerationOptions = pNewGenerationOptions; |
|
} |
|
|
|
bool CMapLayout::SaveMapLayout( const char *filename ) |
|
{ |
|
KeyValues *pLayoutKeys = new KeyValues( "Layout" ); |
|
|
|
if ( m_pGenerationOptions ) |
|
{ |
|
pLayoutKeys->AddSubKey( m_pGenerationOptions->MakeCopy() ); |
|
} |
|
|
|
KeyValues *pMiscKeys = new KeyValues( "mapmisc" ); |
|
pMiscKeys->SetInt( "PlayerStartX", m_iPlayerStartTileX ); |
|
pMiscKeys->SetInt( "PlayerStartY", m_iPlayerStartTileY ); |
|
pLayoutKeys->AddSubKey( pMiscKeys ); |
|
|
|
// save out each room |
|
int iRooms = m_PlacedRooms.Count(); |
|
for (int i=0;i<iRooms;i++) |
|
{ |
|
CRoom *pRoom = m_PlacedRooms[i]; |
|
if (!pRoom) |
|
continue; |
|
|
|
pLayoutKeys->AddSubKey( pRoom->GetKeyValuesCopy() ); |
|
} |
|
// save out logical rooms |
|
iRooms = m_LogicalRooms.Count(); |
|
for (int i=0;i<iRooms;i++) |
|
{ |
|
KeyValues *pRoomKeys = new KeyValues( "logical_room" ); |
|
if ( m_LogicalRooms[i]->m_pLevelTheme ) |
|
{ |
|
pRoomKeys->SetString( "theme", m_LogicalRooms[i]->m_pLevelTheme->m_szName ); |
|
} |
|
pRoomKeys->SetString( "template", m_LogicalRooms[i]->GetFullName() ); |
|
pLayoutKeys->AddSubKey( pRoomKeys ); |
|
} |
|
|
|
for ( int i = 0; i < m_InstanceSpawns.Count(); ++ i ) |
|
{ |
|
KeyValues *pNewInstanceSpawn = new KeyValues( "instance_spawn" ); |
|
m_InstanceSpawns[i].SaveToKeyValues( pNewInstanceSpawn ); |
|
pLayoutKeys->AddSubKey( pNewInstanceSpawn ); |
|
} |
|
for ( int i = 0; i < m_Encounters.Count(); ++ i ) |
|
{ |
|
KeyValues *pEncounterKeys = new KeyValues( "npc_encounter" ); |
|
m_Encounters[i]->SaveToKeyValues( pEncounterKeys ); |
|
pLayoutKeys->AddSubKey( pEncounterKeys ); |
|
} |
|
|
|
CUtlBuffer buf( 0, 0, CUtlBuffer::TEXT_BUFFER ); |
|
for ( KeyValues *pKey = pLayoutKeys->GetFirstSubKey(); pKey; pKey = pKey->GetNextKey() ) |
|
{ |
|
pKey->RecursiveSaveToFile( buf, 0 ); |
|
} |
|
pLayoutKeys->deleteThis(); |
|
if ( !g_pFullFileSystem->WriteFile( filename, "GAME", buf ) ) |
|
{ |
|
Log_Warning( LOG_TilegenLayoutSystem, "Failed to SaveToFile %s\n", filename ); |
|
return false; |
|
} |
|
|
|
return true; |
|
} |
|
|
|
bool CMapLayout::LoadLogicalRoom( KeyValues *pRoomKeys ) |
|
{ |
|
char szLoadingTheme[256]; |
|
char szLoadingTemplate[256]; |
|
szLoadingTheme[0] = '\0'; |
|
szLoadingTemplate[0] = '\0'; |
|
|
|
Q_snprintf( szLoadingTheme, sizeof(szLoadingTheme), "%s", pRoomKeys->GetString( "theme" ) ); |
|
Q_snprintf( szLoadingTemplate, sizeof(szLoadingTemplate), "%s", pRoomKeys->GetString( "template" ) ); |
|
|
|
// find pointer to the room template |
|
// first find the theme with matching name |
|
int iThemes = CLevelTheme::s_LevelThemes.Count(); |
|
for (int i=0;i<iThemes;i++) |
|
{ |
|
CLevelTheme* pTheme = CLevelTheme::s_LevelThemes[i]; |
|
if (!pTheme) |
|
continue; |
|
if ( !Q_stricmp( pTheme->m_szName, szLoadingTheme ) ) |
|
{ |
|
// now find a template within that theme with our template's name |
|
int iTemplates = pTheme->m_RoomTemplates.Count(); |
|
for (int t=0;t<iTemplates;t++) |
|
{ |
|
if ( !Q_stricmp( pTheme->m_RoomTemplates[t]->GetFullName(), szLoadingTemplate ) ) |
|
{ |
|
m_LogicalRooms.AddToTail( pTheme->m_RoomTemplates[t] ); |
|
return true; |
|
} |
|
} |
|
break; |
|
} |
|
} |
|
return false; |
|
} |
|
|
|
bool CMapLayout::LoadMapLayout(const char *filename) |
|
{ |
|
// open our output layout file |
|
KeyValues *pLayoutKeys = new KeyValues( "LayoutKeys" ); |
|
if ( !pLayoutKeys->LoadFromFile( g_pFullFileSystem, filename, "GAME" ) ) |
|
{ |
|
//Msg( "Failed to load map layout %s\n", filename ); |
|
pLayoutKeys->deleteThis(); |
|
return false; |
|
} |
|
|
|
while ( pLayoutKeys ) |
|
{ |
|
if ( !Q_stricmp( pLayoutKeys->GetName(), "room" ) ) |
|
{ |
|
if ( !CRoom::LoadRoomFromKeyValues( pLayoutKeys, this ) ) |
|
return false; |
|
} |
|
else if ( !Q_stricmp( pLayoutKeys->GetName(), "logical_room" ) ) |
|
{ |
|
LoadLogicalRoom( pLayoutKeys ); |
|
} |
|
else if ( !Q_stricmp( pLayoutKeys->GetName(), "mapmisc" ) ) |
|
{ |
|
m_iPlayerStartTileX = pLayoutKeys->GetInt( "PlayerStartX" ); |
|
m_iPlayerStartTileY = pLayoutKeys->GetInt( "PlayerStartY" ); |
|
} |
|
else if ( Q_stricmp( pLayoutKeys->GetName(), "mission_settings" ) == 0 ) |
|
{ |
|
m_pGenerationOptions = pLayoutKeys->MakeCopy(); |
|
} |
|
else if ( Q_stricmp( pLayoutKeys->GetName(), "instance_spawn" ) == 0 ) |
|
{ |
|
m_InstanceSpawns[m_InstanceSpawns.AddToTail()].LoadFromKeyValues( pLayoutKeys ); |
|
} |
|
else if ( Q_stricmp( pLayoutKeys->GetName(), "npc_encounter" ) == 0 ) |
|
{ |
|
CASW_Encounter *pEncounter = new CASW_Encounter(); |
|
pEncounter->LoadFromKeyValues( pLayoutKeys ); |
|
m_Encounters.AddToTail( pEncounter ); |
|
} |
|
pLayoutKeys = pLayoutKeys->GetNextKey(); |
|
} |
|
|
|
MarkEncounterRooms(); |
|
|
|
SetCurrentFilename(filename); |
|
|
|
pLayoutKeys->deleteThis(); |
|
|
|
return true; |
|
} |
|
|
|
void CMapLayout::MarkEncounterRooms() |
|
{ |
|
// mark all rooms with alien encounters |
|
for ( int i = 0; i < m_Encounters.Count(); i++ ) |
|
{ |
|
CRoom *pRoom = GetRoom( m_Encounters[i]->GetEncounterPosition() ); |
|
if ( pRoom ) |
|
{ |
|
pRoom->SetHasAlienEncounter( true ); |
|
} |
|
} |
|
} |
|
|
|
void CMapLayout::SetCurrentFilename(const char *szFilename) |
|
{ |
|
Q_snprintf(m_szFilename, sizeof(m_szFilename), "%s", szFilename); |
|
} |
|
|
|
CRoom* CMapLayout::GetRoom( const Vector &vecPos ) |
|
{ |
|
int nX = ( vecPos.x / ASW_TILE_SIZE ) + MAP_LAYOUT_TILES_WIDE * 0.5f; |
|
int nY = ( vecPos.y / ASW_TILE_SIZE ) + MAP_LAYOUT_TILES_WIDE * 0.5f; |
|
if ( nX >= 0 && nX < MAP_LAYOUT_TILES_WIDE && nY >= 0 && nY < MAP_LAYOUT_TILES_WIDE ) |
|
{ |
|
return GetRoom( nX, nY ); |
|
} |
|
return NULL; |
|
} |
|
|
|
void CMapLayout::GetExtents(int &iTileX_Min, int &iTileX_Max, int &iTileY_Min, int &iTileY_Max) |
|
{ |
|
iTileX_Min = MAP_LAYOUT_TILES_WIDE-1; |
|
iTileY_Min = MAP_LAYOUT_TILES_WIDE-1; |
|
iTileX_Max = 0; |
|
iTileY_Max = 0; |
|
|
|
for (int i=0;i<m_PlacedRooms.Count();i++) |
|
{ |
|
CRoom* pRoom = m_PlacedRooms[i]; |
|
if (!pRoom) |
|
continue; |
|
|
|
if (pRoom->m_iPosX < iTileX_Min) |
|
iTileX_Min = pRoom->m_iPosX; |
|
if (pRoom->m_iPosY < iTileY_Min) |
|
iTileY_Min = pRoom->m_iPosY; |
|
if (pRoom->m_iPosX + pRoom->m_pRoomTemplate->GetTilesX() > iTileX_Max) |
|
iTileX_Max = pRoom->m_iPosX + pRoom->m_pRoomTemplate->GetTilesX(); |
|
if (pRoom->m_iPosY + pRoom->m_pRoomTemplate->GetTilesY() > iTileY_Max) |
|
iTileY_Max = pRoom->m_iPosY + pRoom->m_pRoomTemplate->GetTilesY(); |
|
} |
|
|
|
// don't return out of bounds |
|
if ( iTileX_Min < 0 ) |
|
iTileX_Min = 0; |
|
if ( iTileY_Min < 0 ) |
|
iTileY_Min = 0; |
|
if ( iTileX_Max >= MAP_LAYOUT_TILES_WIDE ) |
|
iTileX_Max = MAP_LAYOUT_TILES_WIDE - 1; |
|
if ( iTileY_Max >= MAP_LAYOUT_TILES_WIDE ) |
|
iTileY_Max = MAP_LAYOUT_TILES_WIDE - 1; |
|
} |
|
|
|
bool CMapLayout::SaveMiscMapProperties(CChunkFile *pFile) |
|
{ |
|
if (!pFile) |
|
return false; |
|
|
|
ChunkFileResult_t eResult = pFile->BeginChunk("mapmisc"); |
|
if (eResult != ChunkFile_Ok) |
|
return false; |
|
|
|
// write out the player start location |
|
if (pFile->WriteKeyValueInt("PlayerStartX", m_iPlayerStartTileX) != ChunkFile_Ok) |
|
return false; |
|
if (pFile->WriteKeyValueInt("PlayerStartY", m_iPlayerStartTileY) != ChunkFile_Ok) |
|
return false; |
|
|
|
if (pFile->EndChunk() != ChunkFile_Ok) |
|
return false; |
|
|
|
return true; |
|
} |
|
|
|
bool CMapLayout::RoomsOverlap( int x, int y, int w, int h, |
|
int x2, int y2, int w2, int h2 ) const |
|
{ |
|
if ( y + h <= y2 ) |
|
return false; |
|
if ( y2 + h2 <= y ) |
|
return false; |
|
|
|
if ( x + w <= x2 ) |
|
return false; |
|
if ( x2 + w2 <= x ) |
|
return false; |
|
|
|
return true; |
|
} |
|
|
|
bool CMapLayout::TemplateFits( const CRoomTemplate *pTemplate, int x, int y, bool bAllowNoExits ) const |
|
{ |
|
// check it's not out of bounds |
|
if ( x < 0 || y < 0 || x + pTemplate->GetTilesX() > MAP_LAYOUT_TILES_WIDE || y + pTemplate->GetTilesY() > MAP_LAYOUT_TILES_WIDE ) |
|
return false; |
|
|
|
// check for overlapping any existing rooms |
|
for (int j = 0 ; j < pTemplate->GetTilesX() ; j++) |
|
{ |
|
for (int k = 0 ; k < pTemplate->GetTilesY() ; k++) |
|
{ |
|
if (m_pRoomGrid[x+j][y+k]) |
|
return false; |
|
} |
|
} |
|
|
|
// if a template has no exits, assume it's a solid block used for capping and therefore fits anywhere |
|
if ( bAllowNoExits && pTemplate->m_Exits.Count() == 0 ) |
|
return true; |
|
|
|
// check for matching exits |
|
if ( !CheckExits( pTemplate, x, y ) ) |
|
return false; |
|
|
|
return true; |
|
} |
|
|
|
bool CMapLayout::CheckExits( const CRoomTemplate *pTemplate, int x, int y, CUtlVector< CRoomTemplateExit * > *pMatchingExits ) const |
|
{ |
|
int iRoomWide = pTemplate->GetTilesX(); |
|
int iRoomTall = pTemplate->GetTilesY(); |
|
|
|
// check exits of surrounding rooms match ours.. |
|
for (int k = 0; k < iRoomWide; k++) |
|
{ |
|
// check bottom |
|
if ( y > 0 && m_pRoomGrid[x + k][y - 1] != NULL ) |
|
{ |
|
if ( !CheckExitsOnSquares( pTemplate, k, iRoomTall - 1, EXITDIR_SOUTH, x + k, y - 1, false, pMatchingExits ) ) |
|
return false; |
|
} |
|
|
|
// check top |
|
if ( ( y + iRoomTall ) < MAP_LAYOUT_TILES_WIDE && m_pRoomGrid[x + k][y + iRoomTall] != NULL ) |
|
{ |
|
if ( !CheckExitsOnSquares( pTemplate, k, 0, EXITDIR_NORTH, x + k, y + iRoomTall, false, pMatchingExits ) ) |
|
return false; |
|
} |
|
} |
|
|
|
for (int j = 0; j < iRoomTall; j++) |
|
{ |
|
// check left |
|
if (x > 0 && m_pRoomGrid[x - 1][y + j] != NULL) |
|
{ |
|
if ( !CheckExitsOnSquares( pTemplate, 0, (iRoomTall - 1) - j, EXITDIR_WEST, x - 1, y + j, false, pMatchingExits ) ) |
|
return false; |
|
} |
|
// check right |
|
if ( ( x + iRoomWide ) < MAP_LAYOUT_TILES_WIDE && m_pRoomGrid[x + iRoomWide][y + j] != NULL ) |
|
{ |
|
if ( !CheckExitsOnSquares( pTemplate, iRoomWide - 1, (iRoomTall - 1) - j, EXITDIR_EAST, x + iRoomWide, y + j, false, pMatchingExits ) ) |
|
return false; |
|
} |
|
} |
|
return true; |
|
} |
|
|
|
// checks if these two squares match properly |
|
bool CMapLayout::CheckExitsOnSquares( const CRoomTemplate *pTemplate1, int offset_x, int offset_y, ExitDirection_t Direction, int x2, int y2, bool bRequireConnection, CUtlVector< CRoomTemplateExit * > *pMatchingExits ) const |
|
{ |
|
CRoom *pRoom2 = m_pRoomGrid[x2][y2]; |
|
Assert( pRoom2 ); |
|
const CRoomTemplate *pTemplate2 = pRoom2->m_pRoomTemplate; |
|
Assert( pTemplate2 ); |
|
|
|
// check if the roomtemplate to be placed has an exit facing this way |
|
CRoomTemplateExit *pTemplate1_Exit = NULL; |
|
for ( int i=0; i < pTemplate1->m_Exits.Count(); i++ ) |
|
{ |
|
if ( pTemplate1->m_Exits[i]->m_bChokepointGrowSource ) // never connect into a chokepoint grow source |
|
continue; |
|
if ( pTemplate1->m_Exits[i]->m_iXPos == offset_x && |
|
pTemplate1->m_Exits[i]->m_iYPos == offset_y && |
|
pTemplate1->m_Exits[i]->m_ExitDirection == Direction ) |
|
{ |
|
pTemplate1_Exit = pTemplate1->m_Exits[i]; |
|
break; |
|
} |
|
} |
|
|
|
// check if the already existing room has an exit facing the opposite way |
|
CRoomTemplateExit *pTemplate2_Exit = NULL; |
|
ExitDirection_t OppositeDirection = CRoomTemplateExit::GetOppositeDirection( Direction ); |
|
int offset_x2 = x2 - pRoom2->m_iPosX; |
|
int offset_y2 = (pTemplate2->GetTilesY()-1) - (y2 - pRoom2->m_iPosY); |
|
for ( int i=0; i < pTemplate2->m_Exits.Count(); i++ ) |
|
{ |
|
if ( pTemplate2->m_Exits[i]->m_iXPos == offset_x2 && |
|
pTemplate2->m_Exits[i]->m_iYPos == offset_y2 && |
|
pTemplate2->m_Exits[i]->m_ExitDirection == OppositeDirection ) |
|
{ |
|
pTemplate2_Exit = pTemplate2->m_Exits[i]; |
|
break; |
|
} |
|
} |
|
|
|
// matching exits |
|
if ( pTemplate1_Exit && pTemplate2_Exit |
|
&& !Q_stricmp( pTemplate1_Exit->m_szExitTag, pTemplate2_Exit->m_szExitTag ) ) // Make sure exit types are equal here |
|
{ |
|
if ( pMatchingExits ) |
|
pMatchingExits->AddToTail( pTemplate1_Exit ); |
|
return true; |
|
} |
|
|
|
// matching walls |
|
if ( !pTemplate1_Exit && !pTemplate2_Exit && !bRequireConnection ) |
|
return true; |
|
|
|
return false; |
|
} |
|
|
|
void CMapLayout::PlaceRoom( CRoom *pRoom ) |
|
{ |
|
Assert( pRoom ); |
|
pRoom->m_nPlacementIndex = m_PlacedRooms.AddToTail( pRoom ); |
|
pRoom->m_pMapLayout = this; |
|
|
|
if ( !pRoom->m_pRoomTemplate ) |
|
return; |
|
|
|
// fill in our pointer grid to easily access the croom later |
|
for (int x = pRoom->m_iPosX ; x < pRoom->m_iPosX + pRoom->m_pRoomTemplate->GetTilesX() ; x++) |
|
{ |
|
for (int y = pRoom->m_iPosY ; y < pRoom->m_iPosY + pRoom->m_pRoomTemplate->GetTilesY() ; y++) |
|
{ |
|
m_pRoomGrid[x][y] = pRoom; |
|
} |
|
} |
|
} |
|
|
|
void CMapLayout::RemoveRoom( CRoom *pRoom ) |
|
{ |
|
m_PlacedRooms.FindAndRemove( pRoom ); |
|
pRoom->m_pMapLayout = NULL; |
|
|
|
if ( !pRoom->m_pRoomTemplate ) |
|
return; |
|
|
|
// clear the pointer grid at the location of this room |
|
int iTileX = pRoom->m_iPosX; |
|
int iTileY = pRoom->m_iPosY; |
|
for ( int x = iTileX ; x < iTileX + pRoom->m_pRoomTemplate->GetTilesX() ; x++ ) |
|
{ |
|
for ( int y = iTileY ; y < iTileY + pRoom->m_pRoomTemplate->GetTilesY() ; y++ ) |
|
{ |
|
m_pRoomGrid[x][y] = NULL; |
|
} |
|
} |
|
} |
|
|
|
void CMapLayout::AddLogicalRoom( CRoomTemplate *pRoomTemplate ) |
|
{ |
|
if ( !pRoomTemplate ) |
|
return; |
|
|
|
m_LogicalRooms.AddToTail( pRoomTemplate ); |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// An NPC spawn encounter in the mission |
|
//----------------------------------------------------------------------------- |
|
|
|
void CASW_Encounter::AddSpawnDef( CASW_Spawn_Definition *pSpawnDef ) |
|
{ |
|
m_SpawnDefs.AddToTail( pSpawnDef ); |
|
} |
|
|
|
void CASW_Encounter::LoadFromKeyValues( KeyValues *pKeys ) |
|
{ |
|
m_SpawnDefs.Purge(); |
|
|
|
m_vecPosition.x = pKeys->GetFloat( "PosX" ); |
|
m_vecPosition.y = pKeys->GetFloat( "PosY" ); |
|
m_vecPosition.z = 0; |
|
m_flEncounterRadius = pKeys->GetFloat( "Radius" ); |
|
for ( KeyValues *pKey = pKeys->GetFirstSubKey(); pKey; pKey = pKey->GetNextKey() ) |
|
{ |
|
if ( !Q_stricmp( pKey->GetName(), "SpawnDef" ) ) |
|
{ |
|
CASW_Spawn_Definition* pSpawnDef = SpawnSelection()->GetSpawnDefByID( pKey->GetInt() ); |
|
if ( pSpawnDef ) |
|
{ |
|
m_SpawnDefs.AddToTail( pSpawnDef ); |
|
} |
|
else |
|
{ |
|
Msg( "Failed to load spawn def %d for encounter.\n", pKey->GetInt() ); |
|
} |
|
} |
|
} |
|
} |
|
|
|
void CASW_Encounter::SaveToKeyValues( KeyValues *pKeys ) |
|
{ |
|
pKeys->SetFloat( "PosX", m_vecPosition.x ); |
|
pKeys->SetFloat( "PosY", m_vecPosition.y ); |
|
//pKeys->SetFloat( "PosZ", m_vecPosition.z ); |
|
pKeys->SetFloat( "Radius", m_flEncounterRadius ); |
|
for ( int i = 0; i < m_SpawnDefs.Count(); i++ ) |
|
{ |
|
KeyValues *pSpawnKeys = new KeyValues( "SpawnDef" ); |
|
pSpawnKeys->SetInt( NULL, m_SpawnDefs[i]->GetID() ); |
|
pKeys->AddSubKey( pSpawnKeys ); |
|
} |
|
} |