diff options
author | /dev/humancontroller <devhc@example.com> | 2017-02-06 19:19:33 +0100 |
---|---|---|
committer | /dev/humancontroller <devhc@example.com> | 2017-03-09 13:51:16 +0100 |
commit | ec2f1dc2f6444d33f3d112be486e9d7675358bd6 (patch) | |
tree | 57f10fa18f031cbb0531eecfc9a1417988cb6cc0 | |
parent | ff4fd573a91bc027c935f32fab107eca66659141 (diff) |
implement layout arithmetic and the addlayout command
layout arithmetic features: layout filtering by buildable team or type, loading of union of filtered layouts, saving filtered layouts
addlayout: an admin command to place layout elements into the game
-rw-r--r-- | src/game/g_admin.c | 28 | ||||
-rw-r--r-- | src/game/g_admin.h | 1 | ||||
-rw-r--r-- | src/game/g_buildable.c | 144 | ||||
-rw-r--r-- | src/game/g_local.h | 2 | ||||
-rw-r--r-- | src/game/g_main.c | 2 | ||||
-rw-r--r-- | src/game/g_svcmds.c | 10 |
6 files changed, 169 insertions, 18 deletions
diff --git a/src/game/g_admin.c b/src/game/g_admin.c index 62a45572..18f317d4 100644 --- a/src/game/g_admin.c +++ b/src/game/g_admin.c @@ -38,6 +38,15 @@ static char g_bfb[ 32000 ]; // note: list ordered alphabetically g_admin_cmd_t g_admin_cmds[ ] = { + {"addlayout", G_admin_addlayout, qfalse, "addlayout", + "place layout elements into the game. the elements are specified by a " + "union of filtered layouts. the syntax is demonstrated by an example: " + "^5westside|reactor,telenode+sewers|alien^7 will place only the " + "reactor and telenodes from the westside layout, and also all alien " + "layout elements from the sewers layout", + "[^3layoutelements^7]" + }, + {"adjustban", G_admin_adjustban, qfalse, "ban", "change the IP address mask, duration or reason of a ban. mask is " "prefixed with '/'. duration is specified as numbers followed by units " @@ -1858,6 +1867,25 @@ qboolean G_admin_unban( gentity_t *ent ) return qtrue; } +qboolean G_admin_addlayout( gentity_t *ent ) +{ + char layout[ MAX_QPATH ]; + + if( trap_Argc( ) != 2 ) + { + ADMP( "^3addlayout: ^7usage: addlayout <layoutelements>\n" ); + return qfalse; + } + + trap_Argv( 1, layout, sizeof( layout ) ); + + G_LayoutLoad( layout ); + + AP( va( "print \"^3addlayout: ^7some layout elements have been placed by %s\n\"", + ent ? ent->client->pers.netname : "console" ) ); + return qtrue; +} + qboolean G_admin_adjustban( gentity_t *ent ) { int bnum; diff --git a/src/game/g_admin.h b/src/game/g_admin.h index de51562b..fd9f6b26 100644 --- a/src/game/g_admin.h +++ b/src/game/g_admin.h @@ -157,6 +157,7 @@ void G_admin_authlog( gentity_t *ent ); qboolean G_admin_time( gentity_t *ent ); qboolean G_admin_setlevel( gentity_t *ent ); qboolean G_admin_kick( gentity_t *ent ); +qboolean G_admin_addlayout( gentity_t *ent ); qboolean G_admin_adjustban( gentity_t *ent ); qboolean G_admin_ban( gentity_t *ent ); qboolean G_admin_unban( gentity_t *ent ); diff --git a/src/game/g_buildable.c b/src/game/g_buildable.c index a5e64d36..dd984d33 100644 --- a/src/game/g_buildable.c +++ b/src/game/g_buildable.c @@ -3943,13 +3943,74 @@ void G_SpawnBuildable( gentity_t *ent, buildable_t buildable ) ent->think = G_SpawnBuildableThink; } +void G_ParseCSVBuildablePlusList( const char *string, int *buildables, int buildablesSize ) +{ + char buffer[ MAX_STRING_CHARS ]; + int i = 0; + char *p, *q; + qboolean EOS = qfalse; + + Q_strncpyz( buffer, string, MAX_STRING_CHARS ); + + p = q = buffer; + + while( *p != '\0' && i < buildablesSize - 1 ) + { + //skip to first , or EOS + while( *p != ',' && *p != '\0' ) + p++; + + if( *p == '\0' ) + EOS = qtrue; + + *p = '\0'; + + //strip leading whitespace + while( *q == ' ' ) + q++; + + if( !Q_stricmp( q, "alien" ) ) + { + buildable_t b; + for( b = BA_A_SPAWN; b <= BA_A_HIVE && i < buildablesSize - 1; ++b ) + buildables[ i++ ] = b; + } + else if( !Q_stricmp( q, "human" ) ) + { + buildable_t b; + for( b = BA_H_SPAWN; b <= BA_H_REPEATER && i < buildablesSize - 1; ++b ) + buildables[ i++ ] = b; + } + else + { + buildables[ i ] = BG_BuildableByName( q )->number; + if( buildables[ i ] == BA_NONE ) + Com_Printf( S_COLOR_YELLOW "WARNING: unknown buildable or special identifier %s\n", q ); + else + i++; + } + + if( !EOS ) + { + p++; + q = p; + } + else + break; + } + + buildables[ i ] = BA_NONE; +} + /* ============ G_LayoutSave ============ */ -void G_LayoutSave( char *name ) +void G_LayoutSave( char *lstr ) { + char *lstrPipePtr; + qboolean bAllowed[ BA_NUM_BUILDABLES ]; char map[ MAX_QPATH ]; char fileName[ MAX_OSPATH ]; fileHandle_t f; @@ -3964,7 +4025,26 @@ void G_LayoutSave( char *name ) G_Printf( "LayoutSave( ): no map is loaded\n" ); return; } - Com_sprintf( fileName, sizeof( fileName ), "layouts/%s/%s.dat", map, name ); + + if( ( lstrPipePtr = strchr( lstr, '|' ) ) ) + { + int bList[ BA_NUM_BUILDABLES ]; + *lstrPipePtr = '\0'; + G_ParseCSVBuildablePlusList( lstrPipePtr + 1, &bList[ 0 ], sizeof( bList ) / sizeof( bList[ 0 ] ) ); + memset( bAllowed, 0, sizeof( bAllowed ) ); + for( i = 0; bList[ i ] != BA_NONE; i++ ) + bAllowed[ bList[ i ] ] = qtrue; + } + else + { + for( i = 0; i < BA_NUM_BUILDABLES; i++ ) + bAllowed[ i ] = qtrue; + } + + Com_sprintf( fileName, sizeof( fileName ), "layouts/%s/%s.dat", map, lstr ); + + if( lstrPipePtr ) + *lstrPipePtr = '|'; len = trap_FS_FOpenFile( fileName, &f, FS_WRITE ); if( len < 0 ) @@ -3981,6 +4061,9 @@ void G_LayoutSave( char *name ) if( ent->s.eType != ET_BUILDABLE ) continue; + if( !bAllowed[ ent->s.modelindex ] ) + continue; + s = va( "%s %f %f %f %f %f %f %f %f %f %f %f %f\n", BG_Buildable( ent->s.modelindex )->name, ent->r.currentOrigin[ 0 ], @@ -4093,7 +4176,7 @@ void G_LayoutSelect( void ) if( !*s ) break; - if( G_LayoutExists( map, s ) ) + if( strchr( s, '+' ) || strchr( s, '|' ) || G_LayoutExists( map, s ) ) { Q_strcat( layouts, sizeof( layouts ), s ); Q_strcat( layouts, sizeof( layouts ), " " ); @@ -4148,13 +4231,12 @@ static void G_LayoutBuildItem( buildable_t buildable, vec3_t origin, /* ============ G_LayoutLoad - -load the layout .dat file indicated by level.layout and spawn buildables -as if a builder was creating them ============ */ -void G_LayoutLoad( void ) +void G_LayoutLoad( char *lstr ) { + char *lstrPlusPtr, *lstrPipePtr; + qboolean bAllowed[ BA_NUM_BUILDABLES ]; fileHandle_t f; int len; char *layout, *layoutHead; @@ -4166,29 +4248,50 @@ void G_LayoutLoad( void ) vec3_t origin2 = { 0.0f, 0.0f, 0.0f }; vec3_t angles2 = { 0.0f, 0.0f, 0.0f }; char line[ MAX_STRING_CHARS ]; - int i = 0; + int i; - if( !level.layout[ 0 ] || !Q_stricmp( level.layout, "*BUILTIN*" ) ) + if( !lstr[ 0 ] || !Q_stricmp( lstr, "*BUILTIN*" ) ) return; + addAnotherLayout: + lstrPlusPtr = strchr( lstr, '+' ); + if( lstrPlusPtr ) + *lstrPlusPtr = '\0'; + + if( ( lstrPipePtr = strchr( lstr, '|' ) ) ) + { + int bList[ BA_NUM_BUILDABLES ]; + *lstrPipePtr = '\0'; + G_ParseCSVBuildablePlusList( lstrPipePtr + 1, &bList[ 0 ], sizeof( bList ) / sizeof( bList[ 0 ] ) ); + memset( bAllowed, 0, sizeof( bAllowed ) ); + for( i = 0; bList[ i ] != BA_NONE; i++ ) + bAllowed[ bList[ i ] ] = qtrue; + } + else + { + for( i = 0; i < BA_NUM_BUILDABLES; i++ ) + bAllowed[ i ] = qtrue; + } + trap_Cvar_VariableStringBuffer( "mapname", map, sizeof( map ) ); - len = trap_FS_FOpenFile( va( "layouts/%s/%s.dat", map, level.layout ), + len = trap_FS_FOpenFile( va( "layouts/%s/%s.dat", map, lstr ), &f, FS_READ ); if( len < 0 ) { - G_Printf( "ERROR: layout %s could not be opened\n", level.layout ); - return; + G_Printf( "ERROR: layout %s could not be opened\n", lstr ); + goto restoreLstr; } layoutHead = layout = BG_Alloc( len + 1 ); trap_FS_Read( layout, len, f ); layout[ len ] = '\0'; trap_FS_FCloseFile( f ); + i = 0; while( *layout ) { if( i >= sizeof( line ) - 1 ) { G_Printf( S_COLOR_RED "ERROR: line overflow in %s before \"%s\"\n", - va( "layouts/%s/%s.dat", map, level.layout ), line ); + va( "layouts/%s/%s.dat", map, lstr ), line ); break; } line[ i++ ] = *layout; @@ -4208,11 +4311,24 @@ void G_LayoutLoad( void ) G_Printf( S_COLOR_YELLOW "WARNING: bad buildable name (%s) in layout." " skipping\n", buildName ); else - G_LayoutBuildItem( buildable, origin, angles, origin2, angles2 ); + { + if( bAllowed[ buildable ] ) + G_LayoutBuildItem( buildable, origin, angles, origin2, angles2 ); + } } layout++; } BG_Free( layoutHead ); + + restoreLstr: + if( lstrPipePtr ) + *lstrPipePtr = '|'; + if( lstrPlusPtr ) + { + *lstrPlusPtr = '+'; + lstr = lstrPlusPtr + 1; + goto addAnotherLayout; + } } /* diff --git a/src/game/g_local.h b/src/game/g_local.h index 1852c783..36dfff88 100644 --- a/src/game/g_local.h +++ b/src/game/g_local.h @@ -818,7 +818,7 @@ void FinishSpawningBuildable( gentity_t *ent ); void G_LayoutSave( char *name ); int G_LayoutList( const char *map, char *list, int len ); void G_LayoutSelect( void ); -void G_LayoutLoad( void ); +void G_LayoutLoad( char *lstr ); void G_BaseSelfDestruct( team_t team ); int G_NextQueueTime( int queuedBP, int totalBP, int queueBaseRate ); void G_QueueBuildPoints( gentity_t *self ); diff --git a/src/game/g_main.c b/src/game/g_main.c index d91b685d..937c578f 100644 --- a/src/game/g_main.c +++ b/src/game/g_main.c @@ -652,7 +652,7 @@ void G_InitGame( int levelTime, int randomSeed, int restart ) G_SpawnEntitiesFromString( ); // load up a custom building layout if there is one - G_LayoutLoad( ); + G_LayoutLoad( level.layout ); // the map might disable some things BG_InitAllowedGameElements( ); diff --git a/src/game/g_svcmds.c b/src/game/g_svcmds.c index c2d61ec3..b5eeda7b 100644 --- a/src/game/g_svcmds.c +++ b/src/game/g_svcmds.c @@ -212,6 +212,7 @@ static void Svcmd_LayoutSave_f( void ) char str2[ MAX_QPATH - 4 ]; char *s; int i = 0; + qboolean pipeEncountered = qfalse; if( trap_Argc( ) != 2 ) { @@ -224,12 +225,17 @@ static void Svcmd_LayoutSave_f( void ) s = &str[ 0 ]; while( *s && i < sizeof( str2 ) - 1 ) { - if( isalnum( *s ) || *s == '-' || *s == '_' ) + if( isalnum( *s ) || *s == '-' || *s == '_' || + pipeEncountered || *s == '|' ) + { str2[ i++ ] = *s; + if( *s == '|' ) + pipeEncountered = qtrue; + } s++; } - if( i == 0 ) + if( i == 0 || str2[ 0 ] == '|' ) { G_Printf( "layoutsave: invalid name \"%s\"\n", str ); return; |