diff --git a/Makefile b/Makefile index 2f3f339..826bf23 100644 --- a/Makefile +++ b/Makefile @@ -21,11 +21,11 @@ else COMPILE_ARCH=$(shell uname -m | sed -e s/i.86/x86/) endif -BUILD_CLIENT = -BUILD_CLIENT_SMP = -BUILD_SERVER = -BUILD_GAME_SO = -BUILD_GAME_QVM = +BUILD_CLIENT =0 +BUILD_CLIENT_SMP =0 +BUILD_SERVER =0 +BUILD_GAME_SO =0 +BUILD_GAME_QVM =1 ############################################################################# # diff --git a/src/game/bg_misc.c b/src/game/bg_misc.c index 0a8aac6..b5ba247 100644 --- a/src/game/bg_misc.c +++ b/src/game/bg_misc.c @@ -3747,6 +3747,27 @@ weaponAttributes_t bg_weapons[ ] = int bg_numWeapons = sizeof( bg_weapons ) / sizeof( bg_weapons[ 0 ] ); +/* +============== +BG_UpdateWeaponData +============== +*/ +void BG_UpdateWeaponData(int proximityMine) { + int i; + + for(i=0; iexec ); admin_log( ent, cmd, skip ); - G_admin_adminlog_log( ent, cmd, skip, qtrue ); + G_admin_adminlog_log( ent, cmd, NULL, skip, qtrue ); } else { ADMP( va( "^3!%s: ^7permission denied\n", g_admin_commands[ i ]->command ) ); admin_log( ent, "attempted", skip - 1 ); - G_admin_adminlog_log( ent, cmd, skip, qfalse ); + G_admin_adminlog_log( ent, cmd, NULL, skip, qfalse ); } return qtrue; } @@ -1324,13 +1334,13 @@ qboolean G_admin_cmd_check( gentity_t *ent, qboolean say ) { g_admin_cmds[ i ].handler( ent, skip ); admin_log( ent, cmd, skip ); - G_admin_adminlog_log( ent, cmd, skip, qtrue ); + G_admin_adminlog_log( ent, cmd, NULL, skip, qtrue ); } else { ADMP( va( "^3!%s: ^7permission denied\n", g_admin_cmds[ i ].keyword ) ); admin_log( ent, "attempted", skip - 1 ); - G_admin_adminlog_log( ent, cmd, skip, qfalse ); + G_admin_adminlog_log( ent, cmd, NULL, skip, qfalse ); } return qtrue; } @@ -2506,6 +2516,7 @@ qboolean G_admin_devmap( gentity_t *ent, int skiparg ) AP( va( "print \"^3!devmap: ^7map '%s' started by %s^7 with cheats %s\n\"", map, ( ent ) ? ent->client->pers.netname : "console", ( layout[ 0 ] ) ? va( "(forcing layout '%s')", layout ) : "" ) ); + G_admin_maplog_result( "D" ); return qtrue; } @@ -2656,6 +2667,183 @@ qboolean G_admin_denybuild( gentity_t *ent, int skiparg ) return qtrue; } +qboolean G_admin_denyweapon( gentity_t *ent, int skiparg ) +{ + int pids[ MAX_CLIENTS ]; + char name[ MAX_NAME_LENGTH ], err[ MAX_STRING_CHARS ]; + char command[ MAX_ADMIN_CMD_LEN ], *cmd; + char buffer[ 32 ]; + int weapon = WP_NONE; + int class = PCL_NONE; + char *realname; + gentity_t *vic; + int flag; + + G_SayArgv( skiparg, command, sizeof( command ) ); + cmd = command; + if( cmd && *cmd == '!' ) + cmd++; + if( G_SayArgc() < 3 + skiparg ) + { + ADMP( va( "^3!%s: ^7usage: !%s [name|slot#] [class|weapon]\n", cmd, cmd ) ); + return qfalse; + } + G_SayArgv( 1 + skiparg, name, sizeof( name ) ); + if( G_ClientNumbersFromString( name, pids ) != 1 ) + { + G_MatchOnePlayer( pids, err, sizeof( err ) ); + ADMP( va( "^3!%s: ^7%s\n", cmd, err ) ); + return qfalse; + } + if( !admin_higher( ent, &g_entities[ pids[ 0 ] ] ) ) + { + ADMP( va( "^3!%s: ^7sorry, but your intended victim has a higher admin" + " level than you\n", cmd ) ); + return qfalse; + } + vic = &g_entities[ pids[ 0 ] ]; + + G_SayArgv( 2 + skiparg, buffer, sizeof( buffer ) ); + + if( !Q_stricmp( buffer, "all" ) && + !Q_stricmp( cmd, "allowweapon" ) ) + { + if( vic->client->pers.denyHumanWeapons || + vic->client->pers.denyAlienClasses ) + { + vic->client->pers.denyHumanWeapons = 0; + vic->client->pers.denyAlienClasses = 0; + + CPx( pids[ 0 ], "cp \"^1You've regained all weapon and class rights\"" ); + AP( va( "print \"^3!%s: ^7all weapon and class rights for ^7%s^7 restored by %s\n\"", + cmd, + vic->client->pers.netname, + ( ent ) ? ent->client->pers.netname : "console" ) ); + } + else + { + ADMP( va( "^3!%s: ^7player already has all rights\n", cmd ) ); + } + return qtrue; + } + + weapon = BG_FindWeaponNumForName( buffer ); + if( weapon < WP_PAIN_SAW || weapon > WP_GRENADE ) + class = BG_FindClassNumForName( buffer ); + if( ( weapon < WP_PAIN_SAW || weapon > WP_GRENADE ) && + ( class < PCL_ALIEN_LEVEL0 || class > PCL_ALIEN_LEVEL4 ) ) + { + ADMP( va( "^3!%s: ^7unknown weapon or class\n", cmd ) ); + return qfalse; + } + + if( class == PCL_NONE ) + { + realname = BG_FindHumanNameForWeapon( weapon ); + flag = 1 << (weapon - WP_BLASTER); + if( !Q_stricmp( cmd, "denyweapon" ) ) + { + if( ( vic->client->pers.denyHumanWeapons & flag ) ) + { + ADMP( va( "^3!%s: ^7player already has no %s rights\n", cmd, realname ) ); + return qtrue; + } + vic->client->pers.denyHumanWeapons |= flag; + if( vic->client->pers.teamSelection == PTE_HUMANS ) + { + if( weapon == WP_GRENADE && + BG_InventoryContainsUpgrade( UP_GRENADE, vic->client->ps.stats ) ) + { + BG_RemoveUpgradeFromInventory( UP_GRENADE, vic->client->ps.stats ); + G_AddCreditToClient( vic->client, (short)BG_FindPriceForUpgrade( UP_GRENADE ), qfalse ); + } + else if( BG_InventoryContainsWeapon( weapon, vic->client->ps.stats ) ) + { + int maxAmmo, maxClips; + + BG_RemoveWeaponFromInventory( weapon, vic->client->ps.stats ); + G_AddCreditToClient( vic->client, (short)BG_FindPriceForWeapon( weapon ), qfalse ); + + BG_AddWeaponToInventory( WP_MACHINEGUN, vic->client->ps.stats ); + BG_FindAmmoForWeapon( WP_MACHINEGUN, &maxAmmo, &maxClips ); + BG_PackAmmoArray( WP_MACHINEGUN, vic->client->ps.ammo, vic->client->ps.powerups, + maxAmmo, maxClips ); + G_ForceWeaponChange( vic, WP_MACHINEGUN ); + vic->client->ps.stats[ STAT_MISC ] = 0; + ClientUserinfoChanged( pids[ 0 ] ); + } + } + } + else + { + if( !( vic->client->pers.denyHumanWeapons & flag ) ) + { + ADMP( va( "^3!%s: ^7player already has %s rights\n", cmd, realname ) ); + return qtrue; + } + vic->client->pers.denyHumanWeapons &= ~flag; + } + } + else + { + realname = BG_FindHumanNameForClassNum( class ); + flag = 1 << class; + if( !Q_stricmp( cmd, "denyweapon" ) ) + { + if( ( vic->client->pers.denyAlienClasses & flag ) ) + { + ADMP( va( "^3!%s: ^7player already has no %s rights\n", cmd, realname ) ); + return qtrue; + } + vic->client->pers.denyAlienClasses |= flag; + if( vic->client->pers.teamSelection == PTE_ALIENS && + ent->client->pers.classSelection == class ) + { + vec3_t infestOrigin; + short cost; + + G_RoomForClassChange( vic, PCL_ALIEN_LEVEL0, infestOrigin ); + + vic->client->pers.evolveHealthFraction = (float)vic->client->ps.stats[ STAT_HEALTH ] / + (float)BG_FindHealthForClass( class ); + if( ent->client->pers.evolveHealthFraction < 0.0f ) + ent->client->pers.evolveHealthFraction = 0.0f; + else if( ent->client->pers.evolveHealthFraction > 1.0f ) + ent->client->pers.evolveHealthFraction = 1.0f; + + ent->client->pers.classSelection = PCL_ALIEN_LEVEL0; + cost = BG_ClassCanEvolveFromTo( PCL_ALIEN_LEVEL0, class, 9, 0 ); + if( cost < 0 ) cost = 0; + G_AddCreditToClient( vic->client, cost, qfalse ); + ClientUserinfoChanged( pids[ 0 ] ); + VectorCopy( infestOrigin, vic->s.pos.trBase ); + ClientSpawn( vic, vic, vic->s.pos.trBase, vic->s.apos.trBase ); + } + } + else + { + if( !( vic->client->pers.denyAlienClasses & flag ) ) + { + ADMP( va( "^3!%s: ^7player already has %s rights\n", cmd, realname ) ); + return qtrue; + } + vic->client->pers.denyAlienClasses &= ~flag; + } + } + + CPx( pids[ 0 ], va( "cp \"^1You've %s your %s rights\"", + ( !Q_stricmp( cmd, "denyweapon" ) ) ? "lost" : "regained", + realname ) ); + AP( va( + "print \"^3!%s: ^7%s rights for ^7%s^7 %s by %s\n\"", + cmd, realname, + vic->client->pers.netname, + ( !Q_stricmp( cmd, "denyweapon" ) ) ? "revoked" : "restored", + ( ent ) ? ent->client->pers.netname : "console" ) ); + + return qtrue; +} + qboolean G_admin_listadmins( gentity_t *ent, int skiparg ) { int i, found = 0; @@ -2863,6 +3051,10 @@ qboolean G_admin_listplayers( gentity_t *ent, int skiparg ) { Q_strncpyz( denied, "B", sizeof( denied ) ); } + if( p->pers.denyHumanWeapons || p->pers.denyAlienClasses ) + { + Q_strncpyz( denied, "W", sizeof( denied ) ); + } dbuilder[ 0 ] = '\0'; if( p->pers.designatedBuilder ) @@ -5280,8 +5472,7 @@ qboolean G_admin_cp( gentity_t *ent, int skiparg ) int minargc; char *s; - - minargc = 2 + skiparg; + minargc = 2 + skiparg; if( G_SayArgc() < minargc ) { @@ -5291,11 +5482,11 @@ qboolean G_admin_cp( gentity_t *ent, int skiparg ) s = G_SayConcatArgs( 1 + skiparg ); Q_strncpyz( msg, s, sizeof( msg ) ); + G_ParseEscapedString( msg ); + trap_SendServerCommand( -1, va( "cp \"%s\"", msg ) ); + trap_SendServerCommand( -1, va( "print \"CP: %s\n\"", msg ) ); -trap_SendServerCommand( -1, va( "cp \"%s\"", msg ) ); - - return qtrue; - + return qtrue; } qboolean G_admin_customgrav( gentity_t *ent, int skiparg ) @@ -5493,7 +5684,7 @@ void G_admin_adminlog_cleanup( void ) admin_adminlog_index = 0; } -void G_admin_adminlog_log( gentity_t *ent, char *command, int skiparg, qboolean success ) +void G_admin_adminlog_log( gentity_t *ent, char *command, char *args, int skiparg, qboolean success ) { g_admin_adminlog_t *adminlog; int previous; @@ -5531,7 +5722,11 @@ void G_admin_adminlog_log( gentity_t *ent, char *command, int skiparg, qboolean adminlog->time = level.time - level.startTime; adminlog->success = success; Q_strncpyz( adminlog->command, command, sizeof( adminlog->command ) ); - Q_strncpyz( adminlog->args, G_SayConcatArgs( 1 + skiparg ), sizeof( adminlog->args ) ); + + if ( args ) + Q_strncpyz( adminlog->args, args, sizeof( adminlog->args ) ); + else + Q_strncpyz( adminlog->args, G_SayConcatArgs( 1 + skiparg ), sizeof( adminlog->args ) ); if( ent ) { @@ -5887,6 +6082,9 @@ qboolean G_admin_maplog( gentity_t *ent, int skiparg ) case 'M': result = "^6admin changed map"; break; + case 'D': + result = "^6admin loaded devmap"; + break; default: result = ""; break; @@ -5939,6 +6137,7 @@ qboolean G_admin_listmaps( gentity_t *ent, int skiparg ) { char fileList[ 4096 ] = {""}; char *fileSort[ MAX_LISTMAPS_MAPS ]; + char search[ 16 ] = {""}; int numFiles; int i; int fileLen = 0; @@ -5946,6 +6145,11 @@ qboolean G_admin_listmaps( gentity_t *ent, int skiparg ) char *filePtr; int rows; + if( G_SayArgc( ) > 1 + skiparg ) + { + G_SayArgv( skiparg + 1, search, sizeof( search ) ); + } + numFiles = trap_FS_GetFileList( "maps/", ".bsp", fileList, sizeof( fileList ) ); filePtr = fileList; @@ -5956,6 +6160,10 @@ qboolean G_admin_listmaps( gentity_t *ent, int skiparg ) continue; filePtr[ fileLen - 4 ] = '\0'; + + if( search[ 0 ] && !strstr( filePtr, search ) ) + continue; + fileSort[ count ] = filePtr; count++; } @@ -5973,7 +6181,11 @@ qboolean G_admin_listmaps( gentity_t *ent, int skiparg ) ( rows + i < count ) ? fileSort[ rows + i ] : "", ( rows * 2 + i < count ) ? fileSort[ rows * 2 + i ] : "" ) ); } - ADMBP( va( "^3!listmaps: ^7listing %d maps.\n", count ) ); + if ( search[ 0 ] ) + ADMBP( va( "^3!listmaps: ^7found %d maps matching '%s^7'.\n", count, search ) ); + else + ADMBP( va( "^3!listmaps: ^7listing %d maps.\n", count ) ); + ADMBP_end(); return qtrue; diff --git a/src/game/g_admin.h b/src/game/g_admin.h index c3b8b0f..2965b9e 100644 --- a/src/game/g_admin.h +++ b/src/game/g_admin.h @@ -184,6 +184,7 @@ qboolean G_admin_devmap( gentity_t *ent, int skiparg ); qboolean G_admin_layoutsave( gentity_t *ent, int skiparg ); qboolean G_admin_mute( gentity_t *ent, int skiparg ); qboolean G_admin_denybuild( gentity_t *ent, int skiparg ); +qboolean G_admin_denyweapon( gentity_t *ent, int skiparg ); qboolean G_admin_showbans( gentity_t *ent, int skiparg ); qboolean G_admin_help( gentity_t *ent, int skiparg ); qboolean G_admin_admintest( gentity_t *ent, int skiparg ); @@ -217,7 +218,7 @@ qboolean G_admin_immunity( gentity_t *ent, int skiparg ); qboolean G_admin_suspendban( gentity_t *ent, int skiparg ); qboolean G_admin_adminlog( gentity_t *ent, int skiparg ); void G_admin_adminlog_cleanup( void ); -void G_admin_adminlog_log( gentity_t *ent, char *command, int skiparg, qboolean success ); +void G_admin_adminlog_log( gentity_t *ent, char *command, char *args, int skiparg, qboolean success ); qboolean G_admin_maplog( gentity_t *ent, int skiparg ); void G_admin_maplog_update( void ); void G_admin_maplog_result( char *flag ); diff --git a/src/game/g_client.c b/src/game/g_client.c index f6ae2d2..a8a8359 100644 --- a/src/game/g_client.c +++ b/src/game/g_client.c @@ -935,10 +935,14 @@ static void ClientCleanName( const char *in, char *out, int outSize ) if( !*in ) break; - // don't allow black in a name, period - if( ColorIndex( *in ) == 0 ) + // two escapes in a row, skip this one + if( *in == Q_COLOR_ESCAPE ) { - in++; + if( len > outSize - 1 ) + break; + + *out++ = ch; + len++; continue; } @@ -947,7 +951,12 @@ static void ClientCleanName( const char *in, char *out, int outSize ) break; *out++ = ch; - *out++ = *in++; + // don't allow black in a name, use white + if( ColorIndex( *in ) == 0 ) + *out++ = '7'; + else + *out++ = *in; + in++; len += 2; continue; } diff --git a/src/game/g_cmds.c b/src/game/g_cmds.c index 8c34d85..5fd920a 100644 --- a/src/game/g_cmds.c +++ b/src/game/g_cmds.c @@ -1178,7 +1178,8 @@ static void Cmd_SayArea_f( gentity_t *ent ) vec3_t mins, maxs; char *msg = ConcatArgs( 1 ); char name[ 64 ]; - + char location[ 64 ]; + if( g_floodMinTime.integer ) if ( G_Flood_Limited( ent ) ) { @@ -1208,8 +1209,13 @@ static void Cmd_SayArea_f( gentity_t *ent ) prefix = ""; G_LogPrintf( "sayarea: %s %s: %s\n", prefix, ent->client->pers.netname, msg ); - Com_sprintf( name, sizeof( name ), EC"%s <%s%c%c"EC"> ", - prefix, ent->client->pers.netname, Q_COLOR_ESCAPE, COLOR_WHITE ); + + if( g_sayAreaLocations.integer && Team_GetLocationMsg( ent, location, sizeof( location ) ) ) + Com_sprintf( name, sizeof( name ), EC"%s<%s%c%c"EC"> (%s)"EC" ", + prefix, ent->client->pers.netname, Q_COLOR_ESCAPE, COLOR_WHITE, location ); + else + Com_sprintf( name, sizeof( name ), EC"%s<%s%c%c"EC"> ", + prefix, ent->client->pers.netname, Q_COLOR_ESCAPE, COLOR_WHITE ); VectorAdd( ent->s.origin, range, maxs ); VectorSubtract( ent->s.origin, range, mins ); @@ -1219,7 +1225,6 @@ static void Cmd_SayArea_f( gentity_t *ent ) G_SayTo( ent, &g_entities[ entityList[ i ] ], SAY_TEAM, color, name, msg, prefix ); } - /* ================== Cmd_Say_f @@ -1453,6 +1458,15 @@ void Cmd_CallVote_f( gentity_t *ent ) // if there is still a vote to be executed if( level.voteExecuteTime ) { + if( !Q_stricmp( level.voteString, "map_restart" ) ) + { + G_admin_maplog_result( "r" ); + } + else if( !Q_stricmpn( level.voteString, "map", 3 ) ) + { + G_admin_maplog_result( "m" ); + } + level.voteExecuteTime = 0; trap_SendConsoleCommand( EXEC_APPEND, va( "%s\n", level.voteString ) ); } @@ -1533,6 +1547,7 @@ void Cmd_CallVote_f( gentity_t *ent ) trap_SendServerCommand( ent-g_entities, "print \"callvote: admin is immune from vote kick\n\"" ); G_AdminsPrintf("%s\n",message); + G_admin_adminlog_log( ent, "vote", NULL, 0, qfalse ); return; } @@ -1558,6 +1573,7 @@ void Cmd_CallVote_f( gentity_t *ent ) trap_SendServerCommand( ent-g_entities, "print \"callvote: admin is immune from vote mute\n\"" ); G_AdminsPrintf("%s\n",message); + G_admin_adminlog_log( ent, "vote", NULL, 0, qfalse ); return; } @@ -1589,6 +1605,7 @@ void Cmd_CallVote_f( gentity_t *ent ) trap_SendServerCommand( ent-g_entities, va( "print \"You cannot call for a restart after %d seconds\n\"", g_mapvoteMaxTime.integer ) ); + G_admin_adminlog_log( ent, "vote", NULL, 0, qfalse ); return; } Com_sprintf( level.voteString, sizeof( level.voteString ), "%s", arg1 ); @@ -1606,6 +1623,7 @@ void Cmd_CallVote_f( gentity_t *ent ) trap_SendServerCommand( ent-g_entities, va( "print \"You cannot call for a mapchange after %d seconds\n\"", g_mapvoteMaxTime.integer ) ); + G_admin_adminlog_log( ent, "vote", NULL, 0, qfalse ); return; } @@ -1615,8 +1633,16 @@ void Cmd_CallVote_f( gentity_t *ent ) "'maps/%s.bsp' could not be found on the server\n\"", arg2 ) ); return; } - - Com_sprintf( level.voteString, sizeof( level.voteString ), "%s %s", arg1, arg2 ); + + if (!g_devmapVotes.integer) + { + Com_sprintf( level.voteString, sizeof( level.voteString ), "map %s", arg2 ); + } + else + { + Com_sprintf( level.voteString, sizeof( level.voteString ), "devmap %s", arg2 ); + } + Com_sprintf( level.voteDisplayString, sizeof( level.voteDisplayString ), "Change to map '%s'", arg2 ); level.votePercentToPass = g_mapVotesPercent.integer; @@ -1702,7 +1728,8 @@ void Cmd_CallVote_f( gentity_t *ent ) { Q_strcat( level.voteDisplayString, sizeof( level.voteDisplayString ), va( " (Needs %d percent)", level.votePercentToPass ) ); } - + + G_admin_adminlog_log( ent, "vote", NULL, 0, qtrue ); trap_SendServerCommand( -1, va( "print \"%s" S_COLOR_WHITE " called a vote: %s\n\"", ent->client->pers.netname, level.voteDisplayString ) ); @@ -1946,6 +1973,7 @@ void Cmd_CallTeamVote_f( gentity_t *ent ) trap_SendServerCommand( ent-g_entities, "print \"callteamvote: admin is immune from vote kick\n\"" ); G_AdminsPrintf("%s\n",message); + G_admin_adminlog_log( ent, "teamvote", NULL, 0, qfalse ); return; } @@ -1973,6 +2001,7 @@ void Cmd_CallTeamVote_f( gentity_t *ent ) trap_SendServerCommand( ent-g_entities, "print \"callteamvote: admin is immune from denybuild\n\"" ); G_AdminsPrintf("%s\n",message); + G_admin_adminlog_log( ent, "teamvote", NULL, 0, qfalse ); return; } @@ -2070,6 +2099,8 @@ void Cmd_CallTeamVote_f( gentity_t *ent ) } ent->client->pers.voteCount++; + G_admin_adminlog_log( ent, "teamvote", arg1, 0, qtrue ); + if( level.teamVotePercentToPass[ cs_offset ] != 50 ) { Q_strcat( level.teamVoteDisplayString[ cs_offset ], sizeof( level.teamVoteDisplayString[ cs_offset ] ), @@ -2195,8 +2226,7 @@ void Cmd_SetViewpos_f( gentity_t *ent ) #define AS_OVER_RT3 ((ALIENSENSE_RANGE*0.5f)/M_ROOT3) -static qboolean G_RoomForClassChange( gentity_t *ent, pClass_t class, - vec3_t newOrigin ) +qboolean G_RoomForClassChange( gentity_t *ent, pClass_t class, vec3_t newOrigin ) { vec3_t fromMins, fromMaxs; vec3_t toMins, toMaxs; @@ -2351,6 +2381,13 @@ void Cmd_Class_f( gentity_t *ent ) return; } + // denyweapons + if( newClass >= PCL_ALIEN_LEVEL1 && newClass <= PCL_ALIEN_LEVEL4 && + ent->client->pers.denyAlienClasses & ( 1 << newClass ) ) + { + trap_SendServerCommand( ent-g_entities, va( "print \"You are denied from using this class\n\"" ) ); + return; + } //guard against selling the HBUILD weapons exploit if( ( currentClass == PCL_ALIEN_BUILDER0 || @@ -2790,7 +2827,10 @@ void Cmd_Buy_f( gentity_t *ent ) int maxAmmo, maxClips; qboolean buyingEnergyAmmo = qfalse; qboolean hasEnergyWeapon = qfalse; - + + BG_UpdateWeaponData(g_proximityMines.integer); + BG_UpdateUpgradeData(g_proximityMines.integer); + for( i = UP_NONE; i < UP_NUM_UPGRADES; i++ ) { if( BG_InventoryContainsUpgrade( i, ent->client->ps.stats ) ) @@ -2812,6 +2852,13 @@ void Cmd_Buy_f( gentity_t *ent ) weapon = BG_FindWeaponNumForName( s ); upgrade = BG_FindUpgradeNumForName( s ); + if ( ent->client->ps.pm_flags&PMF_DUCKED && upgrade == UP_BATTLESUIT ) + { + trap_SendServerCommand( ent-g_entities, va( + "print \"Cannot buy a battlesuit while crouching\n\"" ) ); + return; + } + //special case to keep norf happy if( weapon == WP_NONE && upgrade == UP_AMMO ) { @@ -2849,7 +2896,14 @@ void Cmd_Buy_f( gentity_t *ent ) G_TriggerMenu( ent->client->ps.clientNum, MN_H_ITEMHELD ); return; } - + + // denyweapons + if( weapon >= WP_PAIN_SAW && weapon <= WP_GRENADE && + ent->client->pers.denyHumanWeapons & ( 1 << (weapon - WP_BLASTER) ) ) + { + trap_SendServerCommand( ent-g_entities, va( "print \"You are denied from buying this weapon\n\"" ) ); + return; + } //can afford this? if( BG_FindPriceForWeapon( weapon ) > (short)ent->client->ps.persistant[ PERS_CREDIT ] ) @@ -2922,6 +2976,14 @@ void Cmd_Buy_f( gentity_t *ent ) return; } + // denyweapons + if( upgrade == UP_GRENADE && + ent->client->pers.denyHumanWeapons & ( 1 << (WP_GRENADE - WP_BLASTER) ) ) + { + trap_SendServerCommand( ent-g_entities, va( "print \"You are denied from buying this upgrade\n\"" ) ); + return; + } + //can afford this? if( BG_FindPriceForUpgrade( upgrade ) > (short)ent->client->ps.persistant[ PERS_CREDIT ] ) { @@ -3539,7 +3601,7 @@ qboolean G_FollowNewClient( gentity_t *ent, int dir ) continue; // can't follow another spectator - if( level.clients[ clientnum ].pers.teamSelection == PTE_NONE ) + if( level.clients[ clientnum ].pers.teamSelection == PTE_NONE && !g_specAspec.integer ) continue; // this is good, we can use it @@ -3605,7 +3667,7 @@ void Cmd_Follow_f( gentity_t *ent ) return; // can't follow another spectator - if( level.clients[ i ].pers.teamSelection == PTE_NONE ) + if( level.clients[ i ].pers.teamSelection == PTE_NONE && !g_specAspec.integer ) return; ent->client->sess.spectatorState = SPECTATOR_FOLLOW; @@ -4389,6 +4451,36 @@ void G_DecolorString( char *in, char *out ) *out = '\0'; } +void G_ParseEscapedString( char *buffer ) +{ + int i = 0; + int j = 0; + + while( buffer[i] ) + { + if(!buffer[i]) break; + + if(buffer[i] == '\\') + { + if(buffer[i + 1] == '\\') + buffer[j] = buffer[++i]; + else if(buffer[i + 1] == 'n') + { + buffer[j] = '\n'; + i++; + } + else + buffer[j] = buffer[i]; + } + else + buffer[j] = buffer[i]; + + i++; + j++; + } + buffer[j] = 0; +} + void G_PrivateMessage( gentity_t *ent ) { int pids[ MAX_CLIENTS ]; diff --git a/src/game/g_local.h b/src/game/g_local.h index 34f3c42..df4eb26 100644 --- a/src/game/g_local.h +++ b/src/game/g_local.h @@ -381,6 +381,8 @@ typedef struct char ip[ 16 ]; qboolean muted; qboolean denyBuild; + int denyHumanWeapons; + int denyAlienClasses; qboolean paused; int adminLevel; qboolean specd; @@ -738,6 +740,8 @@ typedef struct int extend_vote_count; + int lastMsgTime; + pTeam_t surrenderTeam; buildHistory_t *buildHistory; @@ -790,6 +794,7 @@ int G_SayArgc( void ); qboolean G_SayArgv( int n, char *buffer, int bufferLength ); char *G_SayConcatArgs( int start ); void G_DecolorString( char *in, char *out ); +void G_ParseEscapedString( char *buffer ); void G_LeaveTeam( gentity_t *self ); void G_ChangeTeam( gentity_t *ent, pTeam_t newTeam ); void G_SanitiseName( char *in, char *out ); @@ -798,6 +803,7 @@ void Cmd_TeamVote_f( gentity_t *ent ); char *G_statsString( statsCounters_t *sc, pTeam_t *pt ); void Cmd_Share_f( gentity_t *ent ); void Cmd_Donate_f( gentity_t *ent ); +qboolean G_RoomForClassChange( gentity_t *ent, pClass_t class, vec3_t newOrigin ); // // g_physics.c @@ -1245,6 +1251,7 @@ extern vmCvar_t g_synchronousClients; extern vmCvar_t g_motd; extern vmCvar_t g_warmup; extern vmCvar_t g_doWarmup; +extern vmCvar_t g_proximityMines; extern vmCvar_t g_blood; extern vmCvar_t g_allowVote; extern vmCvar_t g_voteLimit; @@ -1332,6 +1339,8 @@ extern vmCvar_t g_publicSayadmins; extern vmCvar_t g_myStats; extern vmCvar_t g_antiSpawnBlock; +extern vmCvar_t g_sayAreaLocations; + extern vmCvar_t g_dretchPunt; extern vmCvar_t g_allowActions; @@ -1346,15 +1355,21 @@ extern vmCvar_t g_radiationCreditsCount; extern vmCvar_t g_buyAll; extern vmCvar_t g_multipleWeapons; +extern vmCvar_t g_devmapVotes; extern vmCvar_t g_slapKnockback; extern vmCvar_t g_slapDamage; +extern vmCvar_t g_msg; +extern vmCvar_t g_msgTime; + extern vmCvar_t g_banNotice; extern vmCvar_t g_voteMinTime; extern vmCvar_t g_mapvoteMaxTime; +extern vmCvar_t g_specAspec; + void trap_Printf( const char *fmt ); void trap_Error( const char *fmt ); int trap_Milliseconds( void ); diff --git a/src/game/g_main.c b/src/game/g_main.c index 0b066a7..9caa0a5 100644 --- a/src/game/g_main.c +++ b/src/game/g_main.c @@ -72,6 +72,7 @@ vmCvar_t g_motd; vmCvar_t g_synchronousClients; vmCvar_t g_warmup; vmCvar_t g_doWarmup; +vmCvar_t g_proximityMines; vmCvar_t g_restarted; vmCvar_t g_lockTeamsAtStart; vmCvar_t g_logFile; @@ -168,6 +169,8 @@ vmCvar_t g_decolorLogfiles; vmCvar_t g_tag; +vmCvar_t g_sayAreaLocations; + vmCvar_t g_radiationDamage; vmCvar_t g_radiationTime; vmCvar_t g_radiationCredits; @@ -187,14 +190,20 @@ vmCvar_t g_devmapNoStructDmg; vmCvar_t g_slapKnockback; vmCvar_t g_slapDamage; +vmCvar_t g_msg; +vmCvar_t g_msgTime; + vmCvar_t g_buyAll; vmCvar_t g_multipleWeapons; +vmCvar_t g_devmapVotes; vmCvar_t g_banNotice; vmCvar_t g_voteMinTime; vmCvar_t g_mapvoteMaxTime; +vmCvar_t g_specAspec; + static cvarTable_t gameCvarTable[ ] = { // don't override the cheat state set by the system @@ -222,6 +231,8 @@ static cvarTable_t gameCvarTable[ ] = { &g_synchronousClients, "g_synchronousClients", "0", CVAR_SYSTEMINFO, 0, qfalse }, + { &g_sayAreaLocations, "g_sayAreaLocations", "0", CVAR_ARCHIVE, 0, qtrue }, + { &g_friendlyFire, "g_friendlyFire", "0", CVAR_ARCHIVE | CVAR_SERVERINFO, 0, qtrue }, { &g_friendlyFireAliens, "g_friendlyFireAliens", "0", CVAR_ARCHIVE, 0, qtrue }, { &g_friendlyFireHumans, "g_friendlyFireHumans", "0", CVAR_ARCHIVE, 0, qtrue }, @@ -230,10 +241,15 @@ static cvarTable_t gameCvarTable[ ] = { &g_friendlyFireMovementAttacks, "g_friendlyFireMovementAttacks", "1", CVAR_ARCHIVE, 0, qtrue }, { &g_devmapNoGod, "g_devmapNoGod", "0", CVAR_ARCHIVE, 0, qtrue }, { &g_devmapNoStructDmg, "g_devmapNoStructDmg", "0", CVAR_ARCHIVE, 0, qtrue }, - + + { &g_specAspec, "g_specAspec", "0", CVAR_ARCHIVE, 0, qtrue }, + + { &g_proximityMines, "g_proximityMines", "0", 0, 0, qtrue }, { &g_teamAutoJoin, "g_teamAutoJoin", "0", CVAR_ARCHIVE }, { &g_teamForceBalance, "g_teamForceBalance", "1", CVAR_ARCHIVE }, { &g_buyAll, "g_buyAll", "0", CVAR_ARCHIVE, 0, qtrue }, + { &g_devmapVotes, "g_devmapVotes", "0", CVAR_ARCHIVE, 0, qtrue }, + { &g_multipleWeapons, "g_multipleWeapons", "0", CVAR_ARCHIVE, 0, qtrue }, { &g_warmup, "g_warmup", "10", CVAR_ARCHIVE, 0, qtrue }, { &g_doWarmup, "g_doWarmup", "1", CVAR_ARCHIVE, 0, qtrue }, @@ -367,6 +383,8 @@ static cvarTable_t gameCvarTable[ ] = { &g_slapKnockback, "g_slapKnockback", "200", CVAR_ARCHIVE, 0, qfalse}, { &g_slapDamage, "g_slapDamage", "5", CVAR_ARCHIVE, 0, qfalse}, + { &g_msg, "g_msg", "", CVAR_ARCHIVE, 0, qfalse }, + { &g_msgTime, "g_msgTime", "0", CVAR_ARCHIVE, 0, qfalse }, { &g_rankings, "g_rankings", "0", 0, 0, qfalse }, { &g_allowShare, "g_allowShare", "1", CVAR_ARCHIVE | CVAR_SERVERINFO, 0, qfalse}, @@ -2311,6 +2329,11 @@ void CheckVote( void ) trap_SendServerCommand(-1, va("print \"Vote %s^7 (^2Y:%d^7-^1N:%d^7, %d percent) (%s)\n\"", result, level.voteYes, level.voteNo, voteYesPercent, level.voteDisplayString ) ); + G_admin_adminlog_log( NULL, "vote", + va( "%s^7 (^2Y:%d^7-^1N:%d^7, %d percent)", + result, level.voteYes, level.voteNo, voteYesPercent ), + 0, ( level.voteExecuteTime ) ); + level.voteTime = 0; trap_SetConfigstring( CS_VOTE_TIME, "" ); } @@ -2382,10 +2405,44 @@ void CheckTeamVote( int team ) trap_SendServerCommand( -1, va( "print \"Team vote %s^7 (^2Y:%d^7-^1N:%d^7, %d percent)\n\"", result, level.teamVoteYes[ cs_offset ], level.teamVoteNo[ cs_offset ], voteYesPercent ) ); + G_admin_adminlog_log( NULL, "teamvote", + va( "%s^7 (^2Y:%d^7-^1N:%d^7, %d percent)", + result, level.teamVoteYes[ cs_offset ], level.teamVoteNo[ cs_offset ], voteYesPercent ), + 0, ( strstr( result, "pass" ) != NULL ) ); + level.teamVoteTime[ cs_offset ] = 0; trap_SetConfigstring( CS_TEAMVOTE_TIME + cs_offset, "" ); } +/* +================== +CheckMsgTimer +================== +*/ +void CheckMsgTimer( void ) +{ + if( !g_msgTime.integer ) + return; + + if( level.time - level.lastMsgTime < abs( g_msgTime.integer ) * 60000 ) + return; + + // negative settings only print once per map + if( ( level.lastMsgTime ) && g_msgTime.integer < 0 ) + return; + + level.lastMsgTime = level.time; + + if( g_msg.string[0] ) + { + char buffer[ MAX_STRING_CHARS ]; + + Q_strncpyz( buffer, g_msg.string, sizeof( buffer ) ); + G_ParseEscapedString( buffer ); + trap_SendServerCommand( -1, va( "cp \"%s\"", buffer ) ); + trap_SendServerCommand( -1, va( "print \"%s\n\"", buffer ) ); + } +} /* ================== @@ -2508,6 +2565,8 @@ void G_RunFrame( int levelTime ) } } + CheckMsgTimer( ); + level.framenum++; level.previousTime = level.time; level.time = levelTime; diff --git a/src/game/g_missile.c b/src/game/g_missile.c index a058fd8..b02065c 100644 --- a/src/game/g_missile.c +++ b/src/game/g_missile.c @@ -45,7 +45,11 @@ void G_BounceMissile( gentity_t *ent, trace_t *trace ) if( ent->s.eFlags & EF_BOUNCE_HALF ) { - VectorScale( ent->s.pos.trDelta, 0.65, ent->s.pos.trDelta ); + if(!strcmp(ent->classname,"grenade") && g_proximityMines.integer) { + VectorScale( ent->s.pos.trDelta, 0.00, ent->s.pos.trDelta ); + } else { + VectorScale( ent->s.pos.trDelta, 0.65, ent->s.pos.trDelta ); + } // check for stop if( trace->plane.normal[ 2 ] > 0.2 && VectorLength( ent->s.pos.trDelta ) < 40 ) { @@ -59,7 +63,6 @@ void G_BounceMissile( gentity_t *ent, trace_t *trace ) ent->s.pos.trTime = level.time; } - /* ================ G_ExplodeMissile @@ -97,6 +100,40 @@ void G_ExplodeMissile( gentity_t *ent ) trap_LinkEntity( ent ); } +/* +================ +G_ProcessProximityMine + +If an enemy is close to the entity, go boom! +================ +*/ +void G_ProcessProximityMine(gentity_t *ent) { + int i, total_entities, entityList[MAX_GENTITIES]; + vec3_t range, mins, maxs; + gentity_t *target; + + // Set the next time to run this check (can be overwritten below) + ent->nextthink = level.time + PROXIMITY_CHECK_FREQUENCY; + + // Grab all entities around us + VectorSet(range, PROXIMITY_RANGE, PROXIMITY_RANGE, PROXIMITY_RANGE); + VectorAdd(ent->s.origin, range, maxs); + VectorSubtract(ent->s.origin, range, mins); + + total_entities = trap_EntitiesInBox(mins, maxs, entityList, MAX_GENTITIES); + + // Loop entities looking for an enemy body + for(i=0; iclient && target->client->ps.stats[ STAT_PTEAM ] == PTE_ALIENS) { + // Found an enemy, boom time! + ent->nextthink = level.time + PROXIMITY_BOOM_TIME; + ent->think = G_ExplodeMissile; + return; + } + } +} + void AHive_ReturnToHive( gentity_t *self ); /* @@ -491,8 +528,13 @@ gentity_t *launch_grenade( gentity_t *self, vec3_t start, vec3_t dir ) bolt = G_Spawn( ); bolt->classname = "grenade"; - bolt->nextthink = level.time + 5000; - bolt->think = G_ExplodeMissile; + if(g_proximityMines.integer) { + bolt->nextthink = level.time + PROXIMITY_INIT_TIME; + bolt->think = G_ProcessProximityMine; + } else { + bolt->nextthink = level.time + 5000; + bolt->think = G_ExplodeMissile; + } bolt->s.eType = ET_MISSILE; bolt->r.svFlags = SVF_USE_CURRENT_ORIGIN; bolt->s.weapon = WP_GRENADE; diff --git a/src/game/g_svcmds.c b/src/game/g_svcmds.c index 1c403a1..d927402 100644 --- a/src/game/g_svcmds.c +++ b/src/game/g_svcmds.c @@ -723,29 +723,11 @@ qboolean ConsoleCommand( void ) } else if( !Q_stricmp( cmd, "cp" ) ) { - int i, j; char buffer[MAX_STRING_CHARS]; Q_strncpyz( buffer, ConcatArgs( 1 ), sizeof( buffer ) ); - for( i = j = 0; i < strlen( buffer ); i++, j++ ) - { - if(!buffer[i]) break; - if(buffer[i] == '\\') - { - if(buffer[i + 1] == '\\') - buffer[j] = buffer[++i]; - else if(buffer[i + 1] == 'n') - { - buffer[j] = '\n'; - i++; - } - else - buffer[j] = buffer[i]; - } - else - buffer[j] = buffer[i]; - } - buffer[j] = 0; + G_ParseEscapedString( buffer ); trap_SendServerCommand( -1, va( "cp \"%s\"", buffer ) ); + trap_SendServerCommand( -1, va( "print \"CP: %s\n\"", buffer ) ); G_Printf( "cp: %s\n", ConcatArgs( 1 ) ); return qtrue; } diff --git a/src/game/tremulous.h b/src/game/tremulous.h index 2ea98dd..9466b1f 100644 --- a/src/game/tremulous.h +++ b/src/game/tremulous.h @@ -370,6 +370,13 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA #define GRENADE_RANGE 192.0f #define GRENADE_SPEED 400.0f +// Proximity Mine settings +#define PROXIMITY_INIT_TIME 3000 +#define PROXIMITY_RANGE 100 +#define PROXIMITY_CHECK_FREQUENCY 100 +#define PROXIMITY_BOOM_TIME 20 +#define PROXIMITY_PRICE 800 + #define SHOTGUN_PRICE 150 #define SHOTGUN_SHELLS 8 #define SHOTGUN_PELLETS 8 //used to sync server and client side