diff options
author | Tim Angus <tim@ngus.net> | 2009-10-03 12:49:36 +0000 |
---|---|---|
committer | Tim Angus <tim@ngus.net> | 2013-01-03 00:16:15 +0000 |
commit | 985d15520a5f92b430dae129acabfe1e78bd1e26 (patch) | |
tree | 2b54f67dc6584fcb6bd66b85153f57d2eef6ddff /src/game/g_maprotation.c | |
parent | 1d6748410c6f19f8af2f0c2b71d8c78ac0c3983f (diff) |
* Fairly substantial restructuring of the map rotation system which hopefully
addresses most of the misgivings with it
Diffstat (limited to 'src/game/g_maprotation.c')
-rw-r--r-- | src/game/g_maprotation.c | 583 |
1 files changed, 340 insertions, 243 deletions
diff --git a/src/game/g_maprotation.c b/src/game/g_maprotation.c index 36e6aeb3..b1ab34bd 100644 --- a/src/game/g_maprotation.c +++ b/src/game/g_maprotation.c @@ -25,8 +25,8 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA #include "g_local.h" -#define MAX_MAP_ROTATIONS 16 -#define MAX_MAP_ROTATION_MAPS 64 +#define MAX_MAP_ROTATIONS 64 +#define MAX_MAP_ROTATION_MAPS 256 #define NOT_ROTATING -1 @@ -47,16 +47,14 @@ typedef enum typedef enum { - CT_ERR, - CT_MAP, - CT_ROTATION -} conditionType_t; + DT_ERR, + DT_MAP, + DT_ROTATION +} destinationType_t; typedef struct condition_s { - char dest[ MAX_QPATH ]; - - qboolean unconditional; + struct node_s *target; conditionVariable_t lhs; conditionOp_t op; @@ -65,35 +63,37 @@ typedef struct condition_s team_t lastWin; } condition_t; -typedef struct map_s +typedef struct destination_s { char name[ MAX_QPATH ]; + char postCommand[ MAX_STRING_CHARS ]; char layouts[ MAX_CVAR_VALUE_STRING ]; -} map_t; +} destination_t; typedef enum { - NT_MAP, + NT_DESTINATION, NT_CONDITION } nodeType_t; typedef struct node_s { + nodeType_t type; + union { - map_t map; - condition_t condition; + destination_t destination; + condition_t condition; } u; - nodeType_t type; } node_t; typedef struct mapRotation_s { char name[ MAX_QPATH ]; - node_t nodes[ MAX_MAP_ROTATION_MAPS ]; + node_t *nodes[ MAX_MAP_ROTATION_MAPS ]; int numNodes; int currentNode; } mapRotation_t; @@ -140,6 +140,20 @@ static qboolean G_RotationExists( char *name ) /* =============== +G_AllocateNode + +Allocate memory for a node_t +=============== +*/ +static node_t *G_AllocateNode( void ) +{ + node_t *node = BG_Alloc( sizeof( node_t ) ); + + return node; +} + +/* +=============== G_ParseMapCommandSection Parse a map rotation command section @@ -147,9 +161,9 @@ Parse a map rotation command section */ static qboolean G_ParseMapCommandSection( node_t *node, char **text_p ) { - char *token; - map_t *map = &node->u.map; - int commandLength = 0; + char *token; + destination_t *destination = &node->u.destination; + int commandLength = 0; // read optional parameters while( 1 ) @@ -167,7 +181,7 @@ static qboolean G_ParseMapCommandSection( node_t *node, char **text_p ) if( commandLength > 0 ) { // Replace last ; with \n - map->postCommand[ commandLength - 1 ] = '\n'; + destination->postCommand[ commandLength - 1 ] = '\n'; } return qtrue; //reached the end of this command section @@ -176,33 +190,33 @@ static qboolean G_ParseMapCommandSection( node_t *node, char **text_p ) if( !Q_stricmp( token, "layouts" ) ) { token = COM_ParseExt( text_p, qfalse ); - map->layouts[ 0 ] = '\0'; + destination->layouts[ 0 ] = '\0'; while( token[ 0 ] != 0 ) { - Q_strcat( map->layouts, sizeof( map->layouts ), token ); - Q_strcat( map->layouts, sizeof( map->layouts ), " " ); + Q_strcat( destination->layouts, sizeof( destination->layouts ), token ); + Q_strcat( destination->layouts, sizeof( destination->layouts ), " " ); token = COM_ParseExt( text_p, qfalse ); } continue; } - // Parse the rest of the line into map->postCommand - Q_strcat( map->postCommand, sizeof( map->postCommand ), token ); - Q_strcat( map->postCommand, sizeof( map->postCommand ), " " ); + // Parse the rest of the line into destination->postCommand + Q_strcat( destination->postCommand, sizeof( destination->postCommand ), token ); + Q_strcat( destination->postCommand, sizeof( destination->postCommand ), " " ); token = COM_ParseExt( text_p, qfalse ); while( token[ 0 ] != 0 ) { - Q_strcat( map->postCommand, sizeof( map->postCommand ), token ); - Q_strcat( map->postCommand, sizeof( map->postCommand ), " " ); + Q_strcat( destination->postCommand, sizeof( destination->postCommand ), token ); + Q_strcat( destination->postCommand, sizeof( destination->postCommand ), " " ); token = COM_ParseExt( text_p, qfalse ); } - commandLength = strlen( map->postCommand ); - map->postCommand[ commandLength - 1 ] = ';'; + commandLength = strlen( destination->postCommand ); + destination->postCommand[ commandLength - 1 ] = ';'; } return qfalse; @@ -210,142 +224,148 @@ static qboolean G_ParseMapCommandSection( node_t *node, char **text_p ) /* =============== -G_ParseMapRotation +G_ParseNode -Parse a map rotation section +Parse a node =============== */ -static qboolean G_ParseMapRotation( mapRotation_t *mr, char **text_p ) +static qboolean G_ParseNode( node_t **node, char *token, char **text_p ) { - char *token; - qboolean mnSet = qfalse; - node_t *node = NULL; - - // read optional parameters - while( 1 ) + if( !Q_stricmp( token, "if" ) ) { + condition_t *condition; + + (*node)->type = NT_CONDITION; + condition = &(*node)->u.condition; + token = COM_Parse( text_p ); if( !*token ) - break; - - if( !Q_stricmp( token, "" ) ) return qfalse; - if( !Q_stricmp( token, "{" ) ) + if( !Q_stricmp( token, "numClients" ) ) { - if( !mnSet ) - { - G_Printf( S_COLOR_RED "ERROR: map settings section with no name\n" ); + condition->lhs = CV_NUMCLIENTS; + + token = COM_Parse( text_p ); + + if( !*token ) return qfalse; - } - if( !G_ParseMapCommandSection( node, text_p ) ) + if( !Q_stricmp( token, "<" ) ) + condition->op = CO_LT; + else if( !Q_stricmp( token, ">" ) ) + condition->op = CO_GT; + else if( !Q_stricmp( token, "=" ) ) + condition->op = CO_EQ; + else { - G_Printf( S_COLOR_RED "ERROR: failed to parse map command section\n" ); + G_Printf( S_COLOR_RED "ERROR: invalid operator in expression: %s\n", token ); return qfalse; } - mnSet = qfalse; - continue; - } + token = COM_Parse( text_p ); - node = &mr->nodes[ mr->numNodes ]; + if( !*token ) + return qfalse; - if( !Q_stricmp( token, "goto" ) ) + condition->numClients = atoi( token ); + } + else if( !Q_stricmp( token, "lastWin" ) ) { - condition_t *condition = &node->u.condition; + condition->lhs = CV_LASTWIN; token = COM_Parse( text_p ); if( !*token ) - break; - - condition->unconditional = qtrue; - Q_strncpyz( condition->dest, token, sizeof( condition->dest ) ); + return qfalse; - node->type = NT_CONDITION; - mr->numNodes++; - continue; + if( !Q_stricmp( token, "aliens" ) ) + condition->lastWin = TEAM_ALIENS; + else if( !Q_stricmp( token, "humans" ) ) + condition->lastWin = TEAM_HUMANS; + else + { + G_Printf( S_COLOR_RED "ERROR: invalid right hand side in expression: %s\n", token ); + return qfalse; + } } - else if( !Q_stricmp( token, "if" ) ) + else if( !Q_stricmp( token, "random" ) ) + condition->lhs = CV_RANDOM; + else { - condition_t *condition = &node->u.condition; + G_Printf( S_COLOR_RED "ERROR: invalid left hand side in expression: %s\n", token ); + return qfalse; + } - token = COM_Parse( text_p ); + token = COM_Parse( text_p ); - if( !*token ) - break; + if( !*token ) + return qfalse; - if( !Q_stricmp( token, "numClients" ) ) - { - condition->lhs = CV_NUMCLIENTS; + condition->target = G_AllocateNode( ); + *node = condition->target; + if( !G_ParseNode( node, token, text_p ) ) + return qfalse; + } + else + { + destination_t *destination; - token = COM_Parse( text_p ); + (*node)->type = NT_DESTINATION; + destination = &(*node)->u.destination; - if( !*token ) - break; + Q_strncpyz( destination->name, token, sizeof( destination->name ) ); + destination->postCommand[ 0 ] = '\0'; + } - if( !Q_stricmp( token, "<" ) ) - condition->op = CO_LT; - else if( !Q_stricmp( token, ">" ) ) - condition->op = CO_GT; - else if( !Q_stricmp( token, "=" ) ) - condition->op = CO_EQ; - else - { - G_Printf( S_COLOR_RED "ERROR: invalid operator in expression: %s\n", token ); - return qfalse; - } + return qtrue; +} - token = COM_Parse( text_p ); +/* +=============== +G_ParseMapRotation - if( !*token ) - break; +Parse a map rotation section +=============== +*/ +static qboolean G_ParseMapRotation( mapRotation_t *mr, char **text_p ) +{ + char *token; + node_t *node = NULL; - condition->numClients = atoi( token ); - } - else if( !Q_stricmp( token, "lastWin" ) ) - { - condition->lhs = CV_LASTWIN; + // read optional parameters + while( 1 ) + { + token = COM_Parse( text_p ); - token = COM_Parse( text_p ); + if( !*token ) + break; - if( !*token ) - break; + if( !Q_stricmp( token, "" ) ) + return qfalse; - if( !Q_stricmp( token, "aliens" ) ) - condition->lastWin = TEAM_ALIENS; - else if( !Q_stricmp( token, "humans" ) ) - condition->lastWin = TEAM_HUMANS; - else - { - G_Printf( S_COLOR_RED "ERROR: invalid right hand side in expression: %s\n", token ); - return qfalse; - } - } - else if( !Q_stricmp( token, "random" ) ) - condition->lhs = CV_RANDOM; - else + if( !Q_stricmp( token, "{" ) ) + { + if( node == NULL ) { - G_Printf( S_COLOR_RED "ERROR: invalid left hand side in expression: %s\n", token ); + G_Printf( S_COLOR_RED "ERROR: map command section with no associated map\n" ); return qfalse; } - token = COM_Parse( text_p ); - - if( !*token ) - break; - - condition->unconditional = qfalse; - Q_strncpyz( condition->dest, token, sizeof( condition->dest ) ); + if( !G_ParseMapCommandSection( node, text_p ) ) + { + G_Printf( S_COLOR_RED "ERROR: failed to parse map command section\n" ); + return qfalse; + } - node->type = NT_CONDITION; - mr->numNodes++; continue; } else if( !Q_stricmp( token, "}" ) ) - return qtrue; //reached the end of this map rotation + { + // Reached the end of this map rotation + return qtrue; + } if( mr->numNodes == MAX_MAP_ROTATION_MAPS ) { @@ -354,13 +374,11 @@ static qboolean G_ParseMapRotation( mapRotation_t *mr, char **text_p ) return qfalse; } - Q_strncpyz( node->u.map.name, token, sizeof( node->u.map.name ) ); - node->u.map.postCommand[ 0 ] = '\0'; - - mnSet = qtrue; + node = G_AllocateNode( ); + mr->nodes[ mr->numNodes++ ] = node; - node->type = NT_MAP; - mr->numNodes++; + if( !G_ParseNode( &node, token, text_p ) ) + return qfalse; } return qfalse; @@ -472,32 +490,36 @@ static qboolean G_ParseMapRotationFile( const char *fileName ) for( i = 0; i < mapRotations.numRotations; i++ ) { - for( j = 0; j < mapRotations.rotations[ i ].numNodes; j++ ) + mapRotation_t *mr = &mapRotations.rotations[ i ]; + int destinationCount = 0; + + for( j = 0; j < mr->numNodes; j++ ) { - node_t *node = &mapRotations.rotations[ i ].nodes[ j ]; + node_t *node = mr->nodes[ j ]; + destination_t *destination; - switch( node->type ) - { - case NT_MAP: - if( !G_MapExists( node->u.map.name ) ) - { - G_Printf( S_COLOR_RED "ERROR: map \"%s\" doesn't exist\n", - node->u.map.name ); - return qfalse; - } - break; + if( node->type == NT_DESTINATION ) + destinationCount++; + else while( node->type == NT_CONDITION ) + node = node->u.condition.target; - case NT_CONDITION: - if( !G_MapExists( node->u.condition.dest ) && - !G_RotationExists( node->u.condition.dest ) ) - { - G_Printf( S_COLOR_RED "ERROR: conditional destination \"%s\" doesn't exist\n", - node->u.condition.dest ); - return qfalse; - } - break; + destination = &node->u.destination; + + if( !G_MapExists( destination->name ) && + !G_RotationExists( destination->name ) ) + { + G_Printf( S_COLOR_RED "ERROR: conditional destination \"%s\" doesn't exist\n", + destination->name ); + return qfalse; } } + + if( destinationCount == 0 ) + { + G_Printf( S_COLOR_RED "ERROR: rotation \"%s\" needs at least one unconditional entry\n", + mr->name ); + return qfalse; + } } return qtrue; @@ -505,6 +527,19 @@ static qboolean G_ParseMapRotationFile( const char *fileName ) /* =============== +G_PrintSpaces +=============== +*/ +static void G_PrintSpaces( int spaces ) +{ + int i; + + for( i = 0; i < spaces; i++ ) + G_Printf( " " ); +} + +/* +=============== G_PrintRotations Print the parsed map rotations @@ -513,50 +548,57 @@ Print the parsed map rotations void G_PrintRotations( void ) { int i, j; + int size = sizeof( mapRotations ); G_Printf( "Map rotations as parsed:\n\n" ); for( i = 0; i < mapRotations.numRotations; i++ ) { - G_Printf( "rotation: %s\n{\n", mapRotations.rotations[ i ].name ); + mapRotation_t *mr = &mapRotations.rotations[ i ]; + + G_Printf( "rotation: %s\n{\n", mr->name ); - for( j = 0; j < mapRotations.rotations[ i ].numNodes; j++ ) + size += mr->numNodes * sizeof( node_t ); + + for( j = 0; j < mr->numNodes; j++ ) { - node_t *node = &mapRotations.rotations[ i ].nodes[ j ]; + node_t *node = mr->nodes[ j ]; + int indentation = 0; - switch( node->type ) + while( node->type == NT_CONDITION ) { - case NT_MAP: - G_Printf( " map: %s\n", node->u.map.name ); + G_PrintSpaces( indentation ); + G_Printf( " condition\n" ); + node = node->u.condition.target; - if( strlen( node->u.map.postCommand ) > 0 ) - { - G_Printf( " {\n" ); - G_Printf( " command: %s", node->u.map.postCommand ); - G_Printf( " }\n" ); - } - break; + size += sizeof( node_t ); - case NT_CONDITION: - G_Printf( " conditional: %s\n", node->u.condition.dest ); - break; + indentation += 2; + } + + G_PrintSpaces( indentation ); + G_Printf( " %s\n", node->u.destination.name ); + + if( strlen( node->u.destination.postCommand ) > 0 ) + { + G_Printf( " command: %s", node->u.destination.postCommand ); } } G_Printf( "}\n" ); } - G_Printf( "Total memory used: %d bytes\n", sizeof( mapRotations ) ); + G_Printf( "Total memory used: %d bytes\n", size ); } /* =============== -G_GetCurrentNodeArray +G_CurrentNodeIndexArray Fill a static array with the current node of each rotation =============== */ -static int *G_GetCurrentNodeArray( void ) +static int *G_CurrentNodeIndexArray( void ) { static int currentNode[ MAX_MAP_ROTATIONS ]; int i = 0; @@ -585,15 +627,15 @@ static int *G_GetCurrentNodeArray( void ) /* =============== -G_SetCurrentNode +G_SetCurrentNodeByIndex Set the current map in some rotation =============== */ -static void G_SetCurrentNode( int currentNode, int rotation ) +static void G_SetCurrentNodeByIndex( int currentNode, int rotation ) { char text[ MAX_MAP_ROTATIONS * 2 ] = { 0 }; - int *p = G_GetCurrentNodeArray( ); + int *p = G_CurrentNodeIndexArray( ); int i; p[ rotation ] = currentNode; @@ -607,78 +649,85 @@ static void G_SetCurrentNode( int currentNode, int rotation ) /* =============== -G_GetCurrentNode +G_CurrentNodeIndex -Return the current map in some rotation +Return the current node index in some rotation =============== */ -static int G_GetCurrentNode( int rotation ) +static int G_CurrentNodeIndex( int rotation ) { - int *p = G_GetCurrentNodeArray( ); + int *p = G_CurrentNodeIndexArray( ); return p[ rotation ]; } /* =============== +G_NodeByIndex + +Return a node in a rotation by its index +=============== +*/ +static node_t *G_NodeByIndex( int index, int rotation ) +{ + return mapRotations.rotations[ rotation ].nodes[ index ]; +} + +/* +=============== G_IssueMapChange Send commands to the server to actually change the map =============== */ -static void G_IssueMapChange( int rotation ) +static void G_IssueMapChange( int index, int rotation ) { - int node = G_GetCurrentNode( rotation ); - map_t *map = &mapRotations.rotations[ rotation ].nodes[ node ].u.map; + node_t *node = mapRotations.rotations[ rotation ].nodes[ index ]; + destination_t *destination = &node->u.destination; // allow a manually defined g_layouts setting to override the maprotation - if( !g_layouts.string[ 0 ] && map->layouts[ 0 ] ) + if( !g_layouts.string[ 0 ] && destination->layouts[ 0 ] ) { - trap_Cvar_Set( "g_layouts", map->layouts ); + trap_Cvar_Set( "g_layouts", destination->layouts ); } - trap_SendConsoleCommand( EXEC_APPEND, va( "map %s\n", map->name ) ); + trap_SendConsoleCommand( EXEC_APPEND, va( "map %s\n", destination->name ) ); // Load up map defaults if g_mapConfigs is set - G_MapConfigs( map->name ); + G_MapConfigs( destination->name ); - trap_SendConsoleCommand( EXEC_APPEND, map->postCommand ); + if( strlen( destination->postCommand ) > 0 ) + trap_SendConsoleCommand( EXEC_APPEND, destination->postCommand ); } /* =============== -G_ResolveConditionDestination +G_GotoDestination Resolve the destination of some condition =============== */ -static conditionType_t G_ResolveConditionDestination( int *n, char *name ) +static void G_GotoDestination( int currentRotation, char *name ) { int i; - // Search the current rotation first... - for( i = 0; i < mapRotations.rotations[ g_currentMapRotation.integer ].numNodes; i++ ) - { - node_t *node = &mapRotations.rotations[ g_currentMapRotation.integer ].nodes[ i ]; + G_Printf( "G_GotoDestination( %s )\n", name ); - if( node->type == NT_MAP && !Q_stricmp( node->u.map.name, name ) ) - { - *n = i; - return CT_MAP; - } - } + // Search the rotation names... + if( G_StartMapRotation( name, qtrue ) ) + return; - // ...then search the rotation names - for( i = 0; i < mapRotations.numRotations; i++ ) + // ...then try maps in the current rotation + for( i = 0; i < mapRotations.rotations[ currentRotation ].numNodes; i++ ) { - if( !Q_stricmp( mapRotations.rotations[ i ].name, name ) ) + node_t *node = mapRotations.rotations[ currentRotation ].nodes[ i ]; + + if( node->type == NT_DESTINATION && !Q_stricmp( node->u.destination.name, name ) ) { - *n = i; - return CT_ROTATION; + G_IssueMapChange( i, currentRotation ); + return; } } - - return CT_ERR; } /* @@ -688,42 +737,64 @@ G_EvaluateMapCondition Evaluate a map condition =============== */ -static qboolean G_EvaluateMapCondition( condition_t *condition ) +static qboolean G_EvaluateMapCondition( condition_t **condition ) { - switch( condition->lhs ) + qboolean result = qfalse; + condition_t *localCondition = *condition; + + switch( localCondition->lhs ) { case CV_RANDOM: - return rand( ) & 1; + result = rand( ) & 1; break; case CV_NUMCLIENTS: - switch( condition->op ) + switch( localCondition->op ) { case CO_LT: - return level.numConnectedClients < condition->numClients; + result = level.numConnectedClients < localCondition->numClients; break; case CO_GT: - return level.numConnectedClients > condition->numClients; + result = level.numConnectedClients > localCondition->numClients; break; case CO_EQ: - return level.numConnectedClients == condition->numClients; + result = level.numConnectedClients == localCondition->numClients; break; } break; case CV_LASTWIN: - return level.lastWin == condition->lastWin; + result = level.lastWin == localCondition->lastWin; break; default: case CV_ERR: - G_Printf( S_COLOR_RED "ERROR: malformed map switch condition\n" ); + G_Printf( S_COLOR_RED "ERROR: malformed map switch localCondition\n" ); break; } - return qfalse; + if( localCondition->target->type == NT_CONDITION ) + { + *condition = &localCondition->target->u.condition; + + return result && G_EvaluateMapCondition( condition ); + } + + return result; +} + +/* +=============== +G_NodeIndexAfter +=============== +*/ +static int G_NodeIndexAfter( int currentNode, int rotation ) +{ + mapRotation_t *mr = &mapRotations.rotations[ rotation ]; + + return ( currentNode + 1 ) % mr->numNodes; } /* @@ -735,51 +806,34 @@ Increment the current map rotation */ void G_AdvanceMapRotation( void ) { - mapRotation_t *mr; node_t *node; condition_t *condition; - int currentRotation, currentNode, nextNode; - int n; + int rotation, nodeIndex; - if( ( currentRotation = g_currentMapRotation.integer ) == NOT_ROTATING ) + if( ( rotation = g_currentMapRotation.integer ) == NOT_ROTATING ) return; - currentNode = G_GetCurrentNode( currentRotation ); - - mr = &mapRotations.rotations[ currentRotation ]; - node = &mr->nodes[ currentNode ]; - nextNode = ( currentNode + 1 ) % mr->numNodes; + nodeIndex = G_CurrentNodeIndex( rotation ); + node = G_NodeByIndex( nodeIndex, rotation ); - if( node->type == NT_CONDITION ) + while( node->type == NT_CONDITION ) { condition = &node->u.condition; - if( condition->unconditional || G_EvaluateMapCondition( condition ) ) + if( G_EvaluateMapCondition( &condition ) ) { - switch( G_ResolveConditionDestination( &n, condition->dest ) ) - { - case CT_MAP: - nextNode = n; - break; - - case CT_ROTATION: - // Advance the current rotation so that if we come back to - // it later, the next node in the rotation is evaluated - G_SetCurrentNode( nextNode, currentRotation ); - G_StartMapRotation( condition->dest, qtrue ); - return; - - default: - case CT_ERR: - G_Printf( S_COLOR_YELLOW "WARNING: map switch destination could not be resolved: %s\n", - condition->dest ); - break; - } + node = condition->target; + } + else + { + nodeIndex = G_NodeIndexAfter( nodeIndex, rotation ); + node = G_NodeByIndex( nodeIndex, rotation ); } } - G_SetCurrentNode( nextNode, currentRotation ); - G_IssueMapChange( currentRotation ); + G_GotoDestination( rotation, node->u.destination.name ); + G_SetCurrentNodeByIndex( + G_NodeIndexAfter( nodeIndex, rotation ), rotation ); } /* @@ -801,7 +855,11 @@ qboolean G_StartMapRotation( char *name, qboolean changeMap ) trap_Cvar_Update( &g_currentMapRotation ); if( changeMap ) - G_IssueMapChange( i ); + { + G_IssueMapChange( 0, i ); + G_SetCurrentNodeByIndex( G_NodeIndexAfter( + G_CurrentNodeIndex( i ), i ), i ); + } break; } } @@ -841,7 +899,7 @@ qboolean G_MapRotationActive( void ) =============== G_InitMapRotations -Load and intialise the map rotations +Load and initialise the map rotations =============== */ void G_InitMapRotations( void ) @@ -868,3 +926,42 @@ void G_InitMapRotations( void ) } } } + +/* +=============== +G_FreeNode + +Free up memory used by a node +=============== +*/ +void G_FreeNode( node_t *node ) +{ + if( node->type == NT_CONDITION ) + G_FreeNode( node->u.condition.target ); + + BG_Free( node ); +} + +/* +=============== +G_ShutdownMapRotations + +Free up memory used by map rotations +=============== +*/ +void G_ShutdownMapRotations( void ) +{ + int i, j; + + for( i = 0; i < mapRotations.numRotations; i++ ) + { + mapRotation_t *mr = &mapRotations.rotations[ i ]; + + for( j = 0; j < mr->numNodes; j++ ) + { + node_t *node = mr->nodes[ j ]; + + G_FreeNode( node ); + } + } +} |