ef2gamesource/dlls/game/mp_modifiers.cpp

4156 lines
113 KiB
C++

//-----------------------------------------------------------------------------
//
// $Logfile:: /EF2/Code/DLLs/game/mp_modifiers.cpp $
// $Revision:: 172 $
// $Author:: Singlis $
// $Date:: 9/26/03 2:36p $
//
// 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 "mp_manager.hpp"
#include "mp_modifiers.hpp"
#include "equipment.h"
#include "powerups.h"
#include "weaputils.h"
#include "health.h"
#include "armor.h"
// Setup constants
const float ModifierInstantKill::_instantKillDamage = 1000.0f;
const float ModifierInstantKill::_regenTime = 0.1f;
const int ModifierInstantKill::_regenAmount = 1;
ModifierInstantKill::ModifierInstantKill()
{
_lastRegenTime = 0.0f;
}
void ModifierInstantKill::init( int maxPlayers )
{
multiplayerManager.cacheMultiplayerFiles( "mp_instantKill" );
}
float ModifierInstantKill::playerDamaged( Player *damagedPlayer, Player *attackingPlayer, float damage, int meansOfDeath )
{
float realDamage = 0.0f;
if ( damage > 0.0f )
{
switch( meansOfDeath )
{
case MOD_COMP_RIFLE:
case MOD_IMOD_PRIMARY:
case MOD_IMOD_SECONDARY:
case MOD_DISRUPTOR:
case MOD_SNIPER:
case MOD_MELEE:
realDamage = _instantKillDamage;
break;
default:
realDamage = damage;
break;
}
}
return realDamage;
}
bool ModifierInstantKill::canGivePlayerItem( int entnum, const str &itemName )
{
if ( strstr( itemName.c_str(), "phaser.tik" ) )
return false;
else if ( strstr( itemName.c_str(), "batleth.tik" ) )
return false;
else if ( strstr( itemName.c_str(), "compressionrifle.tik" ) )
return false;
return true;
}
bool ModifierInstantKill::checkRule( const char *rule, bool defaultValue, Player *player )
{
if ( stricmp( rule, "dropWeapons" ) == 0 )
return false;
else
return defaultValue;
}
void ModifierInstantKill::playerSpawned( Player *player )
{
multiplayerManager.givePlayerItem( player->entnum, "models/weapons/worldmodel-sniperrifle.tik" );
multiplayerManager.usePlayerItem( player->entnum, "FederationSniperRifle" );
//multiplayerManager.givePlayerItem( player->entnum, "models/weapons/worldmodel-compressionrifle.tik" );
//multiplayerManager.usePlayerItem( player->entnum, "CompressionRifle" );
//multiplayerManager.givePlayerItem( player->entnum, "models/weapons/worldmodel-imod.tik" );
//multiplayerManager.usePlayerItem( player->entnum, "I-Mod" );
player->GiveAmmo( "Fed", 400, false );
}
bool ModifierInstantKill::shouldKeepNormalItem( Item *item )
{
if ( item->isSubclassOf( Weapon ) )
return false;
else if ( item->isSubclassOf( Health ) )
return false;
else if ( item->isSubclassOf( Armor ) )
return false;
else if ( item->isSubclassOf( AmmoEntity ) )
return false;
else
return true;
}
void ModifierInstantKill::update( float frameTime )
{
int i;
Player *player;
if ( _lastRegenTime + _regenTime < multiplayerManager.getTime() )
{
for ( i = 0 ; i < multiplayerManager.getMaxPlayers() ; i++ )
{
player = multiplayerManager.getPlayer( i );
if ( !player )
continue;
player->GiveAmmo( "Fed", _regenAmount, false );
//player->GiveAmmo( "Plasma", _regenAmount, false );
}
_lastRegenTime = multiplayerManager.getTime();
}
}
// Setup constants
const float ModifierDestruction::_defaultObjectHealth = 500.0f;
const int ModifierDestruction::_pointsForDestroyingObject = 100;
const float ModifierDestruction::_objectHealRate = 75.0f;
const float ModifierDestruction::_maxGuardingDist = 1000.0f;
const float ModifierDestruction::_minDamageForPoints = 100.0f;
const float ModifierDestruction::_minHealingForPoints = 100.0f;
const int ModifierDestruction::_pointsForDamage = 5;
const int ModifierDestruction::_pointsForHealing = 5;
const int ModifierDestruction::_pointsForDestroying = 25;
const int ModifierDestruction::_pointsForGuarding = 10;
ModifierDestruction::ModifierDestruction()
{
_redDestructionObject = NULL;
_blueDestructionObject = NULL;
_destructionPlayerData = NULL;
_redLastDamageSoundTime = 0.0f;
_blueLastDamageSoundTime = 0.0f;
_respawnTime = 0.0f;
_blueObjectDestroyed = false;
_redObjectDestroyed = false;
}
ModifierDestruction::~ModifierDestruction()
{
delete [] _destructionPlayerData;
}
void ModifierDestruction::init( int maxPlayers )
{
_maxPlayers = maxPlayers;
_destructionPlayerData = new DestructionPlayerData[ _maxPlayers ];
multiplayerManager.cacheMultiplayerFiles( "mp_destruction" );
}
void ModifierDestruction::addPlayer( Player *player )
{
// Put the destruction ui on the player's screen
gi.SendServerCommand( player->entnum, "stufftext \"ui_addhud mp_destruction\"\n" );
_destructionPlayerData[ player->entnum ].reset();
}
void ModifierDestruction::playerSpawned( Player *player )
{
multiplayerManager.givePlayerItem( player->entnum, "models/weapons/worldmodel-tricorder.tik" );
}
void ModifierDestruction::playerKilled( Player *killedPlayer, Player *attackingPlayer, Entity *inflictor, int meansOfDeath )
{
Team *victimsTeam;
Team *killersTeam;
float distance;
str printString;
bool objectGuarded;
if ( !attackingPlayer || ( killedPlayer == attackingPlayer ) )
return;
victimsTeam = multiplayerManager.getPlayersTeam( killedPlayer );
killersTeam = multiplayerManager.getPlayersTeam( attackingPlayer );
if ( victimsTeam && killersTeam && ( victimsTeam == killersTeam ) )
return;
// See if the player was guarding a object (either he or the killed player was close to his object)
objectGuarded = false;
distance = findDistanceToTeamsObject( killersTeam->getName(), attackingPlayer->origin );
if ( ( distance > 0 ) && ( distance < _maxGuardingDist ) )
{
objectGuarded = true;
}
else
{
distance = findDistanceToTeamsObject( killersTeam->getName(), killedPlayer->origin );
if ( ( distance > 0 ) && ( distance < _maxGuardingDist ) )
{
objectGuarded = true;
}
}
if ( objectGuarded )
{
//multiplayerManager.playerEventNotification( "controlpoint-guarded", "", attackingPlayer );
printString = "$$ObjectGuarded$$ ";
printString += attackingPlayer->client->pers.netname;
multiplayerManager.playerSound( attackingPlayer->entnum, "localization/sound/dialog/dm/comp_objectguarded.mp3", CHAN_AUTO, DEFAULT_VOL, DEFAULT_MIN_DIST, 1.2f );
multiplayerManager.centerPrintTeamClients( attackingPlayer, printString, CENTERPRINT_IMPORTANCE_HIGH );
// Give points to the player for guarding his teams objects
multiplayerManager.addPoints( attackingPlayer->entnum, _pointsForGuarding );
}
}
float ModifierDestruction::findDistanceToTeamsObject( const str &teamName, const Vector &position )
{
Vector diff;
float distance = -1.0f;
MultiplayerItem *destructionObject = NULL;
// Figure out which object to use
if ( teamName == "Red" )
destructionObject = _redDestructionObject;
else if ( teamName == "Blue" )
destructionObject = _blueDestructionObject;
// Get the distance from the object to the specified point
if ( destructionObject )
{
diff = position - destructionObject->origin;
distance = diff.length();
}
// Return the distance
return distance;
}
int ModifierDestruction::getStat( Player *player, int statNum, int value )
{
float floatRealValue;
if ( statNum == STAT_MP_GENERIC1 )
{
// Return the health of the red team's object
if ( _redDestructionObject )
{
floatRealValue = ( _redDestructionObject->health / _redDestructionObject->max_health ) * 100.0f;
if ( ( floatRealValue < 1.0f ) && ( _redDestructionObject->health > 1.0f ) )
{
floatRealValue = 1.0f;
}
return ( (int)floatRealValue );
}
}
else if ( statNum == STAT_MP_GENERIC2 )
{
// Return the health of the blue team's object
if ( _blueDestructionObject )
{
floatRealValue = ( _blueDestructionObject->health / _blueDestructionObject->max_health ) * 100.0f;
if ( ( floatRealValue < 1.0f ) && ( _blueDestructionObject->health > 1.0f ) )
{
floatRealValue = 1.0f;
}
return ( (int)floatRealValue );
}
}
return value;
}
bool ModifierDestruction::shouldKeepItem( MultiplayerItem *item )
{
Event *event;
// See if we care about this item
if ( strnicmp( item->getName().c_str(), "DestructionObject", sizeof( "DestructionObject" ) - 1 ) == 0 )
{
// It's a destruction object
if ( stricmp( item->getName().c_str(), "DestructionObject-red" ) == 0 )
_redDestructionObject = item;
else if ( stricmp( item->getName().c_str(), "DestructionObject-blue" ) == 0 )
_blueDestructionObject = item;
// Change the multiplayer item to suit our needs
item->setSolidType( SOLID_BBOX );
item->setContents( CONTENTS_SOLID );
item->takedamage = DAMAGE_YES;
event = new Event( EV_Trigger_SetDestructible );
event->AddInteger( true );
item->ProcessEvent( event );
if ( item->health == 0 )
{
item->setMaxHealth( _defaultObjectHealth );
item->setHealth( _defaultObjectHealth );
}
if ( stricmp( item->getName().c_str(), "DestructionObject-red" ) == 0 )
_redObjectLasthealth = item->health;
else if ( stricmp( item->getName().c_str(), "DestructionObject-blue" ) == 0 )
_blueObjectLasthealth = item->health;
// Tell the manager to keep the item
return true;
}
return false;
}
float ModifierDestruction::itemDamaged( MultiplayerItem *item, Player *attackingPlayer, float damage, int meansOfDeath )
{
Team *team;
team = multiplayerManager.getPlayersTeam( attackingPlayer );
if ( !team )
return damage;
if ( ( ( item == _redDestructionObject ) && ( team->getName() == "Red" ) ) ||
( ( item == _blueDestructionObject ) && ( team->getName() == "Blue" ) ) )
{
// Can't hurt our own object
return 0.0f;
}
if ( ( _respawnTime > 0.0f ) && ( _respawnTime > multiplayerManager.getTime() ) )
{
return 0.0f;
}
if ( _blueObjectDestroyed || _redObjectDestroyed )
return 0.0f;
_destructionPlayerData[ attackingPlayer->entnum ]._damageDone += damage;
while( _destructionPlayerData[ attackingPlayer->entnum ]._damageDone > _minDamageForPoints )
{
_destructionPlayerData[ attackingPlayer->entnum ]._damageDone -= _minDamageForPoints;
multiplayerManager.addPoints( attackingPlayer->entnum, _pointsForDamage );
}
// Play a sound to tell everyone the object was damaged
if ( ( item == _redDestructionObject ) && ( multiplayerManager.getTime() > _redLastDamageSoundTime + 0.5 ) )
{
item->Sound( "impact_singularity", CHAN_AUTO, 1.0f, 500 );
_redLastDamageSoundTime = multiplayerManager.getTime();
}
else if ( ( item == _blueDestructionObject ) && ( multiplayerManager.getTime() > _blueLastDamageSoundTime + 0.5 ) )
{
item->Sound( "impact_singularity", CHAN_AUTO, 1.0f, 500 );
_blueLastDamageSoundTime = multiplayerManager.getTime();
}
// Scale the damage done to the singularity inversely to the number of players in the game
damage /= (float)multiplayerManager.getTotalPlayers( false ) + 2.0f;
return damage;
}
void ModifierDestruction::itemDestroyed( Player *player, MultiplayerItem *item )
{
Team *team;
if ( strnicmp( item->getName().c_str(), "DestructionObject", sizeof( "DestructionObject" ) - 1 ) == 0 )
{
// Snap health to 0
item->setHealth( 0.0f );
if ( item->animate && item->animate->HasAnim( "idle" ) )
{
item->animate->RandomAnimate( "idle" );
}
if ( stricmp( item->getName().c_str(), "DestructionObject-red" ) == 0 )
_redObjectLasthealth = item->health;
else if ( stricmp( item->getName().c_str(), "DestructionObject-blue" ) == 0 )
_blueObjectLasthealth = item->health;
item->SpawnEffect( "models/fx/fx-explosion-singularity.tik", item->origin, item->angles, 1.0f );
// Give the team points
team = multiplayerManager.getPlayersTeam( player );
// Give the player points
multiplayerManager.addPoints( player->entnum, _pointsForDestroying );
if ( ( ( team->getName() == "Red" ) && ( item == _blueDestructionObject ) ) ||
( ( team->getName() == "Blue" ) && ( item == _redDestructionObject ) ) )
{
team->addPoints( NULL, _pointsForDestroyingObject );
if ( team->getName() == "Red" )
{
multiplayerManager.centerPrintAllClients( "$$BlueObjectDestroyed$$!", CENTERPRINT_IMPORTANCE_NORMAL );
multiplayerManager.broadcastSound( "localization/sound/dialog/dm/comp_btsestroy.mp3", CHAN_AUTO, DEFAULT_VOL, DEFAULT_MIN_DIST, NULL, 1.5f );
_blueObjectDestroyed = true;
}
else
{
multiplayerManager.centerPrintAllClients( "$$RedObjectDestroyed$$!", CENTERPRINT_IMPORTANCE_NORMAL );
multiplayerManager.broadcastSound( "localization/sound/dialog/dm/comp_rtsestroy.mp3", CHAN_AUTO, DEFAULT_VOL, DEFAULT_MIN_DIST, NULL, 1.5f );
_redObjectDestroyed = true;
}
multiplayerManager.playerEventNotification( "destruction", item->getName().c_str(), player );
// Respawn all of the players in a few seconds
_respawnTime = multiplayerManager.getTime() + 3.0f;
}
}
}
void ModifierDestruction::itemUsed( Entity *entity, MultiplayerItem *item )
{
Player *player;
Equipment *equipment;
Team * team;
// Can't heal singularity during respawn time
if ( _blueObjectDestroyed || _redObjectDestroyed )
return;
if ( ( _respawnTime > 0.0f ) && ( _respawnTime >= multiplayerManager.getTime() ) )
{
return;
}
// We only care about equipment using stuff (tricorders to be exact)
if ( entity && entity->isSubclassOf( Player ) )
{
player = (Player *)entity;
if ( !( player->edict->svflags & SVF_BOT ) )
{
player->loadUseItem( "tricorder" );
}
return;
}
if ( !entity || entity->isSubclassOf( Player ) )
return;
if ( !entity->isSubclassOf( Equipment ) )
return;
equipment = (Equipment *)entity;
if ( stricmp( equipment->getTypeName().c_str(), "tricorder" ) != 0 )
{
return;
}
// The tricorder must have a player as the owner
if ( !equipment->GetOwner() || !equipment->GetOwner()->isSubclassOf( Player ) )
return;
player = (Player *)equipment->GetOwner();
team = multiplayerManager.getPlayersTeam( player );
if ( !team )
return;
// Heal the destruction object if everything is ok
if ( ( ( item == _redDestructionObject ) && ( team->getName() == "Red" ) ) ||
( ( item == _blueDestructionObject ) && ( team->getName() == "Blue" ) ) )
{
if ( _destructionPlayerData[ player->entnum ]._lastHealTime != level.time )
{
_destructionPlayerData[ player->entnum ]._lastHealTime = level.time;
// Scale the healed damage done to the singularity inversely to the number of players in the game
item->addHealth( _objectHealRate * level.frametime / ( multiplayerManager.getTotalPlayers( false ) + 2.0f ) );
// Give points to player for healing object
_destructionPlayerData[ player->entnum ]._healthHealed += _objectHealRate * level.frametime;
while( _destructionPlayerData[ player->entnum ]._healthHealed > _minHealingForPoints )
{
_destructionPlayerData[ player->entnum ]._healthHealed -= _minHealingForPoints;
multiplayerManager.addPoints( player->entnum, _pointsForHealing );
}
}
}
}
void ModifierDestruction::update( float frameTime )
{
float redHealth;
float redMaxHealth;
float blueHealth;
float blueMaxHealth;
int currentStage;
int lastStage;
if ( _redDestructionObject )
{
redHealth = _redDestructionObject->health;
redMaxHealth = _redDestructionObject->max_health;
updateObjectAnim( _redDestructionObject, redHealth, _redObjectLasthealth, redMaxHealth );
currentStage = getStage( redHealth, redMaxHealth );
lastStage = getStage( _redObjectLasthealth, redMaxHealth );
if ( currentStage > lastStage )
{
if ( currentStage == 4 )
{
multiplayerManager.centerPrintAllClients( "$$RedObjectCritical$$", CENTERPRINT_IMPORTANCE_NORMAL );
multiplayerManager.broadcastSound( "localization/sound/dialog/dm/comp_rtscl.mp3", CHAN_AUTO, DEFAULT_VOL, DEFAULT_MIN_DIST, NULL, 1.5f );
}
else if ( currentStage == 3 )
{
multiplayerManager.centerPrintAllClients( "$$RedObject25$$", CENTERPRINT_IMPORTANCE_NORMAL );
multiplayerManager.broadcastSound( "localization/sound/dialog/dm/comp_rts25.mp3", CHAN_AUTO, DEFAULT_VOL, DEFAULT_MIN_DIST, NULL, 1.5f );
}
else if ( currentStage == 2 )
{
multiplayerManager.centerPrintAllClients( "$$RedObject50$$", CENTERPRINT_IMPORTANCE_NORMAL );
multiplayerManager.broadcastSound( "localization/sound/dialog/dm/comp_rts50.mp3", CHAN_AUTO, DEFAULT_VOL, DEFAULT_MIN_DIST, NULL, 1.5f );
}
}
_redObjectLasthealth = redHealth;
}
if ( _blueDestructionObject )
{
blueHealth = _blueDestructionObject->health;
blueMaxHealth = _blueDestructionObject->max_health;
updateObjectAnim( _blueDestructionObject, blueHealth, _blueObjectLasthealth, blueMaxHealth );
currentStage = getStage( blueHealth, blueMaxHealth );
lastStage = getStage( _blueObjectLasthealth, blueMaxHealth );
if ( currentStage > lastStage )
{
if ( currentStage == 4 )
{
multiplayerManager.centerPrintAllClients( "$$BlueObjectCritical$$", CENTERPRINT_IMPORTANCE_NORMAL );
multiplayerManager.broadcastSound( "localization/sound/dialog/dm/comp_btscl.mp3", CHAN_AUTO, DEFAULT_VOL, DEFAULT_MIN_DIST, NULL, 1.5f );
}
else if ( currentStage == 3 )
{
multiplayerManager.centerPrintAllClients( "$$BlueObject25$$", CENTERPRINT_IMPORTANCE_NORMAL );
multiplayerManager.broadcastSound( "localization/sound/dialog/dm/comp_bts25.mp3", CHAN_AUTO, DEFAULT_VOL, DEFAULT_MIN_DIST, NULL, 1.5f );
}
else if ( currentStage == 2 )
{
multiplayerManager.centerPrintAllClients( "$$BlueObject50$$", CENTERPRINT_IMPORTANCE_NORMAL );
multiplayerManager.broadcastSound( "localization/sound/dialog/dm/comp_bts50.mp3", CHAN_AUTO, DEFAULT_VOL, DEFAULT_MIN_DIST, NULL, 1.5f );
}
}
_blueObjectLasthealth = blueHealth;
}
// See if we should respawn everyone
if ( ( _respawnTime > 0.0f ) && ( _respawnTime < multiplayerManager.getTime() ) )
{
multiplayerManager.respawnAllPlayers();
_respawnTime = 0.0f;
// Reset health back up to the max for which ever singularity was destroyed
if ( _blueObjectDestroyed )
{
_blueDestructionObject->setHealth( _blueDestructionObject->max_health );
_blueObjectDestroyed = false;
}
if ( _redObjectDestroyed )
{
_redDestructionObject->setHealth( _redDestructionObject->max_health );
_redObjectDestroyed = false;
}
}
// Regenerate some health
/* if ( _redDestructionObject && ( _redDestructionObject->health < _redDestructionObject->max_health ) )
{
_redDestructionObject->addHealth( 1 * frameTime );
}
if ( _blueDestructionObject && ( _blueDestructionObject->health < _blueDestructionObject->max_health ) )
{
_blueDestructionObject->addHealth( 1 * frameTime );
} */
}
void ModifierDestruction::updateObjectAnim( MultiplayerItem *destructionObject, float health, float lastHealth, float maxHealth )
{
int currentStage;
int lastStage;
str animName;
// Make sure everything is ok
if ( !destructionObject )
return;
// Get the current and the last stage
currentStage = getStage( health, maxHealth );
lastStage = getStage( lastHealth, maxHealth );
// See if we have changed stages
if ( currentStage != lastStage )
{
// Figure out the correct animation to play
if ( currentStage == 1 )
animName = "idle";
else if ( currentStage == 2 )
animName = "stage2";
else if ( currentStage == 3 )
animName = "stage3";
else if ( currentStage == 4 )
animName = "stage4";
// Play the new animation if it exists
if ( destructionObject->animate && destructionObject->animate->HasAnim( animName ) )
{
destructionObject->animate->RandomAnimate( animName );
}
}
}
int ModifierDestruction::getStage( float health, float maxHealth )
{
if ( health < maxHealth * 0.1f )
return 4;
else if ( health < maxHealth * 0.25f )
return 3;
else if ( health < maxHealth * 0.5f )
return 2;
else
return 1;
}
bool ModifierDestruction::checkRule( const char *rule, bool defaultValue, Player *player )
{
// We want team spawnpoints
if ( stricmp( rule, "spawnpoints-team" ) == 0 )
return true;
else if ( stricmp( rule, "keepflags" ) == 0 )
return false;
else
return defaultValue;
}
bool ModifierDestruction::checkGameType( const char *gameType )
{
if ( stricmp( gameType, "destruction" ) == 0 )
return true;
else
return false;
}
bool ModifierOneFlag::shouldKeepItem( MultiplayerItem *item )
{
// We need to keep the one flag
if ( ( stricmp( item->getName().c_str(), "ctfflag-one" ) == 0 ) ||
( stricmp( item->getName().c_str(), "ctfflag-baseone" ) == 0 ) )
{
if ( !multiplayerManager.checkRule ( "keepflags", true ) )
return false;
return true;
}
else
{
return false;
}
}
bool ModifierOneFlag::checkRule( const char *rule, bool defaultValue, Player *player )
{
// Check to see if we care about this rule
if ( strnicmp( rule, "flagscore-", sizeof( "flagscore-" ) - 1 ) == 0 )
{
// See if this flag touch should generate a flag score
if ( stricmp( rule, "flagscore-teamflag" ) == 0 )
return false;
else if ( stricmp( rule, "flagscore-enemyflag" ) == 0 )
return true;
}
else if ( strnicmp( rule, "flagpickup-", sizeof( "flagpickup-" ) - 1 ) == 0 )
{
// See if this flag touch should generate a flag pickup
if ( stricmp( rule, "flagpickup-enemyflag" ) == 0 )
return false;
else if ( stricmp( rule, "flagpickup-otherflag-ctfflag-one" ) == 0 )
return true;
}
return defaultValue;
}
bool ModifierOneFlag::checkGameType( const char *gameType )
{
if ( stricmp( gameType, "oneflag" ) == 0 )
return true;
else
return false;
}
void ModifierOneFlag::addPlayer( Player *player )
{
gi.SendServerCommand( player->entnum, "stufftext \"ui_addhud mp_oneflagstatus\"\n" );
}
const int ModifierElimination::_pointsForBeingLastAlive = 5;
ModifierElimination::ModifierElimination()
{
_respawning = false;
_playerEliminated = false;
_playerEliminationData = NULL;
_eliminatedIconIndex = gi.imageindex( "sysimg/icons/mp/elimination_eliminated" );
_needPlayers = true;
_eliminatedTextIndex = G_FindConfigstringIndex( "$$EliminatedWait$$", CS_GENERAL_STRINGS, MAX_GENERAL_STRINGS, true ) + CS_GENERAL_STRINGS;;
_nextRoundTextIndex = G_FindConfigstringIndex( "$$NextRoundWait$$", CS_GENERAL_STRINGS, MAX_GENERAL_STRINGS, true ) + CS_GENERAL_STRINGS;;
}
ModifierElimination::~ModifierElimination()
{
delete [] _playerEliminationData;
}
void ModifierElimination::init( int maxPlayers )
{
_maxPlayers = maxPlayers;
_playerEliminationData = new EliminationPlayerData[ maxPlayers ];
multiplayerManager.cacheMultiplayerFiles( "mp_elimination" );
}
void ModifierElimination::reset( void )
{
int i;
_playerEliminated = false;
_matchOver = false;
for ( i = 0 ; i < _maxPlayers ; i++ )
{
_playerEliminationData[ i ].reset();
}
}
bool ModifierElimination::checkRule( const char *rule, bool defaultValue, Player *player )
{
// Only let players respawn between matches
if ( ( stricmp( rule, "respawnPlayer" ) == 0 ) )
{
if ( !player || _playerEliminationData[ player->entnum ]._eliminated )
return false;
}
else if ( ( stricmp( rule, "spawnPlayer" ) == 0 ) || ( stricmp( rule, "changeTeams" ) == 0 ) )
{
// Don't spawn him if he has been eliminated
if ( player && _playerEliminationData[ player->entnum ]._eliminated )
return false;
// Ok if in first 30 seconds of match
if ( _matchStartTime + 5 > multiplayerManager.getTime() )
return defaultValue;
// See if we still need players
if ( _needPlayers )
{
return defaultValue;
}
else
{
return false;
}
}
return defaultValue;
}
void ModifierElimination::addPlayer( Player *player )
{
_playerEliminationData[ player->entnum ].reset();
if ( multiplayerManager.checkGameType( "dm" ) )
gi.SendServerCommand( player->entnum, "stufftext \"ui_addhud mp_elimination\"\n" );
else
gi.SendServerCommand( player->entnum, "stufftext \"ui_addhud mp_eliminationteam\"\n" );
if ( multiplayerManager.isPlayerSpectator( player ) && !multiplayerManager.isPlayerSpectatorByChoice( player ) )
{
_playerEliminationData[ player->entnum ]._eliminated = true;
}
}
void ModifierElimination::playerKilled( Player *killedPlayer, Player *attackingPlayer, Entity *inflictor, int meansOfDeath )
{
Team *team;
if ( !killedPlayer )
return;
_playerEliminated = true;
_playerEliminationData[ killedPlayer->entnum ]._eliminated = true;
team = multiplayerManager.getPlayersTeam( killedPlayer );
if ( !team || ( numPlayersAliveOnTeam( team->getName() ) > 0 ) )
{
multiplayerManager.HUDPrintAllClients( va( "%s $$Eliminated$$\n", killedPlayer->client->pers.netname ) );
multiplayerManager.broadcastSound( "localization/sound/dialog/dm/comp_pyelim.mp3", CHAN_AUTO, DEFAULT_VOL, DEFAULT_MIN_DIST, NULL, 1.0f );
}
}
int ModifierElimination::getScoreIcon( Player *player, int index, int value )
{
if ( index == SCOREICON3 )
{
if ( _playerEliminationData[ player->entnum ]._eliminated )
return _eliminatedIconIndex;
else
return 0;
}
return value;
}
int ModifierElimination::getStat( Player *player, int statNum, int value )
{
int numAlive = 0;
Team *team;
Player *currentPlayer;
gentity_t *edict;
int i;
if ( statNum == STAT_MP_GENERIC5 )
{
if ( multiplayerManager.checkGameType( "dm" ) )
{
for( i = 0 ; i < game.maxclients ; i++ )
{
edict = &g_entities[ i ];
// Make sure this edict is a valid player
if ( !edict->inuse || !edict->entity || !edict->entity->isSubclassOf( Player ) )
continue;
currentPlayer = ( Player * )edict->entity;
if ( !_playerEliminationData[ currentPlayer->entnum ]._eliminated && !multiplayerManager.isPlayerSpectator( currentPlayer ) )
numAlive++;
}
return numAlive;
}
else
{
for( i = 0 ; i < game.maxclients ; i++ )
{
edict = &g_entities[ i ];
// Make sure this edict is a valid player
if ( !edict->inuse || !edict->entity || !edict->entity->isSubclassOf( Player ) )
continue;
currentPlayer = ( Player * )edict->entity;
// Get the player's team
team = multiplayerManager.getPlayersTeam( currentPlayer );
if ( team && team->getName() == "Red" && !_playerEliminationData[ currentPlayer->entnum ]._eliminated &&
!multiplayerManager.isPlayerSpectator( currentPlayer ) )
{
numAlive++;
}
}
return numAlive;
}
}
else if ( statNum == STAT_MP_GENERIC6 )
{
if ( !multiplayerManager.checkGameType( "dm" ) )
{
for( i = 0 ; i < game.maxclients ; i++ )
{
edict = &g_entities[ i ];
// Make sure this edict is a valid player
if ( !edict->inuse || !edict->entity || !edict->entity->isSubclassOf( Player ) )
continue;
currentPlayer = ( Player * )edict->entity;
// Get the player's team
team = multiplayerManager.getPlayersTeam( currentPlayer );
if ( team && team->getName() == "Blue" && !_playerEliminationData[ currentPlayer->entnum ]._eliminated &&
!multiplayerManager.isPlayerSpectator( currentPlayer ) )
{
numAlive++;
}
}
return numAlive;
}
}
else if ( statNum == STAT_MP_STATE )
{
if ( _playerEliminationData[ player->entnum ]._eliminated )
return _eliminatedTextIndex;
if ( multiplayerManager.isPlayerSpectator( player ) && multiplayerManager.isFightingAllowed() )
return _nextRoundTextIndex;
}
return value;
}
void ModifierElimination::matchStarting( void )
{
reset();
_matchStartTime = multiplayerManager.getTime();
_needPlayers = true;
}
int ModifierElimination::numPlayersAliveOnTeam( const str &teamName )
{
int i;
Player *player;
gentity_t *edict;
int numPlayers;
Team *team;
numPlayers = 0;
for( i = 0 ; i < game.maxclients ; i++ )
{
edict = &g_entities[ i ];
// Make sure this edict is a valid player
if ( !edict->inuse || !edict->entity || edict->entity->isSubclassOf( Player ) )
continue;
player = ( Player * )edict->entity;
// Get the player's team
team = multiplayerManager.getPlayersTeam( player );
if ( team && ( team->getName() == teamName ) && !_playerEliminationData[ player->entnum ]._eliminated )
{
numPlayers++;
}
}
return numPlayers;
}
void ModifierElimination::update( float frameTime )
{
int numAlive = 0;
int numRedTeamAlive = 0;
int numBlueTeamAlive = 0;
Team *team;
bool redTeam = false;
bool blueTeam = false;
bool usingTeams = false;
bool respawnEveryone;
Player *playerAlive = NULL;
Player *player;
Entity *entity;
gentity_t *edict;
int i;
if ( _matchOver )
return;
// Gather number of people alive and dead
for( i = 0 ; i < game.maxclients ; i++ )
{
edict = &g_entities[ i ];
// Make sure this edict is a valid player
if ( !edict->inuse || !edict->entity )
continue;
entity = edict->entity;
if ( !entity->isSubclassOf( Player ) )
continue;
player = ( Player * )entity;
// Get the player's team
team = multiplayerManager.getPlayersTeam( player );
redTeam = false;
blueTeam = false;
if ( team )
{
if ( stricmp( team->getName().c_str(), "red" ) == 0 )
{
redTeam = true;
usingTeams = true;
}
else if ( stricmp( team->getName().c_str(), "blue" ) == 0 )
{
blueTeam = true;
usingTeams = true;
}
}
// Calculate number of people alive on each team
if ( !_playerEliminationData[ player->entnum ]._eliminated && !multiplayerManager.isPlayerSpectator( player ) )
{
numAlive++;
playerAlive = player;
if ( redTeam )
numRedTeamAlive++;
else if ( blueTeam )
numBlueTeamAlive++;
}
}
// See if we need players
if ( usingTeams )
{
if ( numRedTeamAlive == 0 || numBlueTeamAlive == 0 )
_needPlayers = true;
else
_needPlayers = false;
}
else
{
if ( numAlive < 2 )
_needPlayers = true;
else
_needPlayers = false;
}
if ( !_playerEliminated )
return;
// See if the round is over
respawnEveryone = false;
if ( usingTeams )
{
// Determine if only one team is alive
if ( ( numRedTeamAlive > 0 ) && ( numBlueTeamAlive == 0 ) )
{
multiplayerManager.centerPrintAllClients( "$$BlueTeamEliminated$$", CENTERPRINT_IMPORTANCE_NORMAL );
multiplayerManager.broadcastSound( "localization/sound/dialog/dm/comp_btelim.mp3", CHAN_AUTO, DEFAULT_VOL, DEFAULT_MIN_DIST, NULL, 1.2f );
if ( multiplayerManager.checkRule ( "endmatch-elimination-blue", true, NULL ) )
{
respawnEveryone = true;
multiplayerManager.addTeamPoints( "Red", 1 );
}
else
{
_matchOver = true;
}
}
else if ( ( numBlueTeamAlive > 0 ) && ( numRedTeamAlive == 0 ) )
{
multiplayerManager.centerPrintAllClients( "$$RedTeamEliminated$$", CENTERPRINT_IMPORTANCE_NORMAL );
multiplayerManager.broadcastSound( "localization/sound/dialog/dm/comp_rtelim.mp3", CHAN_AUTO, DEFAULT_VOL, DEFAULT_MIN_DIST, NULL, 1.2f );
if ( multiplayerManager.checkRule ( "endmatch-elimination-red", true, NULL ) )
{
respawnEveryone = true;
multiplayerManager.addTeamPoints( "Blue", 1 );
}
else
{
_matchOver = true;
}
}
else if ( ( numBlueTeamAlive == 0 ) && ( numRedTeamAlive == 0 ) )
{
multiplayerManager.centerPrintAllClients( "$$NoOneWinsRound$$!", CENTERPRINT_IMPORTANCE_NORMAL );
if ( multiplayerManager.checkRule ( "endmatch-elimination-both", true, NULL ) )
{
respawnEveryone = true;
}
else
{
_matchOver = true;
}
}
}
else
{
// Determine if one person won the match
if ( numAlive == 1 )
{
str stringToPrint;
stringToPrint = playerAlive->client->pers.netname;
stringToPrint += " $$WinsRound$$!";
multiplayerManager.centerPrintAllClients( stringToPrint.c_str(), CENTERPRINT_IMPORTANCE_NORMAL );
respawnEveryone = true;
multiplayerManager.addPoints( playerAlive->entnum, _pointsForBeingLastAlive );
}
else if ( numAlive == 0 )
{
multiplayerManager.centerPrintAllClients( "$$NoOneWinsRound$$!", CENTERPRINT_IMPORTANCE_NORMAL );
respawnEveryone = true;
}
}
if ( respawnEveryone )
{
// The match has been won, restart the match
multiplayerManager.endMatch();
//multiplayerManager.restartMatch();
_matchOver = true;
}
}
// Setup constants
const float ModifierDiffusion::_timeNeededToArmBomb = 5.0f;
const float ModifierDiffusion::_timeNeededToDisarmBomb = 5.0f;
const float ModifierDiffusion::_maxGuardingDist = 750.0f;
const float ModifierDiffusion::_maxArmingPause = 1.0f;
const float ModifierDiffusion::_maxDisarmingPause = 1.0f;
const float ModifierDiffusion::_maxBombOnGroundTime = 30.0f;
const int ModifierDiffusion::_pointsForArmingBomb = 25;
const int ModifierDiffusion::_pointsForExplodingBomb = 50;
const int ModifierDiffusion::_pointsForDisarmingBomb = 50;
const int ModifierDiffusion::_pointsForGuardingBase = 5;
const int ModifierDiffusion::_pointsForGuardingTheBomber = 5;
const int ModifierDiffusion::_pointsForGuardingBomb = 5;
const int ModifierDiffusion::_pointsForKillingTheBomber = 10;
const int ModifierDiffusion::_teamPointsForBombing = 250;
DiffusionBombPlace::DiffusionBombPlace()
{
_item = NULL;
reset();
}
void DiffusionBombPlace::reset()
{
_armed = false;
_totalArmingTime = 0.0f;
_totalDisarmingTime = 0.0f;
_lastArmingTime = 0.0f;
_lastDisarmingTime = 0.0f;
_totalArmedTime = 0.0f;
};
ModifierDiffusion::ModifierDiffusion()
{
_bomber = -1;
_bombArmedByPlayer = -1;
_lastBomber = -1;
_bombDroppedTime = 0.0f;
_bomb = NULL;
_tempBombItem = NULL;
_bomberIconIndex = gi.imageindex( "sysimg/icons/mp/diffusion_bomber" );
_redBombPlaceArmedIconIndex = gi.imageindex( "sysimg/icons/mp/diffusion_bombArmed-red" );
_blueBombPlaceArmedIconIndex = gi.imageindex( "sysimg/icons/mp/diffusion_bombArmed-blue" );
_bombCarriedByRedTeamIconIndex = gi.imageindex( "sysimg/icons/mp/diffusion_bombTaken-red" );
_bombCarriedByBlueTeamIconIndex = gi.imageindex( "sysimg/icons/mp/diffusion_bombTaken-blue" );
_bombInBaseIconIndex = gi.imageindex( "sysimg/icons/mp/diffusion_bombNormal" );
_bombOnGroundIconIndex = gi.imageindex( "sysimg/icons/mp/diffusion_bombOnground" );
_respawnTime = 0.0f;
}
ModifierDiffusion::~ModifierDiffusion()
{
multiplayerManager.resetRespawnTime();
}
void ModifierDiffusion::init( int maxPlayers )
{
_maxPlayers = maxPlayers;
_timeNeededForBombToExplode = mp_bombTime->value;
if ( multiplayerManager.getRespawnTime() < 0.0f )
{
multiplayerManager.setRespawnTime( 5.0f );
}
multiplayerManager.cacheMultiplayerFiles( "mp_diffusion" );
}
void ModifierDiffusion::playerSpawned( Player *player )
{
multiplayerManager.givePlayerItem( player->entnum, "models/weapons/worldmodel-tricorder.tik" );
multiplayerManager.givePlayerItem( player->entnum, "models/weapons/worldmodel-compressionrifle.tik" );
multiplayerManager.usePlayerItem( player->entnum, "CompressionRifle" );
}
void ModifierDiffusion::playerEventNotification( const char *eventName, const char *eventItemName, Player *eventPlayer )
{
if ( stricmp( eventName, "use-HoldableItem" ) == 0 )
{
if ( stricmp( eventItemName, "Transporter" ) == 0 )
{
dropBomb( eventPlayer );
}
}
}
bool ModifierDiffusion::checkRule( const char *rule, bool defaultValue, Player *player )
{
// We want team spawnpoints
if ( stricmp( rule, "spawnpoints-team" ) == 0 )
{
return true;
}
return defaultValue;
}
bool ModifierDiffusion::shouldKeepItem( MultiplayerItem *item )
{
if ( strnicmp( item->getName().c_str(), "Diffusion-", strlen( "Diffusion-" ) ) == 0 )
{
// This is a diffusion item so keep track of it
if ( stricmp( item->getName().c_str(), "Diffusion-bombplace-red" ) == 0 )
_redBombPlace._item = item;
else if ( stricmp( item->getName().c_str(), "Diffusion-bombplace-blue" ) == 0 )
_blueBombPlace._item = item;
else if ( stricmp( item->getName().c_str(), "Diffusion-bomb" ) == 0 )
_bomb = item;
else
return false;
return true;
}
return false;
}
void ModifierDiffusion::itemTouched( Player *player, MultiplayerItem *item )
{
str printString;
// Can't pickup bomb during respawn period
if ( _respawnTime > 0.0f )
return;
// Make sure this is a bomb
if ( ( item != _bomb ) && ( item != _tempBombItem ) )
return;
// Make sure this isn't a bot
if ( player->edict->svflags & SVF_BOT )
return;
// Make sure we can't pickup the bomb right after we dropped it
if ( ( player->entnum == _lastBomber ) && ( _bombDroppedTime + 0.5 > multiplayerManager.getTime() ) )
return;
// Give the bomb to the player
makeBomber( player );
// Tell everyone that the bomb has been picked up
printString = "$$BombTaken$$ ";
printString += player->client->pers.netname;
printString += " ($$";
printString += multiplayerManager.getPlayersTeam( player )->getName();
printString += "$$ $$Team$$)!";
multiplayerManager.centerPrintAllClients( printString, CENTERPRINT_IMPORTANCE_HIGH );
if ( multiplayerManager.getPlayersTeam( player )->getName() == "Red" )
{
multiplayerManager.broadcastSound( "localization/sound/dialog/dm/comp_bombtakenred.mp3", CHAN_AUTO, DEFAULT_VOL,
DEFAULT_MIN_DIST, player, 1.5f );
}
else
{
multiplayerManager.broadcastSound( "localization/sound/dialog/dm/comp_bombtakenblue.mp3", CHAN_AUTO, DEFAULT_VOL,
DEFAULT_MIN_DIST, player, 1.5f );
}
if ( item == _tempBombItem )
{
// Get rid of the temporary bomb
_tempBombItem->PostEvent( EV_Remove, 0.0f );
_tempBombItem = NULL;
}
else
{
// Hide the item picked up
_bomb->setSolidType( SOLID_NOT );
_bomb->hideModel();
}
}
void ModifierDiffusion::dropBomb( Player *player )
{
MultiplayerItem *newBomb;
str printString;
// Make sure everything is ok
if ( player != getBomber() )
return;
// Create a new bomb to put on the ground
newBomb = new MultiplayerItem;
newBomb->setModel( _bomb->model );
newBomb->angles = player->angles;
newBomb->setAngles();
newBomb->setOrigin( player->origin );
newBomb->CancelEventsOfType( EV_ProcessInitCommands );
newBomb->ProcessInitCommands( newBomb->edict->s.modelindex );
newBomb->setName( "Diffusion-bomb-temp" );
// Setup the _tempBombItem stuff
_tempBombItem = newBomb;
_tempBombItemTime = multiplayerManager.getTime();
// Change the player back to not being a bomber
clearBomber();
_bombDroppedTime = multiplayerManager.getTime();
// Tell the team that the bomb was dropped
printString = "$$BombDropped$$";
multiplayerManager.centerPrintAllClients( printString, CENTERPRINT_IMPORTANCE_HIGH );
}
void ModifierDiffusion::respawnBomb( bool quiet )
{
str printString;
if ( _tempBombItem )
{
_tempBombItem->PostEvent( EV_Remove, 0.0f );
_tempBombItem = NULL;
}
if ( _bomb )
{
_bomb->showModel();
_bomb->setSolidType( SOLID_TRIGGER );
}
if ( !quiet )
{
printString = "$$BombReturnedToBase$$";
multiplayerManager.centerPrintAllClients( printString, CENTERPRINT_IMPORTANCE_HIGH );
multiplayerManager.broadcastSound( "localization/sound/dialog/dm/comp_bombbase.mp3", CHAN_AUTO, DEFAULT_VOL, DEFAULT_MIN_DIST, NULL, 1.5f );
}
}
void ModifierDiffusion::itemUsed( Entity *entity, MultiplayerItem *item )
{
Equipment *equipment;
Sentient *owner;
Player *player;
bool offense;
bool defense;
Team *team;
DiffusionBombPlace *enemyBombPlace;
DiffusionBombPlace *teamBombPlace;
str printString;
if ( entity && entity->isSubclassOf( Player ) )
{
player = (Player *)entity;
if ( !( player->edict->svflags & SVF_BOT ) )
{
player->loadUseItem( "tricorder" );
}
return;
}
if ( !entity || !entity->isSubclassOf( Equipment ) )
return;
// Get the use info
equipment = (Equipment *)entity;
owner = equipment->GetOwner();
if ( !owner || !owner->isSubclassOf( Player ) )
return;
player = (Player *)owner;
if ( stricmp( equipment->getTypeName().c_str(), "tricorder" ) != 0 )
{
return;
}
// Figure out if the player is on offense or defense
team = multiplayerManager.getPlayersTeam( player );
if ( !team )
return;
offense = false;
defense = false;
enemyBombPlace = NULL;
teamBombPlace = NULL;
if ( team->getName() == "Red" )
{
if ( item == _redBombPlace._item )
defense = true;
else if ( item == _blueBombPlace._item )
offense = true;
enemyBombPlace = &_blueBombPlace;
teamBombPlace = &_redBombPlace;
}
else if ( team->getName() == "Blue" )
{
if ( item == _blueBombPlace._item )
defense = true;
else if ( item == _redBombPlace._item )
offense = true;
enemyBombPlace = &_redBombPlace;
teamBombPlace = &_blueBombPlace;
}
if ( offense )
{
// Must be the bomber
if ( player->entnum != _bomber )
return;
if ( !enemyBombPlace->_armed && ( enemyBombPlace->_lastArmingTime != level.time ) )
{
enemyBombPlace->_lastArmingTime = level.time;
enemyBombPlace->_totalArmingTime += level.frametime;
if ( enemyBombPlace->_totalArmingTime > _timeNeededToArmBomb )
{
SpawnArgs args;
int tagNum;
_bombArmedByPlayer = player->entnum;
enemyBombPlace->_armed = true;
enemyBombPlace->_lastDisarmingTime = 0.0f;
enemyBombPlace->_totalDisarmingTime = 0.0f;
enemyBombPlace->_totalArmedTime = 0.0f;
clearBomber();
// Tell everyone the bomb has been armed
printString = "$$BombArmed$$ ";
printString += player->client->pers.netname;
printString += " ($$";
printString += multiplayerManager.getPlayersTeam( player )->getName();
printString += "$$ $$Team$$)!";
multiplayerManager.centerPrintAllClients( printString, CENTERPRINT_IMPORTANCE_NORMAL );
multiplayerManager.broadcastSound( "localization/sound/dialog/dm/comp_bomba.mp3", CHAN_AUTO, DEFAULT_VOL, DEFAULT_MIN_DIST, NULL, 1.0f );
// Spawn a bomb in the bomb place
args.setArg( "model", "models/item/mp_diffusion_bomb.tik" );
_attachedBomb = args.Spawn();
if ( !_attachedBomb )
return;
tagNum = gi.Tag_NumForName( enemyBombPlace->_item->edict->s.modelindex, "tag_bomb" );
if ( tagNum >= 0 )
{
_attachedBomb->attach( enemyBombPlace->_item->entnum, tagNum );
}
else
{
_attachedBomb->setOrigin( enemyBombPlace->_item->origin );
}
_attachedBomb->ProcessPendingEvents();
_attachedBomb->setSolidType( SOLID_NOT );
_attachedBomb->SetTargetName( "attachedDiffusionBomb" );
if ( !_attachedBomb->animate )
_attachedBomb->animate = new Animate( _attachedBomb );
_attachedBomb->animate->RandomAnimate( "idle" );
}
}
}
else if ( defense )
{
// Make sure the player's team's bomb place has been armed
if ( !teamBombPlace->_armed )
return;
if ( teamBombPlace->_lastDisarmingTime != level.time )
{
teamBombPlace->_lastDisarmingTime = level.time;
teamBombPlace->_totalDisarmingTime += level.frametime;
if ( teamBombPlace->_totalDisarmingTime > _timeNeededToDisarmBomb )
{
// Disarmed the bomb
teamBombPlace->_armed = false;
teamBombPlace->_item->removeAttachedModelByTargetname( "attachedDiffusionBomb" );
makeBomber( player );
// Tell everyone the bomb has been armed
printString = "$$BombDisarmed$$ ";
printString += player->client->pers.netname;
printString += " ($$";
printString += multiplayerManager.getPlayersTeam( player )->getName();
printString += "$$ $$Team$$)!";
multiplayerManager.centerPrintAllClients( printString, CENTERPRINT_IMPORTANCE_NORMAL );
multiplayerManager.broadcastSound( "localization/sound/dialog/dm/comp_bombdisarmed.mp3", CHAN_AUTO, DEFAULT_VOL, DEFAULT_MIN_DIST, player, 1.0f );
}
}
}
}
void ModifierDiffusion::playerChangedModel( Player *player )
{
if ( player->entnum == _bomber )
{
attachBomb( player );
}
}
void ModifierDiffusion::attachBomb( Player *player )
{
Event *attachEvent;
str tagName;
player->removeAttachedModelByTargetname( "attachedDiffusionBomb" );
if ( gi.Tag_NumForName( player->edict->s.modelindex, "Bip01 spine2" ) >= 0 )
tagName = "Bip01 spine2";
else if ( gi.Tag_NumForName( player->edict->s.modelindex, "Bip01 spine1" ) >= 0 )
tagName = "Bip01 spine1";
else if ( gi.Tag_NumForName( player->edict->s.modelindex, "Bip01 Head" ) >= 0 )
tagName = "Bip01 Head";
attachEvent = new Event( EV_AttachModel );
attachEvent->AddString( "models/item/mp_diffusion_bomb.tik" );
attachEvent->AddString( tagName );
attachEvent->AddFloat( 1.0f );
attachEvent->AddString( "attachedDiffusionBomb" );
attachEvent->AddInteger( 0 );
attachEvent->AddFloat( -1.0f );
attachEvent->AddFloat( 0.0f );
attachEvent->AddFloat( -1.0f );
attachEvent->AddFloat( -1.0f );
attachEvent->AddVector( player->getBackpackAttachOffset() );
attachEvent->AddVector( player->getBackpackAttachAngles() );
player->ProcessEvent( attachEvent );
}
int ModifierDiffusion::getStat( Player *player, int statNum, int value )
{
if ( statNum == STAT_MP_GENERIC1 )
{
if ( _redBombPlace._armed )
{
return (int)( 100.0f - ( _redBombPlace._totalDisarmingTime / _timeNeededToDisarmBomb ) * 100.0f );
}
else
{
return (int)( ( _redBombPlace._totalArmingTime / _timeNeededToArmBomb ) * 100.0f );
}
}
else if ( statNum == STAT_MP_GENERIC3 )
{
if ( _blueBombPlace._armed )
{
return (int)( 100.0f - ( _blueBombPlace._totalDisarmingTime / _timeNeededToDisarmBomb ) * 100.0f );
}
else
{
return (int)( ( _blueBombPlace._totalArmingTime / _timeNeededToArmBomb ) * 100.0f );
}
}
else if ( statNum == STAT_MP_GENERIC2 )
{
if ( _redBombPlace._armed )
{
return (int)ceil( _timeNeededForBombToExplode - _redBombPlace._totalArmedTime );
}
else if ( _blueBombPlace._armed )
{
return (int)ceil( _timeNeededForBombToExplode - _blueBombPlace._totalArmedTime );
}
else
{
return 999;
}
}
else if ( statNum == STAT_MP_GENERIC7 )
{
Player *bomber = getBomber();
str bomberTeamName;
if ( bomber )
{
bomberTeamName = multiplayerManager.getPlayersTeam( bomber )->getName();
}
if ( _redBombPlace._armed )
return _redBombPlaceArmedIconIndex;
else if ( _blueBombPlace._armed )
return _blueBombPlaceArmedIconIndex;
else if ( bomber && ( bomberTeamName == "Red" ) )
return _bombCarriedByRedTeamIconIndex;
else if ( bomber && ( bomberTeamName == "Blue" ) )
return _bombCarriedByBlueTeamIconIndex;
else if ( _bomb->getSolidType() != SOLID_NOT )
return _bombInBaseIconIndex;
else
return _bombOnGroundIconIndex;
}
return value;
}
void ModifierDiffusion::addPlayer( Player *player )
{
gi.SendServerCommand( player->entnum, "stufftext \"ui_addhud mp_diffusion\"\n" );
}
void ModifierDiffusion::removePlayer( Player *player )
{
// Put any items back that are necessary
if ( player->entnum == _bomber )
{
dropBomb( player );
}
if ( _bombArmedByPlayer == player->entnum )
{
_bombArmedByPlayer = -1;
}
}
void ModifierDiffusion::playerKilled( Player *killedPlayer, Player *attackingPlayer, Entity *inflictor, int meansOfDeath )
{
bool victimWasBomber;
if ( killedPlayer->entnum == _bomber )
{
dropBomb( killedPlayer );
victimWasBomber = true;
}
else
{
victimWasBomber = false;
}
// Make sure this was a good kill
if ( !attackingPlayer || ( attackingPlayer == killedPlayer ) )
return;
if ( multiplayerManager.getPlayersTeam( killedPlayer ) && multiplayerManager.getPlayersTeam( attackingPlayer ) &&
( multiplayerManager.getPlayersTeam( killedPlayer ) == multiplayerManager.getPlayersTeam( attackingPlayer ) ) )
return;
// Award extra points (if any)
if ( victimWasBomber )
{
// Give points to the player that killed the bomber
multiplayerManager.addPoints( attackingPlayer->entnum, _pointsForKillingTheBomber );
multiplayerManager.broadcastSound( "localization/sound/dialog/dm/comp_bomberKilled.mp3", CHAN_AUTO, DEFAULT_VOL, DEFAULT_MIN_DIST, NULL, 1.0f );
}
// Give more points possibly
if ( playerGuardedBomber( attackingPlayer, killedPlayer ) )
{
// Give points to the player that guarded the bomber
multiplayerManager.addPoints( attackingPlayer->entnum, _pointsForGuardingTheBomber );
multiplayerManager.playerSound( attackingPlayer->entnum, "localization/sound/dialog/dm/comp_bomberguarded.mp3", CHAN_AUTO, DEFAULT_VOL, DEFAULT_MIN_DIST, 1.2f );
}
else if ( playerGuardedBase( attackingPlayer, killedPlayer ) )
{
// Give points to the player that guarded the armed bomb
multiplayerManager.addPoints( attackingPlayer->entnum, _pointsForGuardingBase );
multiplayerManager.playerSound( attackingPlayer->entnum, "localization/sound/dialog/dm/comp_baseguarded.mp3", CHAN_AUTO, DEFAULT_VOL, DEFAULT_MIN_DIST, 1.2f );
}
else if ( playerGuardedBomb( attackingPlayer, killedPlayer ) )
{
// Give points to the player that guarded the armed bomb
multiplayerManager.addPoints( attackingPlayer->entnum, _pointsForGuardingBomb );
multiplayerManager.playerSound( attackingPlayer->entnum, "localization/sound/dialog/dm/comp_bombguarded.mp3", CHAN_AUTO, DEFAULT_VOL, DEFAULT_MIN_DIST, 1.2f );
}
}
Player *ModifierDiffusion::getBomber( void )
{
if ( _bomber >= 0 )
return multiplayerManager.getPlayer( _bomber );
else
return NULL;
}
bool ModifierDiffusion::playerGuardedBomber( Player *attackingPlayer, Player *killedPlayer )
{
Player *bomber;
// Get the bomber
bomber = getBomber();
if ( !bomber )
return false;
// Make sure bomber is on the same team as the attacker
if ( multiplayerManager.getPlayersTeam( attackingPlayer ) != multiplayerManager.getPlayersTeam( bomber ) )
return false;
// See if the attacking or killed player is within the guarding distance of the bomber
if ( withinGuardDistance( bomber->origin, attackingPlayer->origin ) ||
withinGuardDistance( bomber->origin, killedPlayer->origin ) )
return true;
else
return false;
}
bool ModifierDiffusion::playerGuardedBase( Player *attackingPlayer, Player *killedPlayer )
{
MultiplayerItem *bombPlace;
Team *team;
team = multiplayerManager.getPlayersTeam( attackingPlayer );
if ( !team )
return false;
// Get the player's bomb place
if ( team->getName() == "Red" )
bombPlace = _redBombPlace._item;
else
bombPlace = _blueBombPlace._item;
if ( !bombPlace )
return false;
// See if the attacking or killed player is within the guarding distance of the bomb place
if ( withinGuardDistance( bombPlace->origin, attackingPlayer->origin ) ||
withinGuardDistance( bombPlace->origin, killedPlayer->origin ) )
return true;
else
return false;
}
bool ModifierDiffusion::playerGuardedBomb( Player *attackingPlayer, Player *killedPlayer )
{
DiffusionBombPlace *bombPlace;
Team *team;
team = multiplayerManager.getPlayersTeam( attackingPlayer );
if ( !team )
return false;
// Get the player's bomb place
if ( team->getName() == "Red" )
bombPlace = &_blueBombPlace;
else
bombPlace = &_redBombPlace;
if ( !bombPlace )
return false;
if ( !bombPlace->_armed )
return false;
// See if the attacking or killed player is within the guarding distance of the bomb
if ( withinGuardDistance( bombPlace->_item->origin, attackingPlayer->origin ) ||
withinGuardDistance( bombPlace->_item->origin, killedPlayer->origin ) )
return true;
else
return false;
}
bool ModifierDiffusion::withinGuardDistance( const Vector &origin1, const Vector &origin2 )
{
Vector diff;
float distance;
diff = origin1 - origin2;
distance = diff.length();
if ( distance < _maxGuardingDist )
return true;
else
return false;
}
void ModifierDiffusion::playerCommand( Player *player, const char *command, const char *parm )
{
if ( stricmp( command, "dropItem" ) == 0 )
{
if ( player == getBomber() )
{
dropBomb( player );
}
}
}
void ModifierDiffusion::makeBomber( Player *player )
{
_bomber = player->entnum;
_lastBomber = player->entnum;
multiplayerManager.playerSound( player->entnum, "localization/sound/dialog/dm/comp_bomber.mp3", CHAN_AUTO, DEFAULT_VOL, DEFAULT_MIN_DIST, 1.5f );
// Attach the bomb to the player
attachBomb( player );
}
void ModifierDiffusion::clearBomber( void )
{
if ( _bomber >= 0 )
{
Player *player;
player = multiplayerManager.getPlayer( _bomber );
if ( player )
{
player->removeAttachedModelByTargetname( "attachedDiffusionBomb" );
}
}
_bomber = -1;
}
void ModifierDiffusion::update( float frameTime )
{
float currentTime;
currentTime = multiplayerManager.getTime();
// Make sure the red bomb place has been armed recently enough
if ( _redBombPlace._lastArmingTime + _maxArmingPause < currentTime )
{
_redBombPlace._lastArmingTime = 0.0f;
_redBombPlace._totalArmingTime = 0.0f;
}
// Make sure the red bomb place has been diffused recently enough
if ( _redBombPlace._lastDisarmingTime + _maxDisarmingPause < currentTime )
{
_redBombPlace._lastDisarmingTime = 0.0f;
_redBombPlace._totalDisarmingTime = 0.0f;
}
// Make sure the blue bomb place has been armed recently enough
if ( _blueBombPlace._lastArmingTime + _maxArmingPause < currentTime )
{
_blueBombPlace._lastArmingTime = 0.0f;
_blueBombPlace._totalArmingTime = 0.0f;
}
// Make sure the blue bomb place has been diffused recently enough
if ( _blueBombPlace._lastDisarmingTime + _maxDisarmingPause < currentTime )
{
_blueBombPlace._lastDisarmingTime = 0.0f;
_blueBombPlace._totalDisarmingTime = 0.0f;
}
// Return the bomb back to the base if it has been sitting on the ground too long
if ( _tempBombItem && ( _tempBombItemTime + _maxBombOnGroundTime < multiplayerManager.getTime() ) )
{
respawnBomb();
}
// See if the bomb has exploded
if ( _redBombPlace._armed || _blueBombPlace._armed )
{
int lastTimeLeft;
int timeLeft;
DiffusionBombPlace *armedBombPlace;
if ( _redBombPlace._armed )
armedBombPlace = &_redBombPlace;
else
armedBombPlace = &_blueBombPlace;
lastTimeLeft = (int )( _timeNeededForBombToExplode - armedBombPlace->_totalArmedTime + 1 );
armedBombPlace->_totalArmedTime += frameTime;
timeLeft = (int)( _timeNeededForBombToExplode - armedBombPlace->_totalArmedTime + 1 );
// Play computer dialog for time left (if any)
if ( ( timeLeft <= 1 ) && ( lastTimeLeft > 1 ) && ( _timeNeededForBombToExplode > 1 ) )
multiplayerManager.broadcastSound( "localization/sound/dialog/dm/comp_1.mp3", CHAN_AUTO, DEFAULT_VOL,
DEFAULT_MIN_DIST, NULL, 0.5f );
else if ( ( timeLeft <= 2 ) && ( lastTimeLeft > 2 ) && ( _timeNeededForBombToExplode > 2 ) )
multiplayerManager.broadcastSound( "localization/sound/dialog/dm/comp_2.mp3", CHAN_AUTO, DEFAULT_VOL,
DEFAULT_MIN_DIST, NULL, 0.5f );
else if ( ( timeLeft <= 3 ) && ( lastTimeLeft > 3 ) && ( _timeNeededForBombToExplode > 3 ) )
multiplayerManager.broadcastSound( "localization/sound/dialog/dm/comp_3.mp3", CHAN_AUTO, DEFAULT_VOL,
DEFAULT_MIN_DIST, NULL, 0.5f );
else if ( ( timeLeft <= 4 ) && ( lastTimeLeft > 4 ) && ( _timeNeededForBombToExplode > 4 ) )
multiplayerManager.broadcastSound( "localization/sound/dialog/dm/comp_4.mp3", CHAN_AUTO, DEFAULT_VOL,
DEFAULT_MIN_DIST, NULL, 0.5f );
else if ( ( timeLeft <= 5 ) && ( lastTimeLeft > 5 ) && ( _timeNeededForBombToExplode > 5 ) )
multiplayerManager.broadcastSound( "localization/sound/dialog/dm/comp_5.mp3", CHAN_AUTO, DEFAULT_VOL,
DEFAULT_MIN_DIST, NULL, 0.5f );
else if ( ( timeLeft <= 7 ) && ( lastTimeLeft > 7 ) && ( _timeNeededForBombToExplode > 7 ) )
multiplayerManager.broadcastSound( "localization/sound/dialog/dm/comp_bombtime.mp3", CHAN_AUTO, DEFAULT_VOL,
DEFAULT_MIN_DIST, NULL, 0.5f );
else if ( ( timeLeft <= 15 ) && ( lastTimeLeft > 15 ) && ( _timeNeededForBombToExplode > 15 ) )
multiplayerManager.broadcastSound( "localization/sound/dialog/dm/comp_bombtime15.mp3" );
else if ( ( timeLeft <= 30 ) && ( lastTimeLeft > 30 ) && ( _timeNeededForBombToExplode > 30 ) )
multiplayerManager.broadcastSound( "localization/sound/dialog/dm/comp_bombtime30.mp3" );
if ( armedBombPlace->_totalArmedTime > _timeNeededForBombToExplode )
{
str printString;
// The bomb has exploded
armedBombPlace->_item->SpawnEffect( "models/fx/fx-explosion-bomb.tik", armedBombPlace->_item->origin, armedBombPlace->_item->angles, 1.0f );
if ( _bombArmedByPlayer >= 0 )
{
// Give points to the player that armed the bomb
multiplayerManager.addPoints( _bombArmedByPlayer, _pointsForExplodingBomb );
}
// Give the bombing team a lot of points and tell everyone what happened
if ( armedBombPlace == &_redBombPlace )
{
multiplayerManager.addTeamPoints( "Blue", _teamPointsForBombing );
multiplayerManager.centerPrintAllClients( "$$RedBaseDestroyed$$", CENTERPRINT_IMPORTANCE_NORMAL );
multiplayerManager.broadcastSound( "localization/sound/dialog/dm/comp_bombexplodered.mp3", CHAN_AUTO, DEFAULT_VOL, DEFAULT_MIN_DIST, NULL, 2.0f );
}
else
{
multiplayerManager.addTeamPoints( "Red", _teamPointsForBombing );
multiplayerManager.centerPrintAllClients( "$$BlueBaseDestroyed$$", CENTERPRINT_IMPORTANCE_NORMAL );
multiplayerManager.broadcastSound( "localization/sound/dialog/dm/comp_bombexplodeblue.mp3", CHAN_AUTO, DEFAULT_VOL, DEFAULT_MIN_DIST, NULL, 2.0f );
}
armedBombPlace->_armed = false;
respawnBomb( true );
armedBombPlace->_item->removeAttachedModelByTargetname( "attachedDiffusionBomb" );
_attachedBomb->PostEvent( EV_Remove, 0.0f );
_attachedBomb = NULL;
armedBombPlace->_totalArmedTime = 0.0f;
armedBombPlace->_lastArmingTime = 0.0f;
armedBombPlace->_lastDisarmingTime = 0.0f;
// Respawn all of the players in a few seconds
_respawnTime = multiplayerManager.getTime() + 3.0f;
}
}
// See if we should respawn everyone
if ( ( _respawnTime > 0.0f ) && ( _respawnTime < multiplayerManager.getTime() ) )
{
multiplayerManager.respawnAllPlayers();
_respawnTime = 0.0f;
}
}
int ModifierDiffusion::getIcon( Player *player, int statNum, int value )
{
if ( statNum == STAT_MP_MODE_ICON )
{
// Return the icon for the player's specialty
if ( player == getBomber() )
return _bomberIconIndex;
else
return -1;
}
return value;
}
int ModifierDiffusion::getScoreIcon( Player *player, int index, int value )
{
if ( index == SCOREICON5 )
{
if ( player == getBomber() )
return _bomberIconIndex;
else
return 0;
}
return value;
}
void ModifierDiffusion::matchStarted( void )
{
if ( _bomb )
{
_bomb->showModel();
_bomb->setSolidType( SOLID_TRIGGER );
}
if ( _redBombPlace._item )
{
_redBombPlace._item->showModel();
_redBombPlace._item->setSolidType( SOLID_BBOX );
}
if ( _blueBombPlace._item )
{
_blueBombPlace._item->showModel();
_blueBombPlace._item->setSolidType( SOLID_BBOX );
}
}
// Setup constants
const float ModifierSpecialties::_infiltratorMinRespawnTime = 0.0f;
const float ModifierSpecialties::_medicMinRespawnTime = 30.0f;
const float ModifierSpecialties::_technicianMinRespawnTime = 30.0f;
const float ModifierSpecialties::_demolitionistMinRespawnTime = 15.0f;
const float ModifierSpecialties::_heavyweaponsMinRespawnTime = 0.0f;
const float ModifierSpecialties::_sniperMinRespawnTime = 0.0f;
const float ModifierSpecialties::_startingInfiltratorHealth = 100.0f;
const float ModifierSpecialties::_startingInfiltratorMassModifier = 0.5f;
const float ModifierSpecialties::_startingMedicArmor = 75.0f;
const float ModifierSpecialties::_startingTechnicianArmor = 50.0f;
const float ModifierSpecialties::_startingDemolitionistArmor = 50.0f;
const float ModifierSpecialties::_startingHeavyWeaponsHealth = 200.0f;
const float ModifierSpecialties::_startingHeavyWeaponsArmor = 100.0f;
const float ModifierSpecialties::_startingHeavyWeaponsMassModifier = 2.0f;
const float ModifierSpecialties::_startingSniperArmor = 25.0f;
const float ModifierSpecialties::_startingNormalHealth = 100.0f;
const float ModifierSpecialties::_medicHealOtherRate = 20.0f;
const float ModifierSpecialties::_medicHealSelfRate = 2.0f;
const float ModifierSpecialties::_infiltratorMoveSpeedModifier = 1.25f;
const float ModifierSpecialties::_heavyWeaponsMoveSpeedModifier = .75f;
const float ModifierSpecialties::_infiltratorJumpSpeedModifier = 1.1f;
const float ModifierSpecialties::_infiltratorAirAccelerationModifier = 1.5f;
const float ModifierSpecialties::_technicianHoldableItemRegenTime = 20.0f;
const float ModifierSpecialties::_demolitionistHoldableItemRegenTime = 20.0f;
const bool ModifierSpecialties::_medicCanSeeEnemyHealth = true;
const float ModifierSpecialties::_amountOfHealingForPoints = 10.0f;
const int ModifierSpecialties::_pointsForHealing = 1;
const bool ModifierSpecialties::_removeItems = false;
const SpecialtyType SpecialtyPlayerData::_defaultSpecialty = SPECIALTY_INFILTRATOR;
SpecialtyPlayerData::SpecialtyPlayerData()
{
_forced = false;
reset();
}
void SpecialtyPlayerData::reset( void )
{
if ( _forced )
return;
_specialty = _defaultSpecialty;
_item = NULL;
_lastUseTime = 0.0f;
_amountOfHealing = 0.0f;
_lastPlayer = -1;
}
ModifierSpecialties::ModifierSpecialties()
{
_playerSpecialtyData = NULL;
_infiltratorIconIndex = gi.imageindex( "sysimg/icons/mp/specialty_infiltrator" );
_medicIconIndex = gi.imageindex( "sysimg/icons/mp/specialty_medic" );
_technicianIconIndex = gi.imageindex( "sysimg/icons/mp/specialty_technician" );
_demolitionistIconIndex = gi.imageindex( "sysimg/icons/mp/specialty_demolitionist" );
_heavyweaponsIconIndex = gi.imageindex( "sysimg/icons/mp/specialty_heavyweapons" );
_sniperIconIndex = gi.imageindex( "sysimg/icons/mp/specialty_sniper" );
_specialtyItems.FreeObjectList();
}
ModifierSpecialties::~ModifierSpecialties()
{
delete [] _playerSpecialtyData;
_playerSpecialtyData = NULL;
_specialtyItems.FreeObjectList();
}
void ModifierSpecialties::init( int maxPlayers )
{
_maxPlayers = maxPlayers;
_playerSpecialtyData = new SpecialtyPlayerData[ maxPlayers ];
multiplayerManager.cacheMultiplayerFiles( "mp_specialties" );
}
bool ModifierSpecialties::checkRule( const char *rule, bool defaultValue, Player *player )
{
// We want team spawn points
if ( stricmp( rule, "spawnpoints-team" ) == 0 )
return true;
else if ( stricmp( rule, "dropWeapons" ) == 0 )
return false;
else if ( stricmp( rule, "spawnpoints-special" ) == 0 )
{
// We want special spawnpoints in this mode but not for bots
if ( player->edict->svflags & SVF_BOT )
return defaultValue;
else
return true;
}
else
return defaultValue;
}
str ModifierSpecialties::getSpawnPointType( Player *player )
{
Team *team;
team = multiplayerManager.getPlayersTeam( player );
if ( team && team->getName() == "Red" )
return "specialty-red";
else if ( team && team->getName() == "Blue" )
return "specialty-blue";
else
return "specialty";
}
void ModifierSpecialties::playerCommand( Player *player, const char *command, const char *parm )
{
if ( stricmp( command, "setSpecialty" ) == 0 )
{
SpecialtyType specialty;
// Figure out which specialty we want to set
if ( stricmp( parm, "infiltrator" ) == 0 )
specialty = SPECIALTY_INFILTRATOR;
else if ( stricmp( parm, "medic" ) == 0 )
specialty = SPECIALTY_MEDIC;
else if ( stricmp( parm, "technician" ) == 0 )
specialty = SPECIALTY_TECHNICIAN;
else if ( stricmp( parm, "demolitionist" ) == 0 )
specialty = SPECIALTY_DEMOLITIONIST;
else if ( ( stricmp( parm, "heavyweapons" ) == 0 ) || ( stricmp( parm, "heavy" ) == 0 ) )
specialty = SPECIALTY_HEAVY_WEAPONS;
else if ( stricmp( parm, "sniper" ) == 0 )
specialty = SPECIALTY_SNIPER;
else
specialty = SPECIALTY_NONE;
// Setup the specialty
if ( ( specialty == SPECIALTY_NONE ) || ( player->edict->svflags & SVF_BOT ) )
{
setupSpecialty( player, specialty, true );
_playerSpecialtyData[ player->entnum ]._specialty = specialty;
if ( specialty == SPECIALTY_NONE )
_playerSpecialtyData[ player->entnum ]._forced = false;
else
_playerSpecialtyData[ player->entnum ]._forced = true;
}
}
}
bool ModifierSpecialties::shouldKeepItem( MultiplayerItem *item )
{
str itemName;
const char *dash1;
const char *dash2;
itemName = item->getName();
if ( strnicmp( itemName.c_str(), "specialty-", strlen( "specialty-" ) ) == 0 )
{
SpecialtyItem specialtyItem;
// This is a specialty item so keep track of it
specialtyItem._item = item;
specialtyItem._needToRespawn = false;
specialtyItem._respawnTime = 0.0f;
specialtyItem._pickedupTime = 0.0f;
if ( strnicmp( itemName.c_str(), "specialty-infiltrator-", strlen( "specialty-infiltrator-" ) ) == 0 )
{
specialtyItem._type = SPECIALTY_INFILTRATOR;
specialtyItem._minimumRespawnTime = _infiltratorMinRespawnTime;
}
else if ( strnicmp( itemName.c_str(), "specialty-medic-", strlen( "specialty-medic-" ) ) == 0 )
{
specialtyItem._type = SPECIALTY_MEDIC;
specialtyItem._minimumRespawnTime = _medicMinRespawnTime;
}
else if ( strnicmp( itemName.c_str(), "specialty-technician-", strlen( "specialty-technician-" ) ) == 0 )
{
specialtyItem._type = SPECIALTY_TECHNICIAN;
specialtyItem._minimumRespawnTime = _technicianMinRespawnTime;
}
else if ( strnicmp( itemName.c_str(), "specialty-demolitionist-", strlen( "specialty-demolitionist-" ) ) == 0 )
{
specialtyItem._type = SPECIALTY_DEMOLITIONIST;
specialtyItem._minimumRespawnTime = _demolitionistMinRespawnTime;
}
else if ( strnicmp( itemName.c_str(), "specialty-heavyweapons-", strlen( "specialty-heavyweapons-" ) ) == 0 )
{
specialtyItem._type = SPECIALTY_HEAVY_WEAPONS;
specialtyItem._minimumRespawnTime = _heavyweaponsMinRespawnTime;
}
else if ( strnicmp( itemName.c_str(), "specialty-sniper-", strlen( "specialty-sniper-" ) ) == 0 )
{
specialtyItem._type = SPECIALTY_SNIPER;
specialtyItem._minimumRespawnTime = _sniperMinRespawnTime;
}
else
{
specialtyItem._type = SPECIALTY_NONE;
}
// Get the team name
dash1 = strstr( itemName.c_str(), "-" );
if ( dash1 )
{
dash2 = strstr( dash1 + 1, "-" );
if ( dash2 )
{
specialtyItem._teamName = dash2 + 1;
}
}
// Add the item to the list
_specialtyItems.AddObject( specialtyItem );
return true;
}
else
{
return false;
}
}
bool ModifierSpecialties::shouldKeepNormalItem( Item *item )
{
if ( item->isSubclassOf( Weapon ) )
return false;
else
return true;
}
SpecialtyItem *ModifierSpecialties::findSpecialtyItem( MultiplayerItem *item )
{
int i;
SpecialtyItem *specialtyItem;
// Go through the list and find the item
for ( i = 1 ; i <= _specialtyItems.NumObjects() ; i++ )
{
specialtyItem = &_specialtyItems.ObjectAt( i );
if ( specialtyItem->_item == item )
{
return specialtyItem;
}
}
return NULL;
}
void ModifierSpecialties::addPlayer( Player *player )
{
putItemBack( player );
_playerSpecialtyData[ player->entnum ].reset();
if ( _playerSpecialtyData[ player->entnum ]._forced )
{
setupSpecialty( player, _playerSpecialtyData[ player->entnum ]._specialty, false );
}
gi.SendServerCommand( player->entnum, "stufftext \"ui_addhud mp_specialties\"\n" );
}
void ModifierSpecialties::itemTouched( Player *player, MultiplayerItem *item )
{
SpecialtyType specialty;
bool sameTeam = false;
Team *team;
const char *teamName;
SpecialtyItem *specialtyItem;
// Make sure player doesn't already have a class
//if ( _playerSpecialtyData[ player->entnum ]._specialty != SPECIALTY_NONE )
// return;
// Make sure this isn't a bot
if ( player->edict->svflags & SVF_BOT )
return;
// Make sure this is a specialty item
specialtyItem = findSpecialtyItem( item );
if ( !specialtyItem )
return;
specialty = specialtyItem->_type;
// Only bother if the player isn't already the new specialty
if ( _playerSpecialtyData[ player->entnum ]._specialty == specialty )
return;
// Make sure the item and the player are on the same team
team = multiplayerManager.getPlayersTeam( player );
if ( !team )
return;
teamName = team->getName().c_str();
if ( stricmp( teamName, specialtyItem->_teamName ) == 0 )
sameTeam = true;
if ( !sameTeam )
return;
if ( !multiplayerManager.checkRule ( "specialty-pickup", true, player ) )
return;
if ( _playerSpecialtyData[ player->entnum ]._specialty != SPECIALTY_NONE )
{
putItemBack( player );
}
// Pickup the item and change the player's specialty
_playerSpecialtyData[ player->entnum ]._specialty = specialty;
_playerSpecialtyData[ player->entnum ]._item = item;
specialtyItem->_pickedupTime = multiplayerManager.getTime();
setupSpecialty( player, specialty, true );
removeItem( item );
}
void ModifierSpecialties::setupSpecialty( Player *player, SpecialtyType specialty, bool chosen )
{
float armorToGive;
Event *event;
bool hadTricorder;
str specialtyName;
str specialtySoundName;
armorToGive = 0.0f;
// Change the player based on the specialty
// Take away holdable item
player->removeHoldableItem();
// Take away all of the weapons except the tricorder
if ( player->FindItemByModelname( "models/weapons/worldmodel-tricorder.tik" ) )
hadTricorder = true;
else
hadTricorder = false;
if ( !( player->edict->svflags & SVF_BOT ) )
{
player->FreeInventory();
}
multiplayerManager.resetPlayerStateMachine( player );
if ( hadTricorder )
{
multiplayerManager.givePlayerItem( player->entnum, "models/weapons/worldmodel-tricorder.tik" );
}
// Take away any armor
Event *armorEvent = new Event( EV_Sentient_SetMyArmorAmount );
armorEvent->AddFloat( 0.0f );
player->ProcessEvent( armorEvent );
_playerSpecialtyData[ player->entnum ]._regenHoldableItemTime = 0.0f;
switch( specialty )
{
case SPECIALTY_NONE :
multiplayerManager.givePlayerItem( player->entnum, "models/weapons/worldmodel-phaser.tik" );
multiplayerManager.givePlayerItem( player->entnum, "models/weapons/worldmodel-batleth.tik" );
multiplayerManager.usePlayerItem( player->entnum, "Phaser" );
player->setMaxHealth( _startingNormalHealth );
if ( player->getHealth() > _startingNormalHealth )
player->setHealth( _startingNormalHealth );
break;
case SPECIALTY_INFILTRATOR :
specialtyName = "$$Infiltrator$$\n";
specialtySoundName = "localization/sound/dialog/dm/comp_infil.mp3";
player->setMaxHealth( _startingInfiltratorHealth );
if ( player->getHealth() > _startingInfiltratorHealth )
player->setHealth( (int)_startingInfiltratorHealth );
player->mass *= (int)_startingInfiltratorMassModifier;
event = new Event( EV_Sentient_AddResistance );
event->AddString( "falling" );
event->AddInteger( 100 );
player->ProcessEvent( event );
player->setHoldableItem( HoldableItem::createHoldableItem( "Transporter", "models/item/holdable_transporter.tik", player ) );
multiplayerManager.givePlayerItem( player->entnum, "models/weapons/worldmodel-phaser.tik" );
//multiplayerManager.givePlayerItem( player->entnum, "models/weapons/worldmodel-batleth.tik" );
multiplayerManager.givePlayerItem( player->entnum, "models/weapons/worldmodel-compressionrifle.tik" );
multiplayerManager.givePlayerItem( player->entnum, "weapons/worldmodel-imod.tik" );
multiplayerManager.usePlayerItem( player->entnum, "CompressionRifle" );
player->GiveAmmo( "Plasma", 400, false, 400 );
break;
case SPECIALTY_MEDIC :
specialtyName = "$$Medic$$\n";
specialtySoundName = "localization/sound/dialog/dm/comp_medic.mp3";
player->setMaxHealth( _startingNormalHealth );
if ( player->getHealth() > _startingNormalHealth )
player->setHealth( _startingNormalHealth );
armorToGive = _startingMedicArmor;
//player->setHoldableItem( HoldableItem::createHoldableItem( "Health", "models/item/holdable_medkit.tik", player ) );
multiplayerManager.givePlayerItem( player->entnum, "models/weapons/worldmodel-phaser.tik" );
multiplayerManager.givePlayerItem( player->entnum, "models/weapons/worldmodel-tricorder.tik" );
multiplayerManager.givePlayerItem( player->entnum, "models/weapons/worldmodel-batleth.tik" );
multiplayerManager.givePlayerItem( player->entnum, "models/weapons/worldmodel-burstrifle.tik" );
multiplayerManager.usePlayerItem( player->entnum, "BurstRifle" );
player->GiveAmmo( "Plasma", 400, false, 400 );
break;
case SPECIALTY_TECHNICIAN :
specialtyName = "$$Technician$$\n";
specialtySoundName = "localization/sound/dialog/dm/comp_tech.mp3";
player->setMaxHealth( _startingNormalHealth );
if ( player->getHealth() > _startingNormalHealth )
player->setHealth( _startingNormalHealth );
armorToGive = _startingTechnicianArmor;
//event = new Event( EV_Sentient_AddResistance );
//event->AddString( "drown" );
//event->AddInteger( 100 );
//player->ProcessEvent( event );
//player->setHoldableItem( HoldableItem::createHoldableItem( "Protection", "models/item/holdable_forcefield.tik", player ) );
multiplayerManager.givePlayerItem( player->entnum, "models/weapons/worldmodel-phaser.tik" );
//multiplayerManager.givePlayerItem( player->entnum, "models/weapons/worldmodel-batleth.tik" );
multiplayerManager.givePlayerItem( player->entnum, "models/weapons/worldmodel-attrex-rifle.tik" );
multiplayerManager.givePlayerItem( player->entnum, "models/weapons/worldmodel-rom-disruptor.tik" );
multiplayerManager.usePlayerItem( player->entnum, "AttrexianRifle" );
_playerSpecialtyData[ player->entnum ]._regenHoldableItemTime = multiplayerManager.getTime() + _technicianHoldableItemRegenTime;
player->GiveAmmo( "Idryll", 400, false, 400 );
break;
case SPECIALTY_DEMOLITIONIST :
specialtyName = "$$Demolitionist$$\n";
specialtySoundName = "localization/sound/dialog/dm/comp_demoli.mp3";
player->setMaxHealth( _startingNormalHealth );
if ( player->getHealth() > _startingNormalHealth )
player->setHealth( _startingNormalHealth );
armorToGive = _startingDemolitionistArmor;
player->setHoldableItem( HoldableItem::createHoldableItem( "Explosive", "models/item/holdable_explosive.tik", player ) );
multiplayerManager.givePlayerItem( player->entnum, "models/weapons/worldmodel-phaser.tik" );
multiplayerManager.givePlayerItem( player->entnum, "models/weapons/worldmodel-batleth.tik" );
multiplayerManager.givePlayerItem( player->entnum, "models/weapons/worldmodel-fieldassaultrifle.tik" );
multiplayerManager.givePlayerItem( player->entnum, "models/weapons/worldmodel-grenadelauncher.tik" );
multiplayerManager.usePlayerItem( player->entnum, "GrenadeLauncher" );
player->GiveAmmo( "Fed", 400, false, 400 );
break;
case SPECIALTY_HEAVY_WEAPONS :
specialtyName = "$$HeavyWeapons$$\n";
specialtySoundName = "localization/sound/dialog/dm/comp_hw.mp3";
player->setMaxHealth( _startingHeavyWeaponsHealth );
if ( player->getHealth() > _startingHeavyWeaponsHealth )
player->setHealth( _startingHeavyWeaponsHealth );
armorToGive = (int) _startingHeavyWeaponsArmor;
player->mass *= (int)_startingHeavyWeaponsMassModifier;
multiplayerManager.givePlayerItem( player->entnum, "models/weapons/worldmodel-phaser.tik" );
multiplayerManager.givePlayerItem( player->entnum, "models/weapons/worldmodel-batleth.tik" );
multiplayerManager.givePlayerItem( player->entnum, "models/weapons/worldmodel-tetryon.tik" );
multiplayerManager.givePlayerItem( player->entnum, "models/weapons/worldmodel-photon.tik" );
multiplayerManager.usePlayerItem( player->entnum, "PhotonBurst" );
player->GiveAmmo( "Fed", 400, false, 400 );
player->GiveAmmo( "Plasma", 100, false, 400 );
break;
case SPECIALTY_SNIPER :
specialtyName = "$$Sniper$$\n";
specialtySoundName = "localization/sound/dialog/dm/comp_sniper.mp3";
player->setMaxHealth( _startingNormalHealth );
if ( player->getHealth() > _startingNormalHealth )
player->setHealth( _startingNormalHealth );
armorToGive = _startingSniperArmor;
multiplayerManager.givePlayerItem( player->entnum, "models/weapons/worldmodel-phaser.tik" );
//multiplayerManager.givePlayerItem( player->entnum, "models/weapons/worldmodel-batleth.tik" );
multiplayerManager.givePlayerItem( player->entnum, "models/weapons/worldmodel-sniperrifle.tik" );
multiplayerManager.givePlayerItem( player->entnum, "models/weapons/worldmodel-compressionrifle.tik" );
multiplayerManager.usePlayerItem( player->entnum, "FederationSniperRifle" );
player->GiveAmmo( "Fed", 400, false, 400 );
// TODO decoy ?
//player->giveItem( "models/item/decoy.tik", 1, false );
break;
}
// Give the player some armor
if ( armorToGive > 0.0f )
{
Event *armorEvent;
armorEvent = new Event( EV_Sentient_GiveArmor );
armorEvent->AddString( "BasicArmor" );
armorEvent->AddFloat( armorToGive );
armorEvent->AddInteger( false );
player->ProcessEvent( armorEvent );
}
// Tell the player his specialty
if ( !multiplayerManager.isPlayerSpectator( player ) )
{
if ( specialtyName.length() > 0 )
{
// Tell player his new specialty
multiplayerManager.centerPrint( player->entnum, specialtyName.c_str(), CENTERPRINT_IMPORTANCE_HIGH );
// Tell teammates his new specialty
if ( chosen )
{
str stringToPrint;
stringToPrint = player->client->pers.netname;
stringToPrint += " $$BecomesA$$ ";
stringToPrint += specialtyName;
multiplayerManager.HUDPrintTeamClients( player, stringToPrint.c_str() );
}
}
if ( ( specialtySoundName.length() > 0 ) && ( chosen ) )
{
multiplayerManager.playerSound( player->entnum, specialtySoundName, CHAN_AUTO, DEFAULT_VOL, DEFAULT_MIN_DIST, 1.0f );
}
}
attachBackpack( player );
}
void ModifierSpecialties::playerChangedModel( Player *player )
{
attachBackpack( player );
}
void ModifierSpecialties::attachBackpack( Player *player )
{
str attachModelName;
str tagName;
player->removeAttachedModelByTargetname( "attachedSpecialityBackpack" );
switch( _playerSpecialtyData[ player->entnum ]._specialty )
{
case SPECIALTY_INFILTRATOR :
attachModelName = "models/item/mp_specialty_infiltrator.tik";
break;
case SPECIALTY_MEDIC :
attachModelName = "models/item/mp_specialty_medic.tik";
break;
case SPECIALTY_TECHNICIAN :
attachModelName = "models/item/mp_specialty_technician.tik";
break;
case SPECIALTY_DEMOLITIONIST :
attachModelName = "models/item/mp_specialty_demolitionist.tik";
break;
case SPECIALTY_HEAVY_WEAPONS :
attachModelName = "models/item/mp_specialty_heavyweapons.tik";
break;
case SPECIALTY_SNIPER :
attachModelName = "models/item/mp_specialty_sniper.tik";
break;
}
if ( gi.Tag_NumForName( player->edict->s.modelindex, "Bip01 spine2" ) >= 0 )
tagName = "Bip01 spine2";
else if ( gi.Tag_NumForName( player->edict->s.modelindex, "Bip01 spine1" ) >= 0 )
tagName = "Bip01 spine1";
else if ( gi.Tag_NumForName( player->edict->s.modelindex, "Bip01 Head" ) >= 0 )
tagName = "Bip01 Head";
if ( attachModelName.length() )
{
Event *attachEvent;
attachEvent = new Event( EV_AttachModel );
attachEvent->AddString( attachModelName.c_str() );
attachEvent->AddString( tagName );
attachEvent->AddFloat( 1.0f );
attachEvent->AddString( "attachedSpecialityBackpack" );
attachEvent->AddInteger( 0 );
attachEvent->AddFloat( -1.0f );
attachEvent->AddFloat( 0.0f );
attachEvent->AddFloat( -1.0f );
attachEvent->AddFloat( -1.0f );
attachEvent->AddVector( player->getBackpackAttachOffset() );
attachEvent->AddVector( player->getBackpackAttachAngles() );
player->ProcessEvent( attachEvent );
}
}
void ModifierSpecialties::playerUsed( Player *usedPlayer, Player *usingPlayer, Equipment *equipment )
{
// Make sure everything is ok
if ( !usedPlayer || !usingPlayer || !equipment )
return;
// Give health to the player if everything is ok and this is a medic
if ( ( _playerSpecialtyData[ usingPlayer->entnum ]._specialty == SPECIALTY_MEDIC ) &&
( _playerSpecialtyData[ usingPlayer->entnum ]._lastUseTime < multiplayerManager.getTime() ) &&
( multiplayerManager.getPlayersTeam( usedPlayer ) == multiplayerManager.getPlayersTeam( usingPlayer ) ) &&
( stricmp( equipment->getTypeName().c_str(), "tricorder" ) == 0 ) &&
( usedPlayer != usingPlayer ) )
{
float healthToAdd;
float originalHealth;
float healthAdded;
_playerSpecialtyData[ usingPlayer->entnum ]._lastUseTime = multiplayerManager.getTime();
healthToAdd = _medicHealOtherRate * level.frametime;
originalHealth = usedPlayer->getHealth();
usedPlayer->addHealth( healthToAdd, 100.0f );
healthAdded = usedPlayer->getHealth() - originalHealth;
// Give the healing player some points if necessary
_playerSpecialtyData[ usingPlayer->entnum ]._amountOfHealing += healthAdded;
while ( _playerSpecialtyData[ usingPlayer->entnum ]._amountOfHealing >= _amountOfHealingForPoints )
{
_playerSpecialtyData[ usingPlayer->entnum ]._amountOfHealing -= _amountOfHealingForPoints;
multiplayerManager.addPoints( usingPlayer->entnum, _pointsForHealing );
}
}
/* else if ( ( _playerSpecialtyData[ usingPlayer->entnum ]._specialty == SPECIALTY_TECHNICIAN ) &&
( multiplayerManager.getPlayersTeam( usedPlayer ) == multiplayerManager.getPlayersTeam( usingPlayer ) ) )
{
if ( _playerSpecialtyData[ usingPlayer->entnum ]._lastUseTime == 0.0f )
{
Powerup *powerup;
_playerSpecialtyData[ usingPlayer->entnum ]._lastUseTime = multiplayerManager.getTime();
powerup = Powerup::CreatePowerup( "Invisibility", "models/item/powerup_invisibility.tik", usedPlayer );
if ( powerup )
{
powerup->CancelEventsOfType( EV_ProcessInitCommands );
powerup->ProcessInitCommands( powerup->edict->s.modelindex );
usedPlayer->setPowerup( powerup );
}
}
else
{
usingPlayer->Sound( "snd_noammo" );
}
} */
}
void ModifierSpecialties::update( float frameTime )
{
Player *player;
Entity *entity;
gentity_t *edict;
int i;
SpecialtyItem *specialtyItem;
HoldableItem *holdableItem;
// Update all of the players based on their specialty
for( i = 0 ; i < game.maxclients ; i++ )
{
edict = &g_entities[ i ];
if ( !edict->inuse || !edict->entity )
continue;
entity = edict->entity;
if ( !entity->isSubclassOf( Player ) )
continue;
player = ( Player * )entity;
if ( _playerSpecialtyData[ player->entnum ]._specialty == SPECIALTY_MEDIC )
{
player->addHealth( _medicHealSelfRate * frameTime );
}
else if ( _playerSpecialtyData[ player->entnum ]._specialty == SPECIALTY_TECHNICIAN )
{
Event *newEvent = new Event( EV_Sentient_SetViewMode );
newEvent->AddString( "forcevisible" );
newEvent->AddInteger( 0 );
player->ProcessEvent( newEvent );
}
// Respawn holdable items
holdableItem = player->getHoldableItem();
if ( !holdableItem )
{
if ( _playerSpecialtyData[ player->entnum ]._regenHoldableItemTime > 0.0f )
{
if ( _playerSpecialtyData[ player->entnum ]._regenHoldableItemTime < multiplayerManager.getTime() )
{
// Respawn holdable items
if ( _playerSpecialtyData[ player->entnum ]._specialty == SPECIALTY_DEMOLITIONIST )
{
player->setHoldableItem( HoldableItem::createHoldableItem( "Explosive", "models/item/holdable_explosive.tik", player ) );
}
else if ( _playerSpecialtyData[ player->entnum ]._specialty == SPECIALTY_TECHNICIAN )
{
float randomNum;
randomNum = G_Random( 1 );
if ( randomNum < 0.25f )
player->setHoldableItem( HoldableItem::createHoldableItem( "SpawnPowerup", "models/item/holdable_spawnInvis.tik", player ) );
else if ( randomNum < 0.50f )
player->setHoldableItem( HoldableItem::createHoldableItem( "SpawnPowerup", "models/item/holdable_spawnRegen.tik", player ) );
else if ( randomNum < 0.75f )
player->setHoldableItem( HoldableItem::createHoldableItem( "SpawnPowerup", "models/item/holdable_spawnSpeed.tik", player ) );
else
player->setHoldableItem( HoldableItem::createHoldableItem( "SpawnPowerup", "models/item/holdable_spawnStrength.tik", player ) );
}
_playerSpecialtyData[ player->entnum ]._regenHoldableItemTime = 0.0f;
player->Sound( "snd_holdableRespawn" );
}
}
else
{
// The player has no holdable item and no timer is setup
if ( _playerSpecialtyData[ player->entnum ]._specialty == SPECIALTY_DEMOLITIONIST )
{
_playerSpecialtyData[ player->entnum ]._regenHoldableItemTime = multiplayerManager.getTime() +
_demolitionistHoldableItemRegenTime;
}
else if ( _playerSpecialtyData[ player->entnum ]._specialty == SPECIALTY_TECHNICIAN )
{
_playerSpecialtyData[ player->entnum ]._regenHoldableItemTime = multiplayerManager.getTime() +
_technicianHoldableItemRegenTime;
}
}
}
}
// Respawn any specialty items that need to be
for ( i = 1 ; i <= _specialtyItems.NumObjects() ; i++ )
{
specialtyItem = &_specialtyItems.ObjectAt( i );
if ( specialtyItem->_needToRespawn && ( specialtyItem->_respawnTime < multiplayerManager.getTime() ) )
{
specialtyItem->_needToRespawn = false;
specialtyItem->_item->showModel();
specialtyItem->_item->setSolidType( SOLID_TRIGGER );
}
}
}
void ModifierSpecialties::removePlayer( Player *player )
{
int i;
putItemBack( player );
// Wipe out any saved data for the player
for ( i = 0 ; i < _maxPlayers ; i++ )
{
_playerSpecialtyData[ player->entnum ]._lastPlayer = -1;
}
}
void ModifierSpecialties::playerKilled( Player *killedPlayer, Player *attackingPlayer, Entity *inflictor, int meansOfDeath )
{
putItemBack( killedPlayer );
}
void ModifierSpecialties::playerSpawned( Player *player )
{
if ( _playerSpecialtyData[ player->entnum ]._forced )
{
setupSpecialty( player, _playerSpecialtyData[ player->entnum ]._specialty, false );
}
else
{
putItemBack( player );
_playerSpecialtyData[ player->entnum ].reset();
setupSpecialty( player, _playerSpecialtyData[ player->entnum ]._specialty, false );
}
}
void ModifierSpecialties::applySpeedModifiers( Player *player, int *moveSpeed )
{
if ( _playerSpecialtyData[ player->entnum ]._specialty == SPECIALTY_INFILTRATOR )
*moveSpeed *= (int) (_infiltratorMoveSpeedModifier);
else if ( _playerSpecialtyData[ player->entnum ]._specialty == SPECIALTY_HEAVY_WEAPONS )
*moveSpeed = (int)( *moveSpeed * _heavyWeaponsMoveSpeedModifier );
}
void ModifierSpecialties::applyJumpModifiers( Player *player, int *jumpSpeed )
{
if ( _playerSpecialtyData[ player->entnum ]._specialty == SPECIALTY_INFILTRATOR )
*jumpSpeed = (int)( *jumpSpeed * _infiltratorJumpSpeedModifier );
}
void ModifierSpecialties::applyAirAccelerationModifiers( Player *player, int *airAcceleration )
{
if ( _playerSpecialtyData[ player->entnum ]._specialty == SPECIALTY_INFILTRATOR )
*airAcceleration = (int)( *airAcceleration * _infiltratorAirAccelerationModifier );
}
bool ModifierSpecialties::canPickup( Player *player, MultiplayerItemType itemType, const char *item_name )
{
// The infiltrator can't pickup the speed powerup
if ( itemType == MP_ITEM_TYPE_ARMOR )
{
if ( _playerSpecialtyData[ player->entnum ]._specialty == SPECIALTY_INFILTRATOR )
{
// Infiltrator can't pick up armor
return false;
}
}
else if ( itemType == MP_ITEM_TYPE_POWERUP )
{
/* if ( _playerSpecialtyData[ player->entnum ]._specialty == SPECIALTY_INFILTRATOR )
{
if ( stricmp( item_name, "Speed" ) == 0 )
{
return false;
}
}
// No one can pickup the strength powerup except the heavy weapons class
if ( stricmp( item_name, "Strength" ) == 0 )
{
if ( _playerSpecialtyData[ player->entnum ]._specialty != SPECIALTY_HEAVY_WEAPONS )
{
return false;
}
} */
}
else if ( itemType == MP_ITEM_TYPE_WEAPON )
{
// Specialities can't pickup any weapons (they have already been given the weapons their allowed to have)
if ( _playerSpecialtyData[ player->entnum ]._specialty != SPECIALTY_NONE )
return false;
}
return true;
}
void ModifierSpecialties::removeItem( MultiplayerItem *item )
{
if ( !_removeItems )
return;
if ( item )
{
item->setSolidType( SOLID_NOT );
item->hideModel();
}
}
void ModifierSpecialties::putItemBack( Player *player )
{
MultiplayerItem *item;
SpecialtyItem *specialtyItem;
if ( _playerSpecialtyData[ player->entnum ]._forced )
return;
if ( _removeItems )
{
// Find the item in question
item = _playerSpecialtyData[ player->entnum ]._item;
specialtyItem = findSpecialtyItem( item );
// Put the item back
if ( specialtyItem )
{
HoldableItem* holdableItem;
bool respawnNow = false;
holdableItem = player->getHoldableItem();
if ( holdableItem )
{
if ( specialtyItem->_type == SPECIALTY_DEMOLITIONIST )
{
if ( holdableItem->getName() == "Explosive" )
respawnNow = true;
}
else if ( specialtyItem->_type == SPECIALTY_MEDIC )
{
if ( ( holdableItem->getName() == "Health" ) && ( _playerSpecialtyData[ player->entnum ]._lastUseTime == 0.0f ) )
respawnNow = true;
}
/* else if ( specialtyItem->_type == SPECIALTY_TECHNICIAN )
{
if ( ( holdableItem->getName() == "Protection" ) && ( _playerSpecialtyData[ player->entnum ]._lastUseTime == 0.0f ) )
respawnNow = true;
} */
}
if ( respawnNow )
specialtyItem->_respawnTime = specialtyItem->_pickedupTime + 0.0f;
else
specialtyItem->_respawnTime = specialtyItem->_pickedupTime + specialtyItem->_minimumRespawnTime;
specialtyItem->_needToRespawn = true;
}
}
_playerSpecialtyData[ player->entnum ].reset();
}
int ModifierSpecialties::getStat( Player *player, int statNum, int value )
{
Entity *target;
Player *targetPlayer;
int lastPlayer;
float lastPlayerTime;
if ( statNum == STAT_MP_GENERIC4 )
{
if ( _playerSpecialtyData[ player->entnum ]._specialty == SPECIALTY_MEDIC )
{
lastPlayer = _playerSpecialtyData[ player->entnum ]._lastPlayer;
lastPlayerTime = _playerSpecialtyData[ player->entnum ]._lastPlayerTime;
target = player->GetTargetedEntity();
if ( target && target->isSubclassOf( Player ) &&
( ( multiplayerManager.getPlayersTeam( player ) == multiplayerManager.getPlayersTeam( (Player*)target ) ) ||
( _medicCanSeeEnemyHealth ) ) )
{
_playerSpecialtyData[ player->entnum ]._lastPlayer = target->entnum;
_playerSpecialtyData[ player->entnum ]._lastPlayerTime = multiplayerManager.getTime();
return (int)( target->getHealth() + 0.99f );
}
else if ( ( lastPlayer >= 0 ) && ( lastPlayerTime + 1.0f > multiplayerManager.getTime() ) )
{
targetPlayer = multiplayerManager.getPlayer( lastPlayer );
if ( targetPlayer )
{
return (int)( targetPlayer->getHealth() + 0.99f );
}
}
else
{
_playerSpecialtyData[ player->entnum ]._lastPlayer = -1;
}
}
}
return value;
}
int ModifierSpecialties::getIcon( Player *player, int statNum, int value )
{
if ( statNum == STAT_MP_SPECIALTY_ICON )
{
// Return the icon for the player's specialty
switch( _playerSpecialtyData[ player->entnum ]._specialty )
{
case SPECIALTY_NONE :
return value;
case SPECIALTY_INFILTRATOR :
return _infiltratorIconIndex;
case SPECIALTY_MEDIC :
return _medicIconIndex;
case SPECIALTY_TECHNICIAN :
return _technicianIconIndex;
case SPECIALTY_DEMOLITIONIST :
return _demolitionistIconIndex;
case SPECIALTY_HEAVY_WEAPONS :
return _heavyweaponsIconIndex;
case SPECIALTY_SNIPER :
return _sniperIconIndex;
}
}
return value;
}
int ModifierSpecialties::getScoreIcon( Player *player, int index, int value )
{
if ( index == SCOREICON4 )
{
// Return the icon for the player's specialty
switch( _playerSpecialtyData[ player->entnum ]._specialty )
{
case SPECIALTY_NONE :
return value;
case SPECIALTY_INFILTRATOR :
return _infiltratorIconIndex;
case SPECIALTY_MEDIC :
return _medicIconIndex;
case SPECIALTY_TECHNICIAN :
return _technicianIconIndex;
case SPECIALTY_DEMOLITIONIST :
return _demolitionistIconIndex;
case SPECIALTY_HEAVY_WEAPONS :
return _heavyweaponsIconIndex;
case SPECIALTY_SNIPER :
return _sniperIconIndex;
}
}
return value;
}
// Setup constants
const float ModifierControlPoints::_timeNeededToControl = 5.0f;
const int ModifierControlPoints::_maxNumberAwardsForPlayerCapture = 5;
const int ModifierControlPoints::_pointsForEachAwardForCapture = 5;
const int ModifierControlPoints::_pointsForProtectingControlPoint = 5;
const int ModifierControlPoints::_maxGuardingDist = 750;
ModifierControlPoints::ModifierControlPoints()
{
_alphaControlPointRedControlledIndex = gi.imageindex( "sysimg/icons/mp/cp_alpha_red" );
_alphaControlPointBlueControlledIndex = gi.imageindex( "sysimg/icons/mp/cp_alpha_blue" );
_alphaControlPointNeutralControlledIndex = gi.imageindex( "sysimg/icons/mp/cp_alpha_neutral" );
_betaControlPointRedControlledIndex = gi.imageindex( "sysimg/icons/mp/cp_beta_red" );
_betaControlPointBlueControlledIndex = gi.imageindex( "sysimg/icons/mp/cp_beta_blue" );
_betaControlPointNeutralControlledIndex = gi.imageindex( "sysimg/icons/mp/cp_beta_neutral" );
_deltaControlPointRedControlledIndex = gi.imageindex( "sysimg/icons/mp/cp_delta_red" );
_deltaControlPointBlueControlledIndex = gi.imageindex( "sysimg/icons/mp/cp_delta_blue" );
_deltaControlPointNeutralControlledIndex = gi.imageindex( "sysimg/icons/mp/cp_delta_neutral" );
_gammaControlPointRedControlledIndex = gi.imageindex( "sysimg/icons/mp/cp_gamma_red" );
_gammaControlPointBlueControlledIndex = gi.imageindex( "sysimg/icons/mp/cp_gamma_blue" );
_gammaControlPointNeutralControlledIndex = gi.imageindex( "sysimg/icons/mp/cp_gamma_neutral" );
}
ModifierControlPoints::~ModifierControlPoints()
{
_controlPoints.FreeObjectList();
}
void ModifierControlPoints::init( int maxPlayers )
{
multiplayerManager.cacheMultiplayerFiles( "mp_controlPoints" );
}
void ModifierControlPoints::addPlayer( Player *player )
{
gi.SendServerCommand( player->entnum, "stufftext \"ui_addhud mp_control\"\n" );
}
str ModifierControlPoints::getSpawnPointType( Player *player )
{
return "control";
}
bool ModifierControlPoints::checkRule( const char *rule, bool defaultValue, Player *player )
{
if ( stricmp( rule, "spawnpoints-special" ) == 0 )
return true;
else
return defaultValue;
}
/* int ModifierControlPoints::getStat( Player *player, int statNum, int value )
{
int redControlPoints;
int blueControlPoints;
int i;
ControlPointData *controlPoint;
if ( statNum == STAT_MP_GENERIC1 )
{
// Return the number of control points controlled by the red team
redControlPoints = 0;
for ( i = 1 ; i <= _controlPoints.NumObjects() ; i++ )
{
controlPoint = _controlPoints.AddressOfObjectAt( i );
if ( controlPoint && controlPoint->_controllingTeam && controlPoint->_controllingTeam->getName() == "Red" )
{
redControlPoints++;
}
}
return redControlPoints;
}
else if ( statNum == STAT_MP_GENERIC2 )
{
// Return the number of control points controlled by the blue team
blueControlPoints = 0;
for ( i = 1 ; i <= _controlPoints.NumObjects() ; i++ )
{
controlPoint = _controlPoints.AddressOfObjectAt( i );
if ( controlPoint && controlPoint->_controllingTeam && controlPoint->_controllingTeam->getName() == "Blue" )
{
blueControlPoints++;
}
}
return blueControlPoints;
}
return value;
} */
bool ModifierControlPoints::shouldKeepItem( MultiplayerItem *item )
{
ControlPointData controlPoint;
if ( strnicmp( item->getName().c_str(), "controlpoint-", strlen( "controlpoint-" ) ) == 0 )
//if ( strnicmp( item->getName().c_str(), "controlpoint", strlen( "controlpoint" ) ) == 0 )
{
// This is a control point, add it to the list
controlPoint._controlPoint = item;
controlPoint._controllingTeam = NULL;
controlPoint._lastControllingTeam = NULL;
controlPoint._lastTime = 0.0f;
controlPoint._controlPointType = getControlPointType( item->getName() );
//controlPoint._controlPointType = (ControlPointType)( _controlPoints.NumObjects() + 1);
_controlPoints.AddObject( controlPoint );
return true;
}
else
return false;
}
ControlPointType ModifierControlPoints::getControlPointType( const str &name )
{
if ( name == "controlpoint-alpha" )
return CONTROL_POINT_ALPHA;
else if ( name == "controlpoint-beta" )
return CONTROL_POINT_BETA;
else if ( name == "controlpoint-delta" )
return CONTROL_POINT_DELTA;
else if ( name == "controlpoint-gamma" )
return CONTROL_POINT_GAMMA;
else
return CONTROL_POINT_NONE;
}
void ModifierControlPoints::itemTouched( Player *player, MultiplayerItem *item )
{
int i;
ControlPointData *controlPoint;
Team *team;
str animName;
str printString;
// Find the control point
for ( i = 1 ; i <= _controlPoints.NumObjects() ; i++ )
{
controlPoint = _controlPoints.AddressOfObjectAt( i );
if ( controlPoint->_controlPoint == item )
{
// This is the control point that was touched
team = multiplayerManager.getPlayersTeam( player );
// Transfer control if a different team
if ( team != controlPoint->_controllingTeam )
{
controlPoint->_controllingTeam = team;
controlPoint->_lastTime = multiplayerManager.getTime();
// TODO, clear this if the player quits
controlPoint->_lastPlayerToTouch = player->entnum;
controlPoint->_playerPointsAwardedForCapture = 0;
// Change the control point based on who controls it
animName = "control_";
animName += controlPoint->_controllingTeam->getName();
controlPoint->_controlPoint->animate->RandomAnimate( animName );
multiplayerManager.playerSound( player->entnum, "localization/sound/dialog/dm/comp_ctrltaken.mp3", CHAN_AUTO, DEFAULT_VOL, DEFAULT_MIN_DIST, 1.2f );
}
}
}
}
void ModifierControlPoints::update( float frameTime )
{
int i;
ControlPointData *controlPoint;
// Loop through all control points
for ( i = 1 ; i <= _controlPoints.NumObjects() ; i++ )
{
controlPoint = _controlPoints.AddressOfObjectAt( i );
// See if this control point is controlled by a team
if ( controlPoint->_controllingTeam )
{
if ( multiplayerManager.getTime() > controlPoint->_lastTime + _timeNeededToControl )
{
// The team has controlled it for long enough
controlPoint->_controllingTeam->addPoints( NULL, 1 );
controlPoint->_lastTime = multiplayerManager.getTime();
if ( controlPoint->_playerPointsAwardedForCapture < _maxNumberAwardsForPlayerCapture )
{
if ( controlPoint->_playerPointsAwardedForCapture == 0 )
{
if ( controlPoint->_controllingTeam && ( controlPoint->_lastControllingTeam != controlPoint->_controllingTeam ) )
{
str soundName;
if ( controlPoint->_controllingTeam->getName() == "Red" )
{
if ( controlPoint->_controlPointType == CONTROL_POINT_ALPHA )
soundName = "localization/sound/dialog/dm/comp_ctrlredalpha.mp3";
else if ( controlPoint->_controlPointType == CONTROL_POINT_BETA )
soundName = "localization/sound/dialog/dm/comp_ctrlredbeta.mp3";
else if ( controlPoint->_controlPointType == CONTROL_POINT_DELTA )
soundName = "localization/sound/dialog/dm/comp_ctrlreddelta.mp3";
else if ( controlPoint->_controlPointType == CONTROL_POINT_GAMMA )
soundName = "localization/sound/dialog/dm/comp_ctrlredgamma.mp3";
}
else
{
if ( controlPoint->_controlPointType == CONTROL_POINT_ALPHA )
soundName = "localization/sound/dialog/dm/comp_ctrlbluealpha.mp3";
else if ( controlPoint->_controlPointType == CONTROL_POINT_BETA )
soundName = "localization/sound/dialog/dm/comp_ctrlbluebeta.mp3";
else if ( controlPoint->_controlPointType == CONTROL_POINT_DELTA )
soundName = "localization/sound/dialog/dm/comp_ctrlbluedelta.mp3";
else if ( controlPoint->_controlPointType == CONTROL_POINT_GAMMA )
soundName = "localization/sound/dialog/dm/comp_ctrlbluegamma.mp3";
}
multiplayerManager.broadcastSound( soundName, CHAN_AUTO, DEFAULT_VOL, DEFAULT_MIN_DIST, NULL, 1.5f );
}
}
controlPoint->_lastControllingTeam = controlPoint->_controllingTeam;
controlPoint->_playerPointsAwardedForCapture++;
if ( controlPoint->_lastPlayerToTouch >= 0 )
{
multiplayerManager.addPoints( controlPoint->_lastPlayerToTouch, _pointsForEachAwardForCapture );
}
}
}
}
}
}
void ModifierControlPoints::playerKilled( Player *killedPlayer, Player *attackingPlayer, Entity *inflictor, int meansOfDeath )
{
Team *victimsTeam;
Team *killersTeam;
float distance;
str printString;
bool controlPointGuarded;
if ( !attackingPlayer || ( killedPlayer == attackingPlayer ) )
return;
victimsTeam = multiplayerManager.getPlayersTeam( killedPlayer );
killersTeam = multiplayerManager.getPlayersTeam( attackingPlayer );
if ( victimsTeam && killersTeam && ( victimsTeam == killersTeam ) )
return;
// See if the player was guarding a control point (either he or the killed player was close to his flag)
controlPointGuarded = false;
distance = findNearestControlledControlPoint( killersTeam->getName(), attackingPlayer->origin );
if ( ( distance > 0 ) && ( distance < _maxGuardingDist ) )
{
controlPointGuarded = true;
}
else
{
distance = findNearestControlledControlPoint( killersTeam->getName(), killedPlayer->origin );
if ( ( distance > 0 ) && ( distance < _maxGuardingDist ) )
{
controlPointGuarded = true;
}
}
if ( controlPointGuarded )
{
//multiplayerManager.playerEventNotification( "controlpoint-guarded", "", attackingPlayer );
printString = "$$ControlPointGuarded$$ ";
printString += attackingPlayer->client->pers.netname;
multiplayerManager.playerSound( attackingPlayer->entnum, "localization/sound/dialog/dm/comp_ctrlguarded.mp3", CHAN_AUTO, DEFAULT_VOL, DEFAULT_MIN_DIST, 1.5f );
multiplayerManager.centerPrintTeamClients( attackingPlayer, printString, CENTERPRINT_IMPORTANCE_HIGH );
// Give points to the player
multiplayerManager.addPoints( attackingPlayer->entnum, _pointsForProtectingControlPoint );
}
}
float ModifierControlPoints::findNearestControlledControlPoint( const str &teamName, const Vector &position )
{
int i;
float nearestDistance = -1.0f;
Vector diff;
float distance;
ControlPointData *controlPoint;
ControlPointData *nearestControlledControlPoint = NULL;
// Loop through all of the control points
for ( i = 1 ; i <= _controlPoints.NumObjects() ; i++ )
{
controlPoint = _controlPoints.AddressOfObjectAt( i );
// See if this control point is controlled by the specified team
if ( controlPoint->_controllingTeam && ( controlPoint->_controllingTeam->getName() == teamName ) &&
( controlPoint->_playerPointsAwardedForCapture > 0 ) )
{
// Get the distance from the control point to the specified point
diff = position - controlPoint->_controlPoint->origin;
distance = diff.length();
// See if this is the nearest controlled control point
if ( !nearestControlledControlPoint || ( distance < nearestDistance ) )
{
nearestControlledControlPoint = controlPoint;
nearestDistance = distance;
}
}
}
return nearestDistance;
}
int ModifierControlPoints::getStat( Player *player, int statNum, int value )
{
int redControlledIndex;
int blueControlledIndex;
int neutralControlledIndex;
ControlPointData *controlPoint;
int i;
ControlPointType controlPointType;
// Figure out which control point we are referring to (if any) and the set of icons to use
if ( ( statNum == STAT_MP_GENERIC5 ) )
{
controlPointType = CONTROL_POINT_ALPHA;
redControlledIndex = _alphaControlPointRedControlledIndex;
blueControlledIndex = _alphaControlPointBlueControlledIndex;
neutralControlledIndex = _alphaControlPointNeutralControlledIndex;
}
else if ( ( statNum == STAT_MP_GENERIC6 ) )
{
controlPointType = CONTROL_POINT_BETA;
redControlledIndex = _betaControlPointRedControlledIndex;
blueControlledIndex = _betaControlPointBlueControlledIndex;
neutralControlledIndex = _betaControlPointNeutralControlledIndex;
}
else if ( ( statNum == STAT_MP_GENERIC7 ) )
{
controlPointType = CONTROL_POINT_DELTA;
redControlledIndex = _deltaControlPointRedControlledIndex;
blueControlledIndex = _deltaControlPointBlueControlledIndex;
neutralControlledIndex = _deltaControlPointNeutralControlledIndex;
}
else if ( ( statNum == STAT_MP_GENERIC8 ) )
{
controlPointType = CONTROL_POINT_GAMMA;
redControlledIndex = _gammaControlPointRedControlledIndex;
blueControlledIndex = _gammaControlPointBlueControlledIndex;
neutralControlledIndex = _gammaControlPointNeutralControlledIndex;
}
else
{
return value;
}
// Find this control point
for ( i = 1 ; i <= _controlPoints.NumObjects() ; i++ )
{
controlPoint = _controlPoints.AddressOfObjectAt( i );
if ( controlPoint->_controlPointType == controlPointType )
{
// Return the correct index based on which team controls this control point
if ( !controlPoint->_controllingTeam )
{
return neutralControlledIndex;
}
else if ( controlPoint->_controllingTeam->getName() == "Red" )
{
return redControlledIndex;
}
else if ( controlPoint->_controllingTeam->getName() == "Blue" )
{
return blueControlledIndex;
}
}
}
return value;
}
/* int ModifierControlPoints::getPointsForKill( Player *killedPlayer, Player *attackingPlayer, Entity *inflictor, int meansOfDeath, int points )
{
// Players do not get points for kills in control points mode
return 0;
} */
// Setup constants
const float ModifierAutoHandicap::_attackerHandicapModifier = 1.05f;
const float ModifierAutoHandicap::_victimHandicapModifier = 1.05f;
ModifierAutoHandicap::ModifierAutoHandicap()
{
_playerHandicapData = NULL;
}
ModifierAutoHandicap::~ModifierAutoHandicap()
{
delete [] _playerHandicapData;
_playerHandicapData = NULL;
}
void ModifierAutoHandicap::init( int maxPlayers )
{
_playerHandicapData = new HandicapPlayerData[ maxPlayers ];
}
void ModifierAutoHandicap::addPlayer( Player *player )
{
_playerHandicapData[ player->entnum ].reset();
}
float ModifierAutoHandicap::playerDamaged( Player *damagedPlayer, Player *attackingPlayer, float damage, int meansOfDeath )
{
if ( damagedPlayer == attackingPlayer )
return damage;
// Change the damage based on the damaged and the attacking player's current handicap
return damage * _playerHandicapData[ attackingPlayer->entnum ]._handicap /
_playerHandicapData[ damagedPlayer->entnum ]._handicap;
}
void ModifierAutoHandicap::playerKilled( Player *killedPlayer, Player *attackingPlayer, Entity *inflictor, int meansOfDeath )
{
if ( killedPlayer == attackingPlayer || !attackingPlayer )
return;
// Make it harder for the attacker to get another kill
_playerHandicapData[ attackingPlayer->entnum ]._handicap /= _attackerHandicapModifier;
// Make it easier for the victim to get kills
_playerHandicapData[ killedPlayer->entnum ]._handicap *= _victimHandicapModifier;
}
// Setup constants
const float ModifierActionHero::_actionHeroRegenRate = 5.0f;
const int ModifierActionHero::_extraPointsForKillingActionHero = 4;
ModifierActionHero::ModifierActionHero()
{
_actionHeroNum = -1;
_healthRegenRate = _actionHeroRegenRate;
_actionHeroIconIndex = gi.imageindex( "sysimg/icons/mp/actionhero" );
_actionHeroInfoIconIndex = gi.imageindex( "sysimg/icons/mp/actionhero_icon" );
}
void ModifierActionHero::init( int maxPlayers )
{
multiplayerManager.cacheMultiplayerFiles( "mp_actionhero" );
}
void ModifierActionHero::matchStarting( void )
{
_actionHeroNum = -1;
}
void ModifierActionHero::removePlayer( Player *player )
{
if ( player->entnum == _actionHeroNum )
{
// Action hero left the game so make action hero up for grabs
multiplayerManager.centerPrintAllClients( "$$ActionHeroLeft$$", CENTERPRINT_IMPORTANCE_NORMAL );
_actionHeroNum = -1;
}
}
void ModifierActionHero::update( float frameTime )
{
float healthToRegen;
Player *player;
// Regen the action hero's health a little
if ( _actionHeroNum != -1 )
{
healthToRegen = _healthRegenRate * frameTime;
player = multiplayerManager.getPlayer( _actionHeroNum );
if ( player )
{
if ( player->canRegenerate() )
{
multiplayerManager.addPlayerHealth( _actionHeroNum, healthToRegen );
}
}
}
}
void ModifierActionHero::playerKilled( Player *killedPlayer, Player *attackingPlayer, Entity *inflictor, int meansOfDeath )
{
// Make sure everything is ok
if ( !killedPlayer )
return;
// Always stop being the action hero if you die for any reason
if ( killedPlayer->entnum == _actionHeroNum )
{
Event *removeAttachedModel = new Event( EV_RemoveAttachedModelByTargetname );
removeAttachedModel->AddString( "actionHero" );
killedPlayer->ProcessEvent( removeAttachedModel );
}
if ( !attackingPlayer || ( killedPlayer == attackingPlayer ) )
{
if ( killedPlayer->entnum == _actionHeroNum )
{
_actionHeroNum = -1;
multiplayerManager.centerPrintAllClients( "$$ActionHeroDead$$", CENTERPRINT_IMPORTANCE_NORMAL );
}
return;
}
if ( ( _actionHeroNum == -1 ) || ( killedPlayer->entnum == _actionHeroNum ) )
{
// This is either the first kill or the attacking player killed the action hero, either way we have
// a new actio hero
// Give extra points if the last action hero was killed
if ( _actionHeroNum != -1 )
{
multiplayerManager.addPoints( attackingPlayer->entnum, _extraPointsForKillingActionHero );
}
// Make the killer the action hero
_actionHeroNum = attackingPlayer->entnum;
multiplayerManager.givePlayerItem( attackingPlayer->entnum, "models/weapons/worldmodel-attrex-rifle.tik" );
multiplayerManager.givePlayerItem( attackingPlayer->entnum, "models/weapons/worldmodel-burstrifle.tik" );
multiplayerManager.givePlayerItem( attackingPlayer->entnum, "models/weapons/worldmodel-compressionrifle.tik" );
multiplayerManager.givePlayerItem( attackingPlayer->entnum, "models/weapons/worldmodel-drull-staff.tik" );
multiplayerManager.givePlayerItem( attackingPlayer->entnum, "models/weapons/worldmodel-fieldassaultrifle.tik" );
multiplayerManager.givePlayerItem( attackingPlayer->entnum, "models/weapons/worldmodel-grenadelauncher.tik" );
multiplayerManager.givePlayerItem( attackingPlayer->entnum, "models/weapons/worldmodel-imod.tik" );
multiplayerManager.givePlayerItem( attackingPlayer->entnum, "models/weapons/worldmodel-photon.tik" );
multiplayerManager.givePlayerItem( attackingPlayer->entnum, "models/weapons/worldmodel-rom-disruptor.tik" );
multiplayerManager.givePlayerItem( attackingPlayer->entnum, "models/weapons/worldmodel-rom-radgun.tik" );
multiplayerManager.givePlayerItem( attackingPlayer->entnum, "models/weapons/worldmodel-sniperrifle.tik" );
multiplayerManager.givePlayerItem( attackingPlayer->entnum, "models/weapons/worldmodel-tetryon.tik" );
multiplayerManager.givePlayerItem( attackingPlayer->entnum, "models/weapons/worldmodel-tricorder.tik" );
attackingPlayer->GiveAmmo( "Plasma", 400, false, 400 );
attackingPlayer->GiveAmmo( "Fed", 400, false, 400 );
attackingPlayer->GiveAmmo( "Idryll", 400, false, 400 );
multiplayerManager.centerPrintAllClients( va( "%s $$NowActionHero$$", attackingPlayer->client->pers.netname ), CENTERPRINT_IMPORTANCE_NORMAL );
multiplayerManager.broadcastSound( "localization/sound/dialog/dm/comp_nah.mp3", CHAN_AUTO, DEFAULT_VOL, DEFAULT_MIN_DIST, NULL, 1.2f );
Event *attachModel = new Event( EV_AttachModel );
attachModel->AddString( "models/fx/fx-actionHero.tik" );
attachModel->AddString( "Bip01" );
attachModel->AddFloat( 1.0f );
attachModel->AddString( "actionHero" );
attackingPlayer->ProcessEvent( attachModel );
// Max the player's health
attackingPlayer->addHealth( 100.0f );
// Max the player's armor
Event *armorEvent = new Event( EV_Sentient_GiveArmor );
armorEvent->AddString( "BasicArmor" );
armorEvent->AddFloat( 200.0f );
armorEvent->AddInteger( false );
attackingPlayer->ProcessEvent( armorEvent );
}
}
int ModifierActionHero::getIcon( Player *player, int statNum, int value )
{
if ( statNum == STAT_MP_SPECIALTY_ICON )
{
// Return the action hero icon if this player is the action hero
if ( _actionHeroNum == player->entnum )
return _actionHeroIconIndex;
else
return -1;
}
return value;
}
int ModifierActionHero::getInfoIcon( Player *player )
{
if ( _actionHeroNum == player->entnum )
return _actionHeroInfoIconIndex;
else
return 0;
}
int ModifierActionHero::getScoreIcon( Player *player, int index, int value )
{
if ( index == SCOREICON2 )
{
if ( _actionHeroNum == player->entnum )
return _actionHeroIconIndex;
else
return 0;
}
return value;
}
ModifierPointsPerWeapon::~ModifierPointsPerWeapon()
{
_weapons.FreeObjectList();
_projectiles.FreeObjectList();
}
void ModifierPointsPerWeapon::init( int maxPlayers )
{
// Read in all of the projectile/weapon points data
readMultiplayerConfig( "global/mp_PointsPerWeapon.cfg" );
}
void ModifierPointsPerWeapon::readMultiplayerConfig( const char *configName )
{
Script buffer;
const char *token;
// Make sure the file exists
if ( !gi.FS_Exists( configName ) )
return;
// Load the file
buffer.LoadFile( configName );
// Parse the file
while ( buffer.TokenAvailable( true ) )
{
token = buffer.GetToken( true );
if ( !parseConfigToken( token, &buffer ) )
{
gi.DPrintf( "Token %s from %s not handled by anyone\n", token, configName );
}
}
}
bool ModifierPointsPerWeapon::parseConfigToken( const char *key, Script *buffer )
{
PointsPerWeaponData pointsPerWeaponData;
if ( stricmp( key, "projectile" ) == 0 )
{
// Get projectile name
if ( !buffer->TokenAvailable( false ) )
return false;
pointsPerWeaponData._name = buffer->GetToken( false );
// Get points for this projectile
if ( !buffer->TokenAvailable( false ) )
return false;
pointsPerWeaponData._points = atoi( buffer->GetToken( false ) );
// Add projectile to the projectile list
_projectiles.AddObject( pointsPerWeaponData );
return true;
}
else if ( stricmp( key, "weapon" ) == 0 )
{
// Get weapon name
if ( !buffer->TokenAvailable( false ) )
return false;
pointsPerWeaponData._name = buffer->GetToken( false );
// Get points for this projectile
if ( !buffer->TokenAvailable( false ) )
return false;
pointsPerWeaponData._points = atoi( buffer->GetToken( false ) );
// Add weapon to the weapon list
_weapons.AddObject( pointsPerWeaponData );
return true;
}
return false;
}
int ModifierPointsPerWeapon::getPointsForKill( Player *killedPlayer, Player *attackingPlayer, Entity *inflictor, int meansOfDeath, int points )
{
PointsPerWeaponData *pointsPerWeaponData;
int i;
// Make sure everything is ok
if ( killedPlayer == attackingPlayer )
return points;
if ( points <= 0 )
return points;
// See if the kill was by a projectile or directly from a weapon
if ( inflictor && inflictor->isSubclassOf( Projectile ) )
{
Projectile *proj;
proj = (Projectile *)inflictor;
// Determine the points based off of the projectile
for ( i = 1 ; i <= _projectiles.NumObjects() ; i++ )
{
pointsPerWeaponData = &_projectiles.ObjectAt( i );
if ( stricmp( proj->model.c_str(), pointsPerWeaponData->_name.c_str() ) == 0 )
return pointsPerWeaponData->_points;
}
// Didn't find it so just return the default
return points;
}
else
{
str weaponName;
// Get the name of the weapon
attackingPlayer->getActiveWeaponName( WEAPON_ANY, weaponName );
// Determine the points based off of the weapon
for ( i = 1 ; i <= _weapons.NumObjects() ; i++ )
{
pointsPerWeaponData = &_weapons.ObjectAt( i );
if ( stricmp( weaponName.c_str(), pointsPerWeaponData->_name.c_str() ) == 0 )
return pointsPerWeaponData->_points;
}
// Didn't find it so just return the default
return points;
}
}