//----------------------------------------------------------------------------- // // $Logfile:: /Code/DLLs/game/mp_manager.cpp $ // $Revision:: 143 $ // $Author:: Singlis $ // $Date:: 9/26/03 3:53p $ // // Copyright (C) 2002 by Ritual Entertainment, Inc. // All rights reserved. // // This source may not be distributed and/or modified without // expressly written permission by Ritual Entertainment, Inc. // // DESCRIPTION: // #include "_pch_cpp.h" #include "player.h" #include "mp_manager.hpp" #include "mp_modeDm.hpp" #include "mp_modeTeamDm.hpp" #include "mp_modeCtf.hpp" #include "powerups.h" MultiplayerManager multiplayerManager; str playersLastTeam[ MAX_CLIENTS ]; // Setup constants const int MultiplayerManager::_playerFreezeTime = 100; //const int MultiplayerManager::_maxVoteCount = 3; const float MultiplayerManager::_maxVoteTime = 30.0f; const int MultiplayerManager::_maxSayStringLength = 150; const float MultiplayerManager::_inBetweenMatchTime = 3.0f; const int MultiplayerPlayerData::_maxDialogs = 16; MultiplayerPlayerData::MultiplayerPlayerData() { reset(); _dialogData = new MultiplayerDialogData[ _maxDialogs ]; } MultiplayerPlayerData::~MultiplayerPlayerData() { delete [] _dialogData; } void MultiplayerPlayerData::reset( void ) { _votecount = 0; _voted = false; _spectator = false; _spectatorByChoice = false; _valid = false; _waitingForRespawn = false; _teamHud = ""; _named = false; _nextDialogSendSpot = 0; _nextDialogAddSpot = 0; _nextDialogSendTime = 0.0f; _nextTauntTime = 0.0f; } CLASS_DECLARATION( Class, MultiplayerManager, NULL ) { { NULL, NULL } }; MultiplayerManager::MultiplayerManager() { _inMultiplayerGame = false; _multiplayerGame = NULL; _playerData = NULL; _awardSystem = NULL; _gameStarted = false; _gameOver = false; _needToAddBots = true; _inMatch = false; _talkingIconIndex = 0; _waitingToRespawnIconIndex = 0; _restartMatchTime = 0.0f; _voteTime = 0.0f; } MultiplayerManager::~MultiplayerManager() { cleanup( false ); } // // Interface for game dll // void MultiplayerManager::cleanup( qboolean restart ) { _inMultiplayerGame = false; _gameStarted = false; _gameOver = false; if ( !restart ) { _needToAddBots = true; } // Clean up the game delete _multiplayerGame; _multiplayerGame = NULL; // Clean up the player data delete [] _playerData; _playerData = NULL; // Clean up the award system delete _awardSystem; _awardSystem = NULL; // Clean up all the modifiers for ( int i = 1 ; i <= _modifiers.NumObjects() ; i++ ) { MultiplayerModifier *modifier; modifier = _modifiers.ObjectAt( i ); delete modifier; } _modifiers.FreeObjectList(); _voteTime = 0.0f; } void MultiplayerManager::init( void ) { _inMultiplayerGame = false; resetRespawnTime(); checkModifiedCvars( false ); } void MultiplayerManager::start( void ) { if ( !_inMultiplayerGame ) return; _gameStarted = true; _gameOver = false; _talkingIconIndex = gi.imageindex( "sysimg/icons/mp/talking" ); _waitingToRespawnIconIndex = gi.imageindex( "sysimg/icons/mp/elimination_eliminated" ); // Start the modifiers for ( int i = 1 ; i <= _modifiers.NumObjects() ; i++ ) { MultiplayerModifier *modifier; modifier = _modifiers.ObjectAt( i ); if ( modifier ) modifier->start(); } // Start the game _multiplayerGame->start(); } void MultiplayerManager::update( float frameTime ) { int i; if ( !_inMultiplayerGame ) return; // Restart the match if time if ( !_inMatch && !_gameOver && ( _restartMatchTime > 0.0f ) && ( _restartMatchTime < getTime() ) ) { restartMatch(); } // Update the respawn time if ( mp_respawnTime->modified ) { if ( mp_respawnTime->value >= 0.0f ) { setRespawnTime( mp_respawnTime->value ); } mp_respawnTime->modified = false; } // Start the game if not started already if ( !_gameStarted ) start(); if ( _needToAddBots ) addBots(); // Update all of the modifiers if ( _multiplayerGame->inMatch() ) { for ( i = 1 ; i <= _modifiers.NumObjects() ; i++ ) { MultiplayerModifier *modifier; modifier = _modifiers.ObjectAt( i ); if ( modifier ) modifier->update( frameTime ); } } // Update the game _multiplayerGame->update( frameTime ); // Check for voting conditions checkVote(); // Check for modified cvars checkModifiedCvars( true ); // Update cvars if ( strlen( password->string ) ) { if ( !g_needpass->integer ) { gi.cvar_set( "g_needpass", "1" ); } } else { if ( g_needpass->integer ) { gi.cvar_set( "g_needpass", "0" ); } } // Update dialogs for ( i = 0 ; i < maxclients->integer ; i++ ) { Player *player; // Get the player player = getPlayer( i ); if ( !player ) continue; sendNextPlayerSound( player ); } // Check for end of intermission if ( level.intermissiontime ) { G_CheckIntermissionExit(); if ( !_declaredWinner && ( _declareWinnerTime < getTime() ) ) { _multiplayerGame->declareWinner(); _declaredWinner = true; } return; } // Check for end of match if ( _multiplayerGame->isEndOfMatch() ) { _gameOver = true; centerPrintAllClients( "$$MatchOver$$\n", CENTERPRINT_IMPORTANCE_NORMAL ); multiplayerManager.broadcastSound( "localization/sound/dialog/dm/comp_matover.mp3", CHAN_AUTO, DEFAULT_VOL, DEFAULT_MIN_DIST, NULL, 1.2f ); _multiplayerGame->EndMatch(); G_BeginIntermission2(); matchOver(); _declareWinnerTime = getTime() + 2.0f; _declaredWinner = false; setNextMap(); } // Update the players for ( i = 0 ; i < maxclients->integer ; i++ ) { Player *player; Player *playerFollowing; // Get the player player = getPlayer( i ); if ( !player ) continue; if ( isPlayerSpectator( player, SPECTATOR_TYPE_FOLLOW ) ) { playerFollowing = getPlayer( _playerData[ player->entnum ]._spectatorPlayerNum ); if ( !playerFollowing || playerFollowing->deadflag == DEAD_DEAD ) { makePlayerSpectateNextPlayer( player ); if ( !isPlayerSpectator( player, SPECTATOR_TYPE_FOLLOW ) ) continue; playerFollowing = getPlayer( _playerData[ player->entnum ]._spectatorPlayerNum ); } if ( playerFollowing ) { player->setOrigin( playerFollowing->origin ); player->setAngles( playerFollowing->angles ); player->SetViewAngles( playerFollowing->getViewAngles() ); } } if ( _playerData[ player->entnum ]._waitingForRespawn ) { int lastTimeLeft; int timeLeft; str printString; timeLeft = (int)( _playerData[ player->entnum ]._respawnTime - getTime() + 1.0f + ( frameTime / 2.0f ) ); lastTimeLeft = (int)( _playerData[ player->entnum ]._respawnTime - getTime() + frameTime + 1.0f + ( frameTime / 2.0f ) ); if ( ( lastTimeLeft != timeLeft ) && ( timeLeft > 0 ) ) { printString = "$$RespawnIn$$ "; printString += timeLeft; centerPrint( player->entnum, printString, CENTERPRINT_IMPORTANCE_HIGH ); } if ( _playerData[ player->entnum ]._respawnTime <= getTime() ) { respawnPlayer( player, true ); } } } } void MultiplayerManager::addBots( void ) { cvar_t *mp_botcommands; // If this is not a dedicated server make sure the player enters the game first if ( !dedicated->integer && ( !g_entities[ 0 ].inuse || !g_entities[ 0 ].client || !g_entities[ 0 ].entity ) ) return; // Add the bot commands mp_botcommands = gi.cvar( "mp_botcommands", "", 0 ); if ( strlen( mp_botcommands->string ) > 0 ) { gi.SendConsoleCommand( mp_botcommands->string ); //gi.cvar_set( "mp_botcommands", "" ); } _needToAddBots = false; } extern int gametype; // for BOTLIB void MultiplayerManager::initMultiplayerGame( void ) { cvar_t *mp_modifier_Destruction; int i; // Automatically turn off diffusion, it will be turned back on if needed gi.cvar_set( "mp_modifier_diffusion", "0" ); // Create the correct game type switch ( mp_gametype->integer ) // Todo : switch off of a something better than a hardcoded index { case 0 : _multiplayerGame = new ModeDeathmatch(); gametype = GT_FFA; break; case 1 : _multiplayerGame = new ModeTeamDeathmatch(); gametype = GT_TEAM; break; case 2 : _multiplayerGame = new ModeCaptureTheFlag(); gametype = GT_CTF; break ; case 3 : // This is bomb diffusion mode _multiplayerGame = new ModeTeamDeathmatch(); gi.cvar_set( "mp_modifier_diffusion", "1" ); /* gi.cvar_set( "mp_modifier_specialties", "1" ); gi.cvar_set( "mp_modifier_elimination", "1" ); */ //gi.cvar_set( "mp_gametype", "1" ); gametype = GT_TEAM; break ; default: _multiplayerGame = new ModeDeathmatch(); gametype = GT_FFA; break ; } // Setup some stuff for bots mp_modifier_Destruction = gi.cvar( "mp_modifier_Destruction", "0", 0 ); if ( mp_modifier_Destruction->integer ) { gametype = GT_OBELISK; } if ( !_multiplayerGame ) return; // Create the player data _playerData = new MultiplayerPlayerData[ maxclients->integer ]; // Initialize the game _multiplayerGame->init( maxclients->integer ); _multiplayerGame->setPointLimit( mp_pointlimit->integer ); _multiplayerGame->setTimeLimit( mp_timelimit->value * 60.0f ); _inMultiplayerGame = true; // Add all of the needed modifiers addModifiers(); // Initialize all of the needed modifiers for ( i = 1 ; i <= _modifiers.NumObjects() ; i++ ) { MultiplayerModifier *modifier; modifier = _modifiers.ObjectAt( i ); if ( modifier ) modifier->init( maxclients->integer ); } // Initialize the award system _awardSystem = new AwardSystem; _awardSystem->init( maxclients->integer ); // Initialize anything needed that is outside of the multiplayer system // Make sure no tricorder modes are available except those explicitly set by the script Event *event = new Event( "addAvailableViewMode" ); event->AddString( "BogusMode" ); world->ProcessEvent( event ); } void MultiplayerManager::initItems( void ) { int i; int j; bool shouldKeep; MultiplayerItem *item; Item *normalItem; if ( !_inMultiplayerGame ) return; // Tell the game to initialize items _multiplayerGame->initItems(); // Tell all of the modifiers to initialize items for ( i = 1 ; i <= _modifiers.NumObjects() ; i++ ) { MultiplayerModifier *modifier; modifier = _modifiers.ObjectAt( i ); if ( modifier ) modifier->initItems(); } // Tell the award system to initialize items _awardSystem->initItems(); // Find all of the multiplayer items, tell everyone about each of them and see if we need to keep them // TODO: move this to a seperate proc for ( i = 0; i < MAX_GENTITIES; i++ ) { if ( g_entities[ i ].inuse && g_entities[ i ].entity ) { if ( g_entities[ i ].entity->isSubclassOf( MultiplayerItem ) ) { item = (MultiplayerItem *)g_entities[ i ].entity; shouldKeep = false; // Tell modifiers about the item and see if they want to keep it for ( j = 1 ; j <= _modifiers.NumObjects() ; j++ ) { MultiplayerModifier *modifier; modifier = _modifiers.ObjectAt( j ); if ( modifier ) { if ( modifier->shouldKeepItem( item ) ) shouldKeep = true; } } // Tell the mode about the item and see if it wants to keep it if ( _multiplayerGame->shouldKeepItem( item ) ) shouldKeep = true; // If no one said to keep the item get rid of it if ( shouldKeep ) { // Tell all of the modifiers that the item was kept for ( j = 1 ; j <= _modifiers.NumObjects() ; j++ ) { MultiplayerModifier *modifier; modifier = _modifiers.ObjectAt( j ); if ( modifier ) { modifier->itemKept( item ); } } // Tell the mode that the item was kept _multiplayerGame->itemKept( item ); } else { // No one told us to keep this multiplayer item, so get rid of it item->PostEvent( EV_Remove, FRAMETIME ); } } else if ( g_entities[ i ].entity->isSubclassOf( Item ) ) { normalItem = (Item *)g_entities[ i ].entity; shouldKeep = true; // Tell modifiers about the item and see if they want to keep it for ( j = 1 ; j <= _modifiers.NumObjects() ; j++ ) { MultiplayerModifier *modifier; modifier = _modifiers.ObjectAt( j ); if ( modifier ) { if ( !modifier->shouldKeepNormalItem( normalItem ) ) shouldKeep = false; } } // Tell the mode about the item and see if it wants to keep it if ( !_multiplayerGame->shouldKeepNormalItem( normalItem ) ) shouldKeep = false; // If no one said to keep the item get rid of it if ( !shouldKeep ) { // Someone told us to get rid of this item normalItem->PostEvent( EV_Remove, FRAMETIME ); } } } } } void MultiplayerManager::resetItems( void ) { int i; Item *item; // Setup all of the items again for ( i = 0; i < MAX_GENTITIES; i++ ) { if ( g_entities[ i ].inuse && g_entities[ i ].entity && g_entities[ i ].entity->isSubclassOf( Item ) ) { item = (Item *)g_entities[ i ].entity; // Ignore runes and multiplayer items if ( item->isSubclassOf( Rune ) || item->isSubclassOf( MultiplayerItem ) ) continue; if ( item->Respawnable() ) { // Item is a normal respawnable item, so respawn it again item->CancelEventsOfType( EV_Item_Respawn ); item->PostEvent( EV_Item_Respawn, 0.0f ); } else { // Item is a temporary item, so get rid of it item->PostEvent( EV_Remove, 0.0f ); } } } } bool MultiplayerManager::inMultiplayer( void ) { return _inMultiplayerGame; } bool MultiplayerManager::checkFlag( unsigned int flag ) { if ( !_inMultiplayerGame ) return false; if ( mp_flags->integer & flag ) return true; else return false; } bool MultiplayerManager::fullCollision( void ) { if ( !_inMultiplayerGame ) return true; if ( checkFlag( MP_FLAG_FULL_COLLISION ) ) return true; else return false; } bool MultiplayerManager::isFightingAllowed( void ) { if ( !_inMultiplayerGame ) return true; if ( !_inMatch ) return false; return _allowFighting; } void MultiplayerManager::addPlayer( Player *player ) { if ( !_inMultiplayerGame ) return; assert( player ); if ( !player ) return; // See if the player has already been added if ( _playerData[ player->entnum ]._valid ) return; // Initialize the player data _playerData[ player->entnum ].reset(); _playerData[ player->entnum ]._valid = true; // Inform the game about the new player _multiplayerGame->AddPlayer( player ); // Inform all of the modifiers about the new player for ( int i = 1 ; i <= _modifiers.NumObjects() ; i++ ) { MultiplayerModifier *modifier; modifier = _modifiers.ObjectAt( i ); if ( modifier ) modifier->addPlayer( player ); } // Inform the award system about the new player _awardSystem->addPlayer ( player ); // Inform all of the players that the player has joined the game multiplayerManager.HUDPrintAllClients( va( "%s $$JoinedGame$$\n", player->client->pers.netname ) ); } void MultiplayerManager::removePlayer( Player *player ) { if ( !_inMultiplayerGame ) return; assert( player ); if ( !player ) return; if ( !_playerData[ player->entnum ]._valid ) return; // Inform the game about the player being removed _multiplayerGame->RemovePlayer( player ); // Reset the player's data _playerData[ player->entnum ].reset(); // Inform all of the modifiers about the player being removed for ( int i = 1 ; i <= _modifiers.NumObjects() ; i++ ) { MultiplayerModifier *modifier; modifier = _modifiers.ObjectAt( i ); if ( modifier ) modifier->removePlayer( player ); } // Inform the award system about the player being removed _awardSystem->removePlayer ( player ); // Inform all of the players that the player has left the game multiplayerManager.HUDPrintAllClients( va( "%s $$LeftGame$$\n", player->client->pers.netname ) ); } void MultiplayerManager::changePlayerModel( Player *player, const char *modelName, bool force ) { str modelToUse; if ( !_inMultiplayerGame || !player ) return; if ( ( player->model != modelName ) || ( force ) ) { modelToUse = modelName; // Verify that this is an acceptable model to use if ( !isValidPlayerModel( player, modelToUse ) ) { centerPrint( player->entnum, va( "%s is not an acceptable model to use", modelName ), CENTERPRINT_IMPORTANCE_NORMAL ); modelToUse = getDefaultPlayerModel( player ); } if ( checkFlag( MP_FLAG_FORCE_DEFAULT_MODEL ) ) { modelToUse = getDefaultPlayerModel( player ); } // Setup the default backup model player->setBackupModel( getDefaultPlayerModel( player ) ); // Setup the model player->InitModel( modelToUse ); player->CancelEventsOfType( EV_ProcessInitCommands ); player->ProcessInitCommands( player->edict->s.modelindex ); resetPlayerStateMachine( player ); if ( multiplayerManager.isPlayerSpectator( player ) ) { player->hideModel(); player->setSolidType( SOLID_NOT ); } for ( int i = 1 ; i <= _modifiers.NumObjects() ; i++ ) { MultiplayerModifier *modifier; modifier = _modifiers.ObjectAt( i ); if ( modifier ) modifier->playerChangedModel( player ); } _multiplayerGame->playerChangedModel( player ); player->modelChanged(); } } void MultiplayerManager::resetPlayerStateMachine( Player *player ) { if ( !_inMultiplayerGame ) return; if ( player ) { player->SetAnim( "stand_idle", legs, true ); player->SetAnim( "stand_idle", torso, true ); player->LoadStateTable(); } } void MultiplayerManager::changePlayerName( Player *player, const str &playerName ) { if ( !_inMultiplayerGame ) return; if ( player ) { if ( _playerData[ player->entnum ]._named && ( _playerData[ player->entnum ]._name != playerName ) ) { // Inform all of the players that the player has changed his name multiplayerManager.HUDPrintAllClients( va( "%s $$ChangedName$$ %s\n", _playerData[ player->entnum ]._name.c_str(), playerName.c_str() ) ); } _playerData[ player->entnum ]._named = true; _playerData[ player->entnum ]._name = playerName; } } void MultiplayerManager::playerKilled( Player *killedPlayer, Player *attackingPlayer, Entity *inflictor, int meansOfDeath ) { if ( !_inMultiplayerGame ) return; // Inform all of the modifiers about the player being killed for ( int i = 1 ; i <= _modifiers.NumObjects() ; i++ ) { MultiplayerModifier *modifier; modifier = _modifiers.ObjectAt( i ); if ( modifier ) modifier->playerKilled( killedPlayer, attackingPlayer, inflictor, meansOfDeath ); } // Inform the game about the player being killed _multiplayerGame->playerKilled( killedPlayer, attackingPlayer, inflictor, meansOfDeath ); // Inform the award system about the player being killed _awardSystem->playerKilled( killedPlayer, attackingPlayer, inflictor, meansOfDeath ); // Tell the players what happened if ( killedPlayer == attackingPlayer || !attackingPlayer ) { centerPrint( killedPlayer->entnum, va( "^%c$$YouKilledYourself$$^%c", COLOR_RED, COLOR_NONE ), CENTERPRINT_IMPORTANCE_NORMAL ); } else { str printString; centerPrint( killedPlayer->entnum, va( "^%c$$KilledByPlayer$$^%c %s", COLOR_RED, COLOR_NONE, attackingPlayer->client->pers.netname, COLOR_WHITE + 1 ), CENTERPRINT_IMPORTANCE_NORMAL ); printString = va( "^%c$$KilledPlayer$$^%c %s", COLOR_GREEN, COLOR_NONE, killedPlayer->client->pers.netname ); if ( checkRule( "usingIndividualScore", false, attackingPlayer ) ) { str placeName = getPlaceName( attackingPlayer ); int points = getPoints( attackingPlayer ); if ( points == 1 ) printString += va( "\n$$PlaceString1$$ ^%c %s^%c $$PlaceString2$$ ^%c %d^%c $$Point$$", COLOR_CYAN, placeName.c_str(), COLOR_NONE, COLOR_CYAN, points, COLOR_NONE ); else printString += va( "\n$$PlaceString1$$ ^%c %s^%c $$PlaceString2$$ ^%c %d^%c $$Points$$", COLOR_CYAN, placeName.c_str(), COLOR_NONE, COLOR_CYAN, points, COLOR_NONE ); } centerPrint( attackingPlayer->entnum, printString, CENTERPRINT_IMPORTANCE_NORMAL ); multiplayerManager.instantPlayerSound( attackingPlayer->entnum, "snd_mp_killedsomeone", CHAN_COMBAT4 ); } } void MultiplayerManager::matchOver( void ) { if ( !_inMultiplayerGame ) return; int i; // Inform all of the modifiers about the match being over for ( i = 1 ; i <= _modifiers.NumObjects() ; i++ ) { MultiplayerModifier *modifier; modifier = _modifiers.ObjectAt( i ); if ( modifier ) modifier->matchOver(); } // Inform the game about the match being over _multiplayerGame->matchOver(); // Inform the award system about the match being over _awardSystem->matchOver(); _inMatch = false; // Do some solo match work (EF2 specific) cvar_t *mp_solomatch; cvar_t *mp_mapAward; cvar_t *mp_botskilllevel; str cvarName; // Get all the cvars we need cvarName = level.mapname + "_award"; mp_solomatch = gi.cvar( "mp_solomatch", "0", 0 ); mp_mapAward = gi.cvar( cvarName.c_str(), "0", CVAR_ARCHIVE ); mp_botskilllevel = gi.cvar( "mp_botskilllevel", "0", CVAR_ARCHIVE ); // Make sure we are in solomatch if ( mp_solomatch->integer ) { int playersScore; int botsScore; bool wonMatch = true; Player *player; // See if the player won the match player = getPlayer( 0 ); playersScore = getPoints( player ); for ( i = 1 ; i < maxclients->integer ; i++ ) { player = getPlayer( i ); if ( player ) { botsScore = getPoints( player ); if ( botsScore >= playersScore ) { wonMatch = false; break; } } } if ( wonMatch ) { // See if this is the highest bot skill level the player has won on if ( mp_mapAward->integer < mp_botskilllevel->integer ) { // Save cvar gi.cvar_set( cvarName.c_str(), mp_botskilllevel->string ); } } } } int MultiplayerManager::getScoreIcon( Player *player, int index ) { int icon = 0; if ( _inMatch ) { for ( int i = 1 ; i <= _modifiers.NumObjects() ; i++ ) { MultiplayerModifier *modifier; modifier = _modifiers.ObjectAt( i ); if ( modifier ) { icon = modifier->getScoreIcon( player, index, icon ); } } // Allow the game to apply speed modifiers icon = _multiplayerGame->getScoreIcon( player, index, icon ); } else { icon = _awardSystem->getAfterMatchAward( player, index ); } if ( ( index == SCOREICON3 ) && ( icon == 0 ) && _playerData[ player->entnum ]._waitingForRespawn ) { icon = _waitingToRespawnIconIndex; } return icon; } int MultiplayerManager::getAfterMatchAward( Player *player, int index ) { return _awardSystem->getAfterMatchAward( player, index ); } void MultiplayerManager::playerDead( Player *player ) { assert(player); if ( !player ) return; // Inform the game that the player is dead _multiplayerGame->playerDead( player ); } void MultiplayerManager::applySpeedModifiers( Player *player, int *moveSpeed ) { if ( !_inMultiplayerGame ) return; // Allow all of the modifiers to apply speed modifiers for ( int i = 1 ; i <= _modifiers.NumObjects() ; i++ ) { MultiplayerModifier *modifier; modifier = _modifiers.ObjectAt( i ); if ( modifier ) modifier->applySpeedModifiers( player, moveSpeed ); } // Allow the game to apply speed modifiers _multiplayerGame->applySpeedModifiers( player, moveSpeed ); } void MultiplayerManager::applyJumpModifiers( Player *player, int *jumpSpeed ) { if ( !_inMultiplayerGame ) return; // Allow all of the modifiers to apply jump modifiers for ( int i = 1 ; i <= _modifiers.NumObjects() ; i++ ) { MultiplayerModifier *modifier; modifier = _modifiers.ObjectAt( i ); if ( modifier ) modifier->applyJumpModifiers( player, jumpSpeed ); } // Allow the game to apply jump modifiers _multiplayerGame->applyJumpModifiers( player, jumpSpeed ); } void MultiplayerManager::applyAirAccelerationModifiers( Player *player, int *airAcceleration ) { if ( !_inMultiplayerGame ) return; // Allow all of the modifiers to apply air acceleration modifiers for ( int i = 1 ; i <= _modifiers.NumObjects() ; i++ ) { MultiplayerModifier *modifier; modifier = _modifiers.ObjectAt( i ); if ( modifier ) modifier->applyAirAccelerationModifiers( player, airAcceleration ); } // Allow the game to apply air acceleration modifiers _multiplayerGame->applyAirAccelerationModifiers( player, airAcceleration ); } bool MultiplayerManager::canPickup( Player *player, MultiplayerItemType itemType, const char *item_name ) { if ( !_inMultiplayerGame ) return true; // See if all of the modifiers will allow the player to pickup this item for ( int i = 1 ; i <= _modifiers.NumObjects() ; i++ ) { MultiplayerModifier *modifier; modifier = _modifiers.ObjectAt( i ); if ( modifier ) { if ( !modifier->canPickup( player, itemType, item_name ) ) return false; } } // See if the game will allow the player to pickup this item if ( !_multiplayerGame->canPickup( player, itemType, item_name ) ) return false; // The player is allowed to pickup this item return true; } void MultiplayerManager::pickedupItem( Player *player, MultiplayerItemType itemType, const char *itemName ) { if ( !_inMultiplayerGame ) return; // Tell modifiers that an item was picked up for ( int i = 1 ; i <= _modifiers.NumObjects() ; i++ ) { MultiplayerModifier *modifier; modifier = _modifiers.ObjectAt( i ); if ( modifier ) { modifier->pickedupItem( player, itemType, itemName ); } } // Tell game that an item was picked up _multiplayerGame->pickedupItem( player, itemType, itemName ); // Tell the award system that an item was picked up _awardSystem->pickedupItem( player, itemType, itemName ); } int MultiplayerManager::getPointsForKill( Player *killedPlayer, Player *attackingPlayer, Entity *inflictor, int meansOfDeath, int points ) { int realPoints; realPoints = points; // Allow all of the modifiers to change the points given for this kill for ( int i = 1 ; i <= _modifiers.NumObjects() ; i++ ) { MultiplayerModifier *modifier; modifier = _modifiers.ObjectAt( i ); if ( modifier ) realPoints = modifier->getPointsForKill( killedPlayer, attackingPlayer, inflictor, meansOfDeath, realPoints ); } return realPoints; } void MultiplayerManager::respawnPlayer( Player *player, bool forced ) { if ( !_inMultiplayerGame ) return; assert(player); if ( !player ) return; if ( multiplayerManager.isPlayerSpectator( player ) && multiplayerManager.isPlayerSpectatorByChoice( player ) ) return; if ( getRespawnTime() > 0.0f && !forced ) { if ( !_playerData[ player->entnum ]._waitingForRespawn ) { _playerData[ player->entnum ]._waitingForRespawn = true; _playerData[ player->entnum ]._respawnTime = getTime() + getRespawnTime(); } } else { _playerData[ player->entnum ]._waitingForRespawn = false; _multiplayerGame->respawnPlayer( player ); } } void MultiplayerManager::respawnAllPlayers( void ) { int i; Player *player; if ( !_inMultiplayerGame ) return; for( i = 0 ; i < maxclients->integer ; i++ ) { player = getPlayer( i ); if ( !player ) continue; if ( multiplayerManager.isPlayerSpectatorByChoice( player ) && !( player->edict->svflags & SVF_BOT ) ) continue; respawnPlayer( player, true ); } } Entity *MultiplayerManager::getSpawnPoint( Player *player ) { if ( !_inMultiplayerGame ) return NULL; assert( player ); if ( !player ) return NULL; // Get a spawn point for this player from the game return _multiplayerGame->getSpawnPoint( player ); } float MultiplayerManager::playerDamaged( Player *damagedPlayer, Player *attackingPlayer, float damage, int meansOfDeath ) { float realDamage; realDamage = damage; if ( !_inMultiplayerGame ) return realDamage; // Change damage based on cvar realDamage *= mp_damageMultiplier->value; // Change damage based on modifiers for ( int i = 1 ; i <= _modifiers.NumObjects() ; i++ ) { MultiplayerModifier *modifier; modifier = _modifiers.ObjectAt( i ); if ( modifier ) realDamage = modifier->playerDamaged( damagedPlayer, attackingPlayer, realDamage, meansOfDeath ); } // Change damage based on the mode realDamage = _multiplayerGame->playerDamaged( damagedPlayer, attackingPlayer, realDamage, meansOfDeath ); // Inform the award system that someone was damaged _awardSystem->playerDamaged( damagedPlayer, attackingPlayer, realDamage, meansOfDeath ); return realDamage; } void MultiplayerManager::playerTookDamage( Player *damagedPlayer, Player *attackingPlayer, float damage, int meansOfDeath ) { _multiplayerGame->playerTookDamage( damagedPlayer, attackingPlayer, damage, meansOfDeath ); } void MultiplayerManager::playerFired( Player *attackingPlayer ) { if ( !_inMultiplayerGame ) return; // Inform the modifiers that the player shot for ( int i = 1 ; i <= _modifiers.NumObjects() ; i++ ) { MultiplayerModifier *modifier; modifier = _modifiers.ObjectAt( i ); if ( modifier ) modifier->playerFired( attackingPlayer ); } // Inform the game that the player shot _multiplayerGame->playerFired( attackingPlayer ); // Inform the award system that the player shot _awardSystem->playerFired( attackingPlayer ); } float MultiplayerManager::getModifiedKnockback( Player *damagedPlayer, Player *attackingPlayer, float knockback ) { if ( !_inMultiplayerGame ) return knockback; // Change damage based on cvar return knockback * mp_knockbackMultiplier->value; } void MultiplayerManager::itemTouched( Player *player, MultiplayerItem *item ) { if ( !_inMultiplayerGame ) return; // Make sure the player is alive and playing if ( isPlayerSpectator( player ) || ( player->deadflag != DEAD_NO ) || ( player->getHealth() <= 0.0f ) ) return; // Tell all of the modifiers that this item was touched for ( int i = 1 ; i <= _modifiers.NumObjects() ; i++ ) { MultiplayerModifier *modifier; modifier = _modifiers.ObjectAt( i ); if ( modifier ) modifier->itemTouched( player, item ); } // Tell the mode that this item was touched _multiplayerGame->itemTouched( player, item ); } float MultiplayerManager::itemDamaged( MultiplayerItem *item, Player *attackingPlayer, float damage, int meansOfDeath ) { float realDamage; if ( !_inMultiplayerGame ) return damage; realDamage = damage; // Tell all of the modifiers that this item was damaged for ( int i = 1 ; i <= _modifiers.NumObjects() ; i++ ) { MultiplayerModifier *modifier; modifier = _modifiers.ObjectAt( i ); if ( modifier ) { realDamage = modifier->itemDamaged( item, attackingPlayer, realDamage, meansOfDeath ); } } // Tell the mode that this item was destroyed return _multiplayerGame->itemDamaged( item, attackingPlayer, realDamage, meansOfDeath ); } void MultiplayerManager::itemDestroyed( Player *player, MultiplayerItem *item ) { if ( !_inMultiplayerGame ) return; // Tell all of the modifiers that this item was destroyed for ( int i = 1 ; i <= _modifiers.NumObjects() ; i++ ) { MultiplayerModifier *modifier; modifier = _modifiers.ObjectAt( i ); if ( modifier ) modifier->itemDestroyed( player, item ); } // Tell the mode that this item was destroyed _multiplayerGame->itemDestroyed( player, item ); } void MultiplayerManager::itemUsed( Entity *entity, MultiplayerItem *item ) { if ( !_inMultiplayerGame ) return; // Tell all of the modifiers that this item was destroyed for ( int i = 1 ; i <= _modifiers.NumObjects() ; i++ ) { MultiplayerModifier *modifier; modifier = _modifiers.ObjectAt( i ); if ( modifier ) modifier->itemUsed( entity, item ); } // Tell the mode that this item was destroyed _multiplayerGame->itemUsed( entity, item ); } void MultiplayerManager::playerUsed( Player *usedPlayer, Player *usingPlayer, Equipment *equipment ) { if ( !_inMultiplayerGame ) return; // Tell all of the modifiers that this item was destroyed for ( int i = 1 ; i <= _modifiers.NumObjects() ; i++ ) { MultiplayerModifier *modifier; modifier = _modifiers.ObjectAt( i ); if ( modifier ) modifier->playerUsed( usedPlayer, usingPlayer, equipment ); } // Tell the mode that this item was destroyed _multiplayerGame->playerUsed( usedPlayer, usingPlayer, equipment ); } bool MultiplayerManager::checkRule( const char *rule, bool defaultValue, Player *player ) { bool value; if ( !_inMultiplayerGame ) return defaultValue; // Default the value to the value passed in value = defaultValue; // Check this rule with all of the modifiers for ( int i = 1 ; i <= _modifiers.NumObjects() ; i++ ) { MultiplayerModifier *modifier; modifier = _modifiers.ObjectAt( i ); if ( modifier ) { value = modifier->checkRule( rule, value, player ); } } // Check this rule with the mode value = _multiplayerGame->checkRule( rule, value, player ); return value; } bool MultiplayerManager::checkGameType( const char *gameType ) { if ( !_inMultiplayerGame ) return false; // Check for the gametype with the game first if ( _multiplayerGame->checkGameType( gameType ) ) return true; // Check for the gametype with all of the modifiers for ( int i = 1 ; i <= _modifiers.NumObjects() ; i++ ) { MultiplayerModifier *modifier; modifier = _modifiers.ObjectAt( i ); if ( modifier ) { if ( modifier->checkGameType( gameType ) ) return true; } } return false; } bool MultiplayerManager::doesPlayerHaveItem( Player *player, const char *itemName ) { if ( !_inMultiplayerGame ) return false; if ( !player ) return false; // Check to see if the player has the item with the game first if ( _multiplayerGame->doesPlayerHaveItem( player, itemName ) ) return true; // Check to see if the player has the item with all of the modifiers for ( int i = 1 ; i <= _modifiers.NumObjects() ; i++ ) { MultiplayerModifier *modifier; modifier = _modifiers.ObjectAt( i ); if ( modifier ) { if ( modifier->doesPlayerHaveItem( player, itemName ) ) return true; } } return false; } void MultiplayerManager::score( Player *player ) { assert(player); if ( !player ) return; if ( !_inMultiplayerGame ) return; // Tell the game to send the current score to the player _multiplayerGame->score( player ); } int MultiplayerManager::getPoints( Player *player ) { assert(player); if ( !player ) return 0; if ( !_inMultiplayerGame ) return 0; // Get the player's current points from the game return _multiplayerGame->getPoints( player ); } int MultiplayerManager::getKills( Player *player ) { assert(player); if ( !player ) return 0; if ( !_inMultiplayerGame ) return 0; // Get the player's current kills from the game return _multiplayerGame->getKills( player ); } int MultiplayerManager::getDeaths( Player *player ) { assert(player); if ( !player ) return 0; if ( !_inMultiplayerGame ) return 0; // Get the player's current deaths from the game return _multiplayerGame->getDeaths( player ); } int MultiplayerManager::getTeamPoints( Player *player ) { assert(player); if ( !player ) return 0; if ( !_inMultiplayerGame ) return 0; // Get the player's team's current points from the game return _multiplayerGame->getTeamPoints( player ); } int MultiplayerManager::getTeamPoints( const str &teamName ) { if ( !_inMultiplayerGame ) return 0; // Get the player's team's current points from the game return _multiplayerGame->getTeamPoints( teamName ); } void MultiplayerManager::addTeamPoints( const str &teamName, int points ) { if ( !_inMultiplayerGame ) return; // Add team's current points _multiplayerGame->addTeamPoints( teamName, points ); } int MultiplayerManager::getStat( Player *player, int statNum ) { int value = 0; assert(player); if ( !player ) return 0; if ( !_inMultiplayerGame ) return 0; // See if this is one of the stats that the manager cares about if ( ( statNum == STAT_TIMELEFT_SECONDS ) ) { value = 0; if ( mp_timelimit->integer ) { value = (int) (mp_timelimit->integer * 60.0f - level.time); } } if ( statNum == STAT_MP_SPECTATING_ENTNUM ) { value = _playerData[ player->entnum ]._spectatorPlayerNum; } // Allow all of the modifiers to set the stat for ( int i = 1 ; i <= _modifiers.NumObjects() ; i++ ) { MultiplayerModifier *modifier; modifier = _modifiers.ObjectAt( i ); if ( modifier ) { value = modifier->getStat( player, statNum, value ); } } // Allow the game to set the stat value = _multiplayerGame->getStat( player, statNum, value ); value = _awardSystem->getStat( player, statNum, value ); return value; } int MultiplayerManager::getIcon( Player *player, int statNum ) { int value = -1; assert(player); if ( !player ) return -1; if ( !_inMultiplayerGame ) return -1; // Allow all of the modifiers to set the icon for ( int i = 1 ; i <= _modifiers.NumObjects() ; i++ ) { MultiplayerModifier *modifier; modifier = _modifiers.ObjectAt( i ); if ( modifier ) { value = modifier->getIcon( player, statNum, value ); } } // Allow the game to set the icon value = _multiplayerGame->getIcon( player, statNum, value ); value = _awardSystem->getIcon( player, statNum, value ); return value; } Team* MultiplayerManager::getPlayersTeam( const Player *player ) { assert(player); if ( !player ) return NULL; if ( !_inMultiplayerGame ) return NULL; return _multiplayerGame->getPlayersTeam( player ); } void MultiplayerManager::callVote( Player *player, const str &command, const str &arg ) { int i; int count; if ( !_inMultiplayerGame ) return; // Player wants to call a vote if ( checkFlag( MP_FLAG_DONT_ALLOW_VOTE ) ) { HUDPrint( player->entnum, "$$VotingNotAllowed$$.\n" ); return; } // If voteTime is set, then a vote has already been called if ( _voteTime ) { HUDPrint( player->entnum, "$$AlreadyVoting$$.\n" ); return; } // Make sure the player hasn't called too many votes if ( _playerData[ player->entnum ]._votecount >= mp_maxVotes->integer ) { HUDPrint( player->entnum, va( "$$MaxVotes$$ (%d).\n", mp_maxVotes->integer ) ); return; } // Make sure everything is ok if( strchr( command.c_str(), ';' ) || strchr( arg.c_str(), ';' ) ) { HUDPrint( player->entnum, "$$InvalidVote$$\n" ); return; } if ( ( stricmp( command.c_str(), "restart" ) != 0 ) && ( stricmp( command.c_str(), "nextmap" ) != 0 ) && ( stricmp( command.c_str(), "map" ) != 0 ) && ( stricmp( command.c_str(), "g_gametype" ) != 0 ) && ( stricmp( command.c_str(), "kick" ) != 0 ) ) { HUDPrint( player->entnum, "$$InvalidVote$$\n" ); HUDPrint( player->entnum, "$$VoteCommands$$: restart, nextmap, map , g_gametype and kick .\n" ); return; } // If a map command, make sure the map actually exists if ( stricmp( command.c_str(), "map" ) == 0 ) { str fullMapName; str printString; fullMapName = "maps/"; fullMapName += arg; fullMapName += ".bsp"; if ( !gi.FS_Exists( fullMapName.c_str() ) ) { printString = fullMapName + " $$NotFoundOnServer$$\n"; HUDPrint( player->entnum, printString.c_str() ); return; } } // Build the vote string for later use and to tell all clients about if ( stricmp( command.c_str(), "map" ) == 0 ) { // If a map command was issued, preserve the nextmap cvar so we don't lose it if ( strlen( sv_nextmap->string ) ) { _voteString = va( "%s %s; set nextmap \"%s\"", command.c_str(), arg.c_str(), sv_nextmap->string ); } else { _voteString = va( "%s %s", command.c_str(), arg.c_str() ); } } else { _voteString = va( "%s %s", command.c_str(), arg.c_str() ); } // Print out a message to everyone multiplayerManager.HUDPrintAllClients( va( "%s ^4$$CalledVote$$:^8 %s\n", player->client->pers.netname, _voteString.c_str() ) ); // Play a sound to announce a new vote broadcastInstantSound( "sound/ships/attrexian/att-beepreject.wav" ); // Start the voting, the caller automatically votes yes _voteTime = level.time; _voteYes = 1; _voteNo = 0; _playerData[ player->entnum ]._voted = true; _playerData[ player->entnum ]._votecount++; // Clear all the other player's voteflags count = 1; for( i = 0; i < maxclients->integer; i++ ) { Player *currentPlayer; gentity_t *ent = g_entities + i; if ( !ent->inuse || !ent->client || !ent->entity ) continue; if ( ent->svflags & SVF_BOT ) continue; if ( i == player->entnum ) continue; _playerData[ i ]._voted = false; currentPlayer = getPlayer( i ); if ( currentPlayer ) { currentPlayer->setVoteText( va( "$$NewVote$$: %s (F1 = $$Yes$$, F2 = $$No$$)\n", _voteString.c_str() ) ); } count++; } _numVoters = count; } void MultiplayerManager::vote( Player *player, const str &vote ) { // Player is voting on the current vote // Make sure the is a vote current going on if ( !_voteTime ) { HUDPrint( player->entnum, "$$NoVote$$\n" ); return; } // Make sure this player hasn't already voted on this vote if ( _playerData[ player->entnum ]._voted ) { HUDPrint( player->entnum, "$$VoteAlreadyCast$$\n" ); return; } // Make sure the vote is valid if ( vote.length() < 1 ) return; // Vote _playerData[ player->entnum ]._voted = true; player->clearVoteText(); if ( ( vote[0] == 'y' ) || ( vote[0] == 'Y' ) || ( vote[0] == '1' ) ) { _voteYes++; HUDPrint( player->entnum, "$$VoteCast$$ - $$Yes$$\n" ); } else { _voteNo++; HUDPrint( player->entnum, "$$VoteCast$$ - $$No$$\n" ); } // NOTE: a majority will be determined in checkVote } void MultiplayerManager::checkVote( void ) { int i; // Check if a vote is active if ( !_voteTime ) { return; } // Make sure time hasn't run out for this vote if ( level.time - _voteTime >= _maxVoteTime ) { multiplayerManager.HUDPrintAllClients( "$$VoteFailed$$\n" ); } else { // See if we have a majority vote yet if ( _voteYes > ( _numVoters / 2.0f ) ) { // Vote passed - execute the command, then remove the vote multiplayerManager.HUDPrintAllClients( "$$VotePassed$$\n" ); gi.SendConsoleCommand( va("%s\n", _voteString.c_str() ) ); } else if ( _voteNo >= ( _numVoters / 2.0f ) ) { // Vote failed - same behavior as a timeout multiplayerManager.HUDPrintAllClients( "$$VoteFailed$$\n" ); } else { // still waiting for a majority return; } } _voteTime = 0.0f; // Clear all the player's vote text for( i = 0; i < maxclients->integer; i++ ) { Player *currentPlayer; currentPlayer = getPlayer( i ); if ( currentPlayer ) { currentPlayer->clearVoteText(); } } } void MultiplayerManager::joinTeam( Player *player, const str &teamName ) { str realTeamName; int i; // Make sure everything is ok if ( !player || !_inMultiplayerGame ) return; // Fix up the teamName if ( stricmp( teamName.c_str(), "Blue" ) == 0 ) realTeamName = "Blue"; else if ( stricmp( teamName.c_str(), "Red" ) == 0 ) realTeamName = "Red"; else realTeamName = teamName; if ( ( realTeamName == "Red" ) || ( realTeamName == "Blue" ) || ( realTeamName == "normal" ) ) { _playerData[ player->entnum ]._spectatorByChoice = false; } // See if we can change to the specified team if ( !_multiplayerGame->canJoinTeam( player, realTeamName ) ) return; // Tell the modifiers that player left game for ( i = 1 ; i <= _modifiers.NumObjects() ; i++ ) { MultiplayerModifier *modifier; modifier = _modifiers.ObjectAt( i ); if ( modifier ) { modifier->removePlayer( player ); } } // Tell mode that I'm joining the specified team _multiplayerGame->joinTeam( player, realTeamName ); // Tell all of the modifiers that I'm joining the specified team for ( i = 1 ; i <= _modifiers.NumObjects() ; i++ ) { MultiplayerModifier *modifier; modifier = _modifiers.ObjectAt( i ); if ( modifier ) { modifier->addPlayer( player ); modifier->joinedTeam( player, realTeamName ); } } } void MultiplayerManager::say( Player *player, const str &text, bool team ) { str realText; str tempText; int i; str name; if ( player ) { name = player->client->pers.netname; } else { name = "$$ServerName$$"; } realText = name; realText += ":"; // Color the say (team - yellow, normal - cyan) if ( player ) { realText += "^"; if ( team ) realText += COLOR_YELLOW; else realText += COLOR_CYAN; realText += " "; } // Get rid of all color in the say so our defaults will stay tempText = text; for ( i = 0 ; i < tempText.length() ; i++ ) { if ( tempText[ i ] == '^' ) { tempText[ i ] = '*'; } } // Add the say text realText += tempText; // Finish up with the text if ( player ) { realText += "^"; realText += COLOR_NONE; } realText += "\n"; // Strip out any bad characters for ( i = 0 ; i < realText.length() ; i++ ) { if ( realText[ i ] == '%' ) { realText[ i ] = '.'; } } // Don't let text be too long for malicious reasons if ( realText.length() > _maxSayStringLength ) { HUDPrint( player->entnum, "$$SayTooLong$$\n" ); return; } // Send say to console if in a dedicated server if ( dedicated->integer ) { gi.Printf( "%s: %s\n", name.c_str(), text.c_str() ); } // Send the say to appropriate clients if ( player && isPlayerSpectator( player ) ) HUDPrintSpectators( player, realText, team ); else if ( player && team ) HUDPrintTeamClients( player, realText ); else HUDPrintAllClients( realText ); } void MultiplayerManager::tell( Player *player, const str &text, int entnum ) { str realText; str tempText; int i; Player *otherPlayer; realText = player->client->pers.netname; realText += ":"; // Color the say (team - yellow, normal - cyan) realText += "^"; realText += COLOR_MAGENTA; realText += " "; // Get rid of all color in the say so our defaults will stay tempText = text; for ( i = 0 ; i < tempText.length() ; i++ ) { if ( tempText[ i ] == '^' ) { tempText[ i ] = '*'; } } // Add the say text realText += tempText; // Finish up with the text realText += "^"; realText += COLOR_NONE; realText += "\n"; // Don't let text be too long for malicious reasons if ( realText.length() > _maxSayStringLength ) { HUDPrint( player->entnum, "$$SayTooLong$$\n" ); return; } // Get other player otherPlayer = getPlayer( entnum ); if ( !otherPlayer ) return; // Send the say to appropriate clients if ( isPlayerSpectator( player ) && !isPlayerSpectator( otherPlayer ) ) return; HUDSay( otherPlayer->entnum, realText ); } // // Modifier stuff // void MultiplayerManager::addModifiers( void ) { tryAddModifier( "InstantKill" ); tryAddModifier( "ActionHero" ); tryAddModifier( "AutoHandicap" ); tryAddModifier( "PointsPerWeapon" ); tryAddModifier( "ControlPoints" ); tryAddModifier( "Destruction" ); tryAddModifier( "OneFlag" ); tryAddModifier( "Elimination" ); tryAddModifier( "Diffusion" ); tryAddModifier( "Specialties" ); } void MultiplayerManager::tryAddModifier( const str &modifierName ) { cvar_t *mp_modifier; str cvarName; cvarName = "mp_modifier_"; cvarName += modifierName; mp_modifier = gi.cvar( cvarName.c_str(), "0", 0 ); if ( mp_modifier->integer ) { addModifier( modifierName ); } } void MultiplayerManager::addModifier( const str &modifierName ) { MultiplayerModifier *newModifier = NULL; if ( modifierName == "InstantKill" ) { newModifier = new ModifierInstantKill; } else if ( modifierName == "ActionHero" ) { newModifier = new ModifierActionHero; } else if ( modifierName == "AutoHandicap" ) { newModifier = new ModifierAutoHandicap; } else if ( modifierName == "PointsPerWeapon" ) { newModifier = new ModifierPointsPerWeapon; } else if ( modifierName == "ControlPoints" ) { newModifier = new ModifierControlPoints; } else if ( modifierName == "Destruction" ) { newModifier = new ModifierDestruction; } else if ( modifierName == "OneFlag" ) { newModifier = new ModifierOneFlag; } else if ( modifierName == "Elimination" ) { newModifier = new ModifierElimination; } else if ( modifierName == "Diffusion" ) { newModifier = new ModifierDiffusion; } else if ( modifierName == "Specialties" ) { newModifier = new ModifierSpecialties; } if ( newModifier ) { _modifiers.AddObject( newModifier ); } } void MultiplayerManager::addPoints( int entnum, int points ) { if ( !_inMultiplayerGame ) return; _multiplayerGame->addPoints( entnum, points ); } // // Interface for modes // int MultiplayerManager::getClientNum( int entnum ) { gclient_s *client; // Get the client client = getClient( entnum ); if ( client ) return client->ps.clientNum; else return -1; } int MultiplayerManager::getClientPing( int entnum ) { gclient_s *client; // Get the client client = getClient( entnum ); if ( client ) return client->ps.ping; else return -1; } float MultiplayerManager::getTime( void ) { return level.time; } void MultiplayerManager::centerPrint( int entnum, const str &string, CenterPrintImportance importance ) { gentity_t *gentity; if ( ( entnum >= 0 ) && ( entnum < maxclients->integer ) ) { gentity = &g_entities[ entnum ]; if ( gentity->inuse && gentity->entity && gentity->client ) { gi.centerprintf( gentity, importance, string.c_str() ); } } } Player *MultiplayerManager::getPlayer( int entnum ) { gentity_t *gentity; Player *player = NULL; // Make sure everything is ok if ( ( entnum >= 0 ) && ( entnum < maxclients->integer ) ) { gentity = &g_entities[ entnum ]; if ( gentity->inuse && gentity->entity && gentity->client && gentity->entity->isSubclassOf( Player ) ) { player = (Player *)gentity->entity; } } return player; } int MultiplayerManager::getMaxPlayers( void ) { return maxclients->integer; } int MultiplayerManager::getTotalPlayers( bool countSpectators ) { int i; Player *player; int numPlayers; numPlayers = 0; for( i = 0 ; i < maxclients->integer ; i++ ) { player = getPlayer( i ); if ( player ) { if ( !isPlayerSpectator( player ) || !countSpectators ) { numPlayers++; } } } return numPlayers; } gclient_s *MultiplayerManager::getClient( int entnum ) { gentity_t *gentity; // Make sure everything is ok if ( ( entnum >= 0 ) && ( entnum < maxclients->integer ) ) { gentity = &g_entities[ entnum ]; if ( gentity->inuse && gentity->entity && gentity->client && gentity->entity->isSubclassOf( Player ) ) { return gentity->client; } } return NULL; } void MultiplayerManager::HUDSay( int entnum, const str &string ) { str command; Player *player; // Get the player player = getPlayer( entnum ); if ( player ) { // Build the hud print command to send to the client command = "hudsay \""; command += string; command += "\"\n"; if ( gi.GetNumFreeReliableServerCommands( player->edict - g_entities ) > 32 ) { gi.SendServerCommand( player->edict - g_entities, command.c_str() ); } } } void MultiplayerManager::HUDPrint( int entnum, const str &string ) { Player *player; player = getPlayer( entnum ); if ( player ) { player->hudPrint( string ); } } void MultiplayerManager::statusPrint( int entnum, const str &string ) { str command; Player *player; // Get the player player = getPlayer( entnum ); if ( player ) { // Build the status print command to send to the client command = "status \""; command += string; command += "\"\n"; gi.SendServerCommand( player->edict - g_entities, command.c_str() ); } } void MultiplayerManager::playerSound( int entnum, const str &soundName, int channel, float volume, float minDist, float time ) { Player *player; // Get the playaer player = getPlayer( entnum ); // Tell the player to play a sound if ( player ) { addSoundToQueue( player, soundName, channel, volume, minDist, time ); //player->Sound( soundName, channel, volume, minDist, NULL, 1.0f, true ); } } void MultiplayerManager::instantPlayerSound( int entnum, const str &soundName, int channel, float volume, float minDist ) { Player *player; // Get the playaer player = getPlayer( entnum ); // Tell the player to play a sound if ( player ) { player->Sound( soundName, channel, volume, minDist, NULL, 1.0f, true ); } } void MultiplayerManager::broadcastInstantSound( const str &soundName, int channel, float volume, float minDist, Player *except ) { int i; Player *player; // Go through all of the clients for( i = 0; i < maxclients->integer; i++ ) { // Get the player player = getPlayer( i ); // Tell the player to play a sound if ( player && ( player != except ) ) { instantPlayerSound( player->entnum, soundName, channel, volume, minDist ); } } } void MultiplayerManager::teamSound( Team *team, const str &soundName, int channel, float volume, float minDist, float time ) { int i; Player *player; // Go through all of the clients for( i = 0; i < maxclients->integer; i++ ) { // Get the player player = getPlayer( i ); // Tell the player to play a sound if ( player && ( getPlayersTeam( player ) == team ) ) { playerSound( player->entnum, soundName, channel, volume, minDist, time ); } } } void MultiplayerManager::broadcastSound( const str &soundName, int channel, float volume, float minDist, Player *except, float time ) { int i; Player *player; // Go through all of the clients for( i = 0; i < maxclients->integer; i++ ) { // Get the player player = getPlayer( i ); // Tell the player to play a sound if ( player && ( player != except ) ) { playerSound( player->entnum, soundName, channel, volume, minDist, time ); } } } bool MultiplayerManager::isPlayerSpectator( Player *player, SpectatorTypes spectatorType ) { if ( !_inMultiplayerGame ) return false; if ( spectatorType == SPECTATOR_TYPE_ANY ) return _playerData[ player->entnum ]._spectator; else if ( spectatorType == SPECTATOR_TYPE_NONE ) return !_playerData[ player->entnum ]._spectator; else return ( _playerData[ player->entnum ]._spectator && _playerData[ player->entnum ]._spectatorType == spectatorType ); } bool MultiplayerManager::isPlayerSpectatorByChoice( Player *player ) { if ( !_inMultiplayerGame ) return false; if ( _playerData[ player->entnum ]._spectator && _playerData[ player->entnum ]._spectatorByChoice ) return true; else return false; } Player *MultiplayerManager::getPlayerSpectating( Player *player ) { if ( isPlayerSpectator( player, SPECTATOR_TYPE_FOLLOW ) ) { return getPlayer( _playerData[ player->entnum ]._spectatorPlayerNum ); } return NULL; } void MultiplayerManager::makePlayerSpectator( Player *player, SpectatorTypes spectatorType, bool byChoice ) { Team *team; // Make the player into a spectator if ( player ) { initPlayer( player ); _playerData[ player->entnum ]._spectator = true; _playerData[ player->entnum ]._spectatorType = spectatorType; _playerData[ player->entnum ]._spectatorTime = getTime(); if ( byChoice ) { _playerData[ player->entnum ]._spectatorByChoice = true; } _playerData[ player->entnum ]._spectatorPlayerNum = 0; // Print something useful to the player if ( spectatorType == SPECTATOR_TYPE_FOLLOW ) centerPrint( player->entnum, "$$SpectatorFollow$$", CENTERPRINT_IMPORTANCE_NORMAL ); else if ( spectatorType == SPECTATOR_TYPE_FREEFORM ) centerPrint( player->entnum, "$$SpectatorFreeForm$$", CENTERPRINT_IMPORTANCE_NORMAL ); else centerPrint( player->entnum, "$$SpectatorNormal$$", CENTERPRINT_IMPORTANCE_NORMAL ); if ( spectatorType == SPECTATOR_TYPE_FOLLOW ) { Player *playerToSpectate = getLastKillerOfPlayer( player ); if ( playerToSpectate ) makePlayerSpectatePlayer( player, playerToSpectate ); else makePlayerSpectateNextPlayer( player ); } player->takedamage = DAMAGE_NO; player->client->ps.feetfalling = false; player->deadflag = DEAD_NO; player->flags &= ~FL_IMMOBILE; player->flags &= ~FL_STUNNED; //player->movecontrol = MOVECONTROL_USER; // Hide the player model player->hideModel(); // Force them to the stand state player->SetState( "STAND", "STAND" ); // Go not solid player->setSolidType( SOLID_NOT ); // Move in normal walking mode //player->setMoveType( MOVETYPE_NOCLIP ); player->setMoveType( MOVETYPE_WALK ); // Get rid of the inventory player->FreeInventory(); player->disableInventory(); team = getPlayersTeam( player ); if ( !team ) setTeamHud( player, "mp_teamspec" ); else if ( team->getName() == "Red" ) setTeamHud( player, "mp_teamredspec" ); else setTeamHud( player, "mp_teambluespec" ); player->clearItemText(); } } void MultiplayerManager::makePlayerSpectateNextPlayer( Player *player ) { int startIndex; int currentIndex; Player *testPlayer; if ( !isPlayerSpectator( player, SPECTATOR_TYPE_FOLLOW ) ) return; startIndex = _playerData[ player->entnum ]._spectatorPlayerNum; currentIndex = startIndex + 1; if ( currentIndex >= maxclients->integer ) currentIndex = 0; while ( currentIndex != startIndex ) { testPlayer = getPlayer( currentIndex ); if ( testPlayer && !isPlayerSpectator( testPlayer ) ) { _playerData[ player->entnum ]._spectatorPlayerNum = currentIndex; return; } currentIndex++; if ( currentIndex >= maxclients->integer ) currentIndex = 0; } testPlayer = getPlayer( currentIndex ); if ( testPlayer && !isPlayerSpectator( testPlayer ) ) { _playerData[ player->entnum ]._spectatorPlayerNum = currentIndex; return; } else { // If we get here there isn't anyone to spectate makePlayerSpectator( player, SPECTATOR_TYPE_NORMAL ); } } void MultiplayerManager::makePlayerSpectatePrevPlayer( Player *player ) { int startIndex; int currentIndex; Player *testPlayer; if ( !isPlayerSpectator( player, SPECTATOR_TYPE_FOLLOW ) ) return; startIndex = _playerData[ player->entnum ]._spectatorPlayerNum; currentIndex = startIndex - 1; if ( currentIndex < 0 ) currentIndex = maxclients->integer - 1; while ( currentIndex != startIndex ) { testPlayer = getPlayer( currentIndex ); if ( testPlayer && !isPlayerSpectator( testPlayer ) ) { _playerData[ player->entnum ]._spectatorPlayerNum = currentIndex; return; } currentIndex--; if ( currentIndex < 0 ) currentIndex = maxclients->integer - 1; } // If we get here there isn't anyone to spectate makePlayerSpectator( player, SPECTATOR_TYPE_NORMAL ); } void MultiplayerManager::makePlayerSpectatePlayer( Player *player, Player *playerToSpectate ) { if ( !isPlayerSpectator( player, SPECTATOR_TYPE_FOLLOW ) ) return; if ( playerToSpectate && !isPlayerSpectator( playerToSpectate ) ) { _playerData[ player->entnum ]._spectatorPlayerNum = playerToSpectate->entnum; return; } // PlayerToSpectate wasn't valid, try the next player instead makePlayerSpectateNextPlayer( player ); } void MultiplayerManager::playerEnterArena( int entnum, float health ) { Player *player; Team *team; player = getPlayer( entnum ); if ( !player ) return; _playerData[ entnum ]._spectator = false; _playerData[ entnum ]._spectatorByChoice = false; // Make sure player is solid and can take damage player->takedamage = DAMAGE_YES; player->setSolidType( SOLID_BBOX ); // Show the player player->showModel(); // Get rid of our inventory player->FreeInventory(); player->dropRune(); player->dropPowerup(); player->removeHoldableItem(); player->ProcessEvent( EV_Sentient_StopOnFire ); player->stopStasis(); player->removeAttachedModelByTargetname( "attachedSpecialityBackpack" ); player->removeAttachedModelByTargetname( "attachedDiffusionBomb" ); player->removeAttachedModelByTargetname( "actionHero" ); player->clearTempAttachments(); player->enableInventory(); // Init(); // Set the player's health to the specified value player->health = health; // hold in place briefly player->client->ps.pm_time = 100; player->client->ps.pm_flags |= PMF_TIME_TELEPORT; Event *newEvent = new Event( EV_DisplayEffect ); newEvent->AddString( "TransportIn" ); newEvent->AddString( "Multiplayer" ); player->PostEvent( newEvent, 0.0f ); changePlayerModel( player, player->model, true ); team = getPlayersTeam( player ); if ( !team ) setTeamHud( player, "" ); else if ( team->getName() == "Red" ) setTeamHud( player, "mp_teamred" ); else setTeamHud( player, "mp_teamblue" ); } void MultiplayerManager::playerSpawned( Player *player ) { // Tell all of the modifiers that the player has respawned for ( int i = 1 ; i <= _modifiers.NumObjects() ; i++ ) { MultiplayerModifier *modifier; modifier = _modifiers.ObjectAt( i ); if ( modifier ) { modifier->playerSpawned( player ); } } } void MultiplayerManager::allowFighting( bool allowFighting ) { _allowFighting = allowFighting; } void MultiplayerManager::centerPrintAllClients( const str &string, CenterPrintImportance importance ) { int i; gentity_t *ent; // Go through all of the clients for( i = 0; i < maxclients->integer; i++ ) { ent = g_entities + i; // Make sure this is a valid client if ( !ent->inuse || !ent->client || !ent->entity ) continue; // Send centerprint command to the client centerPrint( ent->entity->entnum, string, importance ); } } void MultiplayerManager::HUDPrintAllClients( const str &string ) { int i; gentity_t *ent; // Go through all of the clients for( i = 0; i < maxclients->integer; i++ ) { ent = g_entities + i; // Make sure this is a valid client if ( !ent->inuse || !ent->client || !ent->entity ) continue; // Send hud print command to the client HUDSay( ent->entity->entnum, string ); } } void MultiplayerManager::centerPrintTeamClients( Player *player, const str &string, CenterPrintImportance importance ) { int i; gentity_t *ent; Player *otherPlayer; // Go through all of the clients for( i = 0; i < maxclients->integer; i++ ) { ent = g_entities + i; // Make sure this is a valid client if ( !ent->inuse || !ent->client || !ent->entity ) continue; if ( !ent->entity->isSubclassOf( Player ) ) continue; otherPlayer = (Player *)ent->entity; // Make sure this player is on the same team if ( getPlayersTeam( player ) == getPlayersTeam( otherPlayer ) ) { // Send centerprint command to the client centerPrint( otherPlayer->entnum, string, importance ); } } } void MultiplayerManager::HUDPrintTeamClients( Player *player, const str &string ) { int i; gentity_t *ent; Player *otherPlayer; // Go through all of the clients for( i = 0; i < maxclients->integer; i++ ) { ent = g_entities + i; // Make sure this is a valid client if ( !ent->inuse || !ent->client || !ent->entity ) continue; if ( !ent->entity->isSubclassOf( Player ) ) continue; otherPlayer = (Player *)ent->entity; // Make sure this player is on the same team if ( getPlayersTeam( player ) == getPlayersTeam( otherPlayer ) ) { // Send the hud print command to the client HUDSay( otherPlayer->entnum, string ); } } } void MultiplayerManager::HUDPrintSpectators( Player *player, const str &string, bool team ) { int i; gentity_t *ent; Player *otherPlayer; // Go through all of the clients for( i = 0 ; i < maxclients->integer ; i++ ) { ent = g_entities + i; // Make sure this is a valid client if ( !ent->inuse || !ent->client || !ent->entity ) continue; if ( !ent->entity->isSubclassOf( Player ) ) continue; otherPlayer = (Player *)ent->entity; // Make sure this player is a spectator if ( !isPlayerSpectator( otherPlayer ) ) continue; // Make sure the players are on the same team (if requested) if ( team && ( getPlayersTeam( player ) != getPlayersTeam( otherPlayer ) ) ) continue; // Send the hud print command to the client HUDSay( otherPlayer->entnum, string ); } } void MultiplayerManager::addPlayerHealth( int entnum, float healthToAdd ) { Player *player; player = getPlayer( entnum ); if ( player ) { player->AddHealth( healthToAdd ); } } void MultiplayerManager::givePlayerItem( int entnum, const str &itemName ) { Player *player; Event *event; bool canGive; if ( !_inMatch ) return; player = getPlayer( entnum ); if ( !player ) return; canGive = canGivePlayerItem( entnum, itemName ); if ( canGive ) { event = new Event( EV_Player_GiveCheat ); event->AddString( itemName ); player->ProcessEvent( event ); } } void MultiplayerManager::usePlayerItem( int entnum, const str &itemName ) { Player *player; player = getPlayer( entnum ); if ( !player ) return; // Use the specified item Event *ev = new Event( "use" ); ev->AddString( itemName ); player->ProcessEvent( ev ); } bool MultiplayerManager::canGivePlayerItem( int entnum, const str &itemName ) { int i; Player *player; player = getPlayer( entnum ); if ( !player ) return false; if ( player->FindItem( itemName ) ) return false; // Make sure all of the modifiers allow this item to be given to the player for ( i = 1 ; i <= _modifiers.NumObjects() ; i++ ) { MultiplayerModifier *modifier; modifier = _modifiers.ObjectAt( i ); if ( modifier ) { if ( !modifier->canGivePlayerItem( entnum, itemName ) ) return false; } } // Make sure the game allows this item to be given to the player if ( !_multiplayerGame->canGivePlayerItem( entnum, itemName ) ) return false; return true; } float MultiplayerManager::getItemRespawnMultiplayer( void ) { if ( !_inMultiplayerGame ) return 1.0f; else return mp_itemRespawnMultiplier->value; } float MultiplayerManager::getWeaponRespawnMultiplayer( void ) { if ( !_inMultiplayerGame ) return 1.0f; else return mp_weaponRespawnMultiplier->value; } float MultiplayerManager::getPowerupRespawnMultiplayer( void ) { if ( !_inMultiplayerGame ) return 1.0f; else return mp_powerupRespawnMultiplier->value; } void MultiplayerManager::playerEventNotification( const char *eventName, const char *eventItemName, Player *eventPlayer ) { int i; gentity_t *ent; Player *player; if ( !_inMultiplayerGame ) return; // Notify all of the modifiers about this event for ( i = 1 ; i <= _modifiers.NumObjects() ; i++ ) { MultiplayerModifier *modifier; modifier = _modifiers.ObjectAt( i ); if ( modifier ) modifier->playerEventNotification( eventName, eventItemName, eventPlayer ); } // Notify the award system about this event _awardSystem->playerEventNotification( eventName, eventItemName, eventPlayer ); // Notify all the player's about the event for( i = 0; i < maxclients->integer; i++ ) { ent = g_entities + i; // Make sure this is a valid client if ( !ent->inuse || !ent->client || !ent->entity || !ent->entity->isSubclassOf( Player ) ) continue; player = (Player *)ent->entity; player->notifyPlayerOfMultiplayerEvent( eventName, eventItemName, eventPlayer ); } // Notify the game about the event _multiplayerGame->playerEventNotification( eventName, eventItemName, eventPlayer ); } void MultiplayerManager::startMatch( void ) { int i; _inMatch = true; // Inform all of the modifiers that the match is starting for ( i = 1 ; i <= _modifiers.NumObjects() ; i++ ) { MultiplayerModifier *modifier; modifier = _modifiers.ObjectAt( i ); if ( modifier ) { modifier->matchStarting(); } } // Inform the game that the match has started _multiplayerGame->startMatch(); // Inform all of the modifiers that the match has started for ( i = 1 ; i <= _modifiers.NumObjects() ; i++ ) { MultiplayerModifier *modifier; modifier = _modifiers.ObjectAt( i ); if ( modifier ) { modifier->matchStarted(); } } } void MultiplayerManager::restartMatch( void ) { // Inform the game that the match has ended _multiplayerGame->endMatch(); // Inform all of the modifiers that the match has started for ( int i = 1 ; i <= _modifiers.NumObjects() ; i++ ) { MultiplayerModifier *modifier; modifier = _modifiers.ObjectAt( i ); if ( modifier ) { modifier->matchEnded(); } } resetItems(); // Inform the game that the match has restarted _multiplayerGame->restartMatch(); // Inform all of the modifiers that the match has started /* for ( int i = 1 ; i <= _modifiers.NumObjects() ; i++ ) { MultiplayerModifier *modifier; modifier = _modifiers.ObjectAt( i ); if ( modifier ) { modifier->matchRestarted(); } } */ _inMatch = true; } void MultiplayerManager::endMatch( void ) { _inMatch = false; _restartMatchTime = getTime() + _inBetweenMatchTime; } void MultiplayerManager::initPlayer( Player *player ) { Vector savedAngles; Vector savedViewAngles; qboolean saved_teleport_bit; // Cancel all events that have been posted for the future player->CancelPendingEvents(); // Save off necessary stuff saved_teleport_bit = player->edict->s.eFlags & EF_TELEPORT_BIT; savedAngles = player->client->cmd_angles; savedViewAngles = player->getViewAngles(); // Initialize the player player->Init(); // Restore necessary stuff player->edict->s.eFlags |= saved_teleport_bit; savedAngles.copyTo( player->client->cmd_angles ); player->SetViewAngles( savedViewAngles ); } Player *MultiplayerManager::getLastKilledByPlayer( Player *player, int *meansOfdeath ) { return _multiplayerGame->getLastKilledByPlayer( player, meansOfdeath ); } Player *MultiplayerManager::getLastKillerOfPlayer( Player *player, int *meansOfdeath ) { return _multiplayerGame->getLastKillerOfPlayer( player, meansOfdeath ); } void MultiplayerManager::playerCommand( Player *player, const char *command, const char *parm ) { if ( !_inMultiplayerGame ) return; // Pass the player command to all of the modifiers for ( int i = 1 ; i <= _modifiers.NumObjects() ; i++ ) { MultiplayerModifier *modifier; modifier = _modifiers.ObjectAt( i ); if ( modifier ) { modifier->playerCommand( player, command, parm ); } } // Pass the player command to the game _multiplayerGame->playerCommand( player, command, parm ); } void MultiplayerManager::playerInput( Player *player, int newButtons ) { if ( isPlayerSpectator( player ) ) { if ( newButtons & BUTTON_USE ) { // Change spectator type if ( isPlayerSpectator( player, SPECTATOR_TYPE_FOLLOW ) ) makePlayerSpectator( player, SPECTATOR_TYPE_NORMAL ); else if ( isPlayerSpectator( player, SPECTATOR_TYPE_NORMAL ) ) makePlayerSpectator( player, SPECTATOR_TYPE_FREEFORM ); else makePlayerSpectator( player, SPECTATOR_TYPE_FOLLOW ); } if ( isPlayerSpectator( player, SPECTATOR_TYPE_FOLLOW ) && ( _playerData[ player->entnum ]._spectatorTime != getTime() ) ) { if ( newButtons & BUTTON_ATTACKRIGHT ) { // Follow the next player makePlayerSpectateNextPlayer( player ); } if ( newButtons & BUTTON_ATTACKLEFT ) { // Follow the prev player makePlayerSpectatePrevPlayer( player ); } } } } int MultiplayerManager::getInfoIcon( Player *player, int buttons ) { int icon; // See if the play is talking if ( buttons & BUTTON_TALK ) return _talkingIconIndex; // See if the game has anything icon = _multiplayerGame->getInfoIcon( player ); if ( icon > 0 ) return icon; // See if the award system has anything icon = _awardSystem->getInfoIcon( player ); if ( icon > 0 ) return icon; // See if any modifiers have anything for ( int i = 1 ; i <= _modifiers.NumObjects() ; i++ ) { MultiplayerModifier *modifier; modifier = _modifiers.ObjectAt( i ); if ( modifier ) { icon = modifier->getInfoIcon( player ); if ( icon > 0 ) return icon; } } // No one has anything to display return 0; } void MultiplayerManager::teamPointsChanged( Team *team, int oldPoints, int newPoints ) { if ( !_inMultiplayerGame ) return; // Tell the game that the team points have changed _multiplayerGame->teamPointsChanged( team, oldPoints, newPoints ); } void MultiplayerManager::cacheMultiplayerFiles( const str &cacheFileName ) { str fileToCache; // Build the name of the file to cache fileToCache = "precache/server/"; fileToCache += cacheFileName; fileToCache += ".txt"; // Cache everything in the file (if it is there) if ( gi.FS_ReadFile( fileToCache, NULL, true ) != -1 ) { level.consoleThread->Parse( fileToCache ); } } str MultiplayerManager::getPlaceName( Player *player ) { int place; str placeName; place = _multiplayerGame->getPlace( player ); placeName = "$$Place"; placeName += place; placeName += "$$"; return placeName; } void MultiplayerManager::setTeamHud( Player *player, const str &teamHudName ) { str command; if ( teamHudName == _playerData[ player->entnum ]._teamHud ) return; // Remove the old team hud if ( _playerData[ player->entnum ]._teamHud.length() > 0 ) { command = va( "stufftext \"ui_removehud %s\"\n", _playerData[ player->entnum ]._teamHud.c_str() ); gi.SendServerCommand( player->entnum, command.c_str() ); } // Add the new team hud if ( teamHudName.length() > 0 ) { command = va( "stufftext \"ui_addhud %s\"\n", teamHudName.c_str() ); gi.SendServerCommand( player->entnum, command.c_str() ); } _playerData[ player->entnum ]._teamHud = teamHudName; } str MultiplayerManager::getSpawnPointType( Player *player ) { str spawnPointName; MultiplayerModifier *modifier; int i; float priority; float highestPriority = 0.0f; for ( i = 1 ; i <= _modifiers.NumObjects() ; i++ ) { modifier = _modifiers.ObjectAt( i ); if ( modifier ) { priority = modifier->getSpawnPointPriority( player ); if ( priority > highestPriority ) { spawnPointName = modifier->getSpawnPointType( player ); highestPriority = priority; } } } return spawnPointName; } bool MultiplayerManager::isValidPlayerModel( Player *player, str modelToUse ) { MultiplayerModifier *modifier; int i; bool validPlayerModel = false; int modelIndex; tiki_cmd_t tikicmds; // Check to see if the model itself is ok first modelIndex = gi.modelindex( modelToUse ); if ( gi.InitCommands( modelIndex, &tikicmds ) ) { for( i = 0; i < tikicmds.num_cmds; i++ ) { if ( stricmp( tikicmds.cmds[ i ].args[ 0 ], "validPlayerModel" ) == 0 ) { validPlayerModel = true; break; } } } // Check with the game to see if the model is ok validPlayerModel = _multiplayerGame->isValidPlayerModel( player, modelToUse, validPlayerModel ); // Check with all of the modifiers to see if the model is ok for ( i = 1 ; i <= _modifiers.NumObjects() ; i++ ) { modifier = _modifiers.ObjectAt( i ); if ( modifier ) { validPlayerModel = modifier->isValidPlayerModel( player, modelToUse, validPlayerModel ); } } return validPlayerModel; } str MultiplayerManager::getDefaultPlayerModel( Player *player ) { MultiplayerModifier *modifier; int i; str modelName; modelName = _multiplayerGame->getDefaultPlayerModel( player, "models/char/munro.tik" ); for ( i = 1 ; i <= _modifiers.NumObjects() ; i++ ) { modifier = _modifiers.ObjectAt( i ); if ( modifier ) { modelName = modifier->getDefaultPlayerModel( player, modelName ); } } return modelName; } void MultiplayerManager::setNextMap( void ) { str nextMapName; str fullMapName; if ( ( strlen( sv_nextmap->string ) == 0 ) && ( mp_useMapList->integer ) && ( strlen( mp_mapList->string ) > 0 ) ) { nextMapName = getNextMap(); fullMapName = "maps/"; fullMapName += nextMapName; fullMapName += ".bsp"; if ( gi.FS_Exists( fullMapName ) ) { gi.cvar_set( "nextmap", nextMapName.c_str() ); } else { gi.Printf( "%s map not found\n", fullMapName.c_str() ); } gi.cvar_set( "mp_currentPosInMapList", va( "%d", mp_currentPosInMapList->integer + 1 ) ); } } str MultiplayerManager::getNextMap( void ) { str nextMapName; str mapList; int numMaps; const char *currentPlaceInMapList; int realCurrentPos; int i; str tempString; const char *nextSpace; int diff; mapList = mp_mapList->string; // Get the number of maps in the list numMaps = 0; currentPlaceInMapList = mapList.c_str(); while( 1 ) { currentPlaceInMapList = strstr( currentPlaceInMapList, ";" ); if ( currentPlaceInMapList ) numMaps++; else break; currentPlaceInMapList++; } if ( mapList.length() && ( mapList[ mapList.length() - 1 ] != ';' ) ) numMaps++; if ( numMaps == 0 ) return ""; // Get the position in the list realCurrentPos = mp_currentPosInMapList->integer % numMaps; // Get the next map string currentPlaceInMapList = mapList.c_str(); for ( i = 0 ; i < realCurrentPos ; i++ ) { currentPlaceInMapList = strstr( currentPlaceInMapList, ";" ); currentPlaceInMapList++; } nextMapName = currentPlaceInMapList; currentPlaceInMapList = nextMapName.c_str(); currentPlaceInMapList = strstr( currentPlaceInMapList, ";" ); if ( currentPlaceInMapList ) { nextMapName.CapLength( currentPlaceInMapList - nextMapName.c_str() ); } // Remove spaces from the beginning of the map name while ( ( nextMapName.length() > 0 ) && ( nextMapName[ 0 ] == ' ' ) ) { tempString = nextMapName.c_str() + 1; nextMapName = tempString; } // Remove spaces from the end of the map name nextSpace = strstr( nextMapName.c_str(), " " ); if ( nextSpace ) { diff = nextSpace - nextMapName.c_str(); nextMapName.CapLength( diff ); } return nextMapName; } float MultiplayerManager::getRespawnTime( void ) { return _respawnTime; } void MultiplayerManager::setRespawnTime( float time ) { _respawnTime = time; } void MultiplayerManager::resetRespawnTime( void ) { setRespawnTime( mp_respawnTime->value ); mp_respawnTime->modified = false; } void MultiplayerManager::checkModifiedCvars( bool informPlayers ) { // Inform players about cvar changes (if any ) if ( informPlayers ) { if ( hasFlagChanged( MP_FLAG_WEAPONS_STAY ) ) checkCvar( mp_flags, "$$WeaponsStay$$", MP_CVAR_TYPE_BOOL, MP_FLAG_WEAPONS_STAY ); if ( hasFlagChanged( MP_FLAG_NO_FALLING ) ) checkCvar( mp_flags, "$$NoFalling$$", MP_CVAR_TYPE_BOOL, MP_FLAG_NO_FALLING ); if ( hasFlagChanged( MP_FLAG_FRIENDLY_FIRE ) ) checkCvar( mp_flags, "$$AllowFriendlyFire$$", MP_CVAR_TYPE_BOOL, MP_FLAG_FRIENDLY_FIRE ); if ( hasFlagChanged( MP_FLAG_FORCE_RESPAWN ) ) checkCvar( mp_flags, "$$ForceRespawn$$", MP_CVAR_TYPE_BOOL, MP_FLAG_FORCE_RESPAWN ); if ( hasFlagChanged( MP_FLAG_INFINITE_AMMO ) ) checkCvar( mp_flags, "$$InfiniteAmmo$$", MP_CVAR_TYPE_BOOL, MP_FLAG_INFINITE_AMMO ); if ( hasFlagChanged( MP_FLAG_FIXED_FOV ) ) checkCvar( mp_flags, "$$FixedFOV$$", MP_CVAR_TYPE_BOOL, MP_FLAG_FIXED_FOV ); if ( hasFlagChanged( MP_FLAG_NO_DROP_WEAPONS ) ) checkCvar( mp_flags, "$$DontDropWeapons$$", MP_CVAR_TYPE_BOOL, MP_FLAG_NO_DROP_WEAPONS ); if ( hasFlagChanged( MP_FLAG_NO_FOOTSTEPS ) ) checkCvar( mp_flags, "$$NoFootstepSounds$$", MP_CVAR_TYPE_BOOL, MP_FLAG_NO_FOOTSTEPS ); if ( hasFlagChanged( MP_FLAG_DONT_ALLOW_VOTE ) ) checkCvar( mp_flags, "$$DontAllowVoting$$", MP_CVAR_TYPE_BOOL, MP_FLAG_DONT_ALLOW_VOTE ); if ( hasFlagChanged( MP_FLAG_FULL_COLLISION ) ) checkCvar( mp_flags, "$$FullCollision$$", MP_CVAR_TYPE_BOOL, MP_FLAG_FULL_COLLISION ); checkCvar( mp_pointlimit, "$$PointLimit$$", MP_CVAR_TYPE_INTEGER ); checkCvar( mp_timelimit, "$$TimeLimit$$", MP_CVAR_TYPE_INTEGER ); checkCvar( mp_itemRespawnMultiplier, "$$ItemRespawnMultiplier$$", MP_CVAR_TYPE_FLOAT ); checkCvar( mp_weaponRespawnMultiplier, "$$WeaponRespawnMultiplier$$", MP_CVAR_TYPE_FLOAT ); checkCvar( mp_powerupRespawnMultiplier, "$$PowerupRespawnMultiplier$$", MP_CVAR_TYPE_FLOAT ); checkCvar( mp_knockbackMultiplier, "$$KnocbackMultiplier$$", MP_CVAR_TYPE_INTEGER ); checkCvar( mp_damageMultiplier, "$$DamageMultiplier$$", MP_CVAR_TYPE_FLOAT ); checkCvar( mp_respawnInvincibilityTime, "$$RespawnInvincibilityTime$$", MP_CVAR_TYPE_FLOAT ); checkCvar( mp_warmUpTime, "$$WarmUpTime$$", MP_CVAR_TYPE_INTEGER ); checkCvar( sv_maxspeed, "$$PlayerSpeed$$", MP_CVAR_TYPE_INTEGER ); checkCvar( mp_bigGunMode, "$$OptionBigGunMode$$", MP_CVAR_TYPE_INTEGER ); checkCvar( mp_respawnTime, "$$OptionRespawnTime$$", MP_CVAR_TYPE_INTEGER ); checkCvar( mp_bombTime, "$$OptionBombTime$$", MP_CVAR_TYPE_INTEGER ); checkCvar( mp_maxVotes, "$$OptionMaxVotes$$", MP_CVAR_TYPE_INTEGER ); } // Mark everything as not modified mp_flags->modified = false; mp_pointlimit->modified = false; mp_timelimit->modified = false; mp_itemRespawnMultiplier->modified = false; mp_weaponRespawnMultiplier->modified = false; mp_powerupRespawnMultiplier->modified = false; mp_knockbackMultiplier->modified = false; mp_damageMultiplier->modified = false; mp_respawnInvincibilityTime->modified = false; mp_warmUpTime->modified = false; sv_maxspeed->modified = false; mp_bigGunMode->modified = false; mp_respawnTime->modified = false; mp_bombTime->modified = false; mp_maxVotes->modified = false; // Save off the flags _oldFlags = mp_flags->integer; } void MultiplayerManager::checkCvar( cvar_t *mp_cvarToCheck, str optionName, MPCvarType cvarType, int bitToCheck ) { str stringToPrint; if ( mp_cvarToCheck->modified ) { stringToPrint = "$$ServerOptionChanged$$ : "; stringToPrint += optionName; stringToPrint += " "; if ( cvarType == MP_CVAR_TYPE_INTEGER ) { stringToPrint += mp_cvarToCheck->integer; } else if ( cvarType == MP_CVAR_TYPE_FLOAT ) { stringToPrint += mp_cvarToCheck->value; } else if ( cvarType == MP_CVAR_TYPE_BOOL ) { int value; if ( bitToCheck >= 0 ) { value = mp_cvarToCheck->integer & bitToCheck; } else { value = mp_cvarToCheck->integer; } if ( value == 0 ) stringToPrint += "$$Off$$"; else stringToPrint += "$$On$$"; } stringToPrint += "\n"; multiplayerManager.HUDPrintAllClients( stringToPrint ); } } bool MultiplayerManager::hasFlagChanged( int bitToCheck ) { if ( ( _oldFlags & bitToCheck ) != ( mp_flags->integer & bitToCheck ) ) return true; else return false; } void MultiplayerManager::addSoundToQueue( Player *player, str soundName, int channel, float volume, float minDist, float time ) { MultiplayerDialogData * dialogData; int nextDialogAddSpot; MultiplayerPlayerData * playerData; playerData = &_playerData[ player->entnum ]; nextDialogAddSpot = playerData->getNextDialogAddSpot(); dialogData = &playerData->_dialogData[ nextDialogAddSpot ]; // Add the dialog to the queue dialogData->_soundName = soundName; dialogData->_channel = channel; dialogData->_volume = volume; dialogData->_minDist = minDist; dialogData->_time = time; // Move to the next spot playerData->_nextDialogAddSpot++; } void MultiplayerManager::sendNextPlayerSound( Player *player ) { MultiplayerDialogData * dialogData; MultiplayerPlayerData * playerData; int nextDialogSendSpot; playerData = &_playerData[ player->entnum ]; // Make sure we haven't sent anything too recently if ( playerData->_nextDialogSendTime > multiplayerManager.getTime() ) return; // Make sure we have something to send if ( playerData->_nextDialogSendSpot >= playerData->_nextDialogAddSpot ) return; // Send the sound nextDialogSendSpot = playerData->getNextDialogSendSpot(); dialogData = &playerData->_dialogData[ nextDialogSendSpot ]; player->Sound( dialogData->_soundName, dialogData->_channel, dialogData->_volume, dialogData->_minDist, NULL, 1.0f, true ); // Move to the next slot playerData->_nextDialogSendSpot++; // Don't send another sound for a little while playerData->_nextDialogSendTime = multiplayerManager.getTime() + dialogData->_time; } bool MultiplayerManager::skipWeaponReloads( void ) { if ( !_inMultiplayerGame ) return false; if ( mp_skipWeaponReloads->integer ) return true; if ( _multiplayerGame->skipWeaponReloads() ) return true; for ( int i = 1 ; i <= _modifiers.NumObjects() ; i++ ) { MultiplayerModifier *modifier; modifier = _modifiers.ObjectAt( i ); if ( modifier ) { if ( modifier->skipWeaponReloads() ) return true; } } return false; }