game_shared/multiplay_gamerules.cpp
111213141516
#include "gameeventdefs.h"
#include
#ifdef CLIENT_DLL
#else
1112131415161718
#include "gameeventdefs.h"
#include
#include "ff_projectile_base.h"
#ifdef CLIENT_DLL
#else
27282930313233
#include "voice_gamemgr.h"
#include "iscorer.h"
#include "hltvdirector.h"
#endif
// memdbgon must be the last include file in a .cpp file!!!
2930313233343536373839404142
#include "voice_gamemgr.h"
#include "iscorer.h"
#include "hltvdirector.h"
#include "team.h"
// BEG: Added by Mulchman for Buildable Objects
#include "ff_buildableobjects_shared.h"
// END: Added by Mulchman for Buildable Objects
#include "omnibot_interface.h"
#endif
// memdbgon must be the last include file in a .cpp file!!!
45464748495051
true, 120 );
ConVar mp_timelimit( "mp_timelimit",
"0",
FCVAR_NOTIFY|FCVAR_REPLICATED,
"game time per map in minutes" );
54555657585960
true, 120 );
ConVar mp_timelimit( "mp_timelimit",
"20",
FCVAR_NOTIFY|FCVAR_REPLICATED,
"game time per map in minutes" );
53545556575859
ConVar tv_delaymapchange( "tv_delaymapchange",
"0",
0,
"Delays map change until broadcast is complete" );
#endif
62636465666768
ConVar tv_delaymapchange( "tv_delaymapchange",
"0",
FCVAR_NOTIFY|FCVAR_REPLICATED,
"Delays map change until broadcast is complete" );
#endif
123124125126127128
engine->ServerCommand( szCommand );
}
}
}
//=========================================================
132133134135136137138139
engine->ServerCommand( szCommand );
}
}
m_flIntermissionEndTime = 0.f;
}
//=========================================================
380381382383384385386
//=========================================================
//=========================================================
bool CMultiplayRules::FPlayerCanTakeDamage( CBasePlayer *pPlayer, CBaseEntity *pAttacker )
{
return true;
}
391392393394395396397
//=========================================================
//=========================================================
bool CMultiplayRules::FCanTakeDamage( CBaseEntity *pVictim, CBaseEntity *pAttacker )
{
return true;
}
454455456457458459
if ( pKiller->Classify() == CLASS_PLAYER )
return (CBasePlayer*)pKiller;
// Killing entity might be specifying a scorer player
IScorer *pScorerInterface = dynamic_cast( pKiller );
if ( pScorerInterface )
465466467468469470471472473474475476477478479480481482483484485486487
if ( pKiller->Classify() == CLASS_PLAYER )
return (CBasePlayer*)pKiller;
// BEG: Added by Mulchman
// Buildable Objects need to be specifically tested for
// because pScorer in DeathNotice is NULL when someone
// is killed by a Buildable Object (and this in incorrect -
// the owner of the Buildable Object needs to be credited
// with the kill). So, return the appropriate owner of
// the Buildable Object that made the kill.
if( pKiller->Classify( ) == CLASS_DETPACK )
return ( CBasePlayer * )( ( ( CFFDetpack * )pKiller )->m_hOwner.Get() );
if( pKiller->Classify( ) == CLASS_SENTRYGUN )
return ( CBasePlayer * )( ( ( CFFSentryGun * )pKiller )->m_hOwner.Get() );
if( pKiller->Classify( ) == CLASS_DISPENSER )
return ( CBasePlayer * )( ( ( CFFDispenser * )pKiller )->m_hOwner.Get() );
// END: Added by Mulchman
// Killing entity might be specifying a scorer player
IScorer *pScorerInterface = dynamic_cast( pKiller );
if ( pScorerInterface )
486487488489490491492493494495
// Find the killer & the scorer
CBaseEntity *pInflictor = info.GetInflictor();
CBaseEntity *pKiller = info.GetAttacker();
CBasePlayer *pScorer = GetDeathScorer( pKiller, pInflictor );
pVictim->IncrementDeathCount( 1 );
// dvsents2: uncomment when removing all FireTargets
// variant_t value;
// g_EventQueue.AddEvent( "game_playerdie", "Use", value, 0, pVictim, pVictim );
514515516517518519520521522523524525526527528529530531532533534535536537538
// Find the killer & the scorer
CBaseEntity *pInflictor = info.GetInflictor();
CBaseEntity *pKiller = info.GetAttacker();
// Jiggles: Maybe not the best spot to put this, but...
// If the gun killed someone while in malicious sabotage mode
// we want to give credit to the Spy who did it
CFFBuildableObject *pSabotagedBuildable = CFFBuildableObject::AttackerInflictorBuildable(pKiller, pInflictor);
if ( pSabotagedBuildable )
{
if ( pSabotagedBuildable->IsMaliciouslySabotaged() )
pKiller = pSabotagedBuildable->m_hSaboteur;
}
CBasePlayer *pScorer = GetDeathScorer( pKiller, pInflictor );
pVictim->IncrementDeathCount( 1 );
// Bug #0000529: Total death column doesn't work
if( pVictim->GetTeam() )
pVictim->GetTeam()->AddDeaths( 1 );
// dvsents2: uncomment when removing all FireTargets
// variant_t value;
// g_EventQueue.AddEvent( "game_playerdie", "Use", value, 0, pVictim, pVictim );
499500501502503504505506507508509510511512513514
if ( pVictim == pScorer )
{
// Players lose a frag for killing themselves
pVictim->IncrementFragCount( -1 );
}
else if ( pScorer )
{
// if a player dies in a deathmatch game and the killer is a client, award the killer some points
pScorer->IncrementFragCount( IPointsForKill( pScorer, pVictim ) );
// Allow the scorer to immediately paint a decal
pScorer->AllowImmediateDecalPainting();
// dvsents2: uncomment when removing all FireTargets
//variant_t value;
//g_EventQueue.AddEvent( "game_playerkill", "Use", value, 0, pScorer, pScorer );
542543544545546547548549550551552553554555556557558559560561562563564565566567568569
if ( pVictim == pScorer )
{
// Players lose a frag for killing themselves
//Commenting this out so players dont actually lose stuff on suicides
//pVictim->IncrementFragCount( -1 );
//pScorer->AddFortPoints( -100, "#FF_FORTPOINTS_SUICIDE" );
}
else if ( pScorer )
{
// if a player dies in a deathmatch game and the killer is a client, award the killer some points
pScorer->IncrementFragCount( IPointsForKill( pScorer, pVictim ) );
// AfterShock - scoring system : Just award 100 points for frag (for now)
if( PlayerRelationship( pScorer, pVictim ) == GR_TEAMMATE )
{
pScorer->AddFortPoints( -50, "#FF_FORTPOINTS_TEAMKILL" );
}
else
pScorer->AddFortPoints( 100, "#FF_FORTPOINTS_FRAG" );
// Allow the scorer to immediately paint a decal
pScorer->AllowImmediateDecalPainting();
// dvsents2: uncomment when removing all FireTargets
//variant_t value;
//g_EventQueue.AddEvent( "game_playerkill", "Use", value, 0, pScorer, pScorer );
516517518519520521
}
else
{
// Players lose a frag for letting the world kill them
pVictim->IncrementFragCount( -1 );
}
571572573574575576577578579580
}
else
{
// Bug #0000622: Dying by respawn turret gives you a suicide
if( pKiller && ( pKiller->Classify() == CLASS_TURRET ) )
return;
// Players lose a frag for letting the world kill them
pVictim->IncrementFragCount( -1 );
}
526527528529530531532533534535536537538539540541542543544545546547548549550551
//=========================================================
void CMultiplayRules::DeathNotice( CBasePlayer *pVictim, const CTakeDamageInfo &info )
{
// Work out what killed the player, and send a message to all clients about it
const char *killer_weapon_name = "world"; // by default, the player is killed by the world
int killer_ID = 0;
// Find the killer & the scorer
CBaseEntity *pInflictor = info.GetInflictor();
CBaseEntity *pKiller = info.GetAttacker();
CBasePlayer *pScorer = GetDeathScorer( pKiller, pInflictor );
// Custom kill type?
if ( info.GetCustomKill() )
{
killer_weapon_name = GetCustomKillString( info );
if ( pScorer )
{
killer_ID = pScorer->GetUserID();
}
}
else
{
// Is the killer a client?
if ( pScorer )
{
585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662
//=========================================================
void CMultiplayRules::DeathNotice( CBasePlayer *pVictim, const CTakeDamageInfo &info )
{
//UTIL_LogPrintf("CMultiplayRules::DeathNotice\n");
// Work out what killed the player, and send a message to all clients about it
const char *killer_weapon_name = "world"; // by default, the player is killed by the world
int killer_ID = 0;
int iKilledSGLevel = 0;
int iKillerSGLevel = 0;
// Find the killer & the scorer
CBaseEntity *pInflictor = info.GetInflictor();
CBaseEntity *pKiller = info.GetAttacker();
// Removed, this is now handled further on
// Hack for sg rockets (might break other stuff?)
//if( pKiller->Classify() == CLASS_SENTRYGUN )
// pInflictor = pKiller;
// Jiggles: Maybe not the best spot to put this, but...
// If the gun killed someone while in malicious sabotage mode
// we want to give credit to the Spy who did it
CFFBuildableObject *pSabotagedBuildable = CFFBuildableObject::AttackerInflictorBuildable(pKiller, pInflictor);
if ( pSabotagedBuildable )
{
if ( pSabotagedBuildable->IsMaliciouslySabotaged() )
pKiller = pSabotagedBuildable->m_hSaboteur;
}
// get level of SG if the killer is an SG
CFFBuildableObject *pBuildable = CFFBuildableObject::AttackerInflictorBuildable(pKiller, pInflictor);
if ( pBuildable )
{
if ( pBuildable->Classify() == CLASS_SENTRYGUN )
{
CFFSentryGun *pSentryGun = FF_ToSentrygun( pBuildable );
if (pSentryGun->GetLevel() == 1)
iKillerSGLevel = 1;
else if (pSentryGun->GetLevel() == 2)
iKillerSGLevel = 2;
else if (pSentryGun->GetLevel() == 3)
iKillerSGLevel = 3;
else
DevMsg( "Unknown SG level :(" );
}
}
/*
// HACK: Check for special infection deaths
if( pVictim->IsPlayer() )
{
CFFPlayer *pFFPlayer = ToFFPlayer( pVictim );
if( pFFPlayer && pFFPlayer->GetSpecialInfectedDeath() )
{
// Set killer & attacker to the medic
// that infected the victim
pInflictor = pFFPlayer->GetInfector();
pKiller = pFFPlayer->GetInfector();
}
}
*/
CBasePlayer *pScorer = GetDeathScorer( pKiller, pInflictor );
// Custom kill type?
//if ( info.GetCustomKill() )
//{
// killer_weapon_name = GetCustomKillString( info );
// if ( pScorer )
// {
// killer_ID = pScorer->GetUserID();
// }
//}
//else
{
// Is the killer a client?
if ( pScorer )
{
572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602
killer_weapon_name = STRING( pInflictor->m_iClassname );
}
// strip the NPC_* or weapon_* from the inflictor's classname
if ( strncmp( killer_weapon_name, "weapon_", 7 ) == 0 )
{
killer_weapon_name += 7;
}
else if ( strncmp( killer_weapon_name, "NPC_", 8 ) == 0 )
{
killer_weapon_name += 8;
}
else if ( strncmp( killer_weapon_name, "func_", 5 ) == 0 )
{
killer_weapon_name += 5;
}
}
IGameEvent * event = gameeventmanager->CreateEvent( "player_death" );
if ( event )
{
event->SetInt("userid", pVictim->GetUserID() );
event->SetInt("attacker", killer_ID );
event->SetInt("priority", 7 ); // HLTV event priority, not transmitted
gameeventmanager->FireEvent( event );
}
}
//=========================================================
683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792
killer_weapon_name = STRING( pInflictor->m_iClassname );
}
// --> Mirv: Special case for projectiles
CFFProjectileBase *pProjectile = dynamic_cast (pInflictor);
if (pProjectile && pProjectile->m_iSourceClassname != NULL_STRING)
{
killer_weapon_name = STRING(pProjectile->m_iSourceClassname);
}
// Another important thing to do is to make sure that mirvlet = mirv
// in the death messages
if (Q_strncmp(killer_weapon_name, "ff_grenade_mirvlet", 18) == 0)
{
killer_weapon_name = "ff_grenade_mirv";
}
// <-- Mirv
//fixes for certain time based damage.
switch(info.GetCustomKill())
{
case KILLTYPE_INFECTION:
killer_weapon_name = "ff_weapon_medkit";
break;
case KILLTYPE_BURN_LEVEL1:
killer_weapon_name = "ff_burndeath_level1";
break;
case KILLTYPE_BURN_LEVEL2:
killer_weapon_name = "ff_burndeath_level2";
break;
case KILLTYPE_BURN_LEVEL3:
killer_weapon_name = "ff_burndeath_level3";
break;
case KILLTYPE_GASSED:
killer_weapon_name = "ff_grenade_gas";
break;
case KILLTYPE_HEADSHOT:
killer_weapon_name = "BOOM_HEADSHOT"; // BOOM HEADSHOT! AAAAAAAAHHHH!
break;
case KILLTYPE_BACKSTAB:
killer_weapon_name = "backstab";
break;
case KILLTYPE_SENTRYGUN_DET:
killer_weapon_name = "sg_det";
break;
case KILLTYPE_HEADCRUSH:
killer_weapon_name = "headcrush";
break;
}
//UTIL_LogPrintf(" killer_ID: %i\n",killer_ID);
//UTIL_LogPrintf(" killer_weapon_name: %s\n",killer_weapon_name);
// strip the NPC_* or weapon_* from the inflictor's classname
if ( Q_strnicmp( killer_weapon_name, "weapon_", 7 ) == 0 )
{
//UTIL_LogPrintf(" begins with weapon_, removing\n");
killer_weapon_name += 7;
}
else if ( Q_strnicmp( killer_weapon_name, "NPC_", 8 ) == 0 )
{
//UTIL_LogPrintf(" begins with NPC_, removing\n");
killer_weapon_name += 8;
}
else if ( Q_strnicmp( killer_weapon_name, "func_", 5 ) == 0 )
{
//UTIL_LogPrintf(" begins with func_, removing\n");
killer_weapon_name += 5;
}
// BEG: Added by Mulchman for ff_ entities
else if( Q_strnicmp( killer_weapon_name, "ff_", 3 ) == 0 )
{
//UTIL_LogPrintf( " begins with ff_, removing\n" );
killer_weapon_name += 3;
}
// END: Added by Mulchman for FF_ entities
}
//UTIL_LogPrintf(" userid (victim): %i\n",pVictim->GetUserID());
//UTIL_LogPrintf(" attacker: %i\n",killer_ID);
//UTIL_LogPrintf(" weapon: %s\n",killer_weapon_name);
IGameEvent * event = gameeventmanager->CreateEvent( "player_death" );
if ( event )
{
event->SetInt("userid", pVictim->GetUserID() );
event->SetInt("attacker", killer_ID );
event->SetString("weapon", killer_weapon_name);
event->SetInt("killedsglevel", iKilledSGLevel);
event->SetInt("killersglevel", iKillerSGLevel);
event->SetInt("priority", 10 );
// #0001568: Falling into pitt damage shows electrocution icon, instead of falling damage icon
// Added damagetype field to the player_death message. This field records the type of damage dealt by a trigger_hurt
// so, further down the road, we can determine which death icon to use (e.g. fall, drown, shock) instead of generic -> Defrag
// if a trigger hurt is causing the damage, add its damage type to the event. Otherwise, use DMG_GENERIC
if( Q_stricmp( killer_weapon_name, "trigger_hurt" ) == 0 )
event->SetInt("damagetype", info.GetDamageType() );
else
event->SetInt("damagetype", DMG_GENERIC );
gameeventmanager->FireEvent( event );
}
Omnibot::Notify_Death(pVictim, pKiller, killer_weapon_name);
}
//=========================================================
772773774775776777778
//=========================================================
int CMultiplayRules::DeadPlayerWeapons( CBasePlayer *pPlayer )
{
return GR_PLR_DROP_GUN_ACTIVE;
}
//=========================================================
962963964965966967968969
//=========================================================
int CMultiplayRules::DeadPlayerWeapons( CBasePlayer *pPlayer )
{
// Modified by L0ki: we dont drop weapons in FF
return GR_PLR_DROP_GUN_NO;
}
//=========================================================
779780781782783784785
//=========================================================
int CMultiplayRules::DeadPlayerAmmo( CBasePlayer *pPlayer )
{
return GR_PLR_DROP_AMMO_ACTIVE;
}
CBaseEntity *CMultiplayRules::GetPlayerSpawnSpot( CBasePlayer *pPlayer )
970971972973974975976977
//=========================================================
int CMultiplayRules::DeadPlayerAmmo( CBasePlayer *pPlayer )
{
// Modified by L0ki: we drop all ammo types in FF
return GR_PLR_DROP_AMMO_ALL;
}
CBaseEntity *CMultiplayRules::GetPlayerSpawnSpot( CBasePlayer *pPlayer )
831832833834835836837838
//=========================================================
bool CMultiplayRules::FAllowNPCs( void )
{
return true; // E3 hack
return ( allowNPCs.GetInt() != 0 );
}
//=========================================================
102310241025102610271028102910301031
//=========================================================
bool CMultiplayRules::FAllowNPCs( void )
{
//return true; // E3 hack
//return ( allowNPCs.GetInt() != 0 );
return false; // Jiggles: No need for NPCs in FF :)
}
//=========================================================
854855856857858859860
m_flIntermissionEndTime = gpGlobals->curtime + flWaitTime;
for ( int i = 0; i < MAX_PLAYERS; i++ )
{
CBasePlayer *pPlayer = UTIL_PlayerByIndex( i );
1047104810491050105110521053
m_flIntermissionEndTime = gpGlobals->curtime + flWaitTime;
for ( int i = 1; i <= MAX_PLAYERS; i++ )
{
CBasePlayer *pPlayer = UTIL_PlayerByIndex( i );
862863864865866867868
continue;
pPlayer->ShowViewPortPanel( PANEL_SCOREBOARD );
}
}
void CMultiplayRules::GetNextLevelName( char *pszNextMap, int bufsize )
10551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092
continue;
pPlayer->ShowViewPortPanel( PANEL_SCOREBOARD );
// --> Mirv: Lock into place too
CFFPlayer *pFFPlayer = ToFFPlayer(pPlayer);
pFFPlayer->LockPlayerInPlace();
pFFPlayer->AddFlag(FL_FROZEN);
if ( Q_atoi( engine->GetClientConVarValue( pFFPlayer->entindex(), "hud_takesshots" ) ) )
engine->ClientCommand( pFFPlayer->edict(), "jpeg" );
if (CFFWeaponBase *pWeapon = pFFPlayer->GetActiveFFWeapon())
pWeapon->Holster();
// <-- Mirv
}
IGameEvent *pEvent = gameeventmanager->CreateEvent("game_end");
if(pEvent)
{
//////////////////////////////////////////////////////////////////////////
CTeam *pWinningTeam = 0;
for( int i = 0; i < GetNumberOfTeams(); i++ )
{
CTeam *pTeam = GetGlobalTeam(i);
if(pTeam)
{
if(!pWinningTeam || (pTeam->GetScore() > pWinningTeam->GetScore()))
pWinningTeam = pTeam;
}
}
//////////////////////////////////////////////////////////////////////////
pEvent->SetInt("winner", pWinningTeam ? pWinningTeam->GetTeamNumber() : 0);
gameeventmanager->FireEvent(pEvent);
}
}
void CMultiplayRules::GetNextLevelName( char *pszNextMap, int bufsize )