ef2gamesource/dlls/game/mp_manager.cpp
Walter Julius Hennecke 5bbf27cabd Initial code commit ...
2012-12-30 17:37:54 +01:00

3960 lines
82 KiB
C++

//-----------------------------------------------------------------------------
//
// $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 <mapname>, g_gametype <n> and kick <player>.\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;
}