From 7596b65f3e5577e2c65983dc911ec44a6ab7ec5c Mon Sep 17 00:00:00 2001 From: Paradox460 Date: Thu, 26 Jun 2008 22:20:54 +0000 Subject: [PATCH] Added Nobuild series of commands (Issue 128) --- Makefile | 2 +- src/game/g_admin.c | 64 +++++++++++- src/game/g_admin.h | 2 + src/game/g_buildable.c | 219 +++++++++++++++++++++++++++++++++++++++-- src/game/g_local.h | 6 ++ src/game/g_main.c | 3 + src/game/g_svcmds.c | 39 ++++++++ 7 files changed, 327 insertions(+), 8 deletions(-) diff --git a/Makefile b/Makefile index 4c6faa7..fc3bcda 100644 --- a/Makefile +++ b/Makefile @@ -24,7 +24,7 @@ endif BUILD_CLIENT = 0 BUILD_CLIENT_SMP = 0 BUILD_SERVER = 0 -BUILD_GAME_SO = 1 +BUILD_GAME_SO = 0 BUILD_GAME_QVM = 1 ############################################################################# diff --git a/src/game/g_admin.c b/src/game/g_admin.c index 85f4ea1..6cd703b 100644 --- a/src/game/g_admin.c +++ b/src/game/g_admin.c @@ -32,6 +32,7 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA #include "g_local.h" +void NoThink(gentity_t *ent); // big ugly global buffer for use with buffered printing of long outputs static char g_bfb[ 32000 ]; @@ -195,6 +196,16 @@ g_admin_cmd_t g_admin_cmds[ ] = "[^3mapname^7]" }, + {"nobuild", G_admin_nobuild, "L", + "make an area nobuild", + "[^3game units^7]" + }, + + {"nobuildsave", G_admin_nobuildsave, "L", + "save a map's nobuild markers", + "" + }, + {"listadmins", G_admin_listadmins, "D", "display a list of all server admins and their levels", "(^5name|start admin#^7) (^5minimum level to display^7)" @@ -2837,6 +2848,14 @@ qboolean G_admin_layoutsave( gentity_t *ent, int skiparg ) return qtrue; } +qboolean G_admin_nobuildsave( gentity_t *ent, int skiparg ) +{ + + trap_SendConsoleCommand( EXEC_APPEND, "nobuildsave" ); + AP( va( "print \"^3!nobuildsave: ^7nobuild saved by %s\n\"", ( ent ) ? ent->client->pers.netname : "console" ) ); + return qtrue; +} + qboolean G_admin_mute( gentity_t *ent, int skiparg ) { int pids[ MAX_CLIENTS ]; @@ -7708,4 +7727,47 @@ qboolean G_admin_fireworks( gentity_t *ent, int skiparg ) } } return qtrue; -} +} + +qboolean G_admin_nobuild( gentity_t *ent, int skiparg ) +{ + int minargc; + char units[ MAX_STRING_CHARS ]; + gentity_t *nb; + vec3_t low; + int units2; + minargc = 2 + skiparg; + + if( G_SayArgc() < minargc ) + { + ADMP( "^3!buildno: ^7usage: !nobuild [game units]\n" ); + return qfalse; + } + + if( !ent ) + { + ADMP( "^3!nobuild: ^7console cannot use this command\n" ); + return qfalse; + } + + G_SayArgv( 1 + skiparg, units, sizeof( units ) ); + + VectorAdd( ent->s.origin, ent->r.mins, low ); + + units2 = atoi(units); + low[0] = ent->s.origin[0]; + low[1] = ent->s.origin[1]; + + nb = G_Spawn( ); + nb->s.modelindex = 1337; + nb->think = NoThink; + nb->nextthink = level.time; + VectorCopy( low, nb->s.pos.trBase ); + VectorCopy( low, nb->r.currentOrigin ); + trap_LinkEntity( nb ); + nb->nobuilder = qtrue; + nb->nobuildarea = units2; + + return qtrue; +} + diff --git a/src/game/g_admin.h b/src/game/g_admin.h index e03dde1..cb47d01 100644 --- a/src/game/g_admin.h +++ b/src/game/g_admin.h @@ -269,6 +269,8 @@ qboolean G_admin_customgrav( gentity_t *ent, int skiparg ); qboolean G_admin_explode( gentity_t *ent, int skiparg ); qboolean G_admin_outlaw( gentity_t *ent, int skiparg ); qboolean G_admin_fireworks( gentity_t *ent, int skiparg ); +qboolean G_admin_nobuild( gentity_t *ent, int skiparg ); +qboolean G_admin_nobuildsave( gentity_t *ent, int skiparg ); void G_admin_print( gentity_t *ent, char *m ); void G_admin_buffer_print( gentity_t *ent, char *m ); diff --git a/src/game/g_buildable.c b/src/game/g_buildable.c index 48c9445..c95cba6 100644 --- a/src/game/g_buildable.c +++ b/src/game/g_buildable.c @@ -26,6 +26,12 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA // from g_combat.c extern char *modNames[ ]; + +void NoThink(gentity_t *ent) +{ +return; +} + /* ================ G_SetBuildableAnim @@ -3028,20 +3034,23 @@ Checks to see if a buildable can be built itemBuildError_t G_CanBuild( gentity_t *ent, buildable_t buildable, int distance, vec3_t origin ) { vec3_t angles; - vec3_t entity_origin, normal; + vec3_t entity_origin, normal, tmp; vec3_t mins, maxs, mins1, maxs1; - int num; - int entitylist[ MAX_GENTITIES ]; trace_t tr1, tr2, tr3; - int i; itemBuildError_t reason = IBE_NONE; gentity_t *tempent; + int num; float minNormal; qboolean invert; int contents; playerState_t *ps = &ent->client->ps; int buildPoints; - + vec3_t mins3, maxs3, range; + int i, num2; + int entitylist[ MAX_GENTITIES ]; + gentity_t *nb; + gentity_t *nbent; + BG_FindBBoxForBuildable( buildable, mins, maxs ); BG_PositionBuildableRelativeToPlayer( ps, mins, maxs, trap_Trace, entity_origin, angles, &tr1 ); @@ -3056,7 +3065,48 @@ itemBuildError_t G_CanBuild( gentity_t *ent, buildable_t buildable, int distance VectorCopy( tr1.plane.normal, normal ); minNormal = BG_FindMinNormalForBuildable( buildable ); invert = BG_FindInvertNormalForBuildable( buildable ); + + VectorCopy( entity_origin, tmp ); + + tmp[2] += mins[2]; + + nb = G_Spawn( ); + nb->s.modelindex = 1337; //Coder humor is awesome isn't it? + nb->think = NoThink; + nb->nextthink = level.time; + VectorCopy( tmp, nb->s.pos.trBase ); + VectorCopy( tmp, nb->r.currentOrigin ); + trap_LinkEntity( nb ); + + for ( i = 1, nbent = g_entities + i; i < level.num_entities; i++, nbent++ ) + { + if( nbent->nobuilder == qtrue ) + { + + range[0] = nbent->nobuildarea; + range[1] = nbent->nobuildarea; + range[2] = 0; + + VectorAdd( nbent->r.currentOrigin, range, maxs3 ); + VectorSubtract( nbent->r.currentOrigin, range, mins3 ); + maxs[2] += 5; + + num2 = trap_EntitiesInBox( mins3, maxs3, entitylist, MAX_GENTITIES ); + for(i = 0; i < num2; i++) + { + gentity_t *tent2 = &g_entities[ entitylist[ i ] ]; + + if( tent2 == nb ) + { + reason = IBE_PERMISSION; + } + } + } + } + + G_FreeEntity( nb ); + //can we build at this angle? if( !( normal[ 2 ] >= minNormal || ( invert && normal[ 2 ] <= -minNormal ) ) ) reason = IBE_NORMAL; @@ -3077,6 +3127,7 @@ itemBuildError_t G_CanBuild( gentity_t *ent, buildable_t buildable, int distance for(i = 0; i < num; i++) { gentity_t *tent = &g_entities[ entitylist[ i ] ]; + if( tent->s.eType == ET_PLAYER ) { reason = IBE_NOROOM; @@ -3571,7 +3622,6 @@ static gentity_t *G_Build( gentity_t *builder, buildable_t buildable, vec3_t ori trap_LinkEntity( built ); - if( builder->client ) { builder->client->pers.statscounters.structsbuilt++; @@ -4417,3 +4467,160 @@ char *G_FindBuildLogName( int id ) return ""; } +/* +========================= +Me stealing all of the layout code and making it work for nobuild, i know, im lazy, shutup. +========================= +*/ + +/* +============ +G_NobuildSave + +============ +*/ +void G_NobuildSave( void ) +{ + char map[ MAX_QPATH ]; + char fileName[ MAX_OSPATH ]; + fileHandle_t f; + int len; + int i; + gentity_t *ent; + char *s; + + trap_Cvar_VariableStringBuffer( "mapname", map, sizeof( map ) ); + if( !map[ 0 ] ) + { + G_Printf( "NobuildSave( ): no map is loaded\n" ); + return; + } + Com_sprintf( fileName, sizeof( fileName ), "nobuild/%s.dat", map ); + + len = trap_FS_FOpenFile( fileName, &f, FS_WRITE ); + if( len < 0 ) + { + G_Printf( "nobuildsave: could not open %s\n", fileName ); + return; + } + + G_Printf("nobuildsave: saving nobuild to %s\n", fileName ); + + for( i = MAX_CLIENTS; i < level.num_entities; i++ ) + { + ent = &level.gentities[ i ]; + if( ent->nobuilder != qtrue ) + continue; + + s = va( "%f %f %f %f\n", + ent->s.pos.trBase[ 0 ], + ent->s.pos.trBase[ 1 ], + ent->s.pos.trBase[ 2 ], + ent->nobuildarea ); + trap_FS_Write( s, strlen( s ), f ); + } + trap_FS_FCloseFile( f ); +} + +int G_NobuildList( char *list, int len ) +{ + // up to 128 single character nobuild names could fit in nobuilds + char fileList[ ( MAX_CVAR_VALUE_STRING / 2 ) * 5 ] = {""}; + char nobuild[ MAX_CVAR_VALUE_STRING ] = {""}; + int numFiles, i, fileLen = 0, listLen; + int count = 0; + char *filePtr; + + numFiles = trap_FS_GetFileList( va( "nobuild" ), ".dat", + fileList, sizeof( fileList ) ); + filePtr = fileList; + for( i = 0; i < numFiles; i++, filePtr += fileLen + 1 ) + { + fileLen = strlen( filePtr ); + listLen = strlen( nobuild ); + if( fileLen < 5 ) + continue; + + // list is full, stop trying to add to it + if( ( listLen + fileLen ) >= sizeof( nobuild ) ) + break; + + Q_strcat( nobuild, sizeof( nobuild ), filePtr ); + listLen = strlen( nobuild ); + + // strip extension and add space delimiter + nobuild[ listLen - 4 ] = ' '; + nobuild[ listLen - 3 ] = '\0'; + count++; + } + if( count != numFiles ) + { + G_Printf( S_COLOR_YELLOW "WARNING: nobuild list was truncated to %d " + "nobuilds, but %d nobuild files exist in /nobuilds/.\n", + count, numFiles ); + } + Q_strncpyz( list, nobuild, len ); + return count + 1; +} + +/* +============ +G_NobuildLoad + +load the nobuild markers that were previously saved (if there are any). +============ +*/ +void G_NobuildLoad( void ) +{ + fileHandle_t f; + int len; + char *nobuild; + char map[ MAX_QPATH ]; + vec3_t origin = { 0.0f, 0.0f, 0.0f }; + char line[ MAX_STRING_CHARS ]; + int i = 0; + gentity_t *nb; + float units; + + trap_Cvar_VariableStringBuffer( "mapname", map, sizeof( map ) ); + len = trap_FS_FOpenFile( va( "nobuild/%s.dat", map ), + &f, FS_READ ); + if( len < 0 ) + { + G_Printf( "ERROR: nobuild for %s could not be opened\n", map ); + return; + } + nobuild = G_Alloc( len + 1 ); + trap_FS_Read( nobuild, len, f ); + *( nobuild + len ) = '\0'; + trap_FS_FCloseFile( f ); + while( *nobuild ) + { + if( i >= sizeof( line ) - 1 ) + { + G_Printf( S_COLOR_RED "ERROR: line overflow in %s before \"%s\"\n", + va( "nobuild/%s.dat", map ), line ); + return; + } + line[ i++ ] = *nobuild; + line[ i ] = '\0'; + if( *nobuild == '\n' ) + { + i = 0; + sscanf( line, "%f %f %f %f\n", + &origin[ 0 ], &origin[ 1 ], &origin[ 2 ], &units ); + + nb = G_Spawn( ); + nb->s.modelindex = 1337; //Coder humor is awesome isn't it? + nb->think = NoThink; + nb->nextthink = level.time; + VectorCopy( origin, nb->s.pos.trBase ); + VectorCopy( origin, nb->r.currentOrigin ); + nb->nobuilder = qtrue; + nb->nobuildarea = units; + trap_LinkEntity( nb ); + + } + nobuild++; + } +} diff --git a/src/game/g_local.h b/src/game/g_local.h index e2345a1..80300ff 100644 --- a/src/game/g_local.h +++ b/src/game/g_local.h @@ -244,6 +244,9 @@ struct gentity_s int bdnumb; // buildlog entry ID gentity_t *oldent; int livetime; + + qboolean nobuilder; + float nobuildarea; }; typedef enum @@ -884,6 +887,9 @@ 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_NobuildSave( void ); +int G_NobuildList( char *list, int len ); +void G_NobuildLoad( void ); void G_BaseSelfDestruct( pTeam_t team ); gentity_t *G_InstantBuild( buildable_t buildable, vec3_t origin, vec3_t angles, vec3_t origin2, vec3_t angles2 ); void G_SpawnRevertedBuildable( buildHistory_t *bh, qboolean mark ); diff --git a/src/game/g_main.c b/src/game/g_main.c index e80f14d..4407304 100644 --- a/src/game/g_main.c +++ b/src/game/g_main.c @@ -863,6 +863,9 @@ void G_InitGame( int levelTime, int randomSeed, int restart ) // load up a custom building layout if there is one G_LayoutLoad( ); + + // load nobuilds, if there are any + G_NobuildLoad( ); // the map might disable some things BG_InitAllowedGameElements( ); diff --git a/src/game/g_svcmds.c b/src/game/g_svcmds.c index d927402..38e0239 100644 --- a/src/game/g_svcmds.c +++ b/src/game/g_svcmds.c @@ -544,6 +544,33 @@ void Svcmd_LayoutLoad_f( void ) level.restarted = qtrue; } +/* +=================== +Svcmd_NobuildSave_f + +nobuildsave +=================== +*/ +void Svcmd_NobuildSave_f( void ) +{ + G_NobuildSave(); +} + +char *ConcatArgs( int start ); + +/* +=================== +Svcmd_NobuildLoad_f + +nobuildload + +=================== +*/ +void Svcmd_NobuildLoad_f( void ) +{ + G_NobuildLoad(); +} + static void Svcmd_AdmitDefeat_f( void ) { int team; @@ -688,6 +715,18 @@ qboolean ConsoleCommand( void ) return qtrue; } + if( !Q_stricmp( cmd, "nobuildsave" ) ) + { + Svcmd_NobuildSave_f( ); + return qtrue; + } + + if( !Q_stricmp( cmd, "nobuildload" ) ) + { + Svcmd_NobuildLoad_f( ); + return qtrue; + } + if( !Q_stricmp( cmd, "admitdefeat" ) ) { Svcmd_AdmitDefeat_f( );