1
0
mirror of https://github.com/alliedmodders/hl2sdk.git synced 2025-01-05 17:13:36 +08:00
2010-07-22 01:46:14 -05:00

553 lines
20 KiB
C++

//============ Copyright (c) Valve Corporation, All rights reserved. ============
//
// Definitions of many useful tilegen actions which can be executed
// sequentially by the layout system.
//
//===============================================================================
#ifndef TILEGEN_ACTIONS_H
#define TILEGEN_ACTIONS_H
#if defined( COMPILER_MSVC )
#pragma once
#endif
#include "tilegen_class_interfaces.h"
#include "tilegen_class_factories.h"
#include "tilegen_layout_system.h"
#include "MapLayout.h" // for StringReplace_t
class CLevelTheme;
//-----------------------------------------------------------------------------
// Recursively executes a conditional action.
//-----------------------------------------------------------------------------
class CTilegenAction_NestedActions : public ITilegenAction
{
public:
CTilegenAction_NestedActions();
~CTilegenAction_NestedActions();
virtual void OnBeginGeneration( CLayoutSystem *pLayoutSystem );
virtual void OnStateChanged( CLayoutSystem *pLayoutSystem );
virtual bool LoadFromKeyValues( KeyValues *pKeyValues );
virtual void Execute( CLayoutSystem *pLayoutSystem );
virtual const char *GetTypeName();
private:
CUtlVector< ActionConditionPair_t > m_NestedActions;
ITilegenExpression< bool > *m_pWhileCondition;
};
class CTilegenAction_SetVariable : public ITilegenAction
{
public:
CTilegenAction_SetVariable( ITilegenExpression< const char * > *pVariableName = NULL ) :
m_pVariableName( pVariableName ),
m_bFireOnBeginGeneration( false ),
m_bFireOnChangeState( false )
{
}
~CTilegenAction_SetVariable()
{
delete m_pVariableName;
}
virtual void OnBeginGeneration( CLayoutSystem *pLayoutSystem )
{
if ( m_bFireOnBeginGeneration )
{
InternalExecute( pLayoutSystem );
}
}
virtual void OnStateChanged( CLayoutSystem *pLayoutSystem )
{
if ( m_bFireOnChangeState )
{
InternalExecute( pLayoutSystem );
}
}
virtual bool LoadFromKeyValues( KeyValues *pKeyValues )
{
bool bSuccess = true;
bSuccess &= CreateExpressionFromKeyValuesBlock( pKeyValues, "variable", GetTypeName(), &m_pVariableName );
m_bFireOnBeginGeneration = pKeyValues->GetBool( "on_begin_generation", false );
m_bFireOnChangeState = pKeyValues->GetBool( "on_begin_state", false );
return bSuccess;
}
virtual void Execute( CLayoutSystem *pLayoutSystem )
{
if ( !m_bFireOnBeginGeneration && !m_bFireOnChangeState )
{
InternalExecute( pLayoutSystem );
}
}
protected:
virtual void InternalExecute( CLayoutSystem *pLayoutSystem ) = 0;
ITilegenExpression< const char * > *m_pVariableName;
// This indicates that the expressions should be evaluated & the variable set
// either exactly once (OnBeginGeneration) or every time the state containing the variable is transitioned to.
// If either is set, this action will be skipped during normal execution.
bool m_bFireOnBeginGeneration;
bool m_bFireOnChangeState;
};
//-----------------------------------------------------------------------------
// Sets a named free variable to the result of an expression
//-----------------------------------------------------------------------------
template< typename TVariableType >
class CTilegenAction_SetVariableT : public CTilegenAction_SetVariable
{
public:
CTilegenAction_SetVariableT( ITilegenExpression< const char * > *pVariableName = NULL, ITilegenExpression< TVariableType > *pExpression = NULL ) :
CTilegenAction_SetVariable( pVariableName ),
m_pExpression( pExpression )
{
}
~CTilegenAction_SetVariableT()
{
delete m_pExpression;
}
virtual bool LoadFromKeyValues( KeyValues *pKeyValues )
{
bool bSuccess = true;
bSuccess &= CTilegenAction_SetVariable::LoadFromKeyValues( pKeyValues );
bSuccess &= CreateExpressionFromKeyValuesBlock< TVariableType >( pKeyValues, "value", GetTypeName(), &m_pExpression );
return bSuccess;
}
protected:
virtual void InternalExecute( CLayoutSystem *pLayoutSystem )
{
const char *pVariableName = m_pVariableName->Evaluate( pLayoutSystem->GetFreeVariables() );
pLayoutSystem->GetFreeVariables()->SetOrCreateFreeVariable( pVariableName, ( void * )m_pExpression->Evaluate( pLayoutSystem->GetFreeVariables() ) );
}
ITilegenExpression< TVariableType > *m_pExpression;
};
class CTilegenAction_SetVariableInt : public CTilegenAction_SetVariableT< int >
{
public:
virtual const char *GetTypeName();
};
class CTilegenAction_SetVariableString : public CTilegenAction_SetVariableT< const char * >
{
public:
virtual const char *GetTypeName();
};
// This is somewhat tricky; this sets variables of type ITilegenExpression< bool > but otherwise behaves
// just like an instance of CTilegenAction_SetVariable< bool >, not CTilegenAction_SetVariable< ITilegenExpresion< bool > >.
class CTilegenAction_SetVariableBoolExpression : public CTilegenAction_SetVariableT< bool >
{
public:
virtual const char *GetTypeName();
protected:
virtual void InternalExecute( CLayoutSystem *pLayoutSystem )
{
const char *pVariableName = m_pVariableName->Evaluate( pLayoutSystem->GetFreeVariables() );
pLayoutSystem->GetFreeVariables()->SetOrCreateFreeVariable( pVariableName, m_pExpression );
}
};
class CTilegenAction_SetVariableAction : public CTilegenAction_SetVariable
{
public:
CTilegenAction_SetVariableAction( ITilegenExpression< const char * > *pVariableName = NULL, ITilegenAction *pAction = NULL ) :
CTilegenAction_SetVariable( pVariableName ),
m_pAction( pAction )
{
}
~CTilegenAction_SetVariableAction()
{
delete m_pAction;
}
virtual const char *GetTypeName();
virtual bool LoadFromKeyValues( KeyValues *pKeyValues )
{
bool bSuccess = true;
bSuccess &= CTilegenAction_SetVariable::LoadFromKeyValues( pKeyValues );
ITilegenExpression< bool > *pDummyCondition;
bSuccess &= CreateActionAndConditionFromKeyValuesBlock( pKeyValues, "value", GetTypeName(), &m_pAction, &pDummyCondition );
if ( pDummyCondition != NULL )
{
delete pDummyCondition;
Warning( "'CTilegenAction_SetVariableAction' cannot set actions which have associated conditions.\n" );
bSuccess = false;
}
return bSuccess;
}
protected:
virtual void InternalExecute( CLayoutSystem *pLayoutSystem )
{
const char *pVariableName = m_pVariableName->Evaluate( pLayoutSystem->GetFreeVariables() );
pLayoutSystem->GetFreeVariables()->SetOrCreateFreeVariable( pVariableName, m_pAction );
}
ITilegenAction *m_pAction;
};
//-----------------------------------------------------------------------------
// Builds up a list of room candidates from a given theme and set of open exits
// in the level. The list can be filtered with the specified filter class.
//-----------------------------------------------------------------------------
class CTilegenAction_AddRoomCandidates : public ITilegenAction
{
public:
//-----------------------------------------------------------------------------
// Generates room candidates based on allowed room templates and
// currently open exits.
//
// NOTE: the theme name expression is only evaluated once for performance
// reasons. We can always add a boolean value to control this behavior if
// something else is desired (unlikely).
//-----------------------------------------------------------------------------
CTilegenAction_AddRoomCandidates();
virtual ~CTilegenAction_AddRoomCandidates();
virtual bool LoadFromKeyValues( KeyValues *pKeyValues );
virtual const char *GetTypeName();
virtual void Execute( CLayoutSystem *pLayoutSystem );
private:
CLevelTheme *m_pLevelTheme;
ITilegenExpression< const char * > *m_pThemeNameExpression;
ITilegenExpression< bool > *m_pExitFilter;
ITilegenExpression< bool > *m_pRoomTemplateFilter;
ITilegenExpression< bool > *m_pRoomCandidateFilter;
ITilegenAction *m_pRoomCandidateFilterAction;
ITilegenExpression< bool > *m_pRoomCandidateFilterCondition;
bool m_bExcludeGlobalFilters;
};
//-----------------------------------------------------------------------------
// Builds up a list of room candidates from a given theme at a specific
// location (ignoring open exits).
//-----------------------------------------------------------------------------
class CTilegenAction_AddRoomCandidatesAtLocation : public ITilegenAction
{
public:
//-----------------------------------------------------------------------------
// Generates room candidates at the given location.
// NOTE: the theme name expression is only evaluated once for performance
// reasons. We can always add a boolean value to control this behavior if
// something else is desired (unlikely).
//-----------------------------------------------------------------------------
CTilegenAction_AddRoomCandidatesAtLocation(
ITilegenExpression< const char * > *pThemeNameExpression = NULL,
ITilegenExpression< int > *pXExpression = NULL,
ITilegenExpression< int > *pYExpression = NULL,
ITilegenExpression< bool > *pRoomTemplateFilter = NULL );
virtual ~CTilegenAction_AddRoomCandidatesAtLocation();
virtual bool LoadFromKeyValues( KeyValues *pKeyValues );
virtual const char *GetTypeName();
virtual void Execute( CLayoutSystem *pLayoutSystem );
private:
CLevelTheme *m_pLevelTheme;
ITilegenExpression< const char * > *m_pThemeNameExpression;
ITilegenExpression< int > *m_pXExpression;
ITilegenExpression< int > *m_pYExpression;
ITilegenExpression< bool > *m_pRoomTemplateFilter;
};
//-----------------------------------------------------------------------------
// Chooses a candidate at random from the room candidate list for the
// current iteration.
//-----------------------------------------------------------------------------
class CTilegenAction_ChooseCandidate : public ITilegenAction
{
public:
CTilegenAction_ChooseCandidate( bool bStopProcessingActionsOnSuccess = false ) : m_bStopProcessingActionsOnSuccess( bStopProcessingActionsOnSuccess ) { }
virtual bool LoadFromKeyValues( KeyValues *pKeyValues );
virtual const char *GetTypeName();
virtual void Execute( CLayoutSystem *pLayoutSystem );
private:
bool m_bStopProcessingActionsOnSuccess;
};
//-----------------------------------------------------------------------------
// Filters the candidate list by purging exitsmost strongly in a particular
// direction from the room candidate list for the current iteration.
//-----------------------------------------------------------------------------
class CTilegenAction_FilterCandidatesByDirection : public ITilegenAction
{
public:
CTilegenAction_FilterCandidatesByDirection(
ITilegenExpression< const char * > *pDirectionExpression = NULL,
ITilegenExpression< int > *pThresholdExpression = NULL );
~CTilegenAction_FilterCandidatesByDirection();
virtual bool LoadFromKeyValues( KeyValues *pKeyValues );
virtual const char *GetTypeName();
virtual void Execute( CLayoutSystem *pLayoutSystem );
private:
ITilegenExpression< const char * > *m_pDirectionExpression;
ITilegenExpression< int > *m_pThresholdExpression;
};
//-----------------------------------------------------------------------------
// Filters the candidate list by culling the list down to candidates
// with the fewest number of children, which encourages linear growth.
//-----------------------------------------------------------------------------
class CTilegenAction_FilterCandidatesForLinearGrowth : public ITilegenAction
{
public:
CTilegenAction_FilterCandidatesForLinearGrowth() { }
~CTilegenAction_FilterCandidatesForLinearGrowth() { }
virtual bool LoadFromKeyValues( KeyValues *pKeyValues );
virtual const char *GetTypeName();
virtual void Execute( CLayoutSystem *pLayoutSystem );
private:
ITilegenExpression< int > *m_pThresholdExpression;
};
//-----------------------------------------------------------------------------
// Switches the state machine's current state to the specified state.
//-----------------------------------------------------------------------------
class CTilegenAction_SwitchState : public ITilegenAction
{
public:
CTilegenAction_SwitchState();
~CTilegenAction_SwitchState();
virtual bool LoadFromKeyValues( KeyValues *pKeyValues );
virtual const char *GetTypeName();
virtual void Execute( CLayoutSystem *pLayoutSystem );
private:
// m_pNewStateExpression can be NULL, in which case, simply go to the next sequential state.
ITilegenExpression< const char * > *m_pNewStateExpression;
};
//-----------------------------------------------------------------------------
// Signals the end of level generation.
//-----------------------------------------------------------------------------
class CTilegenAction_FinishGeneration : public ITilegenAction
{
public:
CTilegenAction_FinishGeneration() { }
virtual bool LoadFromKeyValues( KeyValues *pKeyValues ) { return true; }
virtual const char *GetTypeName();
virtual void Execute( CLayoutSystem *pLayoutSystem );
};
//-----------------------------------------------------------------------------
// Signals a fatal error during level generation.
//-----------------------------------------------------------------------------
class CTilegenAction_EpicFail : public ITilegenAction
{
public:
CTilegenAction_EpicFail() { }
virtual bool LoadFromKeyValues( KeyValues *pKeyValues ) { return true; }
virtual const char *GetTypeName();
virtual void Execute( CLayoutSystem *pLayoutSystem );
};
class CTilegenAction_EnsureRoomExists : public ITilegenAction
{
public:
CTilegenAction_EnsureRoomExists() { }
virtual bool LoadFromKeyValues( KeyValues *pKeyValues );
virtual const char *GetTypeName();
virtual void Execute( CLayoutSystem *pLayoutSystem );
private:
ITilegenExpression< const char * > *m_pRoomNameExpression;
};
//-----------------------------------------------------------------------------
// Places a piece which assists in connecting to another piece.
//-----------------------------------------------------------------------------
class CTilegenAction_AddConnectorRoomCandidates : public ITilegenAction
{
public:
CTilegenAction_AddConnectorRoomCandidates( ITilegenAction *pAddRoomCandidates = NULL );
~CTilegenAction_AddConnectorRoomCandidates();
void SetRoomTemplate( const CRoomTemplate *pTargetRoomTemplate );
virtual bool LoadFromKeyValues( KeyValues *pKeyValues );
virtual const char *GetTypeName();
virtual void Execute( CLayoutSystem *pLayoutSystem );
private:
// Theme and room template filter to find the room we're trying to connect to.
CLevelTheme *m_pLevelTheme;
ITilegenExpression< const char * > *m_pTargetThemeNameExpression;
ITilegenExpression< bool > *m_pTargetRoomTemplateFilter;
// When instantiated programmatically, the theme & room template filter are NULL but the room template is specified directly.
const CRoomTemplate *m_pTargetRoomTemplate;
// A nested action which is used to add the connector piece candidates (typically CTilegenAction_AddRoomCandidates).
ITilegenAction *m_pAddConnectorCandidates;
};
//-----------------------------------------------------------------------------
// Places a mission component/objective at a specified time.
//-----------------------------------------------------------------------------
class CTilegenAction_PlaceComponent : public ITilegenAction
{
public:
CTilegenAction_PlaceComponent();
~CTilegenAction_PlaceComponent();
virtual void OnBeginGeneration( CLayoutSystem *pLayoutSystem );
virtual bool LoadFromKeyValues( KeyValues *pKeyValues );
virtual const char *GetTypeName();
virtual void Execute( CLayoutSystem *pLayoutSystem );
private:
struct RoomPlacementInfo_t
{
CRoomTemplate *m_pRoomTemplate;
// The fraction of the way through generating either the current state or the whole map.
// If less than 0.0, implies random placement.
float m_flPlacementFraction;
};
struct RoomPlacementInstance_t
{
RoomPlacementInfo_t *pInfo;
// The fraction of the way through generating either the current state or the whole map.
// If the original placement info indicated random placement, this will be in the range
// [0.05f to 0.95f]; in general, it is always clamped to the range [0.0f, 1.0f].
float m_flPlacementFraction;
// Whether or not the room has been placed yet
bool m_bPlaced;
};
// The maximum number of optional rooms allowed to be parsed
static const int m_nMaxTotalOptionalRooms = 128;
void AddRoomPlacementInstance( CLayoutSystem *pLayoutSystem, RoomPlacementInfo_t *pRoomPlacementInfo );
bool LoadRoomPlacementsFromKeyValues( KeyValues *pKeyValues, CUtlVector< RoomPlacementInfo_t > *pRooms );
bool PlaceRoom( CLayoutSystem *pLayoutSystem, const CRoomTemplate *pRoomTemplate );
bool PlaceConnectorRoom( CLayoutSystem *pLayoutSystem, const CRoomTemplate *pRoomTemplate );
int m_nMinOptionalRooms, m_nMaxOptionalRooms;
ITilegenExpression< bool > *m_pExitFilter;
ITilegenExpression< bool > *m_pRoomCandidateFilter;
ITilegenAction *m_pRoomCandidateFilterAction;
ITilegenExpression< bool > *m_pRoomCandidateFilterCondition;
// An action used to add connector pieces if it proves impossible to place a given component at a specified point in time.
CTilegenAction_AddConnectorRoomCandidates *m_pAddConnectorRoomCandidates;
// An action used to actually place connector pieces if needed.
CTilegenAction_ChooseCandidate *m_pChooseCandidate;
bool m_bExcludeGlobalFilters;
CUtlVector< RoomPlacementInfo_t > m_MandatoryRooms;
CUtlVector< RoomPlacementInfo_t > m_OptionalRooms;
class CRoomPlacementInstanceLessFunc
{
public:
bool Less( const RoomPlacementInstance_t &lhs, const RoomPlacementInstance_t &rhs, void *pContext )
{
return lhs.m_flPlacementFraction < rhs.m_flPlacementFraction;
}
};
CUtlSortVector< RoomPlacementInstance_t, CRoomPlacementInstanceLessFunc > m_RoomsToPlace;
};
//-----------------------------------------------------------------------------
// Adds instance(s) to previous placed rooms meeting some criteria
// during the VMF instancing fix-up phase.
// (This actually schedules a fix-up to occur at a later time by adding
// entries to the map layout file).
//-----------------------------------------------------------------------------
class CTilegenAction_AddInstances : public ITilegenAction
{
public:
CTilegenAction_AddInstances();
~CTilegenAction_AddInstances();
virtual bool LoadFromKeyValues( KeyValues *pKeyValues );
virtual const char *GetTypeName();
virtual void Execute( CLayoutSystem *pLayoutSystem );
private:
// A "template" instance spawn definition, which will be effectively repeated N times (where N is the instance count)
// for various rooms
CInstanceSpawn m_InstanceSpawn;
// # of instances to spawn
ITilegenExpression< int > *m_pInstanceCount;
// Filter used to eliminate placed rooms from consideration
ITilegenExpression< bool > *m_pRoomTemplateFilter;
};
//-----------------------------------------------------------------------------
// Adds an instance to a specific CRoom during the VMF instancing fix-up phase.
// (This actually schedules a fix-up to occur at a later time by adding
// entries to the map layout file).
//-----------------------------------------------------------------------------
class CTilegenAction_AddInstanceToRoom : public ITilegenAction
{
public:
CTilegenAction_AddInstanceToRoom();
~CTilegenAction_AddInstanceToRoom();
virtual bool LoadFromKeyValues( KeyValues *pKeyValues );
virtual const char *GetTypeName();
virtual void Execute( CLayoutSystem *pLayoutSystem );
private:
// A spawn definition for the
CInstanceSpawn m_InstanceSpawn;
ITilegenExpression< const CRoom * > *m_pRoomExpression;
};
//-----------------------------------------------------------------------------
// Loads the rooms from a .layout file directly into this layout.
//-----------------------------------------------------------------------------
class CTilegenAction_LoadLayout : public ITilegenAction
{
public:
CTilegenAction_LoadLayout();
virtual bool LoadFromKeyValues( KeyValues *pKeyValues );
virtual const char *GetTypeName();
virtual void Execute( CLayoutSystem *pLayoutSystem );
private:
char m_LayoutFilename[MAX_PATH];
};
#endif // TILEGEN_ACTIONS_H