2019-09-23 00:09:58 +03:00
# include "precompiled.h"
CCStrikeGameMgrHelper g_GameMgrHelper ;
CHalfLifeMultiplay * g_pMPGameRules = nullptr ;
RewardAccount CHalfLifeMultiplay : : m_rgRewardAccountRules [ RR_END ] ;
RewardAccount CHalfLifeMultiplay : : m_rgRewardAccountRules_default [ ] = {
REWARD_CTS_WIN , // RR_CTS_WIN
REWARD_TERRORISTS_WIN , // RR_TERRORISTS_WIN
REWARD_TARGET_BOMB , // RR_TARGET_BOMB
REWARD_VIP_ESCAPED , // RR_VIP_ESCAPED
REWARD_VIP_ASSASSINATED , // RR_VIP_ASSASSINATED
REWARD_TERRORISTS_ESCAPED , // RR_TERRORISTS_ESCAPED
REWARD_CTS_PREVENT_ESCAPE , // RR_CTS_PREVENT_ESCAPE
REWARD_ESCAPING_TERRORISTS_NEUTRALIZED , // RR_ESCAPING_TERRORISTS_NEUTRALIZED
REWARD_BOMB_DEFUSED , // RR_BOMB_DEFUSED
REWARD_BOMB_PLANTED , // RR_BOMB_PLANTED
REWARD_BOMB_EXPLODED , // RR_BOMB_EXPLODED
REWARD_ALL_HOSTAGES_RESCUED , // RR_ALL_HOSTAGES_RESCUED
REWARD_TARGET_BOMB_SAVED , // RR_TARGET_BOMB_SAVED
REWARD_HOSTAGE_NOT_RESCUED , // RR_HOSTAGE_NOT_RESCUED
REWARD_VIP_NOT_ESCAPED , // RR_VIP_NOT_ESCAPED
REWARD_LOSER_BONUS_DEFAULT , // RR_LOSER_BONUS_DEFAULT
REWARD_LOSER_BONUS_MIN , // RR_LOSER_BONUS_MIN
REWARD_LOSER_BONUS_MAX , // RR_LOSER_BONUS_MAX
REWARD_LOSER_BONUS_ADD , // RR_LOSER_BONUS_ADD
REWARD_RESCUED_HOSTAGE , // RR_RESCUED_HOSTAGE
REWARD_TOOK_HOSTAGE_ACC , // RR_TOOK_HOSTAGE_ACC
REWARD_TOOK_HOSTAGE , // RR_TOOK_HOSTAGE
} ;
bool IsBotSpeaking ( )
{
for ( int i = 1 ; i < = gpGlobals - > maxClients ; i + + )
{
CBasePlayer * pPlayer = UTIL_PlayerByIndex ( i ) ;
2024-05-28 18:44:29 +03:00
if ( ! UTIL_IsValidPlayer ( pPlayer ) )
continue ;
if ( ! pPlayer - > IsBot ( ) )
2019-09-23 00:09:58 +03:00
continue ;
CCSBot * pBot = static_cast < CCSBot * > ( pPlayer ) ;
if ( pBot - > IsUsingVoice ( ) )
return true ;
}
return false ;
}
bool CHalfLifeMultiplay : : IsInCareerRound ( )
{
return IsMatchStarted ( ) ? false : true ;
}
void CHalfLifeMultiplay : : SetCareerMatchLimit ( int minWins , int winDifference )
{
if ( ! IsCareer ( ) )
{
return ;
}
if ( ! m_iCareerMatchWins )
{
m_iCareerMatchWins = minWins ;
m_iRoundWinDifference = winDifference ;
}
}
BOOL CHalfLifeMultiplay : : IsCareer ( )
{
return IS_CAREER_MATCH ( ) ;
}
LINK_HOOK_CLASS_VOID_CUSTOM_CHAIN2 ( CHalfLifeMultiplay , CSGameRules , ServerDeactivate )
void EXT_FUNC CHalfLifeMultiplay : : __API_HOOK ( ServerDeactivate ) ( )
{
if ( ! IsCareer ( ) )
{
return ;
}
CVAR_SET_FLOAT ( " pausable " , 0 ) ;
CVAR_SET_FLOAT ( " mp_windifference " , 1 ) ;
UTIL_LogPrintf ( " Career End \n " ) ;
}
LINK_HOOK_CLASS_CUSTOM_CHAIN ( bool , CCStrikeGameMgrHelper , CSGameRules , CanPlayerHearPlayer , ( CBasePlayer * pListener , CBasePlayer * pSender ) , pListener , pSender )
bool CCStrikeGameMgrHelper : : __API_HOOK ( CanPlayerHearPlayer ) ( CBasePlayer * pListener , CBasePlayer * pSender )
{
2019-12-14 13:24:40 +03:00
# ifdef REGAMEDLL_ADD
if ( ! GetCanHearPlayer ( pListener , pSender ) )
{
return false ;
}
# endif
2019-09-23 00:09:58 +03:00
switch ( ( int ) sv_alltalk . value )
{
case 1 : // allows everyone to talk
return true ;
# ifdef REGAMEDLL_ADD
case 2 :
return ( pListener - > m_iTeam = = pSender - > m_iTeam ) ;
case 3 :
return ( pListener - > m_iTeam = = pSender - > m_iTeam | | pListener - > m_iTeam = = SPECTATOR | | pListener - > m_iTeam = = UNASSIGNED ) ;
case 4 :
return ( pListener - > IsAlive ( ) = = pSender - > IsAlive ( ) | | pSender - > IsAlive ( ) ) ;
2021-06-15 12:59:58 +03:00
case 5 :
return ( ( pListener - > IsAlive ( ) = = pSender - > IsAlive ( ) & & pListener - > m_iTeam = = pSender - > m_iTeam ) | | ! pListener - > IsAlive ( ) ) ;
2019-09-23 00:09:58 +03:00
# endif
default :
{
if (
# ifndef REGAMEDLL_FIXES
! pSender - > IsPlayer ( ) | |
# endif
pListener - > m_iTeam ! = pSender - > m_iTeam ) // Different teams can't hear each other
{
return false ;
}
if ( pListener - > GetObserverMode ( ) ! = OBS_NONE ) // 2 spectators don't need isAlive() checks.
{
return true ;
}
BOOL bListenerAlive = pListener - > IsAlive ( ) ;
BOOL bSenderAlive = pSender - > IsAlive ( ) ;
return ( bListenerAlive = = bSenderAlive | | bSenderAlive ) ; // Dead/alive voice chats are separated, but dead can hear alive.
}
}
}
2019-12-14 13:24:40 +03:00
# ifdef REGAMEDLL_ADD
void CCStrikeGameMgrHelper : : ResetCanHearPlayer ( edict_t * pEdict )
{
int index = ENTINDEX ( pEdict ) - 1 ;
m_iCanHearMasks [ index ] . Init ( TRUE ) ;
for ( int iOtherClient = 0 ; iOtherClient < VOICE_MAX_PLAYERS ; iOtherClient + + )
{
if ( index ! = iOtherClient ) {
m_iCanHearMasks [ iOtherClient ] [ index ] = TRUE ;
}
}
}
void CCStrikeGameMgrHelper : : SetCanHearPlayer ( CBasePlayer * pListener , CBasePlayer * pSender , bool bCanHear )
{
if ( ! pListener - > IsPlayer ( ) | | ! pSender - > IsPlayer ( ) )
{
return ;
}
int listener = pListener - > entindex ( ) - 1 ;
int sender = pSender - > entindex ( ) - 1 ;
m_iCanHearMasks [ listener ] [ sender ] = bCanHear ? TRUE : FALSE ;
}
bool CCStrikeGameMgrHelper : : GetCanHearPlayer ( CBasePlayer * pListener , CBasePlayer * pSender )
{
if ( ! pListener - > IsPlayer ( ) | | ! pSender - > IsPlayer ( ) )
{
return true ;
}
int listener = pListener - > entindex ( ) - 1 ;
int sender = pSender - > entindex ( ) - 1 ;
2019-12-19 11:31:00 +03:00
return m_iCanHearMasks [ listener ] [ sender ] ! = FALSE ;
2019-12-14 13:24:40 +03:00
}
# endif
2019-09-23 00:09:58 +03:00
void Broadcast ( const char * sentence )
{
char text [ 32 ] ;
if ( ! sentence )
{
return ;
}
Q_strcpy ( text , " %!MRAD_ " ) ;
Q_strcat ( text , UTIL_VarArgs ( " %s " , sentence ) ) ;
MESSAGE_BEGIN ( MSG_BROADCAST , gmsgSendAudio ) ;
WRITE_BYTE ( 0 ) ;
WRITE_STRING ( text ) ;
WRITE_SHORT ( PITCH_NORM ) ;
MESSAGE_END ( ) ;
}
char * GetTeam ( int team )
{
switch ( team )
{
case CT : return " CT " ;
case TERRORIST : return " TERRORIST " ;
case SPECTATOR : return " SPECTATOR " ;
default : return " " ;
}
}
void CHalfLifeMultiplay : : EndRoundMessage ( const char * sentence , ScenarioEventEndRound event )
{
char * team = nullptr ;
const char * message = sentence ;
bool bTeamTriggered = true ;
if ( sentence [ 0 ] = = ' # ' )
message = sentence + 1 ;
if ( sentence [ 0 ] )
{
UTIL_ClientPrintAll ( HUD_PRINTCENTER , sentence ) ;
switch ( event )
{
case ROUND_TARGET_BOMB :
case ROUND_VIP_ASSASSINATED :
case ROUND_TERRORISTS_ESCAPED :
case ROUND_TERRORISTS_WIN :
case ROUND_HOSTAGE_NOT_RESCUED :
case ROUND_VIP_NOT_ESCAPED :
team = GetTeam ( TERRORIST ) ;
// tell bots the terrorists won the round
if ( TheBots )
{
TheBots - > OnEvent ( EVENT_TERRORISTS_WIN ) ;
}
break ;
case ROUND_VIP_ESCAPED :
case ROUND_CTS_PREVENT_ESCAPE :
case ROUND_ESCAPING_TERRORISTS_NEUTRALIZED :
case ROUND_BOMB_DEFUSED :
case ROUND_CTS_WIN :
case ROUND_ALL_HOSTAGES_RESCUED :
case ROUND_TARGET_SAVED :
case ROUND_TERRORISTS_NOT_ESCAPED :
team = GetTeam ( CT ) ;
// tell bots the CTs won the round
if ( TheBots )
{
TheBots - > OnEvent ( EVENT_CTS_WIN ) ;
}
break ;
default :
bTeamTriggered = false ;
// tell bots the round was a draw
if ( TheBots )
{
TheBots - > OnEvent ( EVENT_ROUND_DRAW ) ;
}
break ;
}
if ( bTeamTriggered )
{
UTIL_LogPrintf ( " Team \" %s \" triggered \" %s \" (CT \" %i \" ) (T \" %i \" ) \n " , team , message , m_iNumCTWins , m_iNumTerroristWins ) ;
}
else
{
UTIL_LogPrintf ( " World triggered \" %s \" (CT \" %i \" ) (T \" %i \" ) \n " , message , m_iNumCTWins , m_iNumTerroristWins ) ;
}
}
UTIL_LogPrintf ( " World triggered \" Round_End \" \n " ) ;
2024-05-08 16:59:27 +03:00
# ifdef REGAMEDLL_ADD
FireTargets ( " game_round_end " , nullptr , nullptr , USE_TOGGLE , 0.0 ) ;
# endif
2019-09-23 00:09:58 +03:00
}
void CHalfLifeMultiplay : : ReadMultiplayCvars ( )
{
m_iRoundTime = int ( CVAR_GET_FLOAT ( " mp_roundtime " ) * 60 ) ;
m_iC4Timer = int ( CVAR_GET_FLOAT ( " mp_c4timer " ) ) ;
m_iIntroRoundTime = int ( CVAR_GET_FLOAT ( " mp_freezetime " ) ) ;
m_iLimitTeams = int ( CVAR_GET_FLOAT ( " mp_limitteams " ) ) ;
# ifndef REGAMEDLL_ADD
if ( m_iRoundTime > 540 )
{
CVAR_SET_FLOAT ( " mp_roundtime " , 9 ) ;
m_iRoundTime = 540 ;
}
else if ( m_iRoundTime < 60 )
{
CVAR_SET_FLOAT ( " mp_roundtime " , 1 ) ;
m_iRoundTime = 60 ;
}
if ( m_iIntroRoundTime > 60 )
{
CVAR_SET_FLOAT ( " mp_freezetime " , 60 ) ;
m_iIntroRoundTime = 60 ;
}
else if ( m_iIntroRoundTime < 0 )
{
CVAR_SET_FLOAT ( " mp_freezetime " , 0 ) ;
m_iIntroRoundTime = 0 ;
}
if ( m_iC4Timer > 90 )
{
CVAR_SET_FLOAT ( " mp_c4timer " , 90 ) ;
m_iC4Timer = 90 ;
}
else if ( m_iC4Timer < 10 )
{
CVAR_SET_FLOAT ( " mp_c4timer " , 10 ) ;
m_iC4Timer = 10 ;
}
if ( m_iLimitTeams > 20 )
{
CVAR_SET_FLOAT ( " mp_limitteams " , 20 ) ;
m_iLimitTeams = 20 ;
}
else if ( m_iLimitTeams < 0 )
{
CVAR_SET_FLOAT ( " mp_limitteams " , 0 ) ;
m_iLimitTeams = 0 ;
}
# else
// a limit of 500 minutes because
// if you do more minutes would be a bug in the HUD RoundTime in the form 00:00
if ( m_iRoundTime > 30000 )
{
CVAR_SET_FLOAT ( " mp_roundtime " , 500 ) ;
m_iRoundTime = 30000 ;
}
else if ( m_iRoundTime < 0 )
{
CVAR_SET_FLOAT ( " mp_roundtime " , 0 ) ;
m_iRoundTime = 0 ;
}
if ( m_iIntroRoundTime < 0 )
{
CVAR_SET_FLOAT ( " mp_freezetime " , 0 ) ;
m_iIntroRoundTime = 0 ;
}
if ( m_iC4Timer < 0 )
{
CVAR_SET_FLOAT ( " mp_c4timer " , 0 ) ;
m_iC4Timer = 0 ;
}
if ( m_iLimitTeams < 0 )
{
CVAR_SET_FLOAT ( " mp_limitteams " , 0 ) ;
m_iLimitTeams = 0 ;
}
// auto-disable ff
if ( freeforall . value )
{
CVAR_SET_FLOAT ( " mp_friendlyfire " , 0 ) ;
}
# endif
}
CHalfLifeMultiplay : : CHalfLifeMultiplay ( )
{
m_bFreezePeriod = TRUE ;
m_VoiceGameMgr . Init ( & g_GameMgrHelper , gpGlobals - > maxClients ) ;
RefreshSkillData ( ) ;
Q_memcpy ( m_rgRewardAccountRules , m_rgRewardAccountRules_default , sizeof ( m_rgRewardAccountRules ) ) ;
m_flIntermissionEndTime = 0 ;
m_flIntermissionStartTime = 0 ;
m_flRestartRoundTime = 0 ;
m_iAccountCT = 0 ;
m_iAccountTerrorist = 0 ;
m_iHostagesRescued = 0 ;
m_iRoundWinStatus = WINSTATUS_NONE ;
m_iNumCTWins = 0 ;
m_iNumTerroristWins = 0 ;
m_pVIP = nullptr ;
m_iNumCT = 0 ;
m_iNumTerrorist = 0 ;
m_iNumSpawnableCT = 0 ;
m_iNumSpawnableTerrorist = 0 ;
2023-11-26 07:25:08 +03:00
m_bMapHasCameras = - 1 ;
2019-09-23 00:09:58 +03:00
m_iLoserBonus = m_rgRewardAccountRules [ RR_LOSER_BONUS_DEFAULT ] ;
m_iNumConsecutiveCTLoses = 0 ;
m_iNumConsecutiveTerroristLoses = 0 ;
m_iC4Guy = 0 ;
m_bBombDefused = false ;
m_bTargetBombed = false ;
m_bLevelInitialized = false ;
m_tmNextPeriodicThink = 0 ;
m_bGameStarted = false ;
m_bCompleteReset = false ;
m_flRequiredEscapeRatio = 0.5 ;
m_iNumEscapers = 0 ;
// by default everyone can buy
m_bCTCantBuy = false ;
m_bTCantBuy = false ;
m_flBombRadius = 500.0 ;
m_iTotalGunCount = 0 ;
m_iTotalGrenadeCount = 0 ;
m_iTotalArmourCount = 0 ;
m_iConsecutiveVIP = 0 ;
m_iUnBalancedRounds = 0 ;
m_iNumEscapeRounds = 0 ;
m_bRoundTerminating = false ;
g_iHostageNumber = 0 ;
m_iMaxRounds = int ( CVAR_GET_FLOAT ( " mp_maxrounds " ) ) ;
if ( m_iMaxRounds < 0 )
{
m_iMaxRounds = 0 ;
CVAR_SET_FLOAT ( " mp_maxrounds " , 0 ) ;
}
m_iTotalRoundsPlayed = 0 ;
m_iMaxRoundsWon = int ( CVAR_GET_FLOAT ( " mp_winlimit " ) ) ;
if ( m_iMaxRoundsWon < 0 )
{
m_iMaxRoundsWon = 0 ;
CVAR_SET_FLOAT ( " mp_winlimit " , 0 ) ;
}
Q_memset ( m_iMapVotes , 0 , sizeof ( m_iMapVotes ) ) ;
m_iLastPick = 1 ;
m_bMapHasEscapeZone = false ;
m_bMapHasVIPSafetyZone = FALSE ;
m_bMapHasBombZone = false ;
m_bMapHasRescueZone = false ;
m_iStoredSpectValue = int ( allow_spectators . value ) ;
for ( int j = 0 ; j < MAX_VIP_QUEUES ; j + + )
{
m_pVIPQueue [ j ] = nullptr ;
}
# ifdef REGAMEDLL_FIXES
if ( ! IS_DEDICATED_SERVER ( ) )
# endif
{
// NOTE: cvar cl_himodels refers for the client side
CVAR_SET_FLOAT ( " cl_himodels " , 0 ) ;
}
ReadMultiplayCvars ( ) ;
m_iIntroRoundTime + = 2 ;
# ifdef REGAMEDLL_FIXES
m_fMaxIdlePeriod = ( ( ( m_iRoundTime < 60 ) ? 60 : m_iRoundTime ) * 2 ) ;
# else
m_fMaxIdlePeriod = ( m_iRoundTime * 2 ) ;
# endif
float flAutoKickIdle = autokick_timeout . value ;
if ( flAutoKickIdle > 0.0 )
{
m_fMaxIdlePeriod = flAutoKickIdle ;
}
m_bInCareerGame = false ;
m_iRoundTimeSecs = m_iIntroRoundTime ;
if ( IS_DEDICATED_SERVER ( ) )
{
CVAR_SET_FLOAT ( " pausable " , 0 ) ;
}
else if ( IsCareer ( ) )
{
CVAR_SET_FLOAT ( " pausable " , 1 ) ;
CVAR_SET_FLOAT ( " sv_aim " , 0 ) ;
CVAR_SET_FLOAT ( " sv_maxspeed " , 322 ) ;
CVAR_SET_FLOAT ( " sv_cheats " , 0 ) ;
CVAR_SET_FLOAT ( " mp_windifference " , 2 ) ;
m_bInCareerGame = true ;
UTIL_LogPrintf ( " Career Start \n " ) ;
}
else
{
// 3/31/99
// Added lservercfg file cvar, since listen and dedicated servers should not
// share a single config file. (sjb)
// listen server
CVAR_SET_FLOAT ( " pausable " , 0 ) ;
const char * lservercfgfile = CVAR_GET_STRING ( " lservercfgfile " ) ;
if ( lservercfgfile & & lservercfgfile [ 0 ] ! = ' \0 ' )
{
char szCommand [ 256 ] ;
ALERT ( at_console , " Executing listen server config file \n " ) ;
Q_sprintf ( szCommand , " exec %s \n " , lservercfgfile ) ;
SERVER_COMMAND ( szCommand ) ;
}
}
m_fRoundStartTime = 0 ;
m_fRoundStartTimeReal = 0 ;
# ifndef CSTRIKE
InstallBotControl ( ) ;
# endif
InstallHostageManager ( ) ;
InstallCommands ( ) ;
m_bSkipSpawn = m_bInCareerGame ;
m_fCareerRoundMenuTime = 0 ;
m_fCareerMatchMenuTime = 0 ;
m_iCareerMatchWins = 0 ;
m_iRoundWinDifference = int ( CVAR_GET_FLOAT ( " mp_windifference " ) ) ;
if ( IsCareer ( ) )
{
CCareerTaskManager : : Create ( ) ;
}
if ( m_iRoundWinDifference < 1 )
{
m_iRoundWinDifference = 1 ;
CVAR_SET_FLOAT ( " mp_windifference " , 1 ) ;
}
InstallTutor ( CVAR_GET_FLOAT ( " tutor_enable " ) ! = 0.0f ) ;
m_bSkipShowMenu = false ;
m_bNeededPlayers = false ;
m_flEscapeRatio = 0.0f ;
m_flTimeLimit = 0.0f ;
m_flGameStartTime = 0.0f ;
m_bTeamBalanced = false ;
# ifndef REGAMEDLL_FIXES
g_pMPGameRules = this ;
# endif
}
void CHalfLifeMultiplay : : RefreshSkillData ( )
{
// load all default values
CGameRules : : RefreshSkillData ( ) ;
// override some values for multiplay.
gSkillData . plrDmg9MM = 12 ; // Glock Round
gSkillData . plrDmgMP5 = 12 ; // MP5 Round
gSkillData . plrDmg357 = 40 ; // 357 Round
gSkillData . plrDmgRPG = 120 ; // RPG
gSkillData . plrDmgM203Grenade = 100 ; // M203 grenade
gSkillData . plrDmgCrossbowClient = 20 ; // Crossbow
// Shotgun buckshot
// fewer pellets in deathmatch
gSkillData . plrDmgBuckshot = 20 ;
// suitcharger
gSkillData . suitchargerCapacity = 30 ;
}
LINK_HOOK_CLASS_VOID_CUSTOM_CHAIN2 ( CHalfLifeMultiplay , CSGameRules , RemoveGuns )
void EXT_FUNC CHalfLifeMultiplay : : __API_HOOK ( RemoveGuns ) ( )
{
CBaseEntity * toremove = nullptr ;
while ( ( toremove = UTIL_FindEntityByClassname ( toremove , " weaponbox " ) ) )
( ( CWeaponBox * ) toremove ) - > Kill ( ) ;
toremove = nullptr ;
while ( ( toremove = UTIL_FindEntityByClassname ( toremove , " weapon_shield " ) ) )
{
toremove - > SetThink ( & CBaseEntity : : SUB_Remove ) ;
toremove - > pev - > nextthink = gpGlobals - > time + 0.1 ;
}
}
void CHalfLifeMultiplay : : UpdateTeamScores ( )
{
MESSAGE_BEGIN ( MSG_ALL , gmsgTeamScore ) ;
WRITE_STRING ( " CT " ) ;
WRITE_SHORT ( m_iNumCTWins ) ;
MESSAGE_END ( ) ;
MESSAGE_BEGIN ( MSG_ALL , gmsgTeamScore ) ;
WRITE_STRING ( " TERRORIST " ) ;
WRITE_SHORT ( m_iNumTerroristWins ) ;
MESSAGE_END ( ) ;
}
LINK_HOOK_CLASS_VOID_CUSTOM_CHAIN2 ( CHalfLifeMultiplay , CSGameRules , CleanUpMap )
void EXT_FUNC CHalfLifeMultiplay : : __API_HOOK ( CleanUpMap ) ( )
{
# ifdef REGAMEDLL_FIXES
UTIL_RestartOther ( " multi_manager " ) ;
// Release or reset everything entities in depending of flags ObjectCaps
// (FCAP_MUST_RESET / FCAP_MUST_RELEASE)
UTIL_ResetEntities ( ) ;
# endif
// Recreate all the map entities from the map data (preserving their indices),
// then remove everything else except the players.
UTIL_RestartOther ( " cycler_sprite " ) ;
UTIL_RestartOther ( " light " ) ;
UTIL_RestartOther ( " func_breakable " ) ;
UTIL_RestartOther ( " func_door " ) ;
# ifdef REGAMEDLL_FIXES
UTIL_RestartOther ( " func_button " ) ;
UTIL_RestartOther ( " func_rot_button " ) ;
UTIL_RestartOther ( " env_render " ) ;
UTIL_RestartOther ( " env_spark " ) ;
UTIL_RestartOther ( " trigger_push " ) ;
# endif
UTIL_RestartOther ( " func_water " ) ;
UTIL_RestartOther ( " func_door_rotating " ) ;
UTIL_RestartOther ( " func_tracktrain " ) ;
UTIL_RestartOther ( " func_vehicle " ) ;
UTIL_RestartOther ( " func_train " ) ;
UTIL_RestartOther ( " armoury_entity " ) ;
UTIL_RestartOther ( " ambient_generic " ) ;
UTIL_RestartOther ( " env_sprite " ) ;
# ifdef REGAMEDLL_FIXES
UTIL_RestartOther ( " trigger_once " ) ;
UTIL_RestartOther ( " func_wall_toggle " ) ;
UTIL_RestartOther ( " func_healthcharger " ) ;
UTIL_RestartOther ( " func_recharge " ) ;
UTIL_RestartOther ( " trigger_hurt " ) ;
UTIL_RestartOther ( " multisource " ) ;
UTIL_RestartOther ( " env_beam " ) ;
UTIL_RestartOther ( " env_laser " ) ;
UTIL_RestartOther ( " trigger_auto " ) ;
2024-05-08 18:18:24 +03:00
UTIL_RestartOther ( " trigger_multiple " ) ;
2019-09-23 00:09:58 +03:00
# endif
// Remove grenades and C4
const int grenadesRemoveCount = 20 ;
UTIL_RemoveOther ( " grenade " , grenadesRemoveCount ) ;
2019-10-09 13:18:42 +03:00
# ifndef REGAMEDLL_FIXES
2019-09-23 00:09:58 +03:00
// Remove defuse kit
// Old code only removed 4 kits and stopped.
UTIL_RemoveOther ( " item_thighpack " ) ;
2019-10-09 13:18:42 +03:00
# else
// Don't remove level items
CItemThighPack * pDefuser = nullptr ;
while ( ( pDefuser = UTIL_FindEntityByClassname ( pDefuser , " item_thighpack " ) ) )
{
if ( pDefuser - > pev - > spawnflags & SF_NORESPAWN )
{
pDefuser - > SetThink ( & CBaseEntity : : SUB_Remove ) ;
pDefuser - > pev - > nextthink = gpGlobals - > time + 0.1 ;
}
}
# endif
2019-09-23 00:09:58 +03:00
# ifdef REGAMEDLL_FIXES
UTIL_RemoveOther ( " gib " ) ;
UTIL_RemoveOther ( " DelayedUse " ) ;
# endif
RemoveGuns ( ) ;
PLAYBACK_EVENT ( ( FEV_GLOBAL | FEV_RELIABLE ) , 0 , m_usResetDecals ) ;
}
2023-10-08 16:59:45 +03:00
LINK_HOOK_CLASS_CUSTOM_CHAIN2 ( CBasePlayer * , CHalfLifeMultiplay , CSGameRules , GiveC4 )
2019-09-23 00:09:58 +03:00
2023-10-08 16:59:45 +03:00
CBasePlayer * EXT_FUNC CHalfLifeMultiplay : : __API_HOOK ( GiveC4 ) ( )
2019-09-23 00:09:58 +03:00
{
int iTeamCount ;
int iTemp = 0 ;
int humansPresent = 0 ;
iTeamCount = m_iNumTerrorist ;
m_iC4Guy + + ;
bool giveToHumans = ( cv_bot_defer_to_human . value > 0.0 ) ;
if ( giveToHumans )
{
for ( int i = 1 ; i < = gpGlobals - > maxClients ; i + + )
{
CBasePlayer * pPlayer = UTIL_PlayerByIndex ( i ) ;
2024-05-28 18:44:29 +03:00
if ( ! UTIL_IsValidPlayer ( pPlayer ) )
2019-09-23 00:09:58 +03:00
continue ;
if ( pPlayer - > pev - > deadflag ! = DEAD_NO | | pPlayer - > m_iTeam ! = TERRORIST )
continue ;
if ( ! pPlayer - > IsBot ( ) )
humansPresent + + ;
}
if ( humansPresent )
iTeamCount = humansPresent ;
else
giveToHumans = false ;
}
// if we've looped past the last Terrorist.. then give the C4 to the first one.
if ( m_iC4Guy > iTeamCount )
{
m_iC4Guy = 1 ;
}
// Give the C4 to the specified T player..
CBaseEntity * pEntity = nullptr ;
while ( ( pEntity = UTIL_FindEntityByClassname ( pEntity , " player " ) ) )
{
if ( FNullEnt ( pEntity - > edict ( ) ) )
break ;
if ( ! pEntity - > IsPlayer ( ) )
continue ;
if ( pEntity - > IsDormant ( ) )
continue ;
CBasePlayer * pPlayer = GetClassPtr < CCSPlayer > ( ( CBasePlayer * ) pEntity - > pev ) ;
if ( pPlayer - > pev - > deadflag ! = DEAD_NO | | pPlayer - > m_iTeam ! = TERRORIST | | ( giveToHumans & & pPlayer - > IsBot ( ) ) )
continue ;
if ( + + iTemp = = m_iC4Guy )
{
if ( pPlayer - > MakeBomber ( ) )
{
# ifdef REGAMEDLL_FIXES
// we already have bomber
2023-10-08 16:59:45 +03:00
return pPlayer ;
2019-09-23 00:09:58 +03:00
# endif
}
}
}
// if there are no players with a bomb
if ( ! IsThereABomber ( ) )
{
m_iC4Guy = 0 ;
pEntity = nullptr ;
while ( ( pEntity = UTIL_FindEntityByClassname ( pEntity , " player " ) ) )
{
if ( FNullEnt ( pEntity - > edict ( ) ) )
break ;
if ( ! pEntity - > IsPlayer ( ) )
continue ;
if ( pEntity - > IsDormant ( ) )
continue ;
CBasePlayer * pPlayer = GetClassPtr < CCSPlayer > ( ( CBasePlayer * ) pEntity - > pev ) ;
if ( pPlayer - > pev - > deadflag ! = DEAD_NO | | pPlayer - > m_iTeam ! = TERRORIST )
continue ;
2023-10-08 16:59:45 +03:00
if ( pPlayer - > MakeBomber ( ) )
return pPlayer ;
2019-09-23 00:09:58 +03:00
}
}
2023-10-08 16:59:45 +03:00
return nullptr ;
2019-09-23 00:09:58 +03:00
}
void CHalfLifeMultiplay : : QueueCareerRoundEndMenu ( float tmDelay , int iWinStatus )
{
if ( ! TheCareerTasks )
return ;
if ( m_fCareerMatchMenuTime ! = 0.0f )
return ;
m_fCareerRoundMenuTime = tmDelay + gpGlobals - > time ;
bool humansAreCTs = ( Q_strcmp ( humans_join_team . string , " CT " ) = = 0 ) ;
if ( humansAreCTs )
{
CBaseEntity * hostage = nullptr ;
int numHostagesInMap = 0 ;
int numHostagesFollowingHumans = 0 ;
int numHostagesAlive = 0 ;
while ( ( hostage = UTIL_FindEntityByClassname ( hostage , " hostage_entity " ) ) )
{
numHostagesInMap + + ;
CHostage * pHostage = static_cast < CHostage * > ( hostage ) ;
if ( ! pHostage - > IsAlive ( ) )
continue ;
CBasePlayer * pLeader = nullptr ;
if ( pHostage - > IsFollowingSomeone ( ) )
pLeader = static_cast < CBasePlayer * > ( pHostage - > GetLeader ( ) ) ;
if ( pLeader = = nullptr )
{
numHostagesAlive + + ;
}
else
{
if ( ! pLeader - > IsBot ( ) )
{
numHostagesFollowingHumans + + ;
TheCareerTasks - > HandleEvent ( EVENT_HOSTAGE_RESCUED , pLeader , 0 ) ;
}
}
}
if ( ! numHostagesAlive )
{
if ( ( numHostagesInMap * 0.5 ) < = ( numHostagesFollowingHumans + m_iHostagesRescued ) )
{
TheCareerTasks - > HandleEvent ( EVENT_ALL_HOSTAGES_RESCUED ) ;
}
}
}
switch ( iWinStatus )
{
case WINSTATUS_CTS :
TheCareerTasks - > HandleEvent ( humansAreCTs ? EVENT_ROUND_WIN : EVENT_ROUND_LOSS ) ;
break ;
case WINSTATUS_TERRORISTS :
TheCareerTasks - > HandleEvent ( humansAreCTs ? EVENT_ROUND_LOSS : EVENT_ROUND_WIN ) ;
break ;
default :
TheCareerTasks - > HandleEvent ( EVENT_ROUND_DRAW ) ;
break ;
}
if ( m_fCareerMatchMenuTime = = 0.0f & & m_iCareerMatchWins )
{
bool canTsWin = true ;
bool canCTsWin = true ;
if ( m_iNumCTWins < m_iCareerMatchWins | | ( m_iNumCTWins - m_iNumTerroristWins < m_iRoundWinDifference ) )
canCTsWin = false ;
if ( m_iNumTerroristWins < m_iCareerMatchWins | | ( m_iNumTerroristWins - m_iNumCTWins < m_iRoundWinDifference ) )
canTsWin = false ;
if ( ! TheCareerTasks - > AreAllTasksComplete ( ) )
{
if ( humansAreCTs )
return ;
canTsWin = false ;
}
if ( canCTsWin | | canTsWin )
{
m_fCareerRoundMenuTime = 0 ;
m_fCareerMatchMenuTime = gpGlobals - > time + 3.0f ;
}
}
}
LINK_HOOK_CLASS_VOID_CUSTOM_CHAIN2 ( CHalfLifeMultiplay , CSGameRules , CheckWinConditions )
// Check if the scenario has been won/lost.
void EXT_FUNC CHalfLifeMultiplay : : __API_HOOK ( CheckWinConditions ) ( )
{
# ifdef REGAMEDLL_FIXES
// If a winner has already been determined.. then get the heck out of here
if ( m_iRoundWinStatus ! = WINSTATUS_NONE )
2021-10-14 13:54:09 +03:00
{
// still check if we lost players to where we need to do a full reset next round...
int NumDeadCT , NumDeadTerrorist , NumAliveTerrorist , NumAliveCT ;
InitializePlayerCounts ( NumAliveTerrorist , NumAliveCT , NumDeadTerrorist , NumDeadCT ) ;
2019-09-23 00:09:58 +03:00
return ;
2021-10-14 13:54:09 +03:00
}
2019-09-23 00:09:58 +03:00
# else
// If a winner has already been determined and game of started.. then get the heck out of here
if ( m_bGameStarted & & m_iRoundWinStatus ! = WINSTATUS_NONE )
return ;
# endif
# ifdef REGAMEDLL_ADD
int scenarioFlags = UTIL_ReadFlags ( round_infinite . string ) ;
# else
// the icc compiler will cut out all of the code which refers to it
int scenarioFlags = 0 ;
# endif
// Initialize the player counts..
int NumDeadCT , NumDeadTerrorist , NumAliveTerrorist , NumAliveCT ;
InitializePlayerCounts ( NumAliveTerrorist , NumAliveCT , NumDeadTerrorist , NumDeadCT ) ;
if ( HasRoundInfinite ( ) )
return ;
// other player's check
m_bNeededPlayers = false ;
if ( ! ( scenarioFlags & SCENARIO_BLOCK_NEED_PLAYERS ) & & NeededPlayersCheck ( ) )
return ;
// Assasination/VIP scenarion check
if ( ! ( scenarioFlags & SCENARIO_BLOCK_VIP_ESCAPE ) & & VIPRoundEndCheck ( ) )
return ;
// Prison escape check
if ( ! ( scenarioFlags & SCENARIO_BLOCK_PRISON_ESCAPE ) & & PrisonRoundEndCheck ( NumAliveTerrorist , NumAliveCT , NumDeadTerrorist , NumDeadCT ) )
return ;
// Bomb check
if ( ! ( scenarioFlags & SCENARIO_BLOCK_BOMB ) & & BombRoundEndCheck ( ) )
return ;
// Team Extermination check
// CounterTerrorists won by virture of elimination
if ( ! ( scenarioFlags & SCENARIO_BLOCK_TEAM_EXTERMINATION ) & & TeamExterminationCheck ( NumAliveTerrorist , NumAliveCT , NumDeadTerrorist , NumDeadCT ) )
return ;
// Hostage rescue check
if ( ! ( scenarioFlags & SCENARIO_BLOCK_HOSTAGE_RESCUE ) & & HostageRescueRoundEndCheck ( ) )
return ;
// scenario not won - still in progress
}
void CHalfLifeMultiplay : : InitializePlayerCounts ( int & NumAliveTerrorist , int & NumAliveCT , int & NumDeadTerrorist , int & NumDeadCT )
{
NumAliveTerrorist = NumAliveCT = NumDeadCT = NumDeadTerrorist = 0 ;
m_iNumTerrorist = m_iNumCT = m_iNumSpawnableTerrorist = m_iNumSpawnableCT = 0 ;
m_iHaveEscaped = 0 ;
// initialize count dead/alive players
// Count how many dead players there are on each team.
CBaseEntity * pEntity = nullptr ;
while ( ( pEntity = UTIL_FindEntityByClassname ( pEntity , " player " ) ) )
{
if ( FNullEnt ( pEntity - > edict ( ) ) )
break ;
if ( pEntity - > IsDormant ( ) )
continue ;
CBasePlayer * pPlayer = GetClassPtr < CCSPlayer > ( ( CBasePlayer * ) pEntity - > pev ) ;
switch ( pPlayer - > m_iTeam )
{
case CT :
{
m_iNumCT + + ;
if ( pPlayer - > m_iMenu ! = Menu_ChooseAppearance )
{
m_iNumSpawnableCT + + ;
}
if ( pPlayer - > pev - > deadflag ! = DEAD_NO )
NumDeadCT + + ;
else
NumAliveCT + + ;
break ;
}
case TERRORIST :
{
m_iNumTerrorist + + ;
if ( pPlayer - > m_iMenu ! = Menu_ChooseAppearance )
{
m_iNumSpawnableTerrorist + + ;
}
if ( pPlayer - > pev - > deadflag ! = DEAD_NO )
NumDeadTerrorist + + ;
else
NumAliveTerrorist + + ;
// Check to see if this guy escaped.
if ( pPlayer - > m_bEscaped )
m_iHaveEscaped + + ;
break ;
}
default :
break ;
}
}
}
bool CHalfLifeMultiplay : : OnRoundEnd_Intercept ( int winStatus , ScenarioEventEndRound event , float tmDelay )
{
return g_ReGameHookchains . m_RoundEnd . callChain ( & CHalfLifeMultiplay : : OnRoundEnd , this , winStatus , event , tmDelay ) ;
}
bool EXT_FUNC CHalfLifeMultiplay : : OnRoundEnd ( int winStatus , ScenarioEventEndRound event , float tmDelay )
{
switch ( event )
{
case ROUND_TARGET_BOMB : return Target_Bombed ( tmDelay ) ;
case ROUND_VIP_ESCAPED : return VIP_Escaped ( tmDelay ) ;
case ROUND_VIP_ASSASSINATED : return VIP_Died ( tmDelay ) ;
case ROUND_TERRORISTS_ESCAPED : return Prison_Escaped ( tmDelay ) ;
case ROUND_CTS_PREVENT_ESCAPE : return Prison_PreventEscape ( tmDelay ) ;
case ROUND_ESCAPING_TERRORISTS_NEUTRALIZED : return Prison_Neutralized ( tmDelay ) ;
case ROUND_BOMB_DEFUSED : return Target_Defused ( tmDelay ) ;
case ROUND_CTS_WIN : return Round_Cts ( tmDelay ) ;
case ROUND_TERRORISTS_WIN : return Round_Ts ( tmDelay ) ;
case ROUND_END_DRAW : return Round_Draw ( tmDelay ) ;
case ROUND_ALL_HOSTAGES_RESCUED : return Hostage_Rescue ( tmDelay ) ;
case ROUND_TARGET_SAVED : return Target_Saved ( tmDelay ) ;
case ROUND_HOSTAGE_NOT_RESCUED : return Hostage_NotRescued ( tmDelay ) ;
case ROUND_TERRORISTS_NOT_ESCAPED : return Prison_NotEscaped ( tmDelay ) ;
case ROUND_VIP_NOT_ESCAPED : return VIP_NotEscaped ( tmDelay ) ;
case ROUND_GAME_COMMENCE : return NeededPlayersCheck ( tmDelay ) ;
case ROUND_GAME_RESTART : return RestartRoundCheck ( tmDelay ) ;
case ROUND_GAME_OVER : return RoundOver ( tmDelay ) ;
case ROUND_NONE :
default :
break ;
}
return false ;
}
bool EXT_FUNC CHalfLifeMultiplay : : NeededPlayersCheck ( float tmDelay )
{
// Start the round immediately when the first person joins
UTIL_LogPrintf ( " World triggered \" Game_Commencing \" \n " ) ;
// Make sure we are not on the FreezePeriod.
m_bFreezePeriod = FALSE ;
m_bCompleteReset = true ;
EndRoundMessage ( " #Game_Commencing " , ROUND_GAME_COMMENCE ) ;
TerminateRound ( tmDelay , WINSTATUS_DRAW ) ;
m_bGameStarted = true ;
if ( TheBots )
{
TheBots - > OnEvent ( EVENT_GAME_COMMENCE ) ;
}
return true ;
}
bool EXT_FUNC CHalfLifeMultiplay : : NeededPlayersCheck ( )
{
// We needed players to start scoring
// Do we have them now?
// start the game, after the players entered in game
if ( ! m_iNumSpawnableTerrorist | | ! m_iNumSpawnableCT )
{
UTIL_ClientPrintAll ( HUD_PRINTCONSOLE , " #Game_scoring " ) ;
m_bNeededPlayers = true ;
m_bGameStarted = false ;
}
if ( ! m_bGameStarted & & m_iNumSpawnableTerrorist ! = 0 & & m_iNumSpawnableCT ! = 0 )
{
if ( IsCareer ( ) )
{
CBasePlayer * pPlayer = UTIL_PlayerByIndex ( gpGlobals - > maxClients ) ;
2024-05-28 18:44:29 +03:00
if ( ! UTIL_IsValidPlayer ( pPlayer ) | | ! pPlayer - > IsBot ( ) )
2019-09-23 00:09:58 +03:00
return true ;
}
return OnRoundEnd_Intercept ( WINSTATUS_DRAW , ROUND_GAME_COMMENCE , IsCareer ( ) ? 0 : 3 ) ;
}
return false ;
}
bool EXT_FUNC CHalfLifeMultiplay : : VIP_Escaped ( float tmDelay )
{
Broadcast ( " ctwin " ) ;
m_iAccountCT + = m_rgRewardAccountRules [ RR_VIP_ESCAPED ] ;
if ( ! m_bNeededPlayers )
{
m_iNumCTWins + + ;
// Update the clients team score
UpdateTeamScores ( ) ;
}
MESSAGE_BEGIN ( MSG_SPEC , SVC_DIRECTOR ) ;
WRITE_BYTE ( 9 ) ; // command length in bytes
WRITE_BYTE ( DRC_CMD_EVENT ) ; // VIP rescued
WRITE_SHORT ( ENTINDEX ( m_pVIP - > edict ( ) ) ) ; // index number of primary entity
WRITE_SHORT ( 0 ) ; // index number of secondary entity
WRITE_LONG ( 15 | DRC_FLAG_FINAL ) ; // eventflags (priority and flags)
MESSAGE_END ( ) ;
EndRoundMessage ( " #VIP_Escaped " , ROUND_VIP_ESCAPED ) ;
TerminateRound ( tmDelay , WINSTATUS_CTS ) ;
// tell the bots the VIP got out
if ( TheBots )
{
TheBots - > OnEvent ( EVENT_VIP_ESCAPED ) ;
}
if ( IsCareer ( ) )
{
QueueCareerRoundEndMenu ( tmDelay , WINSTATUS_CTS ) ;
}
return true ;
}
bool EXT_FUNC CHalfLifeMultiplay : : VIP_Died ( float tmDelay )
{
Broadcast ( " terwin " ) ;
m_iAccountTerrorist + = m_rgRewardAccountRules [ RR_VIP_ASSASSINATED ] ;
if ( ! m_bNeededPlayers )
{
m_iNumTerroristWins + + ;
// Update the clients team score
UpdateTeamScores ( ) ;
}
EndRoundMessage ( " #VIP_Assassinated " , ROUND_VIP_ASSASSINATED ) ;
TerminateRound ( tmDelay , WINSTATUS_TERRORISTS ) ;
// tell the bots the VIP was killed
if ( TheBots )
{
TheBots - > OnEvent ( EVENT_VIP_ASSASSINATED ) ;
}
if ( IsCareer ( ) )
{
QueueCareerRoundEndMenu ( tmDelay , WINSTATUS_TERRORISTS ) ;
}
return true ;
}
bool EXT_FUNC CHalfLifeMultiplay : : VIPRoundEndCheck ( )
{
// checks to scenario Escaped VIP on map with vip safety zones
if ( m_bMapHasVIPSafetyZone & & m_pVIP )
{
if ( m_pVIP - > m_bEscaped )
{
return OnRoundEnd_Intercept ( WINSTATUS_CTS , ROUND_VIP_ESCAPED , GetRoundRestartDelay ( ) ) ;
}
// The VIP is dead
else if ( m_pVIP - > pev - > deadflag ! = DEAD_NO )
{
return OnRoundEnd_Intercept ( WINSTATUS_TERRORISTS , ROUND_VIP_ASSASSINATED , GetRoundRestartDelay ( ) ) ;
}
}
return false ;
}
bool EXT_FUNC CHalfLifeMultiplay : : Prison_Escaped ( float tmDelay )
{
Broadcast ( " terwin " ) ;
m_iAccountTerrorist + = m_rgRewardAccountRules [ RR_TERRORISTS_ESCAPED ] ;
if ( ! m_bNeededPlayers )
{
m_iNumTerroristWins + + ;
// Update the clients team score
UpdateTeamScores ( ) ;
}
EndRoundMessage ( " #Terrorists_Escaped " , ROUND_TERRORISTS_ESCAPED ) ;
TerminateRound ( tmDelay , WINSTATUS_TERRORISTS ) ;
if ( IsCareer ( ) )
{
QueueCareerRoundEndMenu ( tmDelay , WINSTATUS_TERRORISTS ) ;
}
return true ;
}
bool EXT_FUNC CHalfLifeMultiplay : : Prison_PreventEscape ( float tmDelay )
{
Broadcast ( " ctwin " ) ;
// CTs are rewarded based on how many terrorists have escaped...
m_iAccountCT + = ( 1 - m_flEscapeRatio ) * m_rgRewardAccountRules [ RR_CTS_PREVENT_ESCAPE ] ;
if ( ! m_bNeededPlayers )
{
m_iNumCTWins + + ;
// Update the clients team score
UpdateTeamScores ( ) ;
}
EndRoundMessage ( " #CTs_PreventEscape " , ROUND_CTS_PREVENT_ESCAPE ) ;
TerminateRound ( tmDelay , WINSTATUS_CTS ) ;
if ( IsCareer ( ) )
{
QueueCareerRoundEndMenu ( tmDelay , WINSTATUS_CTS ) ;
}
return true ;
}
bool EXT_FUNC CHalfLifeMultiplay : : Prison_Neutralized ( float tmDelay )
{
Broadcast ( " ctwin " ) ;
// CTs are rewarded based on how many terrorists have escaped...
m_iAccountCT + = ( 1 - m_flEscapeRatio ) * m_rgRewardAccountRules [ RR_ESCAPING_TERRORISTS_NEUTRALIZED ] ;
if ( ! m_bNeededPlayers )
{
m_iNumCTWins + + ;
// Update the clients team score
UpdateTeamScores ( ) ;
}
EndRoundMessage ( " #Escaping_Terrorists_Neutralized " , ROUND_ESCAPING_TERRORISTS_NEUTRALIZED ) ;
TerminateRound ( tmDelay , WINSTATUS_CTS ) ;
if ( IsCareer ( ) )
{
QueueCareerRoundEndMenu ( tmDelay , WINSTATUS_CTS ) ;
}
return true ;
}
bool EXT_FUNC CHalfLifeMultiplay : : PrisonRoundEndCheck ( int NumAliveTerrorist , int NumAliveCT , int NumDeadTerrorist , int NumDeadCT )
{
// checks to scenario Escaped Terrorist's
if ( m_bMapHasEscapeZone )
{
m_flEscapeRatio = real_t ( m_iHaveEscaped ) / real_t ( m_iNumEscapers ) ;
if ( m_flEscapeRatio > = m_flRequiredEscapeRatio )
{
return OnRoundEnd_Intercept ( WINSTATUS_TERRORISTS , ROUND_TERRORISTS_ESCAPED , GetRoundRestartDelay ( ) ) ;
}
else if ( NumAliveTerrorist = = 0 & & m_flEscapeRatio < m_flRequiredEscapeRatio )
{
return OnRoundEnd_Intercept ( WINSTATUS_CTS , ROUND_CTS_PREVENT_ESCAPE , GetRoundRestartDelay ( ) ) ;
}
else if ( NumAliveTerrorist = = 0 & & NumDeadTerrorist ! = 0 & & m_iNumSpawnableCT > 0 )
{
return OnRoundEnd_Intercept ( WINSTATUS_CTS , ROUND_ESCAPING_TERRORISTS_NEUTRALIZED , GetRoundRestartDelay ( ) ) ;
}
// else return true;
}
return false ;
}
bool CHalfLifeMultiplay : : Target_Bombed ( float tmDelay )
{
Broadcast ( " terwin " ) ;
m_iAccountTerrorist + = m_rgRewardAccountRules [ RR_TARGET_BOMB ] ;
if ( ! m_bNeededPlayers )
{
m_iNumTerroristWins + + ;
// Update the clients team score
UpdateTeamScores ( ) ;
}
EndRoundMessage ( " #Target_Bombed " , ROUND_TARGET_BOMB ) ;
TerminateRound ( tmDelay , WINSTATUS_TERRORISTS ) ;
if ( IsCareer ( ) )
{
QueueCareerRoundEndMenu ( tmDelay , WINSTATUS_TERRORISTS ) ;
}
return true ;
}
bool CHalfLifeMultiplay : : Target_Defused ( float tmDelay )
{
Broadcast ( " ctwin " ) ;
# ifdef REGAMEDLL_ADD
if ( old_bomb_defused_sound . value )
{
Broadcast ( " BOMBDEF " ) ;
}
# endif
m_iAccountCT + = m_rgRewardAccountRules [ RR_BOMB_DEFUSED ] ;
m_iAccountTerrorist + = m_rgRewardAccountRules [ RR_BOMB_PLANTED ] ;
if ( ! m_bNeededPlayers )
{
m_iNumCTWins + + ;
// Update the clients team score
UpdateTeamScores ( ) ;
}
EndRoundMessage ( " #Bomb_Defused " , ROUND_BOMB_DEFUSED ) ;
TerminateRound ( tmDelay , WINSTATUS_CTS ) ;
if ( IsCareer ( ) )
{
QueueCareerRoundEndMenu ( tmDelay , WINSTATUS_CTS ) ;
}
return true ;
}
bool CHalfLifeMultiplay : : BombRoundEndCheck ( )
{
// Check to see if the bomb target was hit or the bomb defused.. if so, then let's end the round!
if ( m_bTargetBombed & & m_bMapHasBombTarget )
{
return OnRoundEnd_Intercept ( WINSTATUS_TERRORISTS , ROUND_TARGET_BOMB , GetRoundRestartDelay ( ) ) ;
}
else if ( m_bBombDefused & & m_bMapHasBombTarget )
{
return OnRoundEnd_Intercept ( WINSTATUS_CTS , ROUND_BOMB_DEFUSED , GetRoundRestartDelay ( ) ) ;
}
return false ;
}
bool CHalfLifeMultiplay : : Round_Cts ( float tmDelay )
{
Broadcast ( " ctwin " ) ;
m_iAccountCT + = m_rgRewardAccountRules [ m_bMapHasBombTarget ? RR_BOMB_DEFUSED : RR_CTS_WIN ] ;
if ( ! m_bNeededPlayers )
{
m_iNumCTWins + + ;
// Update the clients team score
UpdateTeamScores ( ) ;
}
EndRoundMessage ( " #CTs_Win " , ROUND_CTS_WIN ) ;
TerminateRound ( tmDelay , WINSTATUS_CTS ) ;
if ( IsCareer ( ) )
{
QueueCareerRoundEndMenu ( tmDelay , WINSTATUS_CTS ) ;
}
return true ;
}
bool CHalfLifeMultiplay : : Round_Ts ( float tmDelay )
{
Broadcast ( " terwin " ) ;
m_iAccountTerrorist + = m_rgRewardAccountRules [ m_bMapHasBombTarget ? RR_BOMB_EXPLODED : RR_TERRORISTS_WIN ] ;
if ( ! m_bNeededPlayers )
{
m_iNumTerroristWins + + ;
// Update the clients team score
UpdateTeamScores ( ) ;
}
EndRoundMessage ( " #Terrorists_Win " , ROUND_TERRORISTS_WIN ) ;
TerminateRound ( tmDelay , WINSTATUS_TERRORISTS ) ;
if ( IsCareer ( ) )
{
QueueCareerRoundEndMenu ( tmDelay , WINSTATUS_TERRORISTS ) ;
}
return true ;
}
bool CHalfLifeMultiplay : : Round_Draw ( float tmDelay )
{
EndRoundMessage ( " #Round_Draw " , ROUND_END_DRAW ) ;
Broadcast ( " rounddraw " ) ;
TerminateRound ( tmDelay , WINSTATUS_DRAW ) ;
return true ;
}
bool CHalfLifeMultiplay : : TeamExterminationCheck ( int NumAliveTerrorist , int NumAliveCT , int NumDeadTerrorist , int NumDeadCT )
{
if ( ( m_iNumCT > 0 & & m_iNumSpawnableCT > 0 ) & & ( m_iNumTerrorist > 0 & & m_iNumSpawnableTerrorist > 0 ) )
{
if ( NumAliveTerrorist = = 0 & & NumDeadTerrorist ! = 0 & & NumAliveCT > 0 )
{
CGrenade * pBomb = nullptr ;
bool nowin = false ;
while ( ( pBomb = UTIL_FindEntityByClassname ( pBomb , " grenade " ) ) )
{
if ( pBomb - > m_bIsC4 & & ! pBomb - > m_bJustBlew )
{
nowin = true ;
# ifdef REGAMEDLL_FIXES
break ;
# endif
}
}
if ( ! nowin )
{
return OnRoundEnd_Intercept ( WINSTATUS_CTS , ROUND_CTS_WIN , GetRoundRestartDelay ( ) ) ;
}
}
// Terrorists WON
else if ( NumAliveCT = = 0 & & NumDeadCT ! = 0 )
{
return OnRoundEnd_Intercept ( WINSTATUS_TERRORISTS , ROUND_TERRORISTS_WIN , GetRoundRestartDelay ( ) ) ;
}
}
else if ( NumAliveCT = = 0 & & NumAliveTerrorist = = 0 )
{
return OnRoundEnd_Intercept ( WINSTATUS_DRAW , ROUND_END_DRAW , GetRoundRestartDelay ( ) ) ;
}
return false ;
}
bool CHalfLifeMultiplay : : Hostage_Rescue ( float tmDelay )
{
Broadcast ( " ctwin " ) ;
m_iAccountCT + = m_rgRewardAccountRules [ RR_ALL_HOSTAGES_RESCUED ] ;
if ( ! m_bNeededPlayers )
{
m_iNumCTWins + + ;
// Update the clients team score
UpdateTeamScores ( ) ;
}
EndRoundMessage ( " #All_Hostages_Rescued " , ROUND_ALL_HOSTAGES_RESCUED ) ;
TerminateRound ( tmDelay , WINSTATUS_CTS ) ;
// tell the bots all the hostages have been rescued
if ( TheBots )
{
TheBots - > OnEvent ( EVENT_ALL_HOSTAGES_RESCUED ) ;
}
if ( IsCareer ( ) )
{
if ( TheCareerTasks )
{
TheCareerTasks - > HandleEvent ( EVENT_ALL_HOSTAGES_RESCUED ) ;
}
}
if ( IsCareer ( ) )
{
QueueCareerRoundEndMenu ( tmDelay , WINSTATUS_CTS ) ;
}
return true ;
}
bool CHalfLifeMultiplay : : HostageRescueRoundEndCheck ( )
{
// Check to see if 50% of the hostages have been rescued.
CBaseEntity * pHostage = nullptr ;
int hostagesCount = 0 ;
// Assume that all hostages are either rescued or dead..
bool bHostageAlive = false ;
while ( ( pHostage = UTIL_FindEntityByClassname ( pHostage , " hostage_entity " ) ) )
{
hostagesCount + + ;
// We've found a live hostage. don't end the round
if ( pHostage - > IsAlive ( ) )
{
bHostageAlive = true ;
}
}
2022-11-24 20:16:37 +03:00
# ifdef REGAMEDLL_ADD
if ( hostagesCount > 0 & & m_iHostagesRescued > = ( hostagesCount * Q_min ( hostages_rescued_ratio . value , 1.0f ) ) )
{
return OnRoundEnd_Intercept ( WINSTATUS_CTS , ROUND_ALL_HOSTAGES_RESCUED , GetRoundRestartDelay ( ) ) ;
}
# else
2019-09-23 00:09:58 +03:00
// There are no hostages alive.. check to see if the CTs have rescued atleast 50% of them.
if ( ! bHostageAlive & & hostagesCount > 0 )
{
if ( m_iHostagesRescued > = ( hostagesCount * 0.5f ) )
{
return OnRoundEnd_Intercept ( WINSTATUS_CTS , ROUND_ALL_HOSTAGES_RESCUED , GetRoundRestartDelay ( ) ) ;
}
}
2022-11-24 20:16:37 +03:00
# endif
2019-09-23 00:09:58 +03:00
return false ;
}
void CHalfLifeMultiplay : : SwapAllPlayers ( )
{
CBaseEntity * pEntity = nullptr ;
while ( ( pEntity = UTIL_FindEntityByClassname ( pEntity , " player " ) ) )
{
if ( FNullEnt ( pEntity - > edict ( ) ) )
break ;
if ( pEntity - > IsDormant ( ) )
continue ;
2021-01-04 18:26:35 +03:00
# ifdef REGAMEDLL_FIXES
// ignore HLTV
if ( pEntity - > IsProxy ( ) )
continue ;
# endif
2019-09-23 00:09:58 +03:00
CBasePlayer * pPlayer = GetClassPtr < CCSPlayer > ( ( CBasePlayer * ) pEntity - > pev ) ;
pPlayer - > SwitchTeam ( ) ;
}
// Swap Team victories
SWAP ( m_iNumTerroristWins , m_iNumCTWins ) ;
// Update the clients team score
UpdateTeamScores ( ) ;
}
LINK_HOOK_CLASS_VOID_CUSTOM_CHAIN2 ( CHalfLifeMultiplay , CSGameRules , BalanceTeams )
void EXT_FUNC CHalfLifeMultiplay : : __API_HOOK ( BalanceTeams ) ( )
{
int iNumToSwap ;
TeamName iTeamToSwap = UNASSIGNED ;
m_bTeamBalanced = false ;
// The ratio for teams is different for Assasination maps
if ( m_bMapHasVIPSafetyZone )
{
int iDesiredNumCT , iDesiredNumTerrorist ;
// uneven number of players
if ( ( m_iNumCT + m_iNumTerrorist ) % 2 ! = 0 )
iDesiredNumCT = int ( ( m_iNumCT + m_iNumTerrorist ) * 0.55f ) + 1 ;
else
iDesiredNumCT = int ( ( m_iNumCT + m_iNumTerrorist ) / 2 ) ;
iDesiredNumTerrorist = ( m_iNumCT + m_iNumTerrorist ) - iDesiredNumCT ;
if ( m_iNumCT < iDesiredNumCT )
{
iTeamToSwap = TERRORIST ;
iNumToSwap = iDesiredNumCT - m_iNumCT ;
}
else if ( m_iNumTerrorist < iDesiredNumTerrorist )
{
iTeamToSwap = CT ;
iNumToSwap = iDesiredNumTerrorist - m_iNumTerrorist ;
}
else
{
return ;
}
}
else
{
if ( m_iNumCT > m_iNumTerrorist )
{
iTeamToSwap = CT ;
iNumToSwap = ( m_iNumCT - m_iNumTerrorist ) / 2 ;
}
else if ( m_iNumTerrorist > m_iNumCT )
{
iTeamToSwap = TERRORIST ;
iNumToSwap = ( m_iNumTerrorist - m_iNumCT ) / 2 ;
}
else
{
// Teams are even.. Get out of here.
return ;
}
}
// Don't swap more than 4 players at a time.. This is a naive method of avoiding infinite loops.
if ( iNumToSwap > 4 )
iNumToSwap = 4 ;
// last person to join the server
int iHighestUserID = 0 ;
CBasePlayer * toSwap = nullptr ;
for ( int i = 1 ; i < = iNumToSwap ; i + + )
{
iHighestUserID = 0 ;
toSwap = nullptr ;
CBaseEntity * pEntity = nullptr ;
// search for player with highest UserID = most recently joined to switch over
while ( ( pEntity = UTIL_FindEntityByClassname ( pEntity , " player " ) ) )
{
if ( FNullEnt ( pEntity - > edict ( ) ) )
break ;
if ( pEntity - > IsDormant ( ) )
continue ;
CBasePlayer * pPlayer = GetClassPtr < CCSPlayer > ( ( CBasePlayer * ) pEntity - > pev ) ;
if ( pPlayer - > CanSwitchTeam ( iTeamToSwap ) & & GETPLAYERUSERID ( pPlayer - > edict ( ) ) > iHighestUserID )
{
iHighestUserID = GETPLAYERUSERID ( pPlayer - > edict ( ) ) ;
toSwap = pPlayer ;
}
}
if ( toSwap ) {
m_bTeamBalanced = true ;
toSwap - > SwitchTeam ( ) ;
m_bTeamBalanced = false ;
}
}
}
LINK_HOOK_CLASS_VOID_CUSTOM_CHAIN2 ( CHalfLifeMultiplay , CSGameRules , CheckMapConditions )
void EXT_FUNC CHalfLifeMultiplay : : __API_HOOK ( CheckMapConditions ) ( )
{
// Check to see if this map has a bomb target in it
if ( UTIL_FindEntityByClassname ( nullptr , " func_bomb_target " ) )
{
m_bMapHasBombTarget = true ;
m_bMapHasBombZone = true ;
}
else if ( UTIL_FindEntityByClassname ( nullptr , " info_bomb_target " ) )
{
m_bMapHasBombTarget = true ;
m_bMapHasBombZone = false ;
}
else
{
m_bMapHasBombTarget = false ;
m_bMapHasBombZone = false ;
}
// Check to see if this map has hostage rescue zones
m_bMapHasRescueZone = ( UTIL_FindEntityByClassname ( nullptr , " func_hostage_rescue " ) ! = nullptr ) ;
// See if the map has func_buyzone entities
// Used by CBasePlayer::HandleSignals() to support maps without these entities
m_bMapHasBuyZone = ( UTIL_FindEntityByClassname ( nullptr , " func_buyzone " ) ! = nullptr ) ;
// GOOSEMAN : See if this map has func_escapezone entities
m_bMapHasEscapeZone = ( UTIL_FindEntityByClassname ( nullptr , " func_escapezone " ) ! = nullptr ) ;
// Check to see if this map has VIP safety zones
m_bMapHasVIPSafetyZone = ( UTIL_FindEntityByClassname ( nullptr , " func_vip_safetyzone " ) ! = nullptr ) ;
}
LINK_HOOK_CLASS_VOID_CUSTOM_CHAIN2 ( CHalfLifeMultiplay , CSGameRules , RestartRound )
void EXT_FUNC CHalfLifeMultiplay : : __API_HOOK ( RestartRound ) ( )
{
// tell bots that the round is restarting
if ( TheBots )
{
TheBots - > RestartRound ( ) ;
}
if ( g_pHostages )
{
g_pHostages - > RestartRound ( ) ;
}
# ifdef REGAMEDLL_FIXES
if ( ! m_bCompleteReset )
# endif
{
m_iTotalRoundsPlayed + + ;
}
ClearBodyQue ( ) ;
// Hardlock the player accelaration to 5.0
CVAR_SET_FLOAT ( " sv_accelerate " , 5.0 ) ;
CVAR_SET_FLOAT ( " sv_friction " , 4.0 ) ;
CVAR_SET_FLOAT ( " sv_stopspeed " , 75 ) ;
// Tabulate the number of players on each team.
m_iNumCT = CountTeamPlayers ( CT ) ;
m_iNumTerrorist = CountTeamPlayers ( TERRORIST ) ;
// reset the dropped bomb on everyone's radar
if ( m_bMapHasBombTarget )
{
MESSAGE_BEGIN ( MSG_ALL , gmsgBombPickup ) ;
MESSAGE_END ( ) ;
# ifdef REGAMEDLL_FIXES
if ( m_iRoundTime > 0 )
# endif
{
MESSAGE_BEGIN ( MSG_ALL , gmsgShowTimer ) ;
MESSAGE_END ( ) ;
}
}
m_bBombDropped = FALSE ;
// reset all players health for HLTV
MESSAGE_BEGIN ( MSG_SPEC , gmsgHLTV ) ;
WRITE_BYTE ( 0 ) ; // 0 = all players
WRITE_BYTE ( 100 | DRC_FLAG_FACEPLAYER ) ; // 100 health + msg flag
MESSAGE_END ( ) ;
// reset all players FOV for HLTV
MESSAGE_BEGIN ( MSG_SPEC , gmsgHLTV ) ;
WRITE_BYTE ( 0 ) ; // all players
WRITE_BYTE ( 0 ) ; // to default FOV value
MESSAGE_END ( ) ;
auto shouldBalancedOnNextRound = [ ] ( ) - > bool
{
# ifdef REGAMEDLL_ADD
return autoteambalance . value = = 1 ;
# else
return autoteambalance . value > 0 ;
# endif
} ;
if ( shouldBalancedOnNextRound ( ) & & m_iUnBalancedRounds > = 1 )
{
BalanceTeams ( ) ;
}
if ( ( m_iNumCT - m_iNumTerrorist ) > = 2 | | ( m_iNumTerrorist - m_iNumCT ) > = 2 )
{
m_iUnBalancedRounds + + ;
}
else
{
m_iUnBalancedRounds = 0 ;
}
// Warn the players of an impending auto-balance next round...
if ( shouldBalancedOnNextRound ( ) & & m_iUnBalancedRounds = = 1 )
{
UTIL_ClientPrintAll ( HUD_PRINTCENTER , " #Auto_Team_Balance_Next_Round " ) ;
}
# ifdef REGAMEDLL_ADD
else if ( autoteambalance . value > = 2 & & m_iUnBalancedRounds > = 1 )
{
BalanceTeams ( ) ;
}
# endif
if ( m_bCompleteReset )
{
// bounds check
if ( timelimit . value < 0 )
{
CVAR_SET_FLOAT ( " mp_timelimit " , 0 ) ;
}
m_flGameStartTime = gpGlobals - > time ;
// Reset timelimit
if ( timelimit . value )
m_flTimeLimit = gpGlobals - > time + ( timelimit . value * 60 ) ;
// Reset total # of rounds played
m_iTotalRoundsPlayed = 0 ;
m_iMaxRounds = int ( CVAR_GET_FLOAT ( " mp_maxrounds " ) ) ;
if ( m_iMaxRounds < 0 )
{
m_iMaxRounds = 0 ;
CVAR_SET_FLOAT ( " mp_maxrounds " , 0 ) ;
}
m_iMaxRoundsWon = int ( CVAR_GET_FLOAT ( " mp_winlimit " ) ) ;
if ( m_iMaxRoundsWon < 0 )
{
m_iMaxRoundsWon = 0 ;
CVAR_SET_FLOAT ( " mp_winlimit " , 0 ) ;
}
// Reset score info
m_iNumTerroristWins = 0 ;
m_iNumCTWins = 0 ;
m_iNumConsecutiveTerroristLoses = 0 ;
m_iNumConsecutiveCTLoses = 0 ;
// Reset team scores
UpdateTeamScores ( ) ;
// Reset the player stats
for ( int i = 1 ; i < = gpGlobals - > maxClients ; i + + )
{
CBasePlayer * pPlayer = UTIL_PlayerByIndex ( i ) ;
2024-05-28 18:44:29 +03:00
if ( ! UTIL_IsValidPlayer ( pPlayer ) )
continue ;
pPlayer - > Reset ( ) ;
2019-09-23 00:09:58 +03:00
}
if ( TheBots )
{
TheBots - > OnEvent ( EVENT_NEW_MATCH ) ;
}
}
m_bFreezePeriod = TRUE ;
m_bRoundTerminating = false ;
ReadMultiplayCvars ( ) ;
float flAutoKickIdle = autokick_timeout . value ;
// set the idlekick max time (in seconds)
if ( flAutoKickIdle > 0 )
m_fMaxIdlePeriod = flAutoKickIdle ;
else
# ifdef REGAMEDLL_FIXES
m_fMaxIdlePeriod = ( ( ( m_iRoundTime < 60 ) ? 60 : m_iRoundTime ) * 2 ) ;
# else
m_fMaxIdlePeriod = ( m_iRoundTime * 2 ) ;
# endif
// This makes the round timer function as the intro timer on the client side
m_iRoundTimeSecs = m_iIntroRoundTime ;
// Check to see if there's a mapping info paramater entity
if ( g_pMapInfo )
g_pMapInfo - > CheckMapInfo ( ) ;
CheckMapConditions ( ) ;
if ( m_bMapHasEscapeZone )
{
// Will increase this later when we count how many Ts are starting
m_iNumEscapers = m_iHaveEscaped = 0 ;
if ( m_iNumEscapeRounds > = 3 )
{
SwapAllPlayers ( ) ;
m_iNumEscapeRounds = 0 ;
}
// Increment the number of rounds played... After 8 rounds, the players will do a whole sale switch..
m_iNumEscapeRounds + + ;
}
if ( m_bMapHasVIPSafetyZone )
{
PickNextVIP ( ) ;
m_iConsecutiveVIP + + ;
}
int acct_tmp = 0 ;
CBaseEntity * hostage = nullptr ;
while ( ( hostage = UTIL_FindEntityByClassname ( hostage , " hostage_entity " ) ) )
{
if ( acct_tmp > = 2000 )
break ;
CHostage * temp = static_cast < CHostage * > ( hostage ) ;
if ( hostage - > pev - > solid ! = SOLID_NOT )
{
acct_tmp + = m_rgRewardAccountRules [ RR_TOOK_HOSTAGE ] ;
if ( hostage - > pev - > deadflag = = DEAD_DEAD )
{
hostage - > pev - > deadflag = DEAD_RESPAWNABLE ;
}
}
temp - > RePosition ( ) ;
}
// Scale up the loser bonus when teams fall into losing streaks
if ( m_iRoundWinStatus = = WINSTATUS_TERRORISTS ) // terrorists won
{
// check to see if they just broke a losing streak
if ( m_iNumConsecutiveTerroristLoses > 1 )
{
// this is the default losing bonus
m_iLoserBonus = m_rgRewardAccountRules [ RR_LOSER_BONUS_MIN ] ;
}
m_iNumConsecutiveTerroristLoses = 0 ; // starting fresh
m_iNumConsecutiveCTLoses + + ; // increment the number of wins the CTs have had
}
else if ( m_iRoundWinStatus = = WINSTATUS_CTS )
{
// check to see if they just broke a losing streak
if ( m_iNumConsecutiveCTLoses > 1 )
{
// this is the default losing bonus
m_iLoserBonus = m_rgRewardAccountRules [ RR_LOSER_BONUS_MIN ] ;
}
m_iNumConsecutiveCTLoses = 0 ; // starting fresh
m_iNumConsecutiveTerroristLoses + + ; // increment the number of wins the Terrorists have had
}
// check if the losing team is in a losing streak & that the loser bonus hasen't maxed out.
if ( m_iNumConsecutiveTerroristLoses > 1 & & m_iLoserBonus < m_rgRewardAccountRules [ RR_LOSER_BONUS_MAX ] )
{
// help out the team in the losing streak
m_iLoserBonus + = m_rgRewardAccountRules [ RR_LOSER_BONUS_ADD ] ;
}
else if ( m_iNumConsecutiveCTLoses > 1 & & m_iLoserBonus < m_rgRewardAccountRules [ RR_LOSER_BONUS_MAX ] )
{
// help out the team in the losing streak
m_iLoserBonus + = m_rgRewardAccountRules [ RR_LOSER_BONUS_ADD ] ;
}
// assign the wining and losing bonuses
if ( m_iRoundWinStatus = = WINSTATUS_TERRORISTS ) // terrorists won
{
m_iAccountTerrorist + = acct_tmp ;
m_iAccountCT + = m_iLoserBonus ;
}
else if ( m_iRoundWinStatus = = WINSTATUS_CTS ) // CT Won
{
m_iAccountCT + = acct_tmp ;
if ( ! m_bMapHasEscapeZone )
{
// only give them the bonus if this isn't an escape map
m_iAccountTerrorist + = m_iLoserBonus ;
}
}
// Update CT account based on number of hostages rescued
m_iAccountCT + = m_iHostagesRescued * m_rgRewardAccountRules [ RR_RESCUED_HOSTAGE ] ;
// Update individual players accounts and respawn players
// the round time stamp must be set before players are spawned
m_fRoundStartTime = m_fRoundStartTimeReal = gpGlobals - > time ;
// Adrian - No cash for anyone at first rounds! ( well, only the default. )
if ( m_bCompleteReset )
{
// No extra cash!
m_iAccountTerrorist = m_iAccountCT = 0 ;
// We are starting fresh. So it's like no one has ever won or lost.
m_iNumTerroristWins = 0 ;
m_iNumCTWins = 0 ;
m_iNumConsecutiveTerroristLoses = 0 ;
m_iNumConsecutiveCTLoses = 0 ;
m_iLoserBonus = m_rgRewardAccountRules [ RR_LOSER_BONUS_DEFAULT ] ;
}
# ifdef REGAMEDLL_FIXES
// Respawn entities (glass, doors, etc..)
CleanUpMap ( ) ;
# endif
// tell bots that the round is restarting
CBaseEntity * pEntity = nullptr ;
while ( ( pEntity = UTIL_FindEntityByClassname ( pEntity , " player " ) ) )
{
if ( FNullEnt ( pEntity - > edict ( ) ) )
break ;
2024-05-28 18:44:29 +03:00
if ( pEntity - > IsDormant ( ) )
2019-09-23 00:09:58 +03:00
continue ;
CBasePlayer * pPlayer = GetClassPtr < CCSPlayer > ( ( CBasePlayer * ) pEntity - > pev ) ;
pPlayer - > m_iNumSpawns = 0 ;
pPlayer - > m_bTeamChanged = false ;
# ifndef REGAMEDLL_FIXES
// NOTE: unreachable code
if ( ! pPlayer - > IsPlayer ( ) )
{
pPlayer - > SyncRoundTimer ( ) ;
}
# endif
if ( pPlayer - > m_iTeam = = CT )
{
if ( ! pPlayer - > m_bReceivesNoMoneyNextRound )
{
pPlayer - > AddAccount ( m_iAccountCT , RT_ROUND_BONUS ) ;
}
}
else if ( pPlayer - > m_iTeam = = TERRORIST )
{
// Add another potential escaper to the mix!
m_iNumEscapers + + ;
if ( ! pPlayer - > m_bReceivesNoMoneyNextRound )
{
pPlayer - > AddAccount ( m_iAccountTerrorist , RT_ROUND_BONUS ) ;
}
// If it's a prison scenario then remove the Ts guns
if ( m_bMapHasEscapeZone )
{
// this will cause them to be reset with default weapons, armor, and items
pPlayer - > m_bNotKilled = false ;
}
}
if ( pPlayer - > m_iTeam ! = UNASSIGNED & & pPlayer - > m_iTeam ! = SPECTATOR )
{
# ifdef REGAMEDLL_FIXES
// remove the c4 if the player is carrying it
if ( pPlayer - > m_bHasC4 ) {
pPlayer - > RemoveBomb ( ) ;
}
# else
// drop the c4 if the player is carrying it
if ( pPlayer - > m_bHasC4 ) {
pPlayer - > DropPlayerItem ( " weapon_c4 " ) ;
}
# endif
pPlayer - > RoundRespawn ( ) ;
2023-09-28 12:18:15 +03:00
2022-12-16 13:10:01 +03:00
# ifdef REGAMEDLL_ADD
FireTargets ( " game_entity_restart " , pPlayer , nullptr , USE_TOGGLE , 0.0 ) ;
# endif
2019-09-23 00:09:58 +03:00
}
// Gooseman : The following code fixes the HUD icon bug
// by removing the C4 and DEFUSER icons from the HUD regardless
// for EVERY player (regardless of what team they're on)
}
// Moved above the loop spawning the players
# ifndef REGAMEDLL_FIXES
CleanUpMap ( ) ;
# endif
// Give C4 to the terrorists
2019-12-17 01:13:33 +03:00
if ( m_bMapHasBombTarget
# ifdef REGAMEDLL_ADD
& & give_player_c4 . value
# endif
)
2019-09-23 00:09:58 +03:00
{
GiveC4 ( ) ;
}
2024-01-12 11:55:00 +03:00
# ifdef REGAMEDLL_ADD
if ( m_bMapHasBombTarget & & ( int ) defuser_allocation . value = = DEFUSERALLOCATION_RANDOM )
GiveDefuserToRandomPlayer ( ) ;
# endif
2019-09-23 00:09:58 +03:00
if ( TheBots )
{
TheBots - > OnEvent ( EVENT_BUY_TIME_START ) ;
}
// Reset game variables
m_flIntermissionEndTime = 0 ;
m_flIntermissionStartTime = 0 ;
m_flRestartRoundTime = 0 ;
m_iAccountTerrorist = m_iAccountCT = 0 ;
m_iHostagesRescued = 0 ;
m_iHostagesTouched = 0 ;
m_iRoundWinStatus = WINSTATUS_NONE ;
m_bTargetBombed = m_bBombDefused = false ;
m_bLevelInitialized = false ;
m_bCompleteReset = false ;
2022-12-16 13:10:01 +03:00
# ifdef REGAMEDLL_ADD
FireTargets ( " game_round_start " , nullptr , nullptr , USE_TOGGLE , 0.0 ) ;
# endif
2019-09-23 00:09:58 +03:00
}
BOOL CHalfLifeMultiplay : : IsThereABomber ( )
{
2024-05-28 18:44:29 +03:00
CBaseEntity * pEntity = nullptr ;
while ( ( pEntity = UTIL_FindEntityByClassname ( pEntity , " player " ) ) )
2019-09-23 00:09:58 +03:00
{
2024-05-28 18:44:29 +03:00
if ( FNullEnt ( pEntity - > edict ( ) ) )
2019-09-23 00:09:58 +03:00
break ;
2024-05-28 18:44:29 +03:00
if ( pEntity - > IsDormant ( ) )
continue ;
CBasePlayer * pPlayer = GetClassPtr < CCSPlayer > ( ( CBasePlayer * ) pEntity - > pev ) ;
2019-09-23 00:09:58 +03:00
if ( pPlayer - > m_iTeam ! = CT & & pPlayer - > IsBombGuy ( ) )
{
// There you are.
return TRUE ;
}
}
// Didn't find a bomber.
return FALSE ;
}
BOOL CHalfLifeMultiplay : : IsThereABomb ( )
{
CGrenade * pBomb = nullptr ;
bool bFoundBomb = false ;
while ( ( pBomb = UTIL_FindEntityByClassname ( pBomb , " grenade " ) ) )
{
if ( pBomb - > m_bIsC4 )
{
bFoundBomb = true ;
break ;
}
}
if ( bFoundBomb | | ( UTIL_FindEntityByClassname ( nullptr , " weapon_c4 " ) ) )
return TRUE ;
return FALSE ;
}
2023-09-05 06:43:40 +03:00
LINK_HOOK_CLASS_CUSTOM_CHAIN ( BOOL , CHalfLifeMultiplay , CSGameRules , TeamFull , ( int team_id ) , team_id )
BOOL EXT_FUNC CHalfLifeMultiplay : : __API_HOOK ( TeamFull ) ( int team_id )
2019-09-23 00:09:58 +03:00
{
switch ( team_id )
{
case TERRORIST :
return ( m_iNumTerrorist > = m_iSpawnPointCount_Terrorist ) ;
case CT :
return ( m_iNumCT > = m_iSpawnPointCount_CT ) ;
}
return FALSE ;
}
2023-09-05 06:43:40 +03:00
LINK_HOOK_CLASS_CUSTOM_CHAIN ( BOOL , CHalfLifeMultiplay , CSGameRules , TeamStacked , ( int newTeam_id , int curTeam_id ) , newTeam_id , curTeam_id )
2019-09-23 00:09:58 +03:00
// checks to see if the desired team is stacked, returns true if it is
2023-09-05 06:43:40 +03:00
BOOL EXT_FUNC CHalfLifeMultiplay : : __API_HOOK ( TeamStacked ) ( int newTeam_id , int curTeam_id )
2019-09-23 00:09:58 +03:00
{
// players are allowed to change to their own team
if ( newTeam_id = = curTeam_id )
return FALSE ;
if ( ! m_iLimitTeams )
return FALSE ;
switch ( newTeam_id )
{
case TERRORIST :
if ( curTeam_id ! = UNASSIGNED & & curTeam_id ! = SPECTATOR )
return ( ( m_iNumTerrorist + 1 ) > ( m_iNumCT + m_iLimitTeams - 1 ) ) ;
else
return ( ( m_iNumTerrorist + 1 ) > ( m_iNumCT + m_iLimitTeams ) ) ;
case CT :
if ( curTeam_id ! = UNASSIGNED & & curTeam_id ! = SPECTATOR )
return ( ( m_iNumCT + 1 ) > ( m_iNumTerrorist + m_iLimitTeams - 1 ) ) ;
else
return ( ( m_iNumCT + 1 ) > ( m_iNumTerrorist + m_iLimitTeams ) ) ;
}
return FALSE ;
}
void CHalfLifeMultiplay : : StackVIPQueue ( )
{
for ( int i = MAX_VIP_QUEUES - 2 ; i > 0 ; i - - )
{
if ( m_pVIPQueue [ i - 1 ] )
{
if ( ! m_pVIPQueue [ i ] )
{
m_pVIPQueue [ i ] = m_pVIPQueue [ i + 1 ] ;
m_pVIPQueue [ i + 1 ] = nullptr ;
}
}
else
{
m_pVIPQueue [ i - 1 ] = m_pVIPQueue [ i ] ;
m_pVIPQueue [ i ] = m_pVIPQueue [ i + 1 ] ;
m_pVIPQueue [ i + 1 ] = nullptr ;
}
}
}
bool CHalfLifeMultiplay : : IsVIPQueueEmpty ( )
{
for ( int i = 0 ; i < MAX_VIP_QUEUES ; i + + )
{
CBasePlayer * toCheck = m_pVIPQueue [ i ] ;
if ( toCheck & & toCheck - > m_iTeam ! = CT )
{
m_pVIPQueue [ i ] = nullptr ;
}
}
StackVIPQueue ( ) ;
return ( ! m_pVIPQueue [ 0 ] & & ! m_pVIPQueue [ 1 ] & & ! m_pVIPQueue [ 2 ] & & ! m_pVIPQueue [ 3 ] & & ! m_pVIPQueue [ 4 ] ) ;
}
bool CHalfLifeMultiplay : : AddToVIPQueue ( CBasePlayer * toAdd )
{
for ( int i = 0 ; i < MAX_VIP_QUEUES ; i + + )
{
CBasePlayer * toCheck = m_pVIPQueue [ i ] ;
if ( toCheck & & toCheck - > m_iTeam ! = CT )
{
m_pVIPQueue [ i ] = nullptr ;
}
}
StackVIPQueue ( ) ;
if ( toAdd - > m_iTeam = = CT )
{
int j ;
for ( j = 0 ; j < MAX_VIP_QUEUES ; j + + )
{
if ( m_pVIPQueue [ j ] = = toAdd )
{
ClientPrint ( toAdd - > pev , HUD_PRINTCENTER , " #Game_in_position " , UTIL_dtos1 ( j + 1 ) ) ;
return FALSE ;
}
}
for ( j = 0 ; j < MAX_VIP_QUEUES ; j + + )
{
if ( ! m_pVIPQueue [ j ] )
{
m_pVIPQueue [ j ] = toAdd ;
StackVIPQueue ( ) ;
ClientPrint ( toAdd - > pev , HUD_PRINTCENTER , " #Game_added_position " , UTIL_dtos1 ( j + 1 ) ) ;
return TRUE ;
}
}
ClientPrint ( toAdd - > pev , HUD_PRINTCENTER , " #All_VIP_Slots_Full " ) ;
}
return FALSE ;
}
void CHalfLifeMultiplay : : ResetCurrentVIP ( )
{
char * infobuffer = GET_INFO_BUFFER ( m_pVIP - > edict ( ) ) ;
int numSkins = AreRunningCZero ( ) ? CZ_NUM_SKIN : CS_NUM_SKIN ;
switch ( RANDOM_LONG ( 0 , numSkins ) )
{
case 1 :
m_pVIP - > m_iModelName = MODEL_GSG9 ;
m_pVIP - > SetClientUserInfoModel ( infobuffer , " gsg9 " ) ;
break ;
case 2 :
m_pVIP - > m_iModelName = MODEL_SAS ;
m_pVIP - > SetClientUserInfoModel ( infobuffer , " sas " ) ;
break ;
case 3 :
m_pVIP - > m_iModelName = MODEL_GIGN ;
m_pVIP - > SetClientUserInfoModel ( infobuffer , " gign " ) ;
break ;
case 4 :
if ( AreRunningCZero ( ) )
{
m_pVIP - > m_iModelName = MODEL_SPETSNAZ ;
m_pVIP - > SetClientUserInfoModel ( infobuffer , " spetsnaz " ) ;
break ;
}
default :
m_pVIP - > m_iModelName = MODEL_URBAN ;
m_pVIP - > SetClientUserInfoModel ( infobuffer , " urban " ) ;
break ;
}
m_pVIP - > m_bIsVIP = false ;
m_pVIP - > m_bNotKilled = false ;
}
void CHalfLifeMultiplay : : PickNextVIP ( )
{
if ( ! IsVIPQueueEmpty ( ) )
{
// Remove the current VIP from his VIP status and make him a regular CT.
if ( m_pVIP )
{
ResetCurrentVIP ( ) ;
}
for ( int i = 0 ; i < MAX_VIP_QUEUES ; i + + )
{
if ( m_pVIPQueue [ i ] )
{
m_pVIP = m_pVIPQueue [ i ] ;
m_pVIP - > MakeVIP ( ) ;
m_pVIPQueue [ i ] = nullptr ; // remove this player from the VIP queue
StackVIPQueue ( ) ; // and re-organize the queue
m_iConsecutiveVIP = 0 ;
return ;
}
}
}
// If it's been the same VIP for 3 rounds already.. then randomly pick a new one
else if ( m_iConsecutiveVIP > = 3 )
{
if ( + + m_iLastPick > m_iNumCT )
m_iLastPick = 1 ;
int iCount = 1 ;
CBaseEntity * pEntity = nullptr ;
CBasePlayer * pLastPlayer = nullptr ;
while ( ( pEntity = UTIL_FindEntityByClassname ( pEntity , " player " ) ) )
{
if ( FNullEnt ( pEntity - > edict ( ) ) )
break ;
if ( pEntity - > IsDormant ( ) )
continue ;
CBasePlayer * pPlayer = GetClassPtr < CCSPlayer > ( ( CBasePlayer * ) pEntity - > pev ) ;
if ( pPlayer - > m_iTeam = = CT & & iCount = = m_iLastPick )
{
if ( pPlayer = = m_pVIP & & pLastPlayer )
pPlayer = pLastPlayer ;
// Remove the current VIP from his VIP status and make him a regular CT.
if ( m_pVIP )
{
ResetCurrentVIP ( ) ;
}
pPlayer - > MakeVIP ( ) ;
m_iConsecutiveVIP = 0 ;
break ;
}
if ( pPlayer - > m_iTeam = = CT )
iCount + + ;
if ( pPlayer - > m_iTeam ! = SPECTATOR )
pLastPlayer = pPlayer ;
}
}
// There is no VIP and there is no one waiting to be the VIP.. therefore just pick the first CT player we can find.
else if ( m_pVIP = = nullptr )
{
CBaseEntity * pEntity = nullptr ;
while ( ( pEntity = UTIL_FindEntityByClassname ( pEntity , " player " ) ) )
{
if ( FNullEnt ( pEntity - > edict ( ) ) )
break ;
if ( pEntity - > IsDormant ( ) )
continue ;
CBasePlayer * pPlayer = GetClassPtr < CCSPlayer > ( ( CBasePlayer * ) pEntity - > pev ) ;
if ( pPlayer - > m_iTeam = = CT )
{
pPlayer - > MakeVIP ( ) ;
m_iConsecutiveVIP = 0 ;
return ;
}
}
}
}
2023-09-05 06:43:40 +03:00
LINK_HOOK_CLASS_VOID_CUSTOM_CHAIN2 ( CHalfLifeMultiplay , CSGameRules , Think )
void EXT_FUNC CHalfLifeMultiplay : : __API_HOOK ( Think ) ( )
2019-09-23 00:09:58 +03:00
{
MonitorTutorStatus ( ) ;
m_VoiceGameMgr . Update ( gpGlobals - > frametime ) ;
if ( g_psv_clienttrace - > value ! = 1.0f )
{
CVAR_SET_FLOAT ( " sv_clienttrace " , 1 ) ;
}
if ( ! m_fRoundStartTime )
{
// initialize the timer time stamps, this happens once only
m_fRoundStartTime = m_fRoundStartTimeReal = gpGlobals - > time ;
}
if ( m_flForceCameraValue ! = forcecamera . value
| | m_flForceChaseCamValue ! = forcechasecam . value
| | m_flFadeToBlackValue ! = fadetoblack . value )
{
MESSAGE_BEGIN ( MSG_ALL , gmsgForceCam ) ;
WRITE_BYTE ( forcecamera . value ! = 0 ) ;
WRITE_BYTE ( forcechasecam . value ! = 0 ) ;
2023-07-16 15:55:58 +03:00
WRITE_BYTE ( fadetoblack . value = = FADETOBLACK_STAY ) ;
2019-09-23 00:09:58 +03:00
MESSAGE_END ( ) ;
m_flForceCameraValue = forcecamera . value ;
m_flForceChaseCamValue = forcechasecam . value ;
m_flFadeToBlackValue = fadetoblack . value ;
}
// Check game rules
if ( CheckGameOver ( ) )
return ;
// have we hit the timelimit?
if ( CheckTimeLimit ( ) )
return ;
// did somebody hit the fraglimit ?
if ( CheckFragLimit ( ) )
return ;
if ( ! IsCareer ( ) )
{
// have we hit the max rounds?
if ( CheckMaxRounds ( ) )
return ;
if ( CheckWinLimit ( ) )
return ;
}
if ( ! IsCareer ( ) | | ( m_fCareerMatchMenuTime < = 0.0 | | m_fCareerMatchMenuTime > = gpGlobals - > time ) )
{
if ( m_iStoredSpectValue ! = allow_spectators . value )
{
m_iStoredSpectValue = allow_spectators . value ;
MESSAGE_BEGIN ( MSG_ALL , gmsgAllowSpec ) ;
WRITE_BYTE ( int ( allow_spectators . value ) ) ;
MESSAGE_END ( ) ;
}
// Check for the end of the round.
if ( IsFreezePeriod ( ) )
{
CheckFreezePeriodExpired ( ) ;
}
else
{
CheckRoundTimeExpired ( ) ;
}
if ( m_flRestartRoundTime > 0.0f & & m_flRestartRoundTime < = gpGlobals - > time )
{
if ( ! IsCareer ( ) | | ! m_fCareerRoundMenuTime )
{
RestartRound ( ) ;
}
else if ( TheCareerTasks )
{
bool isBotSpeaking = false ;
if ( m_flRestartRoundTime + 10.0f > gpGlobals - > time )
{
isBotSpeaking = IsBotSpeaking ( ) ;
}
if ( ! isBotSpeaking )
{
if ( m_fCareerMatchMenuTime = = 0.0f & & m_iCareerMatchWins )
{
bool canCTsWin = true ;
bool canTsWin = true ;
if ( m_iNumCTWins < m_iCareerMatchWins | | ( m_iNumCTWins - m_iNumTerroristWins < m_iRoundWinDifference ) )
canCTsWin = false ;
if ( m_iNumTerroristWins < m_iCareerMatchWins | | ( m_iNumTerroristWins - m_iNumCTWins < m_iRoundWinDifference ) )
canTsWin = false ;
if ( ! Q_strcmp ( humans_join_team . string , " CT " ) )
{
if ( ! TheCareerTasks - > AreAllTasksComplete ( ) )
{
canCTsWin = false ;
}
}
else if ( ! TheCareerTasks - > AreAllTasksComplete ( ) )
{
canTsWin = false ;
}
if ( canCTsWin | | canTsWin )
{
m_fCareerRoundMenuTime = 0 ;
m_fCareerMatchMenuTime = gpGlobals - > time + 3.0f ;
return ;
}
}
m_bFreezePeriod = TRUE ;
for ( int i = 1 ; i < = gpGlobals - > maxClients ; i + + )
{
CBasePlayer * pPlayer = UTIL_PlayerByIndex ( i ) ;
2024-05-28 18:44:29 +03:00
if ( ! UTIL_IsValidPlayer ( pPlayer ) )
continue ;
if ( ! pPlayer - > IsBot ( ) )
2019-09-23 00:09:58 +03:00
{
MESSAGE_BEGIN ( MSG_ONE , gmsgCZCareerHUD , nullptr , pPlayer - > pev ) ;
WRITE_STRING ( " ROUND " ) ;
WRITE_LONG ( m_iNumCTWins ) ;
WRITE_LONG ( m_iNumTerroristWins ) ;
WRITE_BYTE ( m_iCareerMatchWins ) ;
WRITE_BYTE ( m_iRoundWinDifference ) ;
WRITE_BYTE ( m_iRoundWinStatus ) ;
MESSAGE_END ( ) ;
pPlayer - > m_iHideHUD | = HIDEHUD_ALL ;
m_flRestartRoundTime = gpGlobals - > time + 100000.0 ;
UTIL_LogPrintf ( " Career Round %d %d %d %d \n " , m_iRoundWinStatus , m_iNumCTWins , m_iNumTerroristWins , TheCareerTasks - > AreAllTasksComplete ( ) ) ;
break ;
}
}
m_fCareerRoundMenuTime = 0 ;
}
}
if ( TheTutor )
{
TheTutor - > PurgeMessages ( ) ;
}
}
CheckLevelInitialized ( ) ;
if ( gpGlobals - > time > m_tmNextPeriodicThink )
{
CheckRestartRound ( ) ;
m_tmNextPeriodicThink = gpGlobals - > time + 1.0f ;
if ( g_psv_accelerate - > value ! = 5.0f )
{
CVAR_SET_FLOAT ( " sv_accelerate " , 5.0f ) ;
}
if ( g_psv_friction - > value ! = 4.0f )
{
CVAR_SET_FLOAT ( " sv_friction " , 4.0f ) ;
}
if ( g_psv_stopspeed - > value ! = 75.0f )
{
CVAR_SET_FLOAT ( " sv_stopspeed " , 75.0f ) ;
}
m_iMaxRounds = int ( maxrounds . value ) ;
if ( m_iMaxRounds < 0 )
{
m_iMaxRounds = 0 ;
CVAR_SET_FLOAT ( " mp_maxrounds " , 0 ) ;
}
m_iMaxRoundsWon = int ( winlimit . value ) ;
if ( m_iMaxRoundsWon < 0 )
{
m_iMaxRoundsWon = 0 ;
CVAR_SET_FLOAT ( " mp_winlimit " , 0 ) ;
}
}
}
else
{
if ( m_fCareerMatchMenuTime + 10 < = gpGlobals - > time | | ! IsBotSpeaking ( ) )
{
UTIL_CareerDPrintf ( " Ending career match...one team has won the specified number of rounds \n " ) ;
MESSAGE_BEGIN ( MSG_ALL , gmsgCZCareer ) ;
WRITE_STRING ( " MATCH " ) ;
WRITE_LONG ( m_iNumCTWins ) ;
WRITE_LONG ( m_iNumTerroristWins ) ;
MESSAGE_END ( ) ;
MESSAGE_BEGIN ( MSG_ALL , gmsgCZCareerHUD ) ;
WRITE_STRING ( " MATCH " ) ;
WRITE_LONG ( m_iNumCTWins ) ;
WRITE_LONG ( m_iNumTerroristWins ) ;
WRITE_BYTE ( m_iCareerMatchWins ) ;
WRITE_BYTE ( m_iRoundWinDifference ) ;
WRITE_BYTE ( m_iRoundWinStatus ) ;
MESSAGE_END ( ) ;
UTIL_LogPrintf ( " Career Match %d %d %d %d \n " , m_iRoundWinStatus , m_iNumCTWins , m_iNumTerroristWins , TheCareerTasks - > AreAllTasksComplete ( ) ) ;
SERVER_COMMAND ( " setpause \n " ) ;
}
}
}
bool CHalfLifeMultiplay : : CheckGameOver ( )
{
// someone else quit the game already
if ( m_bGameOver )
{
// bounds check
int time = int ( CVAR_GET_FLOAT ( " mp_chattime " ) ) ;
if ( time < 1 )
CVAR_SET_STRING ( " mp_chattime " , " 1 " ) ;
else if ( time > MAX_INTERMISSION_TIME )
CVAR_SET_STRING ( " mp_chattime " , UTIL_dtos1 ( MAX_INTERMISSION_TIME ) ) ;
m_flIntermissionEndTime = m_flIntermissionStartTime + mp_chattime . value ;
// check to see if we should change levels now
if ( m_flIntermissionEndTime < gpGlobals - > time & & ! IsCareer ( ) )
{
if ( ! UTIL_HumansInGame ( ) // if only bots, just change immediately
# ifdef REGAMEDLL_FIXES
| | IsMultiplayer ( )
# endif
| | m_iEndIntermissionButtonHit // check that someone has pressed a key, or the max intermission time is over
| | ( ( m_flIntermissionStartTime + MAX_INTERMISSION_TIME ) < gpGlobals - > time ) )
{
// intermission is over
ChangeLevel ( ) ;
}
}
return true ;
}
return false ;
}
bool CHalfLifeMultiplay : : CheckTimeLimit ( )
{
if ( timelimit . value < 0 )
{
CVAR_SET_FLOAT ( " mp_timelimit " , 0 ) ;
return false ;
}
if ( ! IsCareer ( ) )
{
if ( timelimit . value )
{
m_flTimeLimit = m_flGameStartTime + timelimit . value * 60.0f ;
if ( gpGlobals - > time > = m_flTimeLimit )
{
ALERT ( at_console , " Changing maps because time limit has been met \n " ) ;
GoToIntermission ( ) ;
return true ;
}
}
# ifdef REGAMEDLL_ADD
static int lastTime = 0 ;
int timeRemaining = ( int ) ( timelimit . value ? ( m_flTimeLimit - gpGlobals - > time ) : 0 ) ;
// Updates once per second
if ( timeRemaining ! = lastTime )
{
lastTime = timeRemaining ;
g_engfuncs . pfnCvar_DirectSet ( & timeleft , UTIL_VarArgs ( " %02d:%02d " , timeRemaining / 60 , timeRemaining % 60 ) ) ;
}
# endif
}
return false ;
}
bool CHalfLifeMultiplay : : CheckMaxRounds ( )
{
if ( m_iMaxRounds ! = 0 & & m_iTotalRoundsPlayed > = m_iMaxRounds )
{
ALERT ( at_console , " Changing maps due to maximum rounds have been met \n " ) ;
GoToIntermission ( ) ;
return true ;
}
return false ;
}
bool CHalfLifeMultiplay : : CheckWinLimit ( )
{
// has one team won the specified number of rounds?
if ( m_iMaxRoundsWon ! = 0 & & ( m_iNumCTWins > = m_iMaxRoundsWon | | m_iNumTerroristWins > = m_iMaxRoundsWon ) )
{
if ( ( m_iNumCTWins - m_iNumTerroristWins > = m_iRoundWinDifference ) | | ( m_iNumTerroristWins - m_iNumCTWins > = m_iRoundWinDifference ) )
{
ALERT ( at_console , " Changing maps...one team has won the specified number of rounds \n " ) ;
GoToIntermission ( ) ;
return true ;
}
}
return false ;
}
bool CHalfLifeMultiplay : : CheckFragLimit ( )
{
# ifdef REGAMEDLL_ADD
int fragsRemaining = 0 ;
if ( fraglimit . value > = 1 )
{
int bestFrags = fraglimit . value ;
// check if any player is over the frag limit
for ( int i = 1 ; i < = gpGlobals - > maxClients ; i + + )
{
2024-05-28 18:44:29 +03:00
CBasePlayer * pPlayer = UTIL_PlayerByIndex ( i ) ;
2019-09-23 00:09:58 +03:00
2024-05-28 18:44:29 +03:00
if ( ! UTIL_IsValidPlayer ( pPlayer ) | | pPlayer - > has_disconnected )
2019-09-23 00:09:58 +03:00
continue ;
if ( pPlayer - > pev - > frags > = fraglimit . value )
{
ALERT ( at_console , " Changing maps because frag limit has been met \n " ) ;
GoToIntermission ( ) ;
return true ;
}
int remain = ( int ) ( fraglimit . value - pPlayer - > pev - > frags ) ;
if ( remain < bestFrags )
{
bestFrags = remain ;
}
}
fragsRemaining = bestFrags ;
}
static int lastFrags = 0 ;
// Updates when frags change
if ( fragsRemaining ! = lastFrags )
{
lastFrags = fragsRemaining ;
g_engfuncs . pfnCvar_DirectSet ( & fragsleft , UTIL_VarArgs ( " %i " , fragsRemaining ) ) ;
}
# endif
return false ;
}
void EXT_FUNC CHalfLifeMultiplay : : OnRoundFreezeEnd ( )
{
// Log this information
UTIL_LogPrintf ( " World triggered \" Round_Start \" \n " ) ;
// Freeze period expired: kill the flag
m_bFreezePeriod = FALSE ;
char CT_sentence [ 40 ] ;
char T_sentence [ 40 ] ;
switch ( RANDOM_LONG ( 0 , 3 ) )
{
case 0 :
Q_strncpy ( CT_sentence , " %!MRAD_MOVEOUT " , sizeof ( CT_sentence ) ) ;
Q_strncpy ( T_sentence , " %!MRAD_MOVEOUT " , sizeof ( T_sentence ) ) ;
break ;
case 1 :
Q_strncpy ( CT_sentence , " %!MRAD_LETSGO " , sizeof ( CT_sentence ) ) ;
Q_strncpy ( T_sentence , " %!MRAD_LETSGO " , sizeof ( T_sentence ) ) ;
break ;
case 2 :
Q_strncpy ( CT_sentence , " %!MRAD_LOCKNLOAD " , sizeof ( CT_sentence ) ) ;
Q_strncpy ( T_sentence , " %!MRAD_LOCKNLOAD " , sizeof ( T_sentence ) ) ;
break ;
default :
Q_strncpy ( CT_sentence , " %!MRAD_GO " , sizeof ( CT_sentence ) ) ;
Q_strncpy ( T_sentence , " %!MRAD_GO " , sizeof ( T_sentence ) ) ;
break ;
}
// More specific radio commands for the new scenarios : Prison & Assasination
if ( m_bMapHasEscapeZone )
{
Q_strncpy ( CT_sentence , " %!MRAD_ELIM " , sizeof ( CT_sentence ) ) ;
Q_strncpy ( T_sentence , " %!MRAD_GETOUT " , sizeof ( T_sentence ) ) ;
}
else if ( m_bMapHasVIPSafetyZone )
{
Q_strncpy ( CT_sentence , " %!MRAD_VIP " , sizeof ( CT_sentence ) ) ;
Q_strncpy ( T_sentence , " %!MRAD_LOCKNLOAD " , sizeof ( T_sentence ) ) ;
}
// Reset the round time
m_fRoundStartTimeReal = m_fRoundStartTime = gpGlobals - > time ;
// in seconds
m_iRoundTimeSecs = m_iRoundTime ;
bool bCTPlayed = false ;
bool bTPlayed = false ;
if ( TheCareerTasks )
{
TheCareerTasks - > HandleEvent ( EVENT_ROUND_START ) ;
}
for ( int i = 1 ; i < = gpGlobals - > maxClients ; i + + )
{
CBasePlayer * plr = UTIL_PlayerByIndex ( i ) ;
2024-05-28 18:44:29 +03:00
if ( ! UTIL_IsValidPlayer ( plr ) )
continue ;
# ifndef REGAMEDLL_FIXES
if ( plr - > pev - > flags = = FL_DORMANT )
2019-09-23 00:09:58 +03:00
continue ;
2024-05-28 18:44:29 +03:00
# endif
2019-09-23 00:09:58 +03:00
if ( plr - > m_iJoiningState = = JOINED )
{
if ( plr - > m_iTeam = = CT & & ! bCTPlayed )
{
plr - > Radio ( CT_sentence ) ;
bCTPlayed = true ;
}
else if ( plr - > m_iTeam = = TERRORIST & & ! bTPlayed )
{
plr - > Radio ( T_sentence ) ;
bTPlayed = true ;
}
if ( plr - > m_iTeam ! = SPECTATOR )
{
plr - > ResetMaxSpeed ( ) ;
plr - > m_bCanShoot = true ;
}
}
plr - > SyncRoundTimer ( ) ;
}
if ( TheBots )
{
TheBots - > OnEvent ( EVENT_ROUND_START ) ;
}
if ( TheCareerTasks )
{
TheCareerTasks - > HandleEvent ( EVENT_ROUND_START ) ;
}
2024-05-08 16:59:27 +03:00
# ifdef REGAMEDLL_ADD
FireTargets ( " game_round_freeze_end " , nullptr , nullptr , USE_TOGGLE , 0.0 ) ;
# endif
2019-09-23 00:09:58 +03:00
}
void CHalfLifeMultiplay : : CheckFreezePeriodExpired ( )
{
if ( GetRoundRemainingTime ( ) > 0 )
return ;
g_ReGameHookchains . m_CSGameRules_OnRoundFreezeEnd . callChain ( & CHalfLifeMultiplay : : OnRoundFreezeEnd , this ) ;
}
bool CHalfLifeMultiplay : : Target_Saved ( float tmDelay )
{
Broadcast ( " ctwin " ) ;
m_iAccountCT + = m_rgRewardAccountRules [ RR_TARGET_BOMB_SAVED ] ;
# ifdef REGAMEDLL_FIXES
if ( ! m_bNeededPlayers )
{
m_iNumCTWins + + ;
// Update the clients team score
UpdateTeamScores ( ) ;
}
# else
m_iNumCTWins + + ;
# endif
EndRoundMessage ( " #Target_Saved " , ROUND_TARGET_SAVED ) ;
TerminateRound ( tmDelay , WINSTATUS_CTS ) ;
if ( IsCareer ( ) )
{
QueueCareerRoundEndMenu ( tmDelay , WINSTATUS_CTS ) ;
}
# ifndef REGAMEDLL_FIXES
UpdateTeamScores ( ) ;
# endif
MarkLivingPlayersOnTeamAsNotReceivingMoneyNextRound ( TERRORIST ) ;
return true ;
}
bool CHalfLifeMultiplay : : Hostage_NotRescued ( float tmDelay )
{
Broadcast ( " terwin " ) ;
m_iAccountTerrorist + = m_rgRewardAccountRules [ RR_HOSTAGE_NOT_RESCUED ] ;
# ifdef REGAMEDLL_FIXES
if ( ! m_bNeededPlayers )
{
m_iNumTerroristWins + + ;
// Update the clients team score
UpdateTeamScores ( ) ;
}
# else
m_iNumTerroristWins + + ;
# endif
EndRoundMessage ( " #Hostages_Not_Rescued " , ROUND_HOSTAGE_NOT_RESCUED ) ;
TerminateRound ( tmDelay , WINSTATUS_TERRORISTS ) ;
if ( IsCareer ( ) )
{
QueueCareerRoundEndMenu ( tmDelay , WINSTATUS_TERRORISTS ) ;
}
# ifndef REGAMEDLL_FIXES
UpdateTeamScores ( ) ;
# endif
MarkLivingPlayersOnTeamAsNotReceivingMoneyNextRound ( CT ) ;
return true ;
}
bool CHalfLifeMultiplay : : Prison_NotEscaped ( float tmDelay )
{
Broadcast ( " ctwin " ) ;
# ifdef REGAMEDLL_FIXES
if ( ! m_bNeededPlayers )
{
m_iNumCTWins + + ;
// Update the clients team score
UpdateTeamScores ( ) ;
}
# else
m_iNumCTWins + + ;
# endif
EndRoundMessage ( " #Terrorists_Not_Escaped " , ROUND_TERRORISTS_NOT_ESCAPED ) ;
TerminateRound ( tmDelay , WINSTATUS_CTS ) ;
if ( IsCareer ( ) )
{
QueueCareerRoundEndMenu ( tmDelay , WINSTATUS_CTS ) ;
}
# ifndef REGAMEDLL_FIXES
UpdateTeamScores ( ) ;
# endif
return true ;
}
bool CHalfLifeMultiplay : : VIP_NotEscaped ( float tmDelay )
{
Broadcast ( " terwin " ) ;
m_iAccountTerrorist + = m_rgRewardAccountRules [ RR_VIP_NOT_ESCAPED ] ;
# ifdef REGAMEDLL_FIXES
if ( ! m_bNeededPlayers )
{
m_iNumTerroristWins + + ;
// Update the clients team score
UpdateTeamScores ( ) ;
}
# else
m_iNumTerroristWins + + ;
# endif
EndRoundMessage ( " #VIP_Not_Escaped " , ROUND_VIP_NOT_ESCAPED ) ;
TerminateRound ( tmDelay , WINSTATUS_TERRORISTS ) ;
if ( IsCareer ( ) )
{
QueueCareerRoundEndMenu ( tmDelay , WINSTATUS_TERRORISTS ) ;
}
# ifndef REGAMEDLL_FIXES
UpdateTeamScores ( ) ;
# endif
return true ;
}
bool CHalfLifeMultiplay : : RoundOver ( float tmDelay )
{
EndRoundMessage ( " #Cstrike_Tutor_Round_Over " , ROUND_GAME_OVER ) ;
Broadcast ( " rounddraw " ) ;
TerminateRound ( tmDelay , WINSTATUS_DRAW ) ;
return true ;
}
void CHalfLifeMultiplay : : CheckRoundTimeExpired ( )
{
if ( HasRoundInfinite ( SCENARIO_BLOCK_TIME_EXPRIRED ) )
return ;
if ( ! HasRoundTimeExpired ( ) )
return ;
#if 0
// Round time expired
float flEndRoundTime ;
// Check to see if there's still a live C4 hanging around.. if so, wait until this C4 blows before ending the round
CGrenade * pBomb = ( CGrenade * ) UTIL_FindEntityByClassname ( nullptr , " grenade " ) ;
if ( pBomb )
{
if ( ! pBomb - > m_bJustBlew )
flEndRoundTime = pBomb - > m_flC4Blow ;
else
flEndRoundTime = gpGlobals - > time + 5.0f ;
}
# endif
2020-06-13 12:39:41 +03:00
# ifdef REGAMEDLL_ADD
int scenarioFlags = UTIL_ReadFlags ( round_infinite . string ) ;
# else
// the icc compiler will cut out all of the code which refers to it
int scenarioFlags = 0 ;
# endif
2019-09-23 00:09:58 +03:00
// New code to get rid of round draws!!
2020-06-13 12:39:41 +03:00
if ( ! ( scenarioFlags & SCENARIO_BLOCK_BOMB_TIME ) & & m_bMapHasBombTarget )
2019-09-23 00:09:58 +03:00
{
if ( ! OnRoundEnd_Intercept ( WINSTATUS_CTS , ROUND_TARGET_SAVED , GetRoundRestartDelay ( ) ) )
return ;
}
2021-04-15 20:15:21 +03:00
else if ( ! ( scenarioFlags & SCENARIO_BLOCK_HOSTAGE_RESCUE_TIME ) & & UTIL_FindEntityByClassname ( nullptr , " hostage_entity " ) )
2019-09-23 00:09:58 +03:00
{
if ( ! OnRoundEnd_Intercept ( WINSTATUS_TERRORISTS , ROUND_HOSTAGE_NOT_RESCUED , GetRoundRestartDelay ( ) ) )
return ;
}
2020-06-13 12:39:41 +03:00
else if ( ! ( scenarioFlags & SCENARIO_BLOCK_PRISON_ESCAPE_TIME ) & & m_bMapHasEscapeZone )
2019-09-23 00:09:58 +03:00
{
if ( ! OnRoundEnd_Intercept ( WINSTATUS_CTS , ROUND_TERRORISTS_NOT_ESCAPED , GetRoundRestartDelay ( ) ) )
return ;
}
2020-06-13 12:39:41 +03:00
else if ( ! ( scenarioFlags & SCENARIO_BLOCK_VIP_ESCAPE_TIME ) & & m_bMapHasVIPSafetyZone )
2019-09-23 00:09:58 +03:00
{
if ( ! OnRoundEnd_Intercept ( WINSTATUS_TERRORISTS , ROUND_VIP_NOT_ESCAPED , GetRoundRestartDelay ( ) ) )
return ;
}
# ifdef REGAMEDLL_ADD
else if ( roundover . value )
{
2021-04-12 15:45:49 +03:00
switch ( ( int ) roundover . value )
{
case 1 :
default :
{
if ( ! OnRoundEnd_Intercept ( WINSTATUS_DRAW , ROUND_GAME_OVER , GetRoundRestartDelay ( ) ) )
return ;
break ;
}
case 2 :
{
if ( ! OnRoundEnd_Intercept ( WINSTATUS_TERRORISTS , ROUND_TERRORISTS_WIN , GetRoundRestartDelay ( ) ) )
return ;
break ;
}
case 3 :
{
if ( ! OnRoundEnd_Intercept ( WINSTATUS_CTS , ROUND_CTS_WIN , GetRoundRestartDelay ( ) ) )
return ;
break ;
}
}
2019-09-23 00:09:58 +03:00
}
# endif
// This is done so that the portion of code has enough time to do it's thing.
m_fRoundStartTime = gpGlobals - > time + 60.0f ;
}
void CHalfLifeMultiplay : : CheckLevelInitialized ( )
{
if ( ! m_bLevelInitialized )
{
// Count the number of spawn points for each team
// This determines the maximum number of players allowed on each
2023-11-26 07:25:08 +03:00
m_iSpawnPointCount_Terrorist = UTIL_CountEntities ( " info_player_deathmatch " ) ;
m_iSpawnPointCount_CT = UTIL_CountEntities ( " info_player_start " ) ;
2023-12-22 22:43:42 +03:00
# ifdef REGAMEDLL_FIXES
2023-11-26 07:25:08 +03:00
m_bMapHasCameras = UTIL_CountEntities ( " trigger_camera " ) ;
# endif
2019-09-23 00:09:58 +03:00
m_bLevelInitialized = true ;
}
}
bool CHalfLifeMultiplay : : RestartRoundCheck ( float tmDelay )
{
// log the restart
UTIL_LogPrintf ( " World triggered \" Restart_Round_(%i_%s) \" \n " , ( int ) tmDelay , ( tmDelay = = 1 ) ? " second " : " seconds " ) ;
UTIL_LogPrintf ( " Team \" CT \" scored \" %i \" with \" %i \" players \n " , m_iNumCTWins , m_iNumCT ) ;
UTIL_LogPrintf ( " Team \" TERRORIST \" scored \" %i \" with \" %i \" players \n " , m_iNumTerroristWins , m_iNumTerrorist ) ;
// let the players know
UTIL_ClientPrintAll ( HUD_PRINTCENTER , " #Game_will_restart_in " , UTIL_dtos1 ( tmDelay ) , ( tmDelay = = 1 ) ? " SECOND " : " SECONDS " ) ;
UTIL_ClientPrintAll ( HUD_PRINTCONSOLE , " #Game_will_restart_in_console " , UTIL_dtos1 ( tmDelay ) , ( tmDelay = = 1 ) ? " SECOND " : " SECONDS " ) ;
m_flRestartRoundTime = gpGlobals - > time + tmDelay ;
m_bCompleteReset = true ;
CVAR_SET_FLOAT ( " sv_restartround " , 0 ) ;
CVAR_SET_FLOAT ( " sv_restart " , 0 ) ;
CareerRestart ( ) ;
return true ;
}
void CHalfLifeMultiplay : : CheckRestartRound ( )
{
// Restart the round if specified by the server
int iRestartDelay = int ( restartround . value ) ;
if ( ! iRestartDelay )
{
iRestartDelay = sv_restart . value ;
}
if ( iRestartDelay > 0 )
{
# ifndef REGAMEDLL_ADD
if ( iRestartDelay > 60 )
iRestartDelay = 60 ;
# endif
OnRoundEnd_Intercept ( WINSTATUS_NONE , ROUND_GAME_RESTART , iRestartDelay ) ;
}
}
bool CHalfLifeMultiplay : : HasRoundTimeExpired ( )
{
# ifdef REGAMEDLL_ADD
if ( ! m_iRoundTime )
return false ;
# endif
// We haven't completed other objectives, so go for this!.
if ( GetRoundRemainingTime ( ) > 0 | | m_iRoundWinStatus ! = WINSTATUS_NONE )
{
return false ;
}
// If the bomb is planted, don't let the round timer end the round.
// keep going until the bomb explodes or is defused
if ( ! IsBombPlanted ( ) )
{
if ( cv_bot_nav_edit . value = = 0.0f | | IS_DEDICATED_SERVER ( ) | | UTIL_HumansInGame ( ) ! = 1 )
{
return true ;
}
}
return false ;
}
bool CHalfLifeMultiplay : : IsBombPlanted ( )
{
if ( m_bMapHasBombTarget )
{
CGrenade * bomb = nullptr ;
while ( ( bomb = UTIL_FindEntityByClassname ( bomb , " grenade " ) ) )
{
if ( bomb - > m_bIsC4 )
{
return true ;
}
}
}
return false ;
}
// Living players on the given team need to be marked as not receiving any money next round.
void CHalfLifeMultiplay : : MarkLivingPlayersOnTeamAsNotReceivingMoneyNextRound ( int iTeam )
{
for ( int i = 1 ; i < = gpGlobals - > maxClients ; i + + )
{
CBasePlayer * pPlayer = UTIL_PlayerByIndex ( i ) ;
2024-05-28 18:44:29 +03:00
if ( ! UTIL_IsValidPlayer ( pPlayer ) )
2019-09-23 00:09:58 +03:00
continue ;
if ( pPlayer - > m_iTeam = = iTeam )
{
if ( pPlayer - > pev - > health > 0 & & pPlayer - > pev - > deadflag = = DEAD_NO )
{
pPlayer - > m_bReceivesNoMoneyNextRound = true ;
}
}
}
}
void CHalfLifeMultiplay : : CareerRestart ( )
{
m_bGameOver = false ;
if ( m_flRestartRoundTime = = 0.0f )
{
m_flRestartRoundTime = gpGlobals - > time + 1.0f ;
}
// for reset everything
m_bCompleteReset = true ;
m_fCareerRoundMenuTime = 0 ;
m_fCareerMatchMenuTime = 0 ;
if ( TheCareerTasks )
{
TheCareerTasks - > Reset ( false ) ;
}
m_bSkipSpawn = false ;
for ( int i = 1 ; i < = gpGlobals - > maxClients ; i + + )
{
CBasePlayer * pPlayer = UTIL_PlayerByIndex ( i ) ;
2024-05-28 18:44:29 +03:00
if ( ! UTIL_IsValidPlayer ( pPlayer ) )
2019-09-23 00:09:58 +03:00
continue ;
if ( ! pPlayer - > IsBot ( ) )
{
pPlayer - > ForceClientDllUpdate ( ) ;
}
}
}
BOOL CHalfLifeMultiplay : : IsMultiplayer ( )
{
return TRUE ;
}
BOOL CHalfLifeMultiplay : : IsDeathmatch ( )
{
return TRUE ;
}
BOOL CHalfLifeMultiplay : : IsCoOp ( )
{
return gpGlobals - > coop ;
}
LINK_HOOK_CLASS_CUSTOM_CHAIN ( BOOL , CHalfLifeMultiplay , CSGameRules , FShouldSwitchWeapon , ( CBasePlayer * pPlayer , CBasePlayerItem * pWeapon ) , pPlayer , pWeapon )
BOOL EXT_FUNC CHalfLifeMultiplay : : __API_HOOK ( FShouldSwitchWeapon ) ( CBasePlayer * pPlayer , CBasePlayerItem * pWeapon )
{
if ( ! pWeapon - > CanDeploy ( ) )
{
// that weapon can't deploy anyway.
return FALSE ;
}
if ( ! pPlayer - > m_pActiveItem )
{
// player doesn't have an active item!
return TRUE ;
}
2020-12-05 16:14:53 +03:00
if ( pPlayer - > m_iAutoWepSwitch = = 0 )
2019-09-23 00:09:58 +03:00
return FALSE ;
2020-12-05 16:14:53 +03:00
# ifdef REGAMEDLL_ADD
if ( pPlayer - > m_iAutoWepSwitch = = 2 & & ( pPlayer - > m_afButtonLast & ( IN_ATTACK | IN_ATTACK2 ) ) )
return FALSE ;
# endif
2019-09-23 00:09:58 +03:00
if ( ! pPlayer - > m_pActiveItem - > CanHolster ( ) )
{
// can't put away the active item.
return FALSE ;
}
2021-05-22 14:12:24 +03:00
# ifdef REGAMEDLL_FIXES
if ( pPlayer - > pev - > waterlevel = = 3 )
{
if ( pWeapon - > iFlags ( ) & ITEM_FLAG_NOFIREUNDERWATER )
return FALSE ;
2021-06-15 12:59:58 +03:00
2021-05-22 14:12:24 +03:00
if ( pPlayer - > m_pActiveItem - > iFlags ( ) & ITEM_FLAG_NOFIREUNDERWATER )
return TRUE ;
}
# endif
2019-09-23 00:09:58 +03:00
if ( pWeapon - > iWeight ( ) > pPlayer - > m_pActiveItem - > iWeight ( ) )
return TRUE ;
return FALSE ;
}
LINK_HOOK_CLASS_CUSTOM_CHAIN ( BOOL , CHalfLifeMultiplay , CSGameRules , GetNextBestWeapon , ( CBasePlayer * pPlayer , CBasePlayerItem * pCurrentWeapon ) , pPlayer , pCurrentWeapon )
BOOL EXT_FUNC CHalfLifeMultiplay : : __API_HOOK ( GetNextBestWeapon ) ( CBasePlayer * pPlayer , CBasePlayerItem * pCurrentWeapon )
{
CBasePlayerItem * pCheck ;
CBasePlayerItem * pBest ; // this will be used in the event that we don't find a weapon in the same category.
int iBestWeight ;
int i ;
2021-05-22 14:12:24 +03:00
bool inWater = pPlayer - > pev - > waterlevel = = 3 ;
2019-09-23 00:09:58 +03:00
if ( ! pCurrentWeapon - > CanHolster ( ) )
{
// can't put this gun away right now, so can't switch.
return FALSE ;
}
iBestWeight = - 1 ; // no weapon lower than -1 can be autoswitched to
pBest = nullptr ;
for ( i = 0 ; i < MAX_ITEM_TYPES ; i + + )
{
pCheck = pPlayer - > m_rgpPlayerItems [ i ] ;
while ( pCheck )
{
// don't reselect the weapon we're trying to get rid of
2021-05-22 14:12:24 +03:00
if ( pCheck - > iWeight ( ) > iBestWeight & & pCheck ! = pCurrentWeapon
# ifdef REGAMEDLL_FIXES
& & ! ( inWater & & ( pCheck - > iFlags ( ) & ITEM_FLAG_NOFIREUNDERWATER ) )
# endif
)
2019-09-23 00:09:58 +03:00
{
//ALERT (at_console, "Considering %s\n", STRING(pCheck->pev->classname));
// we keep updating the 'best' weapon just in case we can't find a weapon of the same weight
// that the player was using. This will end up leaving the player with his heaviest-weighted weapon.
if ( pCheck - > CanDeploy ( ) )
{
// if this weapon is useable, flag it as the best
iBestWeight = pCheck - > iWeight ( ) ;
pBest = pCheck ;
}
}
pCheck = pCheck - > m_pNext ;
}
}
// if we make it here, we've checked all the weapons and found no useable
// weapon in the same catagory as the current weapon.
// if pBest is null, we didn't find ANYTHING. Shouldn't be possible- should always
// at least get the crowbar, but ya never know.
if ( ! pBest )
{
return FALSE ;
}
pPlayer - > SwitchWeapon ( pBest ) ;
return TRUE ;
}
BOOL CHalfLifeMultiplay : : ClientCommand_DeadOrAlive ( CBasePlayer * pPlayer , const char * pcmd )
{
return m_VoiceGameMgr . ClientCommand ( pPlayer , pcmd ) ;
}
BOOL CHalfLifeMultiplay : : ClientCommand ( CBasePlayer * pPlayer , const char * pcmd )
{
return FALSE ;
}
BOOL CHalfLifeMultiplay : : ClientConnected ( edict_t * pEntity , const char * pszName , const char * pszAddress , char * szRejectReason )
{
m_VoiceGameMgr . ClientConnected ( pEntity ) ;
return TRUE ;
}
void CHalfLifeMultiplay : : UpdateGameMode ( CBasePlayer * pPlayer )
{
MESSAGE_BEGIN ( MSG_ONE , gmsgGameMode , nullptr , pPlayer - > edict ( ) ) ;
WRITE_BYTE ( 1 ) ;
MESSAGE_END ( ) ;
}
void CHalfLifeMultiplay : : InitHUD ( CBasePlayer * pl )
{
int i ;
// notify other clients of player joining the game
UTIL_LogPrintf ( " \" %s<%i><%s><> \" entered the game \n " , STRING ( pl - > pev - > netname ) , GETPLAYERUSERID ( pl - > edict ( ) ) , GETPLAYERAUTHID ( pl - > edict ( ) ) ) ;
UpdateGameMode ( pl ) ;
if ( ! CVAR_GET_FLOAT ( " sv_cheats " ) )
{
MESSAGE_BEGIN ( MSG_ONE , gmsgViewMode , nullptr , pl - > edict ( ) ) ;
MESSAGE_END ( ) ;
}
// sending just one score makes the hud scoreboard active; otherwise
// it is just disabled for single play
MESSAGE_BEGIN ( MSG_ONE , gmsgScoreInfo , nullptr , pl - > edict ( ) ) ;
WRITE_BYTE ( ENTINDEX ( pl - > edict ( ) ) ) ;
WRITE_SHORT ( 0 ) ;
WRITE_SHORT ( 0 ) ;
WRITE_SHORT ( 0 ) ;
WRITE_SHORT ( pl - > m_iTeam ) ;
MESSAGE_END ( ) ;
MESSAGE_BEGIN ( MSG_ONE , gmsgShadowIdx , nullptr , pl - > edict ( ) ) ;
WRITE_LONG ( g_iShadowSprite ) ;
MESSAGE_END ( ) ;
if ( IsCareer ( ) )
{
MESSAGE_BEGIN ( MSG_ONE , gmsgCZCareer , nullptr , pl - > edict ( ) ) ;
WRITE_STRING ( " START " ) ;
WRITE_SHORT ( m_iRoundTime ) ;
MESSAGE_END ( ) ;
}
else
SendMOTDToClient ( pl - > edict ( ) ) ;
// loop through all active players and send their score info to the new client
for ( i = 1 ; i < = gpGlobals - > maxClients ; i + + )
{
// FIXME: Probably don't need to cast this just to read m_iDeaths
CBasePlayer * plr = UTIL_PlayerByIndex ( i ) ;
2024-05-28 18:44:29 +03:00
if ( ! UTIL_IsValidPlayer ( plr ) )
2019-09-23 00:09:58 +03:00
continue ;
MESSAGE_BEGIN ( MSG_ONE , gmsgScoreInfo , nullptr , pl - > edict ( ) ) ;
WRITE_BYTE ( i ) ; // client number
WRITE_SHORT ( int ( plr - > pev - > frags ) ) ;
WRITE_SHORT ( plr - > m_iDeaths ) ;
WRITE_SHORT ( 0 ) ;
WRITE_SHORT ( plr - > m_iTeam ) ;
MESSAGE_END ( ) ;
}
MESSAGE_BEGIN ( MSG_ONE , gmsgTeamScore , nullptr , pl - > edict ( ) ) ;
WRITE_STRING ( " TERRORIST " ) ;
WRITE_SHORT ( m_iNumTerroristWins ) ;
MESSAGE_END ( ) ;
MESSAGE_BEGIN ( MSG_ONE , gmsgTeamScore , nullptr , pl - > edict ( ) ) ;
WRITE_STRING ( " CT " ) ;
WRITE_SHORT ( m_iNumCTWins ) ;
MESSAGE_END ( ) ;
MESSAGE_BEGIN ( MSG_ONE , gmsgAllowSpec , nullptr , pl - > edict ( ) ) ;
WRITE_BYTE ( int ( allow_spectators . value ) ) ;
MESSAGE_END ( ) ;
MESSAGE_BEGIN ( MSG_ONE , gmsgForceCam , nullptr , pl - > edict ( ) ) ;
WRITE_BYTE ( forcecamera . value ! = 0 ) ;
WRITE_BYTE ( forcechasecam . value ! = 0 ) ;
2023-07-16 15:55:58 +03:00
WRITE_BYTE ( fadetoblack . value = = FADETOBLACK_STAY ) ;
2019-09-23 00:09:58 +03:00
MESSAGE_END ( ) ;
if ( m_bGameOver )
{
MESSAGE_BEGIN ( MSG_ONE , SVC_INTERMISSION , nullptr , pl - > edict ( ) ) ;
MESSAGE_END ( ) ;
}
for ( i = 1 ; i < = gpGlobals - > maxClients ; i + + )
{
CBasePlayer * plr = UTIL_PlayerByIndex ( i ) ;
2024-05-28 18:44:29 +03:00
if ( ! UTIL_IsValidPlayer ( plr ) )
2019-09-23 00:09:58 +03:00
continue ;
MESSAGE_BEGIN ( MSG_ONE , gmsgTeamInfo , nullptr , pl - > edict ( ) ) ;
WRITE_BYTE ( plr - > entindex ( ) ) ;
WRITE_STRING ( GetTeamName ( plr - > m_iTeam ) ) ;
MESSAGE_END ( ) ;
plr - > SetScoreboardAttributes ( pl ) ;
if ( pl - > entindex ( ) ! = i )
{
# ifndef REGAMEDLL_FIXES
2024-05-28 18:44:29 +03:00
if ( plr - > IsDormant ( ) )
2019-09-23 00:09:58 +03:00
continue ;
# endif
if ( plr - > pev - > deadflag = = DEAD_NO
# ifdef BUILD_LATEST_FIXES
& & plr - > m_iTeam = = pl - > m_iTeam
# endif
)
{
MESSAGE_BEGIN ( MSG_ONE , gmsgRadar , nullptr , pl - > edict ( ) ) ;
WRITE_BYTE ( plr - > entindex ( ) ) ;
WRITE_COORD ( plr - > pev - > origin . x ) ;
WRITE_COORD ( plr - > pev - > origin . y ) ;
WRITE_COORD ( plr - > pev - > origin . z ) ;
MESSAGE_END ( ) ;
}
}
# ifdef BUILD_LATEST
2019-12-17 17:25:24 +03:00
MESSAGE_BEGIN ( MSG_ONE , gmsgHealthInfo , nullptr , pl - > edict ( ) ) ;
WRITE_BYTE ( plr - > entindex ( ) ) ;
WRITE_LONG ( plr - > ShouldToShowHealthInfo ( pl ) ? plr - > m_iClientHealth : - 1 /* means that 'HP' field will be hidden */ ) ;
MESSAGE_END ( ) ;
2019-09-23 00:09:58 +03:00
2019-12-17 17:25:24 +03:00
MESSAGE_BEGIN ( MSG_ONE , gmsgAccount , nullptr , pl - > edict ( ) ) ;
WRITE_BYTE ( plr - > entindex ( ) ) ;
WRITE_LONG ( plr - > ShouldToShowAccount ( pl ) ? plr - > m_iAccount : - 1 /* means that this 'Money' will be hidden */ ) ;
MESSAGE_END ( ) ;
2019-09-23 00:09:58 +03:00
# endif // BUILD_LATEST
}
auto SendMsgBombDrop = [ & pl ] ( const int flag , const Vector & pos )
{
MESSAGE_BEGIN ( MSG_ONE , gmsgBombDrop , nullptr , pl - > edict ( ) ) ;
WRITE_COORD ( pos . x ) ;
WRITE_COORD ( pos . y ) ;
WRITE_COORD ( pos . z ) ;
WRITE_BYTE ( flag ) ;
MESSAGE_END ( ) ;
} ;
if ( m_bBombDropped )
{
CBaseEntity * pWeaponC4 = UTIL_FindEntityByClassname ( nullptr , " weapon_c4 " ) ;
if ( pWeaponC4 )
{
SendMsgBombDrop ( BOMB_FLAG_DROPPED , pWeaponC4 - > pev - > origin ) ;
}
}
# ifdef REGAMEDLL_FIXES
else
{
CGrenade * bomb = nullptr ;
while ( ( bomb = UTIL_FindEntityByClassname ( bomb , " grenade " ) ) )
{
if ( bomb - > m_bIsC4 )
{
// if the bomb was planted, which will trigger the round timer to hide.
SendMsgBombDrop ( BOMB_FLAG_PLANTED , bomb - > pev - > origin ) ;
if ( m_iRoundTime > 0 | | GetRoundRemainingTime ( ) > = 1.0f )
{
MESSAGE_BEGIN ( MSG_ONE , gmsgShowTimer , nullptr , pl - > pev ) ;
MESSAGE_END ( ) ;
}
else
{
// HACK HACK, we need to hide only the timer.
SendMsgBombDrop ( BOMB_FLAG_PLANTED , g_vecZero ) ;
MESSAGE_BEGIN ( MSG_ONE , gmsgBombPickup , nullptr , pl - > pev ) ;
MESSAGE_END ( ) ;
}
break ;
}
}
}
# endif
}
void CHalfLifeMultiplay : : ClientDisconnected ( edict_t * pClient )
{
if ( pClient )
{
CBasePlayer * pPlayer = CBasePlayer : : Instance ( pClient ) ;
if ( pPlayer )
{
pPlayer - > has_disconnected = true ;
pPlayer - > pev - > deadflag = DEAD_DEAD ;
pPlayer - > SetScoreboardAttributes ( ) ;
if ( pPlayer - > m_bHasC4 )
{
pPlayer - > DropPlayerItem ( " weapon_c4 " ) ;
}
2023-12-22 22:43:42 +03:00
2019-09-23 00:09:58 +03:00
if ( pPlayer - > m_bHasDefuser )
{
2023-10-11 01:05:13 +03:00
# ifdef REGAMEDLL_FIXES
SpawnDefuser ( pPlayer - > pev - > origin , nullptr ) ;
# else
pPlayer - > DropPlayerItem ( " item_thighpack " ) ; // DropPlayerItem didn't handle item_thighpack
2019-09-23 00:09:58 +03:00
# endif
2023-10-11 01:05:13 +03:00
}
2019-09-23 00:09:58 +03:00
if ( pPlayer - > m_bIsVIP )
{
m_pVIP = nullptr ;
}
pPlayer - > m_iCurrentKickVote = 0 ;
if ( pPlayer - > m_iMapVote )
{
m_iMapVotes [ pPlayer - > m_iMapVote ] - - ;
if ( m_iMapVotes [ pPlayer - > m_iMapVote ] < 0 )
{
m_iMapVotes [ pPlayer - > m_iMapVote ] = 0 ;
}
}
MESSAGE_BEGIN ( MSG_ALL , gmsgScoreInfo ) ;
WRITE_BYTE ( ENTINDEX ( pClient ) ) ;
WRITE_SHORT ( 0 ) ;
WRITE_SHORT ( 0 ) ;
WRITE_SHORT ( 0 ) ;
WRITE_SHORT ( 0 ) ;
MESSAGE_END ( ) ;
MESSAGE_BEGIN ( MSG_ALL , gmsgTeamInfo ) ;
WRITE_BYTE ( ENTINDEX ( pClient ) ) ;
WRITE_STRING ( " UNASSIGNED " ) ;
MESSAGE_END ( ) ;
MESSAGE_BEGIN ( MSG_ALL , gmsgLocation ) ;
WRITE_BYTE ( ENTINDEX ( pClient ) ) ;
WRITE_STRING ( " " ) ;
MESSAGE_END ( ) ;
char * team = GetTeam ( pPlayer - > m_iTeam ) ;
FireTargets ( " game_playerleave " , pPlayer , pPlayer , USE_TOGGLE , 0 ) ;
UTIL_LogPrintf ( " \" %s<%i><%s><%s> \" disconnected \n " , STRING ( pPlayer - > pev - > netname ) , GETPLAYERUSERID ( pPlayer - > edict ( ) ) , GETPLAYERAUTHID ( pPlayer - > edict ( ) ) , team ) ;
// destroy all of the players weapons and items
pPlayer - > RemoveAllItems ( TRUE ) ;
if ( pPlayer - > m_pObserver )
{
pPlayer - > m_pObserver - > SUB_Remove ( ) ;
}
CBasePlayer * pObserver = nullptr ;
while ( ( pObserver = UTIL_FindEntityByClassname ( pObserver , " player " ) ) )
{
if ( FNullEnt ( pObserver - > edict ( ) ) )
break ;
if ( ! pObserver - > pev | | pObserver = = pPlayer )
continue ;
2024-05-28 18:44:29 +03:00
if ( pObserver - > IsDormant ( ) )
continue ;
2019-09-23 00:09:58 +03:00
// If a spectator was chasing this player, move him/her onto the next player
if ( pObserver - > m_hObserverTarget = = pPlayer )
{
int iMode = pObserver - > pev - > iuser1 ;
pObserver - > pev - > iuser1 = OBS_NONE ;
2020-11-28 03:32:52 +03:00
# ifdef REGAMEDLL_FIXES
pObserver - > m_flNextFollowTime = 0.0 ;
# endif
2019-09-23 00:09:58 +03:00
pObserver - > Observer_SetMode ( iMode ) ;
}
}
2020-07-16 14:07:34 +03:00
# ifdef REGAMEDLL_FIXES
// Client is gone, make sure that his body disappeared and became not solid
pPlayer - > MakeDormant ( ) ;
# endif
2019-09-23 00:09:58 +03:00
}
}
CheckWinConditions ( ) ;
}
LINK_HOOK_CLASS_CUSTOM_CHAIN ( float , CHalfLifeMultiplay , CSGameRules , FlPlayerFallDamage , ( CBasePlayer * pPlayer ) , pPlayer )
float EXT_FUNC CHalfLifeMultiplay : : __API_HOOK ( FlPlayerFallDamage ) ( CBasePlayer * pPlayer )
{
2020-05-27 04:26:45 +03:00
2020-07-16 14:07:34 +03:00
# ifdef REGAMEDLL_ADD
2020-05-27 04:26:45 +03:00
if ( ! falldamage . value )
{
return 0.0f ;
}
# endif
2019-09-23 00:09:58 +03:00
pPlayer - > m_flFallVelocity - = MAX_PLAYER_SAFE_FALL_SPEED ;
return pPlayer - > m_flFallVelocity * DAMAGE_FOR_FALL_SPEED * 1.25 ;
}
LINK_HOOK_CLASS_CUSTOM_CHAIN ( BOOL , CHalfLifeMultiplay , CSGameRules , FPlayerCanTakeDamage , ( CBasePlayer * pPlayer , CBaseEntity * pAttacker ) , pPlayer , pAttacker )
BOOL EXT_FUNC CHalfLifeMultiplay : : __API_HOOK ( FPlayerCanTakeDamage ) ( CBasePlayer * pPlayer , CBaseEntity * pAttacker )
{
if ( ! pAttacker | | PlayerRelationship ( pPlayer , pAttacker ) ! = GR_TEAMMATE )
{
return TRUE ;
}
if ( friendlyfire . value ! = 0.0f | | pAttacker = = pPlayer )
{
return TRUE ;
}
return FALSE ;
}
void CHalfLifeMultiplay : : PlayerThink ( CBasePlayer * pPlayer )
{
if ( m_bGameOver )
{
// check for button presses
if ( ! IsCareer ( ) & & ( pPlayer - > m_afButtonPressed & ( IN_DUCK | IN_ATTACK | IN_ATTACK2 | IN_USE | IN_JUMP ) ) )
{
m_iEndIntermissionButtonHit = TRUE ;
}
// clear attack/use commands from player
pPlayer - > m_afButtonPressed = 0 ;
pPlayer - > pev - > button = 0 ;
pPlayer - > m_afButtonReleased = 0 ;
}
if ( ! pPlayer - > m_bCanShoot & & ! IsFreezePeriod ( ) )
{
pPlayer - > m_bCanShoot = true ;
}
if ( pPlayer - > m_pActiveItem & & pPlayer - > m_pActiveItem - > IsWeapon ( ) )
{
CBasePlayerWeapon * pWeapon = static_cast < CBasePlayerWeapon * > ( pPlayer - > m_pActiveItem - > GetWeaponPtr ( ) ) ;
2021-05-22 14:12:24 +03:00
if ( pWeapon - > m_iWeaponState & WPNSTATE_SHIELD_DRAWN
# ifdef REGAMEDLL_ADD
| | ( ( pWeapon - > iFlags ( ) & ITEM_FLAG_NOFIREUNDERWATER ) & & pPlayer - > pev - > waterlevel = = 3 )
# endif
)
2019-09-23 00:09:58 +03:00
{
pPlayer - > m_bCanShoot = false ;
}
}
if ( pPlayer - > m_iMenu ! = Menu_ChooseTeam & & pPlayer - > m_iJoiningState = = SHOWTEAMSELECT )
{
int slot = MENU_SLOT_TEAM_UNDEFINED ;
if ( ! Q_stricmp ( humans_join_team . string , " T " ) )
{
slot = MENU_SLOT_TEAM_TERRORIST ;
}
else if ( ! Q_stricmp ( humans_join_team . string , " CT " ) )
{
slot = MENU_SLOT_TEAM_CT ;
}
# ifdef REGAMEDLL_ADD
else if ( ! Q_stricmp ( humans_join_team . string , " any " ) & & auto_join_team . value ! = 0.0f )
{
slot = MENU_SLOT_TEAM_RANDOM ;
}
else if ( ! Q_stricmp ( humans_join_team . string , " SPEC " ) & & auto_join_team . value ! = 0.0f )
{
slot = MENU_SLOT_TEAM_SPECT ;
}
# endif
else
{
if ( allow_spectators . value = = 0.0f )
ShowVGUIMenu ( pPlayer , VGUI_Menu_Team , ( MENU_KEY_1 | MENU_KEY_2 | MENU_KEY_5 ) , " #Team_Select " ) ;
else
ShowVGUIMenu ( pPlayer , VGUI_Menu_Team , ( MENU_KEY_1 | MENU_KEY_2 | MENU_KEY_5 | MENU_KEY_6 ) , " #Team_Select_Spect " ) ;
}
pPlayer - > m_iMenu = Menu_ChooseTeam ;
pPlayer - > m_iJoiningState = PICKINGTEAM ;
if ( slot ! = MENU_SLOT_TEAM_UNDEFINED & & ! pPlayer - > IsBot ( )
# ifdef REGAMEDLL_ADD
& & ! ( pPlayer - > pev - > flags & FL_FAKECLIENT )
# endif
)
{
# ifdef REGAMEDLL_ADD
m_bSkipShowMenu = ( auto_join_team . value ! = 0.0f ) & & ! ( pPlayer - > pev - > flags & FL_FAKECLIENT ) ;
if ( HandleMenu_ChooseTeam ( pPlayer , slot ) )
{
if ( slot ! = MENU_SLOT_TEAM_SPECT & & ( IsCareer ( ) | | m_bSkipShowMenu ) )
{
// slot 6 - chooses randomize the appearance to model player
HandleMenu_ChooseAppearance ( pPlayer , 6 ) ;
}
}
else
{
m_bSkipShowMenu = false ;
if ( allow_spectators . value = = 0.0f )
ShowVGUIMenu ( pPlayer , VGUI_Menu_Team , ( MENU_KEY_1 | MENU_KEY_2 | MENU_KEY_5 ) , " #Team_Select " ) ;
else
ShowVGUIMenu ( pPlayer , VGUI_Menu_Team , ( MENU_KEY_1 | MENU_KEY_2 | MENU_KEY_5 | MENU_KEY_6 ) , " #Team_Select_Spect " ) ;
}
m_bSkipShowMenu = false ;
# else
HandleMenu_ChooseTeam ( pPlayer , slot ) ;
if ( slot ! = MENU_SLOT_TEAM_SPECT & & IsCareer ( ) )
{
// slot 6 - chooses randomize the appearance to model player
HandleMenu_ChooseAppearance ( pPlayer , 6 ) ;
}
# endif
}
}
}
LINK_HOOK_CLASS_VOID_CUSTOM_CHAIN ( CHalfLifeMultiplay , CSGameRules , PlayerSpawn , ( CBasePlayer * pPlayer ) , pPlayer )
// Purpose: Player has just spawned. Equip them.
void EXT_FUNC CHalfLifeMultiplay : : __API_HOOK ( PlayerSpawn ) ( CBasePlayer * pPlayer )
{
// This is tied to the joining state (m_iJoiningState).. add it when the joining state is there.
if ( pPlayer - > m_bJustConnected )
return ;
2020-12-05 16:14:53 +03:00
# ifdef REGAMEDLL_ADD
int iAutoWepSwitch = pPlayer - > m_iAutoWepSwitch ;
pPlayer - > m_iAutoWepSwitch = 1 ;
# endif
2019-09-23 00:09:58 +03:00
pPlayer - > pev - > weapons | = ( 1 < < WEAPON_SUIT ) ;
pPlayer - > OnSpawnEquip ( ) ;
pPlayer - > SetPlayerModel ( false ) ;
2020-12-05 16:14:53 +03:00
# ifdef REGAMEDLL_ADD
pPlayer - > m_iAutoWepSwitch = iAutoWepSwitch ;
# endif
2019-09-23 00:09:58 +03:00
# ifdef REGAMEDLL_ADD
if ( respawn_immunitytime . value > 0 )
pPlayer - > SetSpawnProtection ( respawn_immunitytime . value ) ;
2024-01-12 11:55:00 +03:00
// remove any defusers left over from previous random if there is just one random one
if ( m_bMapHasBombTarget & & ( int ) defuser_allocation . value = = DEFUSERALLOCATION_RANDOM )
pPlayer - > RemoveDefuser ( ) ;
2019-09-23 00:09:58 +03:00
# endif
}
LINK_HOOK_CLASS_CUSTOM_CHAIN ( BOOL , CHalfLifeMultiplay , CSGameRules , FPlayerCanRespawn , ( CBasePlayer * pPlayer ) , pPlayer )
BOOL EXT_FUNC CHalfLifeMultiplay : : __API_HOOK ( FPlayerCanRespawn ) ( CBasePlayer * pPlayer )
{
# ifdef REGAMEDLL_ADD
if ( forcerespawn . value < = 0 )
# endif
{
// Player cannot respawn twice in a round
if ( pPlayer - > m_iNumSpawns > 0 )
{
return FALSE ;
}
// Player cannot respawn until next round if more than 20 seconds in
// Tabulate the number of players on each team.
m_iNumCT = CountTeamPlayers ( CT ) ;
m_iNumTerrorist = CountTeamPlayers ( TERRORIST ) ;
if ( m_iNumTerrorist > 0 & & m_iNumCT > 0 )
{
# ifdef REGAMEDLL_ADD
// means no time limit
if ( GetRoundRespawnTime ( ) ! = - 1 )
# endif
{
// TODO: to be correct, need use time the real one starts of round, m_fRoundStartTimeReal instead of it.
// m_fRoundStartTime able to extend the time to 60 seconds when there is a remaining time of round.
# ifdef REGAMEDLL_FIXES
if ( gpGlobals - > time > m_fRoundStartTimeReal + GetRoundRespawnTime ( ) )
# else
if ( gpGlobals - > time > m_fRoundStartTime + GetRoundRespawnTime ( ) )
# endif
{
// If this player just connected and fadetoblack is on, then maybe
// the server admin doesn't want him peeking around.
2023-07-16 15:55:58 +03:00
if ( fadetoblack . value = = FADETOBLACK_STAY )
2019-09-23 00:09:58 +03:00
{
UTIL_ScreenFade ( pPlayer , Vector ( 0 , 0 , 0 ) , 3 , 3 , 255 , ( FFADE_OUT | FFADE_STAYOUT ) ) ;
}
return FALSE ;
}
}
}
}
// Player cannot respawn while in the Choose Appearance menu
if ( pPlayer - > m_iMenu = = Menu_ChooseAppearance )
{
return FALSE ;
}
return TRUE ;
}
float CHalfLifeMultiplay : : FlPlayerSpawnTime ( CBasePlayer * pPlayer )
{
return gpGlobals - > time ;
}
BOOL CHalfLifeMultiplay : : AllowAutoTargetCrosshair ( )
{
return FALSE ;
}
// How many points awarded to anyone that kills this player?
int CHalfLifeMultiplay : : IPointsForKill ( CBasePlayer * pAttacker , CBasePlayer * pKilled )
{
return 1 ;
}
LINK_HOOK_CLASS_VOID_CUSTOM_CHAIN ( CHalfLifeMultiplay , CSGameRules , PlayerKilled , ( CBasePlayer * pVictim , entvars_t * pKiller , entvars_t * pInflictor ) , pVictim , pKiller , pInflictor )
// Someone/something killed this player
void EXT_FUNC CHalfLifeMultiplay : : __API_HOOK ( PlayerKilled ) ( CBasePlayer * pVictim , entvars_t * pKiller , entvars_t * pInflictor )
{
DeathNotice ( pVictim , pKiller , pInflictor ) ;
2023-09-28 12:18:15 +03:00
# ifdef REGAMEDLL_FIXES
2023-03-31 20:53:04 +03:00
pVictim - > pev - > flags & = ~ FL_FROZEN ;
# endif
2019-09-23 00:09:58 +03:00
pVictim - > m_afPhysicsFlags & = ~ PFLAG_ONTRAIN ;
pVictim - > m_iDeaths + + ;
pVictim - > m_bNotKilled = false ;
pVictim - > m_bEscaped = false ;
pVictim - > m_iTrain = ( TRAIN_NEW | TRAIN_OFF ) ;
SET_VIEW ( ENT ( pVictim - > pev ) , ENT ( pVictim - > pev ) ) ;
CBasePlayer * peKiller = nullptr ;
CBaseEntity * ktmp = CBaseEntity : : Instance ( pKiller ) ;
if ( ktmp & & ktmp - > Classify ( ) = = CLASS_PLAYER )
{
peKiller = static_cast < CBasePlayer * > ( ktmp ) ;
}
else if ( ktmp & & ktmp - > Classify ( ) = = CLASS_VEHICLE )
{
CBasePlayer * pDriver = static_cast < CBasePlayer * > ( ( ( CFuncVehicle * ) ktmp ) - > m_pDriver ) ;
2022-12-06 22:11:25 +03:00
# ifdef REGAMEDLL_FIXES
if ( pDriver & & ! pDriver - > has_disconnected )
# else
2019-09-23 00:09:58 +03:00
if ( pDriver )
2022-12-06 22:11:25 +03:00
# endif
2019-09-23 00:09:58 +03:00
{
pKiller = pDriver - > pev ;
peKiller = static_cast < CBasePlayer * > ( pDriver ) ;
}
}
FireTargets ( " game_playerdie " , pVictim , pVictim , USE_TOGGLE , 0 ) ;
2024-01-31 14:38:47 +03:00
# ifdef REGAMEDLL_FIXES
// Did the player die from a fall?
if ( pVictim - > m_bitsDamageType & DMG_FALL )
{
// do nothing
}
else
# endif
2019-09-23 00:09:58 +03:00
// Did the player kill himself?
if ( pVictim - > pev = = pKiller )
{
// Players lose a frag for killing themselves
2024-01-31 14:38:47 +03:00
pVictim - > pev - > frags - = 1 ;
2019-09-23 00:09:58 +03:00
}
else if ( peKiller & & peKiller - > IsPlayer ( ) )
{
// if a player dies in a deathmatch game and the killer is a client, award the killer some points
CBasePlayer * killer = GetClassPtr < CCSPlayer > ( ( CBasePlayer * ) pKiller ) ;
2021-04-12 15:55:03 +03:00
if ( g_pGameRules - > PlayerRelationship ( pVictim , killer ) = = GR_TEAMMATE )
2019-09-23 00:09:58 +03:00
{
// if a player dies by from teammate
pKiller - > frags - = IPointsForKill ( peKiller , pVictim ) ;
killer - > AddAccount ( PAYBACK_FOR_KILLED_TEAMMATES , RT_TEAMMATES_KILLED ) ;
killer - > m_iTeamKills + + ;
killer - > m_bJustKilledTeammate = true ;
ClientPrint ( killer - > pev , HUD_PRINTCENTER , " #Killed_Teammate " ) ;
ClientPrint ( killer - > pev , HUD_PRINTCONSOLE , " #Game_teammate_kills " , UTIL_dtos1 ( killer - > m_iTeamKills ) ) ;
# ifdef REGAMEDLL_ADD
if ( autokick . value & & max_teamkills . value & & killer - > m_iTeamKills > = ( int ) max_teamkills . value )
# else
if ( autokick . value & & killer - > m_iTeamKills = = 3 )
# endif
{
# ifdef REGAMEDLL_FIXES
ClientPrint ( killer - > pev , HUD_PRINTCONSOLE , " #Banned_For_Killing_Teammates " ) ;
# else
ClientPrint ( killer - > pev , HUD_PRINTCONSOLE , " #Banned_For_Killing_Teamates " ) ;
# endif
int iUserID = GETPLAYERUSERID ( killer - > edict ( ) ) ;
if ( iUserID ! = - 1 )
{
# ifdef REGAMEDLL_FIXES
SERVER_COMMAND ( UTIL_VarArgs ( " kick #%d \" For killing too many teammates \" \n " , iUserID ) ) ;
# else
SERVER_COMMAND ( UTIL_VarArgs ( " kick # %d \n " , iUserID ) ) ;
# endif
}
}
if ( ! ( killer - > m_flDisplayHistory & DHF_FRIEND_KILLED ) )
{
killer - > m_flDisplayHistory | = DHF_FRIEND_KILLED ;
killer - > HintMessage ( " #Hint_careful_around_teammates " ) ;
}
}
else
{
// if a player dies in a deathmatch game and the killer is a client, award the killer some points
pKiller - > frags + = IPointsForKill ( peKiller , pVictim ) ;
if ( pVictim - > m_bIsVIP )
{
killer - > HintMessage ( " #Hint_reward_for_killing_vip " , TRUE ) ;
killer - > AddAccount ( REWARD_KILLED_VIP , RT_VIP_KILLED ) ;
MESSAGE_BEGIN ( MSG_SPEC , SVC_DIRECTOR ) ;
WRITE_BYTE ( 9 ) ;
WRITE_BYTE ( DRC_CMD_EVENT ) ;
WRITE_SHORT ( ENTINDEX ( pVictim - > edict ( ) ) ) ;
WRITE_SHORT ( ENTINDEX ( ENT ( pInflictor ) ) ) ;
WRITE_LONG ( DRC_FLAG_PRIO_MASK | DRC_FLAG_DRAMATIC | DRC_FLAG_FINAL ) ;
MESSAGE_END ( ) ;
UTIL_LogPrintf ( " \" %s<%i><%s><TERRORIST> \" triggered \" Assassinated_The_VIP \" \n " , STRING ( killer - > pev - > netname ) , GETPLAYERUSERID ( killer - > edict ( ) ) , GETPLAYERAUTHID ( killer - > edict ( ) ) ) ;
}
else
killer - > AddAccount ( REWARD_KILLED_ENEMY , RT_ENEMY_KILLED ) ;
if ( ! ( killer - > m_flDisplayHistory & DHF_ENEMY_KILLED ) )
{
killer - > m_flDisplayHistory | = DHF_ENEMY_KILLED ;
killer - > HintMessage ( " #Hint_win_round_by_killing_enemy " ) ;
}
}
FireTargets ( " game_playerkill " , peKiller , peKiller , USE_TOGGLE , 0 ) ;
}
else
{
// killed by the world
pKiller - > frags - = 1 ;
}
// update the scores
// killed scores
# ifndef REGAMEDLL_FIXES
MESSAGE_BEGIN ( MSG_BROADCAST , gmsgScoreInfo ) ;
# else
MESSAGE_BEGIN ( MSG_ALL , gmsgScoreInfo ) ;
# endif
WRITE_BYTE ( ENTINDEX ( pVictim - > edict ( ) ) ) ;
WRITE_SHORT ( int ( pVictim - > pev - > frags ) ) ;
WRITE_SHORT ( pVictim - > m_iDeaths ) ;
WRITE_SHORT ( 0 ) ;
WRITE_SHORT ( pVictim - > m_iTeam ) ;
MESSAGE_END ( ) ;
// killers score, if it's a player
CBaseEntity * ep = CBaseEntity : : Instance ( pKiller ) ;
if ( ep & & ep - > Classify ( ) = = CLASS_PLAYER )
{
CBasePlayer * PK = static_cast < CBasePlayer * > ( ep ) ;
MESSAGE_BEGIN ( MSG_ALL , gmsgScoreInfo ) ;
WRITE_BYTE ( ENTINDEX ( PK - > edict ( ) ) ) ;
WRITE_SHORT ( int ( PK - > pev - > frags ) ) ;
WRITE_SHORT ( PK - > m_iDeaths ) ;
WRITE_SHORT ( 0 ) ;
WRITE_SHORT ( PK - > m_iTeam ) ;
MESSAGE_END ( ) ;
// let the killer paint another decal as soon as he'd like.
PK - > m_flNextDecalTime = gpGlobals - > time ;
}
}
LINK_HOOK_CLASS_VOID_CUSTOM_CHAIN ( CHalfLifeMultiplay , CSGameRules , DeathNotice , ( CBasePlayer * pVictim , entvars_t * pKiller , entvars_t * pevInflictor ) , pVictim , pKiller , pevInflictor )
2023-09-28 12:18:15 +03:00
void EXT_FUNC CHalfLifeMultiplay : : __API_HOOK ( DeathNotice ) ( CBasePlayer * pVictim , entvars_t * pevKiller , entvars_t * pevInflictor )
2019-09-23 00:09:58 +03:00
{
// by default, the player is killed by the world
2023-09-28 12:18:15 +03:00
CBasePlayer * pKiller = ( pevKiller - > flags & FL_CLIENT ) ? CBasePlayer : : Instance ( pevKiller ) : nullptr ;
const char * killer_weapon_name = pVictim - > GetKillerWeaponName ( pevInflictor , pevKiller ) ;
2019-09-23 00:09:58 +03:00
2023-09-28 12:18:15 +03:00
if ( ! TheTutor )
2019-09-23 00:09:58 +03:00
{
2023-09-28 12:18:15 +03:00
int iRarityOfKill = 0 ;
int iDeathMessageFlags = PLAYERDEATH_POSITION ; // set default bit
2019-09-23 00:09:58 +03:00
2023-09-28 12:18:15 +03:00
CBasePlayer * pAssister = nullptr ;
bool bFlashAssist = false ;
if ( ( pAssister = CheckAssistsToKill ( pKiller , pVictim , bFlashAssist ) ) )
2019-09-23 00:09:58 +03:00
{
2023-09-28 12:18:15 +03:00
// Add a flag indicating the presence of an assistant who assisted in the kill
iDeathMessageFlags | = PLAYERDEATH_ASSISTANT ;
2019-09-23 00:09:58 +03:00
}
2023-09-28 12:18:15 +03:00
iRarityOfKill = GetRarityOfKill ( pKiller , pVictim , pAssister , killer_weapon_name , bFlashAssist ) ;
if ( iRarityOfKill ! = 0 )
{
// Add a flag indicating that the attacker killed the victim in a rare way
iDeathMessageFlags | = PLAYERDEATH_KILLRARITY ;
}
2019-09-23 00:09:58 +03:00
2024-05-08 18:59:40 +03:00
# ifdef REGAMEDLL_ADD
iDeathMessageFlags & = UTIL_ReadFlags ( deathmsg_flags . string ) ; // leave only allowed bitsums for extra info
// Send the victim's death position only
// 1. if it is not a free for all mode
// 2. if the attacker is a player and they are not teammates
if ( IsFreeForAll ( ) | | ! pKiller | | PlayerRelationship ( pKiller , pVictim ) = = GR_TEAMMATE )
iDeathMessageFlags & = ~ PLAYERDEATH_POSITION ; // do not send a position
# endif
2023-09-28 12:18:15 +03:00
SendDeathMessage ( pKiller , pVictim , pAssister , pevInflictor , killer_weapon_name , iDeathMessageFlags , iRarityOfKill ) ;
2019-09-23 00:09:58 +03:00
2023-09-28 12:18:15 +03:00
// Updates the stats of who has killed whom
if ( pKiller & & pKiller - > IsPlayer ( ) & & PlayerRelationship ( pVictim , pKiller ) ! = GR_TEAMMATE )
{
int iPlayerIndexKiller = pKiller - > entindex ( ) ;
int iPlayerIndexVictim = pVictim - > entindex ( ) ;
2019-09-23 00:09:58 +03:00
2023-09-28 12:18:15 +03:00
pKiller - > CSPlayer ( ) - > m_iNumKilledByUnanswered [ iPlayerIndexVictim - 1 ] = 0 ;
pVictim - > CSPlayer ( ) - > m_iNumKilledByUnanswered [ iPlayerIndexKiller - 1 ] + + ;
}
}
2019-09-23 00:09:58 +03:00
// Did he kill himself?
2023-09-28 12:18:15 +03:00
if ( pVictim - > pev = = pevKiller )
2019-09-23 00:09:58 +03:00
{
// killed self
char * team = GetTeam ( pVictim - > m_iTeam ) ;
UTIL_LogPrintf ( " \" %s<%i><%s><%s> \" committed suicide with \" %s \" \n " , STRING ( pVictim - > pev - > netname ) , GETPLAYERUSERID ( pVictim - > edict ( ) ) ,
GETPLAYERAUTHID ( pVictim - > edict ( ) ) , team , killer_weapon_name ) ;
}
2023-09-28 12:18:15 +03:00
else if ( pevKiller - > flags & FL_CLIENT )
2019-09-23 00:09:58 +03:00
{
const char * VictimTeam = GetTeam ( pVictim - > m_iTeam ) ;
2023-09-28 12:18:15 +03:00
const char * KillerTeam = ( pKiller & & pKiller - > IsPlayer ( ) ) ? GetTeam ( pKiller - > m_iTeam ) : " " ;
2019-09-23 00:09:58 +03:00
2023-09-28 12:18:15 +03:00
UTIL_LogPrintf ( " \" %s<%i><%s><%s> \" killed \" %s<%i><%s><%s> \" with \" %s \" \n " , STRING ( pevKiller - > netname ) , GETPLAYERUSERID ( ENT ( pevKiller ) ) , GETPLAYERAUTHID ( ENT ( pevKiller ) ) ,
2019-09-23 00:09:58 +03:00
KillerTeam , STRING ( pVictim - > pev - > netname ) , GETPLAYERUSERID ( pVictim - > edict ( ) ) , GETPLAYERAUTHID ( pVictim - > edict ( ) ) , VictimTeam , killer_weapon_name ) ;
}
else
{
// killed by the world
char * team = GetTeam ( pVictim - > m_iTeam ) ;
UTIL_LogPrintf ( " \" %s<%i><%s><%s> \" committed suicide with \" %s \" (world) \n " , STRING ( pVictim - > pev - > netname ) , GETPLAYERUSERID ( pVictim - > edict ( ) ) ,
GETPLAYERAUTHID ( pVictim - > edict ( ) ) , team , killer_weapon_name ) ;
}
// TODO: It is called in CBasePlayer::Killed too, most likely,
// an unnecessary call. (Need investigate)
CheckWinConditions ( ) ;
MESSAGE_BEGIN ( MSG_SPEC , SVC_DIRECTOR ) ;
WRITE_BYTE ( 9 ) ; // command length in bytes
WRITE_BYTE ( DRC_CMD_EVENT ) ; // player killed
WRITE_SHORT ( ENTINDEX ( pVictim - > edict ( ) ) ) ; // index number of primary entity
if ( pevInflictor )
WRITE_SHORT ( ENTINDEX ( ENT ( pevInflictor ) ) ) ; // index number of secondary entity
else
2023-09-28 12:18:15 +03:00
WRITE_SHORT ( ENTINDEX ( ENT ( pevKiller ) ) ) ; // index number of secondary entity
2019-09-23 00:09:58 +03:00
if ( pVictim - > m_bHeadshotKilled )
WRITE_LONG ( 9 | DRC_FLAG_DRAMATIC | DRC_FLAG_SLOWMOTION ) ;
else
WRITE_LONG ( 7 | DRC_FLAG_DRAMATIC ) ; // eventflags (priority and flags)
MESSAGE_END ( ) ;
}
2023-09-05 06:43:40 +03:00
LINK_HOOK_CLASS_VOID_CUSTOM_CHAIN ( CHalfLifeMultiplay , CSGameRules , PlayerGotWeapon , ( CBasePlayer * pPlayer , CBasePlayerItem * pWeapon ) , pPlayer , pWeapon )
2019-09-23 00:09:58 +03:00
// Player has grabbed a weapon that was sitting in the world
2023-09-05 06:43:40 +03:00
void EXT_FUNC CHalfLifeMultiplay : : __API_HOOK ( PlayerGotWeapon ) ( CBasePlayer * pPlayer , CBasePlayerItem * pWeapon )
2019-09-23 00:09:58 +03:00
{
;
}
// What is the time in the future at which this weapon may spawn?
float CHalfLifeMultiplay : : FlWeaponRespawnTime ( CBasePlayerItem * pWeapon )
{
2024-08-03 20:17:52 +03:00
# ifdef REGAMEDLL_ADD
return gpGlobals - > time + weapon_respawn_time . value ;
# else
2019-09-23 00:09:58 +03:00
return gpGlobals - > time + WEAPON_RESPAWN_TIME ;
2024-08-03 20:17:52 +03:00
# endif
2019-09-23 00:09:58 +03:00
}
// Returns 0 if the weapon can respawn now,
// otherwise it returns the time at which it can try to spawn again.
float CHalfLifeMultiplay : : FlWeaponTryRespawn ( CBasePlayerItem * pWeapon )
{
if ( pWeapon & & pWeapon - > m_iId & & ( pWeapon - > iFlags ( ) & ITEM_FLAG_LIMITINWORLD ) )
{
if ( NUMBER_OF_ENTITIES ( ) < ( gpGlobals - > maxEntities - ENTITY_INTOLERANCE ) )
return 0 ;
// we're past the entity tolerance level, so delay the respawn
return FlWeaponRespawnTime ( pWeapon ) ;
}
return 0 ;
}
// Where should this weapon spawn?
// Some game variations may choose to randomize spawn locations
Vector CHalfLifeMultiplay : : VecWeaponRespawnSpot ( CBasePlayerItem * pWeapon )
{
return pWeapon - > pev - > origin ;
}
// Any conditions inhibiting the respawning of this weapon?
int CHalfLifeMultiplay : : WeaponShouldRespawn ( CBasePlayerItem * pWeapon )
{
if ( pWeapon - > pev - > spawnflags & SF_NORESPAWN )
{
return GR_WEAPON_RESPAWN_NO ;
}
return GR_WEAPON_RESPAWN_YES ;
}
LINK_HOOK_CLASS_CUSTOM_CHAIN ( BOOL , CHalfLifeMultiplay , CSGameRules , CanHavePlayerItem , ( CBasePlayer * pPlayer , CBasePlayerItem * pItem ) , pPlayer , pItem )
// Returns FALSE if the player is not allowed to pick up this weapon
BOOL EXT_FUNC CHalfLifeMultiplay : : __API_HOOK ( CanHavePlayerItem ) ( CBasePlayer * pPlayer , CBasePlayerItem * pItem )
{
return CGameRules : : CanHavePlayerItem ( pPlayer , pItem ) ;
}
BOOL CHalfLifeMultiplay : : CanHaveItem ( CBasePlayer * pPlayer , CItem * pItem )
{
return TRUE ;
}
void CHalfLifeMultiplay : : PlayerGotItem ( CBasePlayer * pPlayer , CItem * pItem )
{
;
}
int CHalfLifeMultiplay : : ItemShouldRespawn ( CItem * pItem )
{
if ( pItem - > pev - > spawnflags & SF_NORESPAWN )
{
return GR_ITEM_RESPAWN_NO ;
}
return GR_ITEM_RESPAWN_YES ;
}
// At what time in the future may this Item respawn?
float CHalfLifeMultiplay : : FlItemRespawnTime ( CItem * pItem )
{
2024-08-05 23:26:10 +03:00
# ifdef REGAMEDLL_ADD
2024-08-03 20:17:52 +03:00
return gpGlobals - > time + item_respawn_time . value ;
# else
2019-09-23 00:09:58 +03:00
return gpGlobals - > time + ITEM_RESPAWN_TIME ;
2024-08-03 20:17:52 +03:00
# endif
2019-09-23 00:09:58 +03:00
}
// Where should this item respawn?
// Some game variations may choose to randomize spawn locations
Vector CHalfLifeMultiplay : : VecItemRespawnSpot ( CItem * pItem )
{
return pItem - > pev - > origin ;
}
void CHalfLifeMultiplay : : PlayerGotAmmo ( CBasePlayer * pPlayer , char * szName , int iCount )
{
;
}
BOOL CHalfLifeMultiplay : : IsAllowedToSpawn ( CBaseEntity * pEntity )
{
return TRUE ;
}
int CHalfLifeMultiplay : : AmmoShouldRespawn ( CBasePlayerAmmo * pAmmo )
{
if ( pAmmo - > pev - > spawnflags & SF_NORESPAWN )
{
return GR_AMMO_RESPAWN_NO ;
}
return GR_AMMO_RESPAWN_YES ;
}
float CHalfLifeMultiplay : : FlAmmoRespawnTime ( CBasePlayerAmmo * pAmmo )
{
2024-08-03 20:17:52 +03:00
# ifdef REGAMEDLL_ADD
return gpGlobals - > time + ammo_respawn_time . value ;
# else
2024-08-03 20:11:08 +03:00
return gpGlobals - > time + AMMO_RESPAWN_TIME ;
2024-08-03 20:17:52 +03:00
# endif
2019-09-23 00:09:58 +03:00
}
Vector CHalfLifeMultiplay : : VecAmmoRespawnSpot ( CBasePlayerAmmo * pAmmo )
{
return pAmmo - > pev - > origin ;
}
float CHalfLifeMultiplay : : FlHealthChargerRechargeTime ( )
{
return 60 ;
}
float CHalfLifeMultiplay : : FlHEVChargerRechargeTime ( )
{
return 30 ;
}
LINK_HOOK_CLASS_CUSTOM_CHAIN ( int , CHalfLifeMultiplay , CSGameRules , DeadPlayerWeapons , ( CBasePlayer * pPlayer ) , pPlayer )
int EXT_FUNC CHalfLifeMultiplay : : __API_HOOK ( DeadPlayerWeapons ) ( CBasePlayer * pPlayer )
{
2023-07-10 15:45:24 +03:00
# ifdef REGAMEDLL_ADD
switch ( ( int ) weapondrop . value )
{
case 3 :
return GR_PLR_DROP_GUN_ALL ;
2023-09-28 12:18:15 +03:00
case 2 :
2023-07-10 15:45:24 +03:00
break ;
case 1 :
return GR_PLR_DROP_GUN_BEST ;
2023-09-28 12:18:15 +03:00
default :
2023-07-10 15:45:24 +03:00
return GR_PLR_DROP_GUN_NO ;
}
# endif
return GR_PLR_DROP_GUN_ACTIVE ; // keep original value in return
2019-09-23 00:09:58 +03:00
}
int CHalfLifeMultiplay : : DeadPlayerAmmo ( CBasePlayer * pPlayer )
{
2023-07-10 15:45:24 +03:00
# ifdef REGAMEDLL_ADD
if ( ammodrop . value = = 0.0f )
return GR_PLR_DROP_AMMO_NO ;
# endif
2019-09-23 00:09:58 +03:00
return GR_PLR_DROP_AMMO_ACTIVE ;
}
LINK_HOOK_CLASS_CUSTOM_CHAIN ( edict_t * , CHalfLifeMultiplay , CSGameRules , GetPlayerSpawnSpot , ( CBasePlayer * pPlayer ) , pPlayer )
edict_t * EXT_FUNC CHalfLifeMultiplay : : __API_HOOK ( GetPlayerSpawnSpot ) ( CBasePlayer * pPlayer )
{
// gat valid spawn point
edict_t * pentSpawnSpot = CGameRules : : GetPlayerSpawnSpot ( pPlayer ) ;
if ( IsMultiplayer ( ) )
{
if ( pentSpawnSpot - > v . target )
{
FireTargets ( STRING ( pentSpawnSpot - > v . target ) , pPlayer , pPlayer , USE_TOGGLE , 0 ) ;
}
}
return pentSpawnSpot ;
}
int CHalfLifeMultiplay : : PlayerRelationship ( CBasePlayer * pPlayer , CBaseEntity * pTarget )
{
2024-01-12 05:16:20 +03:00
if ( pPlayer = = pTarget )
return GR_TEAMMATE ;
2019-09-23 00:09:58 +03:00
# ifdef REGAMEDLL_ADD
if ( IsFreeForAll ( ) )
{
return GR_NOTTEAMMATE ;
}
# endif
if ( ! pPlayer | | ! pTarget )
{
return GR_NOTTEAMMATE ;
}
if ( ! pTarget - > IsPlayer ( ) )
{
return GR_NOTTEAMMATE ;
}
if ( pPlayer - > m_iTeam ! = static_cast < CBasePlayer * > ( pTarget ) - > m_iTeam )
{
return GR_NOTTEAMMATE ;
}
return GR_TEAMMATE ;
}
BOOL CHalfLifeMultiplay : : FAllowFlashlight ( )
{
return flashlight . value ? TRUE : FALSE ;
}
BOOL CHalfLifeMultiplay : : FAllowMonsters ( )
{
# ifdef REGAMEDLL_FIXES
return FALSE ;
# else
return allowmonsters . value ! = 0.0f ;
# endif
}
LINK_HOOK_CLASS_VOID_CUSTOM_CHAIN2 ( CHalfLifeMultiplay , CSGameRules , GoToIntermission )
void EXT_FUNC CHalfLifeMultiplay : : __API_HOOK ( GoToIntermission ) ( )
{
if ( m_bGameOver )
{
// intermission has already been triggered, so ignore.
return ;
}
UTIL_LogPrintf ( " Team \" CT \" scored \" %i \" with \" %i \" players \n " , m_iNumCTWins , m_iNumCT ) ;
UTIL_LogPrintf ( " Team \" TERRORIST \" scored \" %i \" with \" %i \" players \n " , m_iNumTerroristWins , m_iNumTerrorist ) ;
if ( IsCareer ( ) )
{
MESSAGE_BEGIN ( MSG_ALL , gmsgCZCareer ) ;
WRITE_STRING ( " MATCH " ) ;
WRITE_LONG ( m_iNumCTWins ) ;
WRITE_LONG ( m_iNumTerroristWins ) ;
MESSAGE_END ( ) ;
MESSAGE_BEGIN ( MSG_ALL , gmsgCZCareerHUD ) ;
WRITE_STRING ( " MATCH " ) ;
WRITE_LONG ( m_iNumCTWins ) ;
WRITE_LONG ( m_iNumTerroristWins ) ;
WRITE_BYTE ( m_iCareerMatchWins ) ;
WRITE_BYTE ( m_iRoundWinDifference ) ;
WRITE_BYTE ( m_iRoundWinStatus ) ;
MESSAGE_END ( ) ;
if ( TheCareerTasks )
{
UTIL_LogPrintf ( " Career Match %d %d %d %d \n " , m_iRoundWinStatus , m_iNumCTWins , m_iNumTerroristWins , TheCareerTasks - > AreAllTasksComplete ( ) ) ;
}
}
MESSAGE_BEGIN ( MSG_ALL , SVC_INTERMISSION ) ;
MESSAGE_END ( ) ;
if ( IsCareer ( ) )
{
SERVER_COMMAND ( " setpause \n " ) ;
}
// bounds check
int time = int ( CVAR_GET_FLOAT ( " mp_chattime " ) ) ;
if ( time < 1 )
CVAR_SET_STRING ( " mp_chattime " , " 1 " ) ;
else if ( time > MAX_INTERMISSION_TIME )
CVAR_SET_STRING ( " mp_chattime " , UTIL_dtos1 ( MAX_INTERMISSION_TIME ) ) ;
m_flIntermissionEndTime = gpGlobals - > time + int ( mp_chattime . value ) ;
m_flIntermissionStartTime = gpGlobals - > time ;
m_bGameOver = true ;
m_iEndIntermissionButtonHit = FALSE ;
m_iSpawnPointCount_Terrorist = 0 ;
m_iSpawnPointCount_CT = 0 ;
m_bLevelInitialized = false ;
}
// Clean up memory used by mapcycle when switching it
void DestroyMapCycle ( mapcycle_t * cycle )
{
mapcycle_item_t * p , * n , * start ;
p = cycle - > items ;
if ( p )
{
start = p ;
p = p - > next ;
while ( p ! = start )
{
n = p - > next ;
delete p ;
p = n ;
}
delete cycle - > items ;
}
cycle - > items = nullptr ;
cycle - > next_item = nullptr ;
}
// Parses mapcycle.txt file into mapcycle_t structure
int ReloadMapCycleFile ( char * filename , mapcycle_t * cycle )
{
char szBuffer [ MAX_RULE_BUFFER ] ;
char szMap [ MAX_MAPNAME_LENGHT ] ;
int length ;
char * pToken ;
char * pFileList ;
char * aFileList = pFileList = ( char * ) LOAD_FILE_FOR_ME ( filename , & length ) ;
bool hasBuffer ;
mapcycle_item_s * item , * newlist = nullptr , * next ;
if ( pFileList & & length )
{
// the first map name in the file becomes the default
while ( true )
{
hasBuffer = false ;
Q_memset ( szBuffer , 0 , sizeof ( szBuffer ) ) ;
pFileList = SharedParse ( pFileList ) ;
pToken = SharedGetToken ( ) ;
if ( Q_strlen ( pToken ) < = 0 )
break ;
2020-11-12 02:25:00 +03:00
# ifdef REGAMEDLL_FIXES
Q_strncpy ( szMap , pToken , sizeof ( szMap ) - 1 ) ;
2020-11-12 02:26:59 +03:00
szMap [ sizeof ( szMap ) - 1 ] = ' \0 ' ;
2020-11-12 02:25:00 +03:00
# else
2019-09-23 00:09:58 +03:00
Q_strcpy ( szMap , pToken ) ;
2020-11-12 02:25:00 +03:00
# endif
2019-09-23 00:09:58 +03:00
// Any more tokens on this line?
if ( SharedTokenWaiting ( pFileList ) )
{
pFileList = SharedParse ( pFileList ) ;
if ( Q_strlen ( pToken ) > 0 )
{
hasBuffer = true ;
Q_strcpy ( szBuffer , pToken ) ;
}
}
// Check map
if ( IS_MAP_VALID ( szMap ) )
{
// Create entry
char * s ;
item = new mapcycle_item_s ;
Q_strcpy ( item - > mapname , szMap ) ;
item - > minplayers = 0 ;
item - > maxplayers = 0 ;
Q_memset ( item - > rulebuffer , 0 , sizeof ( item - > rulebuffer ) ) ;
if ( hasBuffer )
{
s = GET_KEY_VALUE ( szBuffer , " minplayers " ) ;
if ( s & & s [ 0 ] ! = ' \0 ' )
{
item - > minplayers = Q_atoi ( s ) ;
item - > minplayers = Q_max ( item - > minplayers , 0 ) ;
item - > minplayers = Q_min ( item - > minplayers , gpGlobals - > maxClients ) ;
}
s = GET_KEY_VALUE ( szBuffer , " maxplayers " ) ;
if ( s & & s [ 0 ] ! = ' \0 ' )
{
item - > maxplayers = Q_atoi ( s ) ;
item - > maxplayers = Q_max ( item - > maxplayers , 0 ) ;
item - > maxplayers = Q_min ( item - > maxplayers , gpGlobals - > maxClients ) ;
}
// Remove keys
REMOVE_KEY_VALUE ( szBuffer , " minplayers " ) ;
REMOVE_KEY_VALUE ( szBuffer , " maxplayers " ) ;
Q_strcpy ( item - > rulebuffer , szBuffer ) ;
}
item - > next = cycle - > items ;
cycle - > items = item ;
}
else
{
ALERT ( at_console , " Skipping %s from mapcycle, not a valid map \n " , szMap ) ;
}
}
FREE_FILE ( aFileList ) ;
}
// Fixup circular list pointer
item = cycle - > items ;
// Reverse it to get original order
while ( item )
{
next = item - > next ;
item - > next = newlist ;
newlist = item ;
item = next ;
}
cycle - > items = newlist ;
item = cycle - > items ;
// Didn't parse anything
if ( ! item )
{
return 0 ;
}
while ( item - > next )
{
item = item - > next ;
}
item - > next = cycle - > items ;
cycle - > next_item = item - > next ;
return 1 ;
}
// Determine the current # of active players on the server for map cycling logic
int CountPlayers ( )
{
int nCount = 0 ;
for ( int i = 1 ; i < = gpGlobals - > maxClients ; i + + )
{
CBasePlayer * pPlayer = UTIL_PlayerByIndex ( i ) ;
2024-05-28 18:44:29 +03:00
if ( ! UTIL_IsValidPlayer ( pPlayer ) | | pPlayer - > IsBot ( ) )
continue ;
nCount + + ;
2019-09-23 00:09:58 +03:00
}
return nCount ;
}
// Parse commands/key value pairs to issue right after map xxx command is issued on server level transition
void ExtractCommandString ( char * s , char * szCommand )
{
// Now make rules happen
char pkey [ 512 ] ;
char value [ 512 ] ; // use two buffers so compares
// work without stomping on each other
char * c ;
int nCount ;
while ( * s )
{
if ( * s = = ' \\ ' )
{
// skip the slash
s + + ;
}
// Copy a key
c = pkey ;
nCount = 0 ;
while ( * s ! = ' \\ ' )
{
if ( ! * s )
{
// allow value to be ended with NULL
break ;
}
if ( nCount > = sizeof ( pkey ) )
{
s + + ;
// skip oversized key chars till the slash or EOL
continue ;
}
* c + + = * s + + ;
nCount + + ;
}
* c = ' \0 ' ;
s + + ; // skip the slash
// Copy a value
c = value ;
nCount = 0 ;
while ( * s ! = ' \\ ' )
{
if ( ! * s )
{
// allow value to be ended with NULL
break ;
}
if ( nCount > = sizeof ( value ) )
{
s + + ;
// skip oversized value chars till the slash or EOL
continue ;
}
* c + + = * s + + ;
nCount + + ;
}
* c = ' \0 ' ;
Q_strcat ( szCommand , pkey ) ;
if ( Q_strlen ( value ) > 0 )
{
Q_strcat ( szCommand , " " ) ;
Q_strcat ( szCommand , value ) ;
}
Q_strcat ( szCommand , " \n " ) ;
/*if (!*s)
{
return ;
}
s + + ; */
}
}
void CHalfLifeMultiplay : : ResetAllMapVotes ( )
{
CBaseEntity * pEntity = nullptr ;
while ( ( pEntity = UTIL_FindEntityByClassname ( pEntity , " player " ) ) )
{
if ( FNullEnt ( pEntity - > edict ( ) ) )
break ;
2024-05-28 18:44:29 +03:00
if ( pEntity - > IsDormant ( ) )
continue ;
2019-09-23 00:09:58 +03:00
CBasePlayer * pPlayer = GetClassPtr < CCSPlayer > ( ( CBasePlayer * ) pEntity - > pev ) ;
if ( pPlayer - > m_iTeam ! = UNASSIGNED )
{
pPlayer - > m_iMapVote = 0 ;
}
}
for ( int j = 0 ; j < MAX_VOTE_MAPS ; j + + )
m_iMapVotes [ j ] = 0 ;
}
int GetMapCount ( )
{
static mapcycle_t mapcycle ;
char * mapcfile = ( char * ) CVAR_GET_STRING ( " mapcyclefile " ) ;
DestroyMapCycle ( & mapcycle ) ;
ReloadMapCycleFile ( mapcfile , & mapcycle ) ;
int nCount = 0 ;
auto item = mapcycle . next_item ;
do
{
if ( ! item )
break ;
nCount + + ;
item = item - > next ;
} while ( item ! = mapcycle . next_item ) ;
return nCount ;
}
void CHalfLifeMultiplay : : DisplayMaps ( CBasePlayer * pPlayer , int iVote )
{
static mapcycle_t mapcycle2 ;
char * mapcfile = ( char * ) CVAR_GET_STRING ( " mapcyclefile " ) ;
char * pszNewMap = nullptr ;
int iCount = 0 , done = 0 ;
DestroyMapCycle ( & mapcycle2 ) ;
ReloadMapCycleFile ( mapcfile , & mapcycle2 ) ;
mapcycle_item_s * item = mapcycle2 . next_item ;
while ( ! done & & item )
{
if ( item - > next = = mapcycle2 . next_item )
done = 1 ;
iCount + + ;
if ( pPlayer )
{
if ( m_iMapVotes [ iCount ] = = 1 )
{
ClientPrint ( pPlayer - > pev , HUD_PRINTCONSOLE , " #Vote " , UTIL_dtos1 ( iCount ) , item - > mapname , UTIL_dtos2 ( 1 ) ) ;
}
else
{
ClientPrint ( pPlayer - > pev , HUD_PRINTCONSOLE , " #Votes " , UTIL_dtos1 ( iCount ) , item - > mapname , UTIL_dtos2 ( m_iMapVotes [ iCount ] ) ) ;
}
}
if ( iCount = = iVote )
{
pszNewMap = item - > mapname ;
}
item = item - > next ;
}
if ( ! pszNewMap | | ! iVote )
{
return ;
}
if ( Q_strcmp ( pszNewMap , STRING ( gpGlobals - > mapname ) ) ! = 0 )
{
CHANGE_LEVEL ( pszNewMap , nullptr ) ;
return ;
}
if ( timelimit . value )
{
timelimit . value + = 30 ;
UTIL_ClientPrintAll ( HUD_PRINTCENTER , " #Map_Vote_Extend " ) ;
}
ResetAllMapVotes ( ) ;
}
void CHalfLifeMultiplay : : ProcessMapVote ( CBasePlayer * pPlayer , int iVote )
{
CBaseEntity * pEntity = nullptr ;
int iValidVotes = 0 , iNumPlayers = 0 ;
while ( ( pEntity = UTIL_FindEntityByClassname ( pEntity , " player " ) ) )
{
if ( FNullEnt ( pEntity - > edict ( ) ) )
break ;
2024-05-28 18:44:29 +03:00
if ( pEntity - > IsDormant ( ) )
continue ;
2019-09-23 00:09:58 +03:00
CBasePlayer * pPlayer = GetClassPtr < CCSPlayer > ( ( CBasePlayer * ) pEntity - > pev ) ;
if ( pPlayer - > m_iTeam ! = UNASSIGNED )
{
iNumPlayers + + ;
if ( pPlayer - > m_iMapVote = = iVote )
iValidVotes + + ;
}
}
m_iMapVotes [ iVote ] = iValidVotes ;
float ratio = mapvoteratio . value ;
if ( mapvoteratio . value > 1 )
{
ratio = 1 ;
CVAR_SET_STRING ( " mp_mapvoteratio " , " 1.0 " ) ;
}
else if ( mapvoteratio . value < 0.35f )
{
ratio = 0.35f ;
CVAR_SET_STRING ( " mp_mapvoteratio " , " 0.35 " ) ;
}
int iRequiredVotes = 2 ;
if ( iNumPlayers > 2 )
{
iRequiredVotes = int ( iNumPlayers * ratio + 0.5f ) ;
}
if ( iValidVotes < iRequiredVotes )
{
DisplayMaps ( pPlayer , 0 ) ;
ClientPrint ( pPlayer - > pev , HUD_PRINTCONSOLE , " #Game_required_votes " , UTIL_dtos1 ( iRequiredVotes ) ) ;
}
else
{
DisplayMaps ( nullptr , iVote ) ;
}
}
2023-09-05 06:43:40 +03:00
LINK_HOOK_CLASS_VOID_CUSTOM_CHAIN2 ( CHalfLifeMultiplay , CSGameRules , ChangeLevel )
2019-09-23 00:09:58 +03:00
// Server is changing to a new level, check mapcycle.txt for map name and setup info
void EXT_FUNC CHalfLifeMultiplay : : __API_HOOK ( ChangeLevel ) ( )
{
static char szPreviousMapCycleFile [ 256 ] ;
static mapcycle_t mapcycle ;
char szNextMap [ MAX_MAPNAME_LENGHT ] ;
char szFirstMapInList [ MAX_MAPNAME_LENGHT ] ;
char szCommands [ 1500 ] ;
char szRules [ 1500 ] ;
int minplayers = 0 , maxplayers = 0 ;
# ifdef REGAMEDLL_FIXES
// the absolute default level is de_dust
Q_strcpy ( szFirstMapInList , " de_dust " ) ;
# else
// the absolute default level is hldm1
Q_strcpy ( szFirstMapInList , " hldm1 " ) ;
# endif
int curplayers ;
bool do_cycle = true ;
// find the map to change to
char * mapcfile = ( char * ) CVAR_GET_STRING ( " mapcyclefile " ) ;
2023-12-13 23:16:27 +03:00
Assert ( mapcfile ! = nullptr ) ;
2019-09-23 00:09:58 +03:00
szCommands [ 0 ] = ' \0 ' ;
szRules [ 0 ] = ' \0 ' ;
curplayers = CountPlayers ( ) ;
// Has the map cycle filename changed?
if ( Q_stricmp ( mapcfile , szPreviousMapCycleFile ) ! = 0 )
{
Q_strcpy ( szPreviousMapCycleFile , mapcfile ) ;
DestroyMapCycle ( & mapcycle ) ;
if ( ! ReloadMapCycleFile ( mapcfile , & mapcycle ) | | ! mapcycle . items )
{
ALERT ( at_console , " Unable to load map cycle file %s \n " , mapcfile ) ;
do_cycle = false ;
}
}
if ( do_cycle & & mapcycle . items )
{
bool keeplooking = false ;
bool found = false ;
mapcycle_item_s * item ;
// Assume current map
Q_strcpy ( szNextMap , STRING ( gpGlobals - > mapname ) ) ;
Q_strcpy ( szFirstMapInList , STRING ( gpGlobals - > mapname ) ) ;
// Traverse list
for ( item = mapcycle . next_item ; item - > next ! = mapcycle . next_item ; item = item - > next )
{
keeplooking = false ;
2023-12-13 23:16:27 +03:00
Assert ( item ! = nullptr ) ;
2019-09-23 00:09:58 +03:00
if ( item - > minplayers ! = 0 )
{
if ( curplayers > = item - > minplayers )
{
found = true ;
minplayers = item - > minplayers ;
}
else
{
keeplooking = true ;
}
}
if ( item - > maxplayers ! = 0 )
{
if ( curplayers < = item - > maxplayers )
{
found = true ;
maxplayers = item - > maxplayers ;
}
else
{
keeplooking = true ;
}
}
if ( keeplooking )
{
continue ;
}
found = true ;
break ;
}
if ( ! found )
{
item = mapcycle . next_item ;
}
// Increment next item pointer
mapcycle . next_item = item - > next ;
// Perform logic on current item
Q_strcpy ( szNextMap , item - > mapname ) ;
ExtractCommandString ( item - > rulebuffer , szCommands ) ;
Q_strcpy ( szRules , item - > rulebuffer ) ;
}
if ( ! IS_MAP_VALID ( szNextMap ) )
{
Q_strcpy ( szNextMap , szFirstMapInList ) ;
}
m_bGameOver = true ;
ALERT ( at_console , " CHANGE LEVEL: %s \n " , szNextMap ) ;
if ( minplayers | | maxplayers )
{
ALERT ( at_console , " PLAYER COUNT: min %i max %i current %i \n " , minplayers , maxplayers , curplayers ) ;
}
if ( Q_strlen ( szRules ) > 0 )
{
ALERT ( at_console , " RULES: %s \n " , szRules ) ;
}
CHANGE_LEVEL ( szNextMap , nullptr ) ;
if ( Q_strlen ( szCommands ) > 0 )
{
SERVER_COMMAND ( szCommands ) ;
}
}
void CHalfLifeMultiplay : : SendMOTDToClient ( edict_t * client )
{
// read from the MOTD.txt file
int length , char_count = 0 ;
char * pFileList ;
char * aFileList = pFileList = ( char * ) LOAD_FILE_FOR_ME ( ( char * ) CVAR_GET_STRING ( " motdfile " ) , & length ) ;
// send the server name
MESSAGE_BEGIN ( MSG_ONE , gmsgServerName , nullptr , client ) ;
WRITE_STRING ( CVAR_GET_STRING ( " hostname " ) ) ;
MESSAGE_END ( ) ;
// Send the message of the day
// read it chunk-by-chunk, and send it in parts
while ( pFileList & & * pFileList & & char_count < MAX_MOTD_LENGTH )
{
char chunk [ MAX_MOTD_CHUNK + 1 ] ;
if ( Q_strlen ( pFileList ) < sizeof ( chunk ) )
{
Q_strcpy ( chunk , pFileList ) ;
}
else
{
Q_strncpy ( chunk , pFileList , sizeof ( chunk ) - 1 ) ;
// Q_strncpy doesn't always append the null terminator
chunk [ sizeof ( chunk ) - 1 ] = ' \0 ' ;
}
char_count + = Q_strlen ( chunk ) ;
if ( char_count < MAX_MOTD_LENGTH )
pFileList = aFileList + char_count ;
else
* pFileList = ' \0 ' ;
MESSAGE_BEGIN ( MSG_ONE , gmsgMOTD , nullptr , client ) ;
WRITE_BYTE ( ( * pFileList ! = ' \0 ' ) ? FALSE : TRUE ) ; // FALSE means there is still more message to come
WRITE_STRING ( chunk ) ;
MESSAGE_END ( ) ;
}
FREE_FILE ( aFileList ) ;
}
LINK_HOOK_CLASS_VOID_CUSTOM_CHAIN ( CHalfLifeMultiplay , CSGameRules , ClientUserInfoChanged , ( CBasePlayer * pPlayer , char * infobuffer ) , pPlayer , infobuffer ) ;
void EXT_FUNC CHalfLifeMultiplay : : __API_HOOK ( ClientUserInfoChanged ) ( CBasePlayer * pPlayer , char * infobuffer )
{
pPlayer - > SetPlayerModel ( pPlayer - > m_bHasC4 ) ;
pPlayer - > SetPrefsFromUserinfo ( infobuffer ) ;
}
void CHalfLifeMultiplay : : ServerActivate ( )
{
// Check to see if there's a mapping info paramater entity
if ( g_pMapInfo )
g_pMapInfo - > CheckMapInfo ( ) ;
ReadMultiplayCvars ( ) ;
CheckMapConditions ( ) ;
}
TeamName CHalfLifeMultiplay : : SelectDefaultTeam ( )
{
TeamName team = UNASSIGNED ;
if ( m_iNumTerrorist < m_iNumCT )
{
team = TERRORIST ;
}
else if ( m_iNumTerrorist > m_iNumCT )
{
team = CT ;
}
// Choose the team that's losing
else if ( m_iNumTerroristWins < m_iNumCTWins )
{
team = TERRORIST ;
}
else if ( m_iNumCTWins < m_iNumTerroristWins )
{
team = CT ;
}
else
{
// Teams and scores are equal, pick a random team
team = ( RANDOM_LONG ( 0 , 1 ) = = 0 ) ? CT : TERRORIST ;
}
if ( TeamFull ( team ) )
{
// Pick the opposite team
team = ( team = = TERRORIST ) ? CT : TERRORIST ;
// No choices left
if ( TeamFull ( team ) )
{
return UNASSIGNED ;
}
}
return team ;
}
void CHalfLifeMultiplay : : ChangePlayerTeam ( CBasePlayer * pPlayer , const char * pTeamName , BOOL bKill , BOOL bGib )
{
if ( ! pTeamName | | ! pTeamName [ 0 ] )
return ;
if ( ! pPlayer - > IsAlive ( ) | | pPlayer - > m_iJoiningState ! = JOINED )
return ;
TeamName newTeam ;
if ( ! Q_stricmp ( pTeamName , " CT " ) )
{
newTeam = CT ;
}
else if ( ! Q_stricmp ( pTeamName , " TERRORIST " ) )
{
newTeam = TERRORIST ;
}
else if ( ! Q_stricmp ( pTeamName , " SPECTATOR " ) )
{
newTeam = SPECTATOR ;
}
else
{
return ;
}
if ( pPlayer - > m_iTeam ! = UNASSIGNED & & pPlayer - > m_iTeam ! = newTeam )
{
if ( bKill )
{
pPlayer - > m_LastHitGroup = HITGROUP_GENERIC ;
// have the player kill themself
pPlayer - > pev - > health = 0 ;
pPlayer - > Killed ( pPlayer - > pev , bGib ? GIB_ALWAYS : GIB_NEVER ) ;
// add 1 to frags to balance out the 1 subtracted for killing yourself
pPlayer - > pev - > frags + + ;
}
pPlayer - > m_iTeam = newTeam ;
pPlayer - > SetPlayerModel ( pPlayer - > m_bHasC4 ) ;
pPlayer - > TeamChangeUpdate ( ) ;
CSGameRules ( ) - > CheckWinConditions ( ) ;
}
}
bool CHalfLifeMultiplay : : CanPlayerBuy ( CBasePlayer * pPlayer ) const
{
if ( pPlayer - > m_iTeam = = CT & & m_bCTCantBuy )
{
return false ;
}
else if ( pPlayer - > m_iTeam = = TERRORIST & & m_bTCantBuy )
{
return false ;
}
else if ( m_bCTCantBuy & & m_bTCantBuy )
{
return false ;
}
return true ;
}
2023-09-28 12:18:15 +03:00
//
// Checks for assists in a kill situation
//
// This function analyzes damage records and player actions to determine the player who contributed the most to a kill,
// considering factors such as damage dealt and the use of flashbang grenades
//
// pKiller - The killer entity (Note: The killer may be a non-player)
// pVictim - The victim player
// bFlashAssist - A flag indicating whether a flashbang was used in the assist
// Returns - A pointer to the player who gave the most assistance, or NULL if appropriate assistant is not found
//
CBasePlayer * CHalfLifeMultiplay : : CheckAssistsToKill ( CBaseEntity * pKiller , CBasePlayer * pVictim , bool & bFlashAssist )
{
# ifdef REGAMEDLL_ADD
CCSPlayer : : DamageList_t & victimDamageTakenList = pVictim - > CSPlayer ( ) - > GetDamageList ( ) ;
float maxDamage = 0.0f ;
int maxDamageIndex = - 1 ;
CBasePlayer * maxDamagePlayer = nullptr ;
// Find the best assistant
for ( int i = 1 ; i < = gpGlobals - > maxClients ; i + + )
{
const CCSPlayer : : CDamageRecord_t & record = victimDamageTakenList [ i - 1 ] ;
if ( record . flDamage = = 0 )
continue ; // dealt no damage
CBasePlayer * pAttackerPlayer = UTIL_PlayerByIndex ( i ) ;
2024-05-28 18:44:29 +03:00
if ( ! UTIL_IsValidPlayer ( pAttackerPlayer ) )
2023-09-28 12:18:15 +03:00
continue ; // ignore idle clients
CCSPlayer * pCSAttackerPlayer = pAttackerPlayer - > CSPlayer ( ) ;
if ( record . userId ! = pCSAttackerPlayer - > m_iUserID )
continue ; // another client?
if ( pAttackerPlayer = = pKiller | | pAttackerPlayer = = pVictim )
continue ; // ignore involved as killer or victim
if ( record . flDamage > maxDamage )
{
// If the assistant used a flash grenade to aid in the kill,
// make sure that the victim was blinded, and that the duration of the flash effect is still preserved
if ( record . flFlashDurationTime > 0 & & ( ! pVictim - > IsBlind ( ) | | record . flFlashDurationTime < = gpGlobals - > time ) )
continue ;
maxDamage = record . flDamage ;
maxDamagePlayer = pAttackerPlayer ;
maxDamageIndex = i ;
}
}
// Note: Only the highest damaging player can be an assistant
// The condition checks if the damage dealt by the player exceeds a certain percentage of the victim's max health
// Default threshold is 40%, meaning the assistant must deal at least 40% of the victim's max health as damage
if ( maxDamagePlayer & & maxDamage > ( assist_damage_threshold . value / 100.0f ) * pVictim - > pev - > max_health )
{
bFlashAssist = victimDamageTakenList [ maxDamageIndex - 1 ] . flFlashDurationTime > 0 ; // if performed the flash assist
return maxDamagePlayer ;
}
# endif
return nullptr ;
}
//
// Check the rarity estimation for a kill
//
// Estimation to represent the rarity of a kill based on various factors, including assists with flashbang grenades,
// headshot kills, kills through walls, the killer's blindness, no-scope sniper rifle kills, and kills through smoke
//
// pKiller - The entity who committed the kill (Note: The killer may be a non-player)
// pVictim - The player who was killed
// pAssister - The assisting player (if any)
// killerWeaponName - The name of the weapon used by the killer
// bFlashAssist - A flag indicating whether an assist was made with a flashbang
// Returns an integer estimation representing the rarity of the kill
// Use with PLAYERDEATH_KILLRARITY flag to indicate a rare kill in death messages
//
int CHalfLifeMultiplay : : GetRarityOfKill ( CBaseEntity * pKiller , CBasePlayer * pVictim , CBasePlayer * pAssister , const char * killerWeaponName , bool bFlashAssist )
{
int iRarity = 0 ;
// The killer player kills the victim with an assistant flashbang grenade
if ( pAssister & & bFlashAssist )
2023-09-30 21:30:56 +03:00
iRarity | = KILLRARITY_ASSISTEDFLASH ;
2023-09-28 12:18:15 +03:00
// The killer player kills the victim with a headshot
if ( pVictim - > m_bHeadshotKilled )
iRarity | = KILLRARITY_HEADSHOT ;
2023-12-22 22:43:42 +03:00
CBasePlayer * pKillerPlayer = static_cast < CBasePlayer * > ( pKiller ) ;
2024-05-08 20:30:57 +03:00
if ( pKillerPlayer & & pKillerPlayer - > IsPlayer ( ) & & pKillerPlayer ! = pVictim )
2023-09-28 12:18:15 +03:00
{
WeaponClassType weaponClass = AliasToWeaponClass ( killerWeaponName ) ;
2024-05-08 20:30:57 +03:00
if ( weaponClass ! = WEAPONCLASS_NONE & &
weaponClass ! = WEAPONCLASS_KNIFE & &
weaponClass ! = WEAPONCLASS_GRENADE )
2023-12-22 22:43:42 +03:00
{
// The killer player kills the victim through the walls
if ( pVictim - > GetDmgPenetrationLevel ( ) > 0 )
iRarity | = KILLRARITY_PENETRATED ;
2024-05-08 19:01:02 +03:00
// The killer player was blind
2023-12-22 22:51:04 +03:00
if ( pKillerPlayer - > IsFullyBlind ( ) )
2023-12-22 22:43:42 +03:00
iRarity | = KILLRARITY_KILLER_BLIND ;
2023-09-28 12:18:15 +03:00
2023-12-22 22:43:42 +03:00
// The killer player kills the victim with a sniper rifle with no scope
if ( weaponClass = = WEAPONCLASS_SNIPERRIFLE & & pKillerPlayer - > m_iClientFOV = = DEFAULT_FOV )
iRarity | = KILLRARITY_NOSCOPE ;
// The killer player kills the victim through smoke
const Vector inEyePos = pKillerPlayer - > EyePosition ( ) ;
if ( TheCSBots ( ) - > IsLineBlockedBySmoke ( & inEyePos , & pVictim - > pev - > origin ) )
iRarity | = KILLRARITY_THRUSMOKE ;
2024-05-08 22:38:12 +03:00
// The killer player kills the victim while in air
if ( ! ( pKillerPlayer - > pev - > flags & FL_ONGROUND ) )
iRarity | = KILLRARITY_INAIR ;
2023-12-22 22:43:42 +03:00
}
2023-09-28 12:18:15 +03:00
// Calculate # of unanswered kills between killer & victim
// This is plus 1 as this function gets called before the stat is updated
// That is done so that the domination and revenge will be calculated prior
// to the death message being sent to the clients
int iAttackerEntityIndex = pKillerPlayer - > entindex ( ) ;
2023-12-13 23:16:27 +03:00
Assert ( iAttackerEntityIndex > 0 & & iAttackerEntityIndex < = MAX_CLIENTS ) ;
2023-09-28 12:18:15 +03:00
int iKillsUnanswered = pVictim - > CSPlayer ( ) - > m_iNumKilledByUnanswered [ iAttackerEntityIndex - 1 ] + 1 ;
if ( iKillsUnanswered = = CS_KILLS_FOR_DOMINATION | | pKillerPlayer - > CSPlayer ( ) - > IsPlayerDominated ( pVictim - > entindex ( ) - 1 ) )
{
2024-05-08 18:59:40 +03:00
// Sets the beginning of domination over the victim until he takes revenge
if ( iKillsUnanswered = = CS_KILLS_FOR_DOMINATION )
iRarity | = KILLRARITY_DOMINATION_BEGAN ;
2023-09-28 12:18:15 +03:00
// this is the Nth unanswered kill between killer and victim, killer is now dominating victim
iRarity | = KILLRARITY_DOMINATION ;
// set victim to be dominated by killer
pKillerPlayer - > CSPlayer ( ) - > SetPlayerDominated ( pVictim , true ) ;
}
else if ( pVictim - > CSPlayer ( ) - > IsPlayerDominated ( pKillerPlayer - > entindex ( ) - 1 ) )
{
// the killer killed someone who was dominating him, gains revenge
iRarity | = KILLRARITY_REVENGE ;
// set victim to no longer be dominating the killer
pVictim - > CSPlayer ( ) - > SetPlayerDominated ( pKillerPlayer , false ) ;
}
}
return iRarity ;
}
LINK_HOOK_CLASS_VOID_CUSTOM_CHAIN ( CHalfLifeMultiplay , CSGameRules , SendDeathMessage , ( CBaseEntity * pKiller , CBasePlayer * pVictim , CBasePlayer * pAssister , entvars_t * pevInflictor , const char * killerWeaponName , int iDeathMessageFlags , int iRarityOfKill ) , pKiller , pVictim , pAssister , pevInflictor , killerWeaponName , iDeathMessageFlags , iRarityOfKill )
//
// Sends death messages to all players, including info about the killer, victim, weapon used,
// extra death flags, death position, assistant, and kill rarity
//
//
// pKiller - The entity who performed the kill (Note: The killer may be a non-player)
// pVictim - The player who was killed
// pAssister - The assisting player (if any)
// killerWeaponName - The name of the weapon used by the killer
// iDeathMessageFlags - Flags indicating extra death message info
// iRarityOfKill - An bitsums representing the rarity classification of the kill
//
void EXT_FUNC CHalfLifeMultiplay : : __API_HOOK ( SendDeathMessage ) ( CBaseEntity * pKiller , CBasePlayer * pVictim , CBasePlayer * pAssister , entvars_t * pevInflictor , const char * killerWeaponName , int iDeathMessageFlags , int iRarityOfKill )
{
2023-09-30 21:30:56 +03:00
MESSAGE_BEGIN ( MSG_ALL , gmsgDeathMsg ) ;
WRITE_BYTE ( ( pKiller & & pKiller - > IsPlayer ( ) ) ? pKiller - > entindex ( ) : 0 ) ; // the killer
WRITE_BYTE ( pVictim - > entindex ( ) ) ; // the victim
2024-05-08 18:59:40 +03:00
WRITE_BYTE ( ( iRarityOfKill & KILLRARITY_HEADSHOT ) ) ; // is killed headshot
2023-09-30 21:30:56 +03:00
WRITE_STRING ( killerWeaponName ) ; // what they were killed by (should this be a string?)
2023-09-28 12:18:15 +03:00
2023-09-30 21:30:56 +03:00
# ifdef REGAMEDLL_ADD
if ( iDeathMessageFlags > 0 )
{
WRITE_LONG ( iDeathMessageFlags ) ;
2023-09-28 12:18:15 +03:00
2023-09-30 21:30:56 +03:00
// Writes the coordinates of the place where the victim died
// The victim has just been killed, so this usefully display 'X' dead icon on the HUD radar
if ( iDeathMessageFlags & PLAYERDEATH_POSITION )
2023-09-28 12:18:15 +03:00
{
2023-09-30 21:30:56 +03:00
WRITE_COORD ( pVictim - > pev - > origin . x ) ;
WRITE_COORD ( pVictim - > pev - > origin . y ) ;
WRITE_COORD ( pVictim - > pev - > origin . z ) ;
2023-09-28 12:18:15 +03:00
}
2023-09-30 21:30:56 +03:00
// Writes the index of the teammate who assisted in the kill
if ( iDeathMessageFlags & PLAYERDEATH_ASSISTANT )
2024-05-08 18:59:40 +03:00
WRITE_BYTE ( ( pAssister & & pAssister - > IsPlayer ( ) ) ? pAssister - > entindex ( ) : 0 ) ;
2023-09-30 21:30:56 +03:00
// Writes the rarity classification of the kill
if ( iDeathMessageFlags & PLAYERDEATH_KILLRARITY )
WRITE_LONG ( iRarityOfKill ) ;
2023-09-28 12:18:15 +03:00
}
2023-09-30 21:30:56 +03:00
# endif
MESSAGE_END ( ) ;
2023-09-28 12:18:15 +03:00
}
2024-01-12 11:55:00 +03:00
void CHalfLifeMultiplay : : GiveDefuserToRandomPlayer ( )
{
int iDefusersToGive = 2 ;
CUtlVector < CBasePlayer * > candidates ;
candidates . EnsureCapacity ( MAX_CLIENTS ) ;
// add all CT candidates to a list
for ( int i = 1 ; i < = gpGlobals - > maxClients ; i + + )
{
CBasePlayer * pPlayer = UTIL_PlayerByIndex ( i ) ;
2024-05-28 18:44:29 +03:00
if ( ! UTIL_IsValidPlayer ( pPlayer ) )
2024-01-12 11:55:00 +03:00
continue ;
if ( ! pPlayer - > IsAlive ( ) | | pPlayer - > m_iTeam ! = CT )
continue ;
candidates . AddToTail ( pPlayer ) ;
}
2024-01-31 14:38:47 +03:00
2024-01-12 11:55:00 +03:00
// randomly shuffle the list; this will keep the selection random in case of ties
for ( int i = 0 ; i < candidates . Count ( ) ; i + + ) {
SWAP ( candidates [ i ] , candidates [ RANDOM_LONG ( 0 , candidates . Count ( ) - 1 ) ] ) ;
}
// now sort the shuffled list into subgroups
candidates . Sort ( [ ] ( CBasePlayer * const * left , CBasePlayer * const * right ) - > int {
// should we prioritize humans over bots?
if ( cv_bot_defer_to_human . value ! = 0.0f )
{
if ( ( * left ) - > IsBot ( ) & & ! ( * right ) - > IsBot ( ) )
return 1 ;
if ( ! ( * left ) - > IsBot ( ) & & ( * right ) - > IsBot ( ) )
return - 1 ;
}
return 0 ;
}
) ;
// give defusers to the first N candidates
for ( int i = 0 ; i < iDefusersToGive & & i < candidates . Count ( ) ; + + i )
{
CBasePlayer * pPlayer = candidates [ i ] ;
2024-06-01 16:26:00 +03:00
DbgAssert ( pPlayer & & pPlayer - > m_iTeam = = CT & & pPlayer - > IsAlive ( ) ) ;
2024-01-12 11:55:00 +03:00
pPlayer - > GiveDefuser ( ) ;
2024-06-01 16:26:00 +03:00
pPlayer - > HintMessage ( " #Got_defuser " , FALSE , TRUE ) ;
2024-01-12 11:55:00 +03:00
}
}