Modified source engine (2017) developed by valve and leaked in 2020. Not for commercial purporses
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.
 
 
 
 
 
 

271 lines
7.2 KiB

#include "LevelTheme.h"
#include "KeyValues.h"
#include "RoomTemplate.h"
#include "filesystem.h"
#include "TagList.h"
// memdbgon must be the last include file in a .cpp file!!!
#include <tier0/memdbgon.h>
ExitDirection_t GetDirectionFromString( const char *pDirectionString )
{
if ( Q_stricmp( pDirectionString, "north" ) == 0 )
{
return EXITDIR_NORTH;
}
else if ( Q_stricmp( pDirectionString, "south" ) == 0 )
{
return EXITDIR_SOUTH;
}
else if ( Q_stricmp( pDirectionString, "east" ) == 0 )
{
return EXITDIR_EAST;
}
else if ( Q_stricmp( pDirectionString, "west" ) == 0 )
{
return EXITDIR_WEST;
}
return EXITDIR_END;
}
CRoomTemplate::CRoomTemplate( CLevelTheme* pLevelTheme ) :
m_pLevelTheme( pLevelTheme ),
m_nSpawnWeight( 0 ),
m_nTilesX( 1 ),
m_nTilesY( 1 )
{
m_FullName[0] = '\0';
m_SubFolder[0] = '\0';
m_TemplateName[0] = '\0';
m_Description[0] = '\0';
m_Soundscape[0] = '\0';
m_nTileType = ASW_TILETYPE_UNKNOWN;
}
CRoomTemplate::~CRoomTemplate()
{
m_Exits.PurgeAndDeleteElements();
}
void CRoomTemplate::LoadFromKeyValues( const char *pRoomName, KeyValues *pKeyValues )
{
m_nTilesX = pKeyValues->GetInt( "TilesX", 1 );
m_nTilesY = pKeyValues->GetInt( "TilesY", 1 );
SetSpawnWeight( pKeyValues->GetInt( "SpawnWeight", MIN_SPAWN_WEIGHT ) );
SetFullName( pRoomName );
Q_strncpy( m_Description, pKeyValues->GetString( "RoomTemplateDescription", "" ), m_nMaxDescriptionLength );
Q_strncpy( m_Soundscape, pKeyValues->GetString( "Soundscape", "" ), m_nMaxSoundscapeLength );
SetTileType( pKeyValues->GetInt( "TileType", ASW_TILETYPE_UNKNOWN ) );
m_Tags.RemoveAll();
// search through all the exit subsections
KeyValues *pkvSubSection = pKeyValues->GetFirstSubKey();
bool bClearedExits = false;
while ( pkvSubSection )
{
// mission details
if ( Q_stricmp(pkvSubSection->GetName(), "EXIT")==0 )
{
if ( !bClearedExits )
{
// if we haven't cleared previous exits yet then do so now
m_Exits.PurgeAndDeleteElements();
bClearedExits = true;
}
CRoomTemplateExit *pExit = new CRoomTemplateExit();
pExit->m_iXPos = pkvSubSection->GetInt("XPos");
pExit->m_iYPos = pkvSubSection->GetInt("YPos");
pExit->m_ExitDirection = (ExitDirection_t) pkvSubSection->GetInt("ExitDirection");
pExit->m_iZChange = pkvSubSection->GetInt("ZChange");
Q_strncpy( pExit->m_szExitTag, pkvSubSection->GetString( "ExitTag" ), sizeof( pExit->m_szExitTag ) );
pExit->m_bChokepointGrowSource = !!pkvSubSection->GetInt("ChokeGrow", 0);
// discard exits outside the room bounds
if ( pExit->m_iXPos < 0 || pExit->m_iYPos < 0 || pExit->m_iXPos >= m_nTilesX || pExit->m_iYPos >= m_nTilesY )
{
delete pExit;
}
else
{
m_Exits.AddToTail(pExit);
}
}
else if ( Q_stricmp(pkvSubSection->GetName(), "Tags")==0 && TagList() )
{
for ( KeyValues *sub = pkvSubSection->GetFirstSubKey(); sub != NULL; sub = sub->GetNextKey() )
{
if ( !Q_stricmp( sub->GetName(), "tag" ) )
{
AddTag( sub->GetString() );
}
}
}
pkvSubSection = pkvSubSection->GetNextKey();
}
}
bool CRoomTemplate::SaveRoomTemplate()
{
if (!m_pLevelTheme)
return false;
char szThemeDirName[MAX_PATH];
Q_snprintf(szThemeDirName, sizeof(szThemeDirName), "tilegen/roomtemplates/%s", m_pLevelTheme->m_szName);
g_pFullFileSystem->CreateDirHierarchy( szThemeDirName, "GAME" );
char szFullFileName[MAX_PATH];
Q_snprintf( szFullFileName, sizeof(szFullFileName), "tilegen/roomtemplates/%s/%s.roomtemplate", m_pLevelTheme->m_szName, m_FullName );
KeyValues *pRoomTemplateKeyValues = new KeyValues( m_FullName );
pRoomTemplateKeyValues->SetInt( "TilesX", m_nTilesX );
pRoomTemplateKeyValues->SetInt( "TilesY", m_nTilesY );
pRoomTemplateKeyValues->SetInt( "SpawnWeight", m_nSpawnWeight );
pRoomTemplateKeyValues->SetString( "RoomTemplateDescription", m_Description );
pRoomTemplateKeyValues->SetString( "Soundscape", m_Soundscape );
pRoomTemplateKeyValues->SetInt( "TileType", m_nTileType );
// exits
int iExits = m_Exits.Count();
for (int i=0;i<iExits;i++)
{
KeyValues *pkvSubSection = new KeyValues("EXIT");
pkvSubSection->SetInt("XPos", m_Exits[i]->m_iXPos);
pkvSubSection->SetInt("YPos", m_Exits[i]->m_iYPos);
pkvSubSection->SetInt("ExitDirection", (int) m_Exits[i]->m_ExitDirection);
pkvSubSection->SetInt("ZChange", m_Exits[i]->m_iZChange);
pkvSubSection->SetString("ExitTag", m_Exits[i]->m_szExitTag);
pkvSubSection->SetBool("ChokeGrow", m_Exits[i]->m_bChokepointGrowSource);
pRoomTemplateKeyValues->AddSubKey(pkvSubSection);
}
// tags
KeyValues *pkvSubSection = new KeyValues("Tags");
for ( int i=0;i<GetNumTags();i++ )
{
pkvSubSection->AddSubKey( new KeyValues( "tag", NULL, GetTag( i ) ) );
}
pRoomTemplateKeyValues->AddSubKey(pkvSubSection);
if (!pRoomTemplateKeyValues->SaveToFile(g_pFullFileSystem, szFullFileName, "GAME"))
{
Msg("Error: Failed to save room template %s\n", szFullFileName);
return false;
}
return true;
}
void CRoomTemplate::SetFullName( const char *pFullName )
{
Q_strncpy( m_FullName, pFullName, MAX_PATH );
Q_StripExtension( m_FullName, m_FullName, MAX_PATH );
Q_FixSlashes( m_FullName );
Q_ExtractFilePath( m_FullName, m_SubFolder, MAX_PATH );
Q_AppendSlash( m_SubFolder, MAX_PATH );
Q_strncpy( m_TemplateName, m_FullName + Q_strlen( m_SubFolder ), MAX_PATH );
}
void CRoomTemplate::SetDescription( const char *pDescription )
{
Q_strncpy( m_Description, pDescription, m_nMaxDescriptionLength );
}
void CRoomTemplate::SetSoundscape( const char *pSoundscape )
{
Q_strncpy( m_Soundscape, pSoundscape, m_nMaxSoundscapeLength );
}
void CRoomTemplateExit::GetExitOffset( ExitDirection_t Direction, int *pX, int *pY )
{
switch ( Direction )
{
case EXITDIR_NORTH: *pX = 0; *pY = -1; break;
case EXITDIR_EAST: *pX = 1; *pY = 0; break;
case EXITDIR_SOUTH: *pX = 0; *pY = 1; break;
case EXITDIR_WEST: *pX = -1; *pY = 0; break;
default: break;
}
}
ExitDirection_t CRoomTemplateExit::GetOppositeDirection( ExitDirection_t Direction )
{
switch (Direction)
{
case EXITDIR_NORTH: return EXITDIR_SOUTH; break;
case EXITDIR_EAST: return EXITDIR_WEST; break;
case EXITDIR_SOUTH: return EXITDIR_NORTH; break;
case EXITDIR_WEST: return EXITDIR_EAST; break;
default: break;
}
return EXITDIR_NORTH;
}
bool CRoomTemplate::IsStartRoom() const
{
return HasTag( "Start" );
}
bool CRoomTemplate::IsEscapeRoom() const
{
return HasTag( "Escape" );
}
bool CRoomTemplate::IsBorderRoom() const
{
return HasTag( "Border" );
}
bool CRoomTemplate::ShouldOnlyPlaceByRequest() const
{
return HasTag( "Special" ) || HasTag( "Start" ) || HasTag( "Escape" );
}
bool CRoomTemplate::HasTag( const char* szTag ) const
{
for ( int i=0;i<m_Tags.Count();i++ )
{
if ( !Q_stricmp( m_Tags[i], szTag ) )
{
return true;
}
}
return false;
}
bool CRoomTemplate::AddTag( const char *szTag )
{
if ( !TagList() )
return false;
// check it's a valid tag
const char *pszFoundTag = TagList()->FindTag( szTag );
if ( !pszFoundTag )
return false;
// check we don't have it already
if ( HasTag( pszFoundTag ) )
return false;
m_Tags.AddToTail( pszFoundTag );
return true;
}
bool CRoomTemplate::RemoveTag( const char *szTag )
{
if ( !TagList() )
return false;
for ( int i=0;i<m_Tags.Count();i++ )
{
if ( !Q_stricmp( m_Tags[i], szTag ) )
{
m_Tags.Remove( i );
return true;
}
}
return false;
}