//----------------------------------------------------------------------------- // // $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; } }