Portable Half-Life SDK. GoldSource and Xash3D. Crossplatform.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

1439 lines
37 KiB

/***
*
* Copyright (c) 2001, Valve LLC. All rights reserved.
*
* This product contains software technology licensed from Id
* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc.
* All Rights Reserved.
*
* Use, distribution, and modification of this source code and/or resulting
* object code is restricted to non-commercial enhancements to products from
* Valve LLC. All other use, distribution, or modification is prohibited
* without written permission from Valve LLC.
*
****/
/*
===== threewave_gamerules.cpp ========================================================
This contains all the gamerules for the ThreeWave CTF Gamemode.
It also contains the Flag entity information.
*/
#define NUM_TEAMS 2
const char *sTeamNames[] =
{
"SPECTATOR",
"RED",
"BLUE"
};
#include "extdll.h"
#include "util.h"
#include "cbase.h"
#include "player.h"
#include "weapons.h"
#include "gamerules.h"
#include "skill.h"
#include "game.h"
#include "items.h"
#include "threewave_gamerules.h"
#include "flags.h"
#include "runes.h"
#include "grapple.h"
static char team_names[MAX_TEAMS][MAX_TEAMNAME_LENGTH];
static int team_scores[MAX_TEAMS];
static int num_teams = 0;
bool g_bSpawnedRunes;
extern void SpawnRunes( void );
extern bool g_bHaveMOTD;
extern unsigned short g_usCarried;
extern edict_t *EntSelectSpawnPoint( CBaseEntity *pPlayer, bool bCheckDM );
extern edict_t *RuneSelectSpawnPoint( void );
#ifndef NO_VOICEGAMEMGR
class CThreeWaveGameMgrHelper : public IVoiceGameMgrHelper
{
public:
virtual bool CanPlayerHearPlayer( CBasePlayer *pPlayer1, CBasePlayer *pPlayer2 )
{
return stricmp( pPlayer1->TeamID(), pPlayer2->TeamID() ) == 0;
}
};
static CThreeWaveGameMgrHelper g_GameMgrHelper;
#endif
extern DLL_GLOBAL BOOL g_fGameOver;
const char *GetTeamName( int team )
{
if( team < 0 || team > NUM_TEAMS )
team = 0;
return sTeamNames[team];
}
CThreeWave::CThreeWave()
{
#ifndef NO_VOICEGAMEMGR
// CHalfLifeMultiplay already initialized it - just override its helper callback.
m_VoiceGameMgr.SetHelper( &g_GameMgrHelper );
#endif
m_DisableDeathMessages = FALSE;
m_DisableDeathPenalty = FALSE;
memset( team_names, 0, sizeof(team_names) );
memset( team_scores, 0, sizeof(team_scores) );
num_teams = 0;
iBlueTeamScore = iRedTeamScore = 0;
g_bSpawnedRunes = FALSE;
// Copy over the team from the server config
m_szTeamList[0] = 0;
// Cache this because the team code doesn't want to deal with changing this in the middle of a game
strncpy( m_szTeamList, teamlist.string, TEAMPLAY_TEAMLISTLENGTH );
edict_t *pWorld = INDEXENT( 0 );
if( pWorld && pWorld->v.team )
{
if( teamoverride.value )
{
const char *pTeamList = STRING( pWorld->v.team );
if( pTeamList && strlen( pTeamList ) )
{
strncpy( m_szTeamList, pTeamList, TEAMPLAY_TEAMLISTLENGTH );
}
}
}
// Has the server set teams
if( strlen( m_szTeamList ) )
m_teamLimit = TRUE;
else
m_teamLimit = FALSE;
RecountTeams();
}
BOOL CThreeWave::ClientConnected( edict_t *pEntity, const char *pszName, const char *pszAddress, char szRejectReason[128] )
{
return CHalfLifeMultiplay::ClientConnected( pEntity, pszName, pszAddress, szRejectReason );
}
extern cvar_t timeleft, fragsleft;
void CThreeWave::Think( void )
{
#ifndef NO_VOICEGAMEMGR
m_VoiceGameMgr.Update( gpGlobals->frametime );
#endif
///// Check game rules /////
static int last_frags;
static int last_time;
int frags_remaining = 0;
int time_remaining = 0;
if( g_fGameOver ) // someone else quit the game already
{
CHalfLifeMultiplay::Think();
return;
}
// Update HUD timer and effective time.
m_Timer.Think();
float flTimeLimit = CVAR_GET_FLOAT("mp_timelimit") * 60;
time_remaining = (int)(flTimeLimit ? ( flTimeLimit - gpGlobals->time ) : 0);
if( flTimeLimit != 0 && gpGlobals->time >= flTimeLimit )
{
GoToIntermission();
return;
}
float flFragLimit = fraglimit.value;
if( flFragLimit )
{
int bestfrags = 9999;
int remain;
// check if any team is over the frag limit
for( int i = 0; i < num_teams; i++ )
{
if( team_scores[i] >= flFragLimit )
{
GoToIntermission();
return;
}
remain = flFragLimit - team_scores[i];
if( remain < bestfrags )
{
bestfrags = remain;
}
}
frags_remaining = bestfrags;
}
if( !g_bSpawnedRunes )
SpawnRunes();
if( m_flFlagStatusTime && m_flFlagStatusTime <= gpGlobals->time )
GetFlagStatus( NULL );
// Updates when frags change
if( frags_remaining != last_frags )
{
g_engfuncs.pfnCvar_DirectSet( &fragsleft, UTIL_VarArgs( "%i", frags_remaining ) );
}
// Updates once per second
if( timeleft.value != last_time )
{
g_engfuncs.pfnCvar_DirectSet( &timeleft, UTIL_VarArgs( "%i", time_remaining ) );
}
last_frags = frags_remaining;
last_time = time_remaining;
}
void CThreeWave::JoinTeam( CBasePlayer *pPlayer, int iTeam )
{
bool bIsNotSpawn = false;
if( pPlayer->pev->team == iTeam )
return;
if( pPlayer->m_flNextTeamChange > gpGlobals->time )
return;
pPlayer->m_flNextTeamChange = gpGlobals->time + 5;
if( pPlayer->pev->team == 0 )
bIsNotSpawn = true;
ChangePlayerTeam( pPlayer, iTeam );
RecountTeams();
if( bIsNotSpawn )
pPlayer->Spawn();
}
int CThreeWave::TeamWithFewestPlayers()
{
CBaseEntity *pPlayer = NULL;
CBasePlayer *player = NULL;
int iNumRed, iNumBlue;
int iTeam = 0;
// Initialize the player counts..
iNumRed = iNumBlue = 0;
for( int i = 1; i <= gpGlobals->maxClients; i++ )
{
CBasePlayer *pPlayer = (CBasePlayer *)UTIL_PlayerByIndex( i );
if( pPlayer && pPlayer->pev->flags != FL_DORMANT )
{
if( pPlayer->pev->team == RED )
iNumRed += 1;
else if( pPlayer->pev->team == BLUE )
iNumBlue += 1;
}
}
if( ( iNumRed == iNumBlue ) || ( iNumRed == 0 && iNumBlue == 0 ) )
iTeam = RANDOM_LONG( RED, BLUE );
else if( iNumRed > iNumBlue )
iTeam = BLUE;
else if( iNumRed < iNumBlue )
iTeam = RED;
return iTeam;
}
extern void DropRune( CBasePlayer *pPlayer );
//=========================================================
// ClientCommand
// the user has typed a command which is unrecognized by everything else;
// this check to see if the gamerules knows anything about the command
//=========================================================
BOOL CThreeWave::ClientCommand( CBasePlayer *pPlayer, const char *pcmd )
{
#ifndef NO_VOICEGAMEMGR
if( m_VoiceGameMgr.ClientCommand( pPlayer, pcmd ) )
return TRUE;
#endif
if( pPlayer->m_bHadFirstSpawn == false && g_bHaveMOTD )
pPlayer->m_bHadFirstSpawn = true;
if( FStrEq( pcmd, "menuselect" ) )
{
int iTeam = 0;
if( CMD_ARGC() < 2 )
return TRUE;
int slot = atoi( CMD_ARGV( 1 ) );
// select the item from the current menu
switch( pPlayer->m_iMenu )
{
case Team_Menu:
case Team_Menu_IG:
switch ( slot )
{
case 1:
iTeam = RED;
break;
case 2:
iTeam = BLUE;
break;
case 5:
iTeam = TeamWithFewestPlayers();
break;
default:
return TRUE;
}
break;
default:
return TRUE;
}
JoinTeam( pPlayer, iTeam );
return TRUE;
}
else if( FStrEq( pcmd, "droprune" ) )
{
DropRune( pPlayer );
return TRUE;
}
else if( FStrEq( pcmd, "changeteam" ) )
{
if( pPlayer->pev->team != 0 )
{
pPlayer->ShowMenu( 1 + 2 + 16 + 512, -1, FALSE, "#Team_Menu_Join_IG" );
pPlayer->m_iMenu = Team_Menu_IG;
}
return TRUE;
}
return FALSE;
}
extern int gmsgGameMode;
extern int gmsgSayText;
extern int gmsgTeamInfo;
void CThreeWave::UpdateGameMode( CBasePlayer *pPlayer )
{
MESSAGE_BEGIN( MSG_ONE, gmsgGameMode, NULL, pPlayer->edict() );
WRITE_BYTE( 1 ); // game mode teamplay
MESSAGE_END();
}
edict_t *CThreeWave::GetPlayerSpawnSpot( CBasePlayer *pPlayer )
{
BOOL bCheckDM;
edict_t *pentSpawnSpot;
if( FBitSet( pPlayer->m_afPhysicsFlags, PFLAG_OBSERVER ) || pPlayer->pev->team == 0 )
bCheckDM = FALSE;
else
{
if( RANDOM_LONG( 1, 7 ) < 3 )
bCheckDM = TRUE;
else
bCheckDM = FALSE;
}
pentSpawnSpot = EntSelectSpawnPoint( pPlayer, bCheckDM );
if( IsMultiplayer() && pentSpawnSpot->v.target )
{
FireTargets( STRING( pentSpawnSpot->v.target ), pPlayer, pPlayer, USE_TOGGLE, 0 );
}
pPlayer->pev->origin = VARS( pentSpawnSpot )->origin + Vector( 0, 0, 1 );
pPlayer->pev->v_angle = g_vecZero;
pPlayer->pev->velocity = g_vecZero;
pPlayer->pev->angles = VARS( pentSpawnSpot )->angles;
pPlayer->pev->punchangle = g_vecZero;
pPlayer->pev->fixangle = TRUE;
return pentSpawnSpot;
}
void CThreeWave::PlayerTakeDamage( CBasePlayer *pPlayer, CBaseEntity *pAttacker )
{
if( !pAttacker->IsPlayer() )
return;
if( pPlayer->pev->team == pAttacker->pev->team )
return;
if( pPlayer->m_bHasFlag )
{
pPlayer->pCarrierHurter = (CBasePlayer *)pAttacker;
pPlayer->m_flCarrierHurtTime = gpGlobals->time + TEAM_CAPTURE_CARRIER_DANGER_PROTECT_TIMEOUT;
}
}
void CThreeWave::PlayerSpawn( CBasePlayer *pPlayer )
{
BOOL addDefault;
CBaseEntity *pWeaponEntity = NULL;
if( pPlayer->pev->team == 0 )
{
pPlayer->pev->takedamage = DAMAGE_NO;
pPlayer->pev->solid = SOLID_NOT;
pPlayer->pev->movetype = MOVETYPE_NOCLIP;
pPlayer->pev->effects |= EF_NODRAW;
pPlayer->pev->flags |= FL_NOTARGET;
pPlayer->m_afPhysicsFlags |= PFLAG_OBSERVER;
pPlayer->m_iHideHUD |= HIDEHUD_WEAPONS | HIDEHUD_FLASHLIGHT | HIDEHUD_HEALTH;
pPlayer->m_flFlagStatusTime = gpGlobals->time + 0.1;
}
else
{
pPlayer->pev->weapons |= ( 1 << WEAPON_SUIT );
addDefault = TRUE;
while( ( pWeaponEntity = UTIL_FindEntityByClassname( pWeaponEntity, "game_player_equip" ) ) )
{
pWeaponEntity->Touch( pPlayer );
addDefault = FALSE;
}
if( addDefault )
{
pPlayer->m_bHasFlag = FALSE;
pPlayer->m_iHideHUD &= ~HIDEHUD_WEAPONS;
pPlayer->m_iHideHUD &= ~HIDEHUD_FLASHLIGHT;
pPlayer->m_iHideHUD &= ~HIDEHUD_HEALTH;
pPlayer->m_afPhysicsFlags &= ~PFLAG_OBSERVER;
// Start with init ammoload
pPlayer->m_iAmmoShells = 25;
// Start with shotgun and axe
pPlayer->GiveNamedItem( "weapon_quakegun" );
if( arcade.value )
{
pPlayer->m_iQuakeItems |= ( IT_AXE | IT_SHOTGUN | IT_SUPER_SHOTGUN | IT_NAILGUN | IT_SUPER_NAILGUN | IT_GRENADE_LAUNCHER | IT_ROCKET_LAUNCHER | IT_LIGHTNING );
pPlayer->m_iAmmoRockets = 100;
pPlayer->m_iAmmoCells = 100;
pPlayer->m_iAmmoShells = 100;
pPlayer->m_iAmmoNails = 200;
pPlayer->pev->health = 200;
pPlayer->pev->armortype = 0.8;
pPlayer->pev->armorvalue = 200;
pPlayer->m_iQuakeItems &= ~( IT_ARMOR1 | IT_ARMOR2 | IT_ARMOR3 );
pPlayer->m_iQuakeItems |= IT_ARMOR3;
}
else
pPlayer->m_iQuakeItems |= ( IT_SHOTGUN | IT_AXE );
if( allowhook.value )
pPlayer->m_iQuakeItems |= IT_EXTRA_WEAPON;
pPlayer->m_iQuakeWeapon = pPlayer->W_BestWeapon();
pPlayer->W_SetCurrentAmmo();
pPlayer->m_flFlagStatusTime = gpGlobals->time + 0.1;
}
}
/* MESSAGE_BEGIN( MSG_ONE, gmsgRuneStatus, NULL, pPlayer->pev);
WRITE_BYTE( pPlayer->m_iRuneStatus );
MESSAGE_END();*/
}
void CBasePlayer::ShowMenu( int bitsValidSlots, int nDisplayTime, BOOL fNeedMore, const char *pszText )
{
MESSAGE_BEGIN( MSG_ONE, gmsgShowMenu, NULL, pev );
WRITE_SHORT( bitsValidSlots);
WRITE_CHAR( nDisplayTime );
WRITE_BYTE( fNeedMore );
WRITE_STRING( pszText );
MESSAGE_END();
}
//=========================================================
// InitHUD
//=========================================================
void CThreeWave::InitHUD( CBasePlayer *pPlayer )
{
CHalfLifeMultiplay::InitHUD( pPlayer );
int clientIndex = pPlayer->entindex();
// update this player with all the other players team info
// loop through all active players and send their team info to the new client
for( int i = 1; i <= gpGlobals->maxClients; i++ )
{
CBaseEntity *plr = UTIL_PlayerByIndex( i );
if( plr )
{
MESSAGE_BEGIN( MSG_ONE, gmsgTeamInfo, NULL, pPlayer->edict() );
WRITE_BYTE( plr->entindex() );
WRITE_STRING( plr->TeamID() );
MESSAGE_END();
if( ( (CBasePlayer *)plr )->m_bHasFlag )
{
MESSAGE_BEGIN( MSG_ONE, gmsgFlagCarrier, NULL, pPlayer->edict() );
WRITE_BYTE( plr->entindex() );
WRITE_BYTE( 1 );
MESSAGE_END();
}
}
}
// Remove Rune icon if we have one.
MESSAGE_BEGIN( MSG_ONE, gmsgRuneStatus, NULL, pPlayer->pev );
WRITE_BYTE( 0 );
MESSAGE_END();
if( pPlayer->pev->team == 0 )
{
pPlayer->ShowMenu( 1 + 2 + 16, -1, FALSE, "#Team_Menu_Join" );
pPlayer->m_iMenu = Team_Menu;
}
}
void CThreeWave::ChangePlayerTeam( CBasePlayer *pPlayer, int iTeam )
{
int clientIndex = pPlayer->entindex();
int damageFlags = DMG_GENERIC;
if( pPlayer->pev->team != 0 )
{
damageFlags |= DMG_ALWAYSGIB;
// kill the player, remove a death, and let them start on the new team
m_DisableDeathMessages = TRUE;
m_DisableDeathPenalty = TRUE;
entvars_t *pevWorld = VARS( INDEXENT( 0 ) );
pPlayer->TakeDamage( pevWorld, pevWorld, 900, damageFlags );
m_DisableDeathMessages = FALSE;
m_DisableDeathPenalty = FALSE;
}
int oldTeam = pPlayer->pev->team;
pPlayer->pev->team = iTeam;
strcpy( pPlayer->m_szTeamName, sTeamNames[pPlayer->pev->team] );
ClientUserInfoChanged( pPlayer, NULL );
// notify everyone's HUD of the team change
MESSAGE_BEGIN( MSG_ALL, gmsgTeamInfo );
WRITE_BYTE( clientIndex );
WRITE_STRING( pPlayer->m_szTeamName );
MESSAGE_END();
MESSAGE_BEGIN( MSG_ALL, gmsgScoreInfo );
WRITE_BYTE( ENTINDEX(pPlayer->edict()) );
WRITE_SHORT( pPlayer->pev->frags );
WRITE_SHORT( pPlayer->m_iDeaths );
WRITE_SHORT( pPlayer->pev->team );
MESSAGE_END();
// log the change
UTIL_LogPrintf( "\"%s<%i><%s><%s>\" joined team \"%s\"\n",
STRING(pPlayer->pev->netname),
GETPLAYERUSERID( pPlayer->edict() ),
GETPLAYERAUTHID( pPlayer->edict() ),
GetTeamName( oldTeam ),
pPlayer->m_szTeamName );
}
//=========================================================
// ClientUserInfoChanged
//=========================================================
void CThreeWave::ClientUserInfoChanged( CBasePlayer *pPlayer, char *infobuffer )
{
int clientIndex = pPlayer->entindex();
const char *pszModel = "";
int iTopColor = 0;
if( pPlayer->pev->team == RED )
{
pszModel = "red";
iTopColor = 255;
}
else if( pPlayer->pev->team == BLUE )
{
pszModel = "blue";
iTopColor = 153;
}
g_engfuncs.pfnSetClientKeyValue( clientIndex, g_engfuncs.pfnGetInfoKeyBuffer( pPlayer->edict() ), "topcolor", UTIL_VarArgs( "%d", iTopColor ) );
g_engfuncs.pfnSetClientKeyValue( clientIndex, g_engfuncs.pfnGetInfoKeyBuffer( pPlayer->edict() ), "model", pszModel );
}
extern int gmsgDeathMsg;
//=========================================================
// Deathnotice.
//=========================================================
void CThreeWave::DeathNotice( CBasePlayer *pVictim, entvars_t *pKiller, entvars_t *pevInflictor )
{
if( m_DisableDeathMessages )
return;
if( pVictim && pKiller && pKiller->flags & FL_CLIENT )
{
CBasePlayer *pk = (CBasePlayer*)CBaseEntity::Instance( pKiller );
if( pk )
{
if( ( pk != pVictim ) && ( PlayerRelationship( pVictim, pk ) == GR_TEAMMATE ) )
{
MESSAGE_BEGIN( MSG_ALL, gmsgDeathMsg );
WRITE_BYTE( ENTINDEX( ENT( pKiller ) ) ); // the killer
WRITE_BYTE( ENTINDEX( pVictim->edict() ) ); // the victim
WRITE_STRING( "teammate" ); // flag this as a teammate kill
MESSAGE_END();
return;
}
}
}
CHalfLifeMultiplay::DeathNotice( pVictim, pKiller, pevInflictor );
}
//=========================================================
//=========================================================
void CThreeWave::ClientDisconnected( edict_t *pClient )
{
if( pClient )
{
CBasePlayer *pPlayer = (CBasePlayer *)CBaseEntity::Instance( pClient );
if( pPlayer )
{
//We have the flag, spawn it
if( pPlayer->m_bHasFlag )
{
CBaseEntity *pEnt = NULL;
//We have the BLUE flag, Spawn it
if( pPlayer->pev->team == RED )
{
pEnt = CBaseEntity::Create( "item_flag_team2", pPlayer->pev->origin, pPlayer->pev->angles, pPlayer->edict() );
UTIL_LogPrintf( "\"%s<%i><%s><%s>\" triggered \"Dropped_Blue_Flag\"\n",
STRING( pPlayer->pev->netname ),
GETPLAYERUSERID( pPlayer->edict() ),
GETPLAYERAUTHID( pPlayer->edict() ),
GetTeamName( pPlayer->pev->team ) );
}
//We have the RED flag, Spawn it
else if( pPlayer->pev->team == BLUE )
{
pEnt = CBaseEntity::Create( "item_flag_team1", pPlayer->pev->origin, pPlayer->pev->angles, pPlayer->edict() );
UTIL_LogPrintf( "\"%s<%i><%s><%s>\" triggered \"Dropped_Red_Flag\"\n",
STRING( pPlayer->pev->netname ),
GETPLAYERUSERID( pPlayer->edict() ),
GETPLAYERAUTHID( pPlayer->edict() ),
GetTeamName( pPlayer->pev->team ) );
}
pEnt->pev->velocity = pPlayer->pev->velocity * 1.2;
pEnt->pev->angles.x = 0;
CItemFlag *pFlag = (CItemFlag *)pEnt;
pFlag->Dropped = TRUE;
pFlag->m_flDroppedTime = gpGlobals->time + TEAM_CAPTURE_FLAG_RETURN_TIME;
PLAYBACK_EVENT_FULL( FEV_GLOBAL | FEV_RELIABLE,
pPlayer->edict(), g_usCarried, 0, (float*)&g_vecZero, (float*)&g_vecZero,
0.0, 0.0, pPlayer->entindex(), pPlayer->pev->team, 1, 0 );
MESSAGE_BEGIN( MSG_ALL, gmsgCTFMsgs, NULL );
if( pPlayer->pev->team == RED )
WRITE_BYTE( BLUE_FLAG_LOST );
else if( pPlayer->pev->team == BLUE )
WRITE_BYTE( RED_FLAG_LOST );
WRITE_STRING( STRING( pPlayer->pev->netname ) );
MESSAGE_END();
m_flFlagStatusTime = gpGlobals->time + 0.1;
pPlayer->m_bHasFlag = FALSE;
}
// drop any runes the player has
if( pPlayer->m_iRuneStatus )
{
CItemRune *pRune = (CItemRune*)CBaseEntity::Create( g_RuneEntityName[pPlayer->m_iRuneStatus], pPlayer->pev->origin, pPlayer->pev->angles, pPlayer->edict() );
if( pRune )
{
pRune->pev->velocity = pPlayer->pev->velocity * 1.5;
pRune->pev->angles.x = 0;
pRune->dropped = true;
UTIL_LogPrintf( "\"%s<%i><%s><%s>\" triggered \"Dropped_%s\"\n",
STRING(pPlayer->pev->netname),
GETPLAYERUSERID( pPlayer->edict() ),
GETPLAYERAUTHID( pPlayer->edict() ),
pPlayer->m_szTeamName,
g_RuneName[pPlayer->m_iRuneStatus] );
}
pPlayer->m_iRuneStatus = 0;
}
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() ),
GetTeamName( pPlayer->pev->team ) );
pPlayer->RemoveAllItems( TRUE );// destroy all of the players weapons and items
}
}
}
void CThreeWave::PlayerThink( CBasePlayer *pPlayer )
{
if( g_fGameOver )
{
// check for button presses
if( 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->pFlagCarrierKiller )
{
if( pPlayer->m_flFlagCarrierKillTime <= gpGlobals->time )
pPlayer->pFlagCarrierKiller = NULL;
}
if( pPlayer->pFlagReturner )
{
if( pPlayer->m_flFlagReturnTime <= gpGlobals->time )
pPlayer->pFlagReturner = NULL;
}
if( pPlayer->pCarrierHurter )
{
if( pPlayer->m_flCarrierHurtTime <= gpGlobals->time )
pPlayer->pCarrierHurter = NULL;
}
if( pPlayer->m_iRuneStatus == ITEM_RUNE4_FLAG )
{
if( pPlayer->m_flRegenTime <= gpGlobals->time )
{
if( pPlayer->pev->health < 150 )
{
pPlayer->pev->health += 5;
if( pPlayer->pev->health > 150)
pPlayer->pev->health = 150;
pPlayer->m_flRegenTime = gpGlobals->time + 1;
EMIT_SOUND( ENT( pPlayer->pev), CHAN_ITEM, "rune/rune4.wav", 1, ATTN_NORM );
}
if( pPlayer->pev->armorvalue < 150 && pPlayer->pev->armorvalue )
{
pPlayer->pev->armorvalue += 5;
if( pPlayer->pev->armorvalue > 150)
pPlayer->pev->armorvalue = 150;
pPlayer->m_flRegenTime = gpGlobals->time + 1;
EMIT_SOUND( ENT( pPlayer->pev ), CHAN_ITEM, "rune/rune4.wav", 1, ATTN_NORM );
}
}
}
if( pPlayer->m_bOn_Hook )
pPlayer->Service_Grapple();
if( pPlayer->m_flFlagStatusTime && pPlayer->m_flFlagStatusTime <= gpGlobals->time )
GetFlagStatus( pPlayer );
}
//=========================================================
//=========================================================
void CThreeWave::PlayerKilled( CBasePlayer *pVictim, entvars_t *pKiller, entvars_t *pInflictor )
{
CBasePlayer *pk = NULL;
if( pKiller )
{
CBaseEntity *pTemp = CBaseEntity::Instance( pKiller );
if( pTemp->IsPlayer() )
pk = (CBasePlayer*)pTemp;
}
//Only award a bonus if the Flag carrier had the flag for more than 2 secs
//Prevents from people waiting for the flag carrier to grab the flag and then killing him
//Instead of actually defending the flag.
if( pVictim->m_bHasFlag )
{
if( pk )
{
if( pVictim->pev->team != pk->pev->team )
{
if( pVictim->m_flCarrierPickupTime <= gpGlobals->time )
pk->AddPoints( TEAM_CAPTURE_FRAG_CARRIER_BONUS, TRUE );
if( pk->pev->team == RED )
{
UTIL_ClientPrintAll( HUD_PRINTNOTIFY, STRING( pk->pev->netname ) );
UTIL_ClientPrintAll( HUD_PRINTNOTIFY, " fragged " );
UTIL_ClientPrintAll( HUD_PRINTNOTIFY, "BLUE" );
UTIL_ClientPrintAll( HUD_PRINTNOTIFY, "'s flag carrier!\n" );
UTIL_LogPrintf( "\"%s<%i><%s><%s>\" triggered \"Killed_Enemy_Flag_Carrier\"\n",
STRING( pk->pev->netname ),
GETPLAYERUSERID( pk->edict() ),
GETPLAYERAUTHID( pk->edict() ),
GetTeamName( pk->pev->team ) );
if( iBlueFlagStatus == BLUE_FLAG_STOLEN )
{
for( int i = 1; i <= gpGlobals->maxClients; i++ )
{
CBasePlayer *pTeamMate = (CBasePlayer *)UTIL_PlayerByIndex( i );
if( pTeamMate )
{
if( pTeamMate->m_bHasFlag )
{
pTeamMate->pFlagCarrierKiller = pk;
pTeamMate->m_flFlagCarrierKillTime = gpGlobals->time + TEAM_CAPTURE_FRAG_CARRIER_ASSIST_TIMEOUT;
}
}
}
}
}
if( pk->pev->team == BLUE )
{
UTIL_ClientPrintAll( HUD_PRINTNOTIFY, STRING( pk->pev->netname ) );
UTIL_ClientPrintAll( HUD_PRINTNOTIFY, " fragged " );
UTIL_ClientPrintAll( HUD_PRINTNOTIFY, "RED" );
UTIL_ClientPrintAll( HUD_PRINTNOTIFY, "'s flag carrier!\n" );
UTIL_LogPrintf( "\"%s<%i><%s><%s>\" triggered \"Killed_Enemy_Flag_Carrier\"\n",
STRING( pk->pev->netname ),
GETPLAYERUSERID( pk->edict() ),
GETPLAYERAUTHID( pk->edict() ),
GetTeamName( pk->pev->team ) );
if( iRedFlagStatus == RED_FLAG_STOLEN )
{
for( int i = 1; i <= gpGlobals->maxClients; i++ )
{
CBasePlayer *pTeamMate = (CBasePlayer *)UTIL_PlayerByIndex( i );
if( pTeamMate )
{
if( pTeamMate->m_bHasFlag )
{
pTeamMate->pFlagCarrierKiller = pk;
pTeamMate->m_flFlagCarrierKillTime = gpGlobals->time + TEAM_CAPTURE_FRAG_CARRIER_ASSIST_TIMEOUT;
}
}
}
}
}
}
}
CBaseEntity *pEnt = NULL;
// We have the BLUE flag, Spawn it
if( pVictim->pev->team == RED )
{
pEnt = CBaseEntity::Create( "item_flag_team2", pVictim->pev->origin, pVictim->pev->angles, pVictim->edict() );
UTIL_LogPrintf( "\"%s<%i><%s><%s>\" triggered \"Dropped_Blue_Flag\"\n",
STRING( pVictim->pev->netname ),
GETPLAYERUSERID( pVictim->edict() ),
GETPLAYERAUTHID( pVictim->edict() ),
GetTeamName( pVictim->pev->team ) );
}
else if( pVictim->pev->team == BLUE )
{
pEnt = CBaseEntity::Create( "item_flag_team1", pVictim->pev->origin, pVictim->pev->angles, pVictim->edict() );
UTIL_LogPrintf( "\"%s<%i><%s><%s>\" triggered \"Dropped_Red_Flag\"\n",
STRING( pVictim->pev->netname ),
GETPLAYERUSERID( pVictim->edict() ),
GETPLAYERAUTHID( pVictim->edict() ),
GetTeamName( pVictim->pev->team ) );
}
pEnt->pev->velocity = pVictim->pev->velocity * 1.2;
pEnt->pev->angles.x = 0;
CItemFlag *pFlag = (CItemFlag *)pEnt;
pFlag->Dropped = TRUE;
PLAYBACK_EVENT_FULL( FEV_GLOBAL | FEV_RELIABLE,
pVictim->edict(), g_usCarried, 0, (float *)&g_vecZero, (float *)&g_vecZero,
0.0, 0.0, pVictim->entindex(), pVictim->pev->team, 1, 0 );
pFlag->m_flDroppedTime = gpGlobals->time + TEAM_CAPTURE_FLAG_RETURN_TIME;
MESSAGE_BEGIN ( MSG_ALL, gmsgCTFMsgs, NULL );
if( pVictim->pev->team == RED )
WRITE_BYTE( BLUE_FLAG_LOST );
else if( pVictim->pev->team == BLUE )
WRITE_BYTE( RED_FLAG_LOST );
WRITE_STRING( STRING( pVictim->pev->netname ) );
MESSAGE_END();
pVictim->m_bHasFlag = FALSE;
m_flFlagStatusTime = gpGlobals->time + 0.1;
}
else
{
if( pk )
{
if( pk->pev->team == RED )
{
if( iBlueFlagStatus == BLUE_FLAG_STOLEN )
{
for( int i = 1; i <= gpGlobals->maxClients; i++ )
{
CBasePlayer *pTeamMate = (CBasePlayer *)UTIL_PlayerByIndex( i );
if ( pTeamMate && pTeamMate != pk )
{
if ( pTeamMate->pev->team == pk->pev->team )
{
if ( pTeamMate->m_bHasFlag )
{
if ( pTeamMate->pCarrierHurter )
{
if ( pTeamMate->pCarrierHurter == pVictim )
{
if ( pTeamMate->m_flCarrierHurtTime > gpGlobals->time )
{
UTIL_ClientPrintAll( HUD_PRINTNOTIFY, STRING( pk->pev->netname ) );
UTIL_ClientPrintAll( HUD_PRINTNOTIFY, " defends ");
UTIL_ClientPrintAll( HUD_PRINTNOTIFY, "RED" );
UTIL_ClientPrintAll( HUD_PRINTNOTIFY, "'s flag carrier against an agressive enemy\n");
pk->AddPoints( TEAM_CAPTURE_CARRIER_DANGER_PROTECT_BONUS, TRUE );
}
}
}
}
}
}
}
}
}
if( pk->pev->team == BLUE )
{
if( iRedFlagStatus == RED_FLAG_STOLEN )
{
for( int i = 1; i <= gpGlobals->maxClients; i++ )
{
CBasePlayer *pTeamMate = (CBasePlayer *)UTIL_PlayerByIndex( i );
if( pTeamMate && pTeamMate != pk )
{
if( pTeamMate->pev->team == pk->pev->team )
{
if( pTeamMate->m_bHasFlag )
{
if( pTeamMate->pCarrierHurter )
{
if( pTeamMate->pCarrierHurter == pVictim )
{
if( pTeamMate->m_flCarrierHurtTime > gpGlobals->time )
{
UTIL_ClientPrintAll( HUD_PRINTNOTIFY, STRING( pk->pev->netname ) );
UTIL_ClientPrintAll( HUD_PRINTNOTIFY, " defends ");
UTIL_ClientPrintAll( HUD_PRINTNOTIFY, "BLUE" );
UTIL_ClientPrintAll( HUD_PRINTNOTIFY, "'s flag carrier against an agressive enemy\n");
pk->AddPoints( TEAM_CAPTURE_CARRIER_DANGER_PROTECT_BONUS, TRUE );
}
}
}
}
}
}
}
}
}
}
}
// Find if this guy is near our flag or our flag carrier
CBaseEntity *ent = NULL;
float Dist;
if( pk )
{
if( pk->pev->team == RED )
{
while( ( ent = UTIL_FindEntityByClassname( ent, "item_flag_team1" ) ) != NULL )
{
//Do not defend a invisible flag
if( ent->pev->effects & EF_NODRAW )
break;
Dist = ( pk->pev->origin - ent->pev->origin ).Length();
if( Dist <= TEAM_CAPTURE_TARGET_PROTECT_RADIUS )
{
UTIL_ClientPrintAll( HUD_PRINTNOTIFY, STRING ( pk->pev->netname ) );
UTIL_ClientPrintAll( HUD_PRINTNOTIFY, " defends the ");
UTIL_ClientPrintAll( HUD_PRINTNOTIFY, "RED");
UTIL_ClientPrintAll( HUD_PRINTNOTIFY, " flag\n");
pk->AddPoints( TEAM_CAPTURE_FLAG_DEFENSE_BONUS, TRUE );
break;
}
}
if( iBlueFlagStatus == BLUE_FLAG_STOLEN )
{
for( int i = 1; i <= gpGlobals->maxClients; i++ )
{
CBasePlayer *pTeamMate = (CBasePlayer *)UTIL_PlayerByIndex( i );
if( pTeamMate && pTeamMate != pk )
{
if( pTeamMate->pev->team == pk->pev->team )
{
if( pTeamMate->m_bHasFlag )
{
Dist = ( pk->pev->origin - pTeamMate->pev->origin ).Length();
if( Dist <= TEAM_CAPTURE_TARGET_PROTECT_RADIUS )
{
UTIL_ClientPrintAll( HUD_PRINTNOTIFY, STRING( pk->pev->netname ) );
UTIL_ClientPrintAll( HUD_PRINTNOTIFY, " defends " );
UTIL_ClientPrintAll( HUD_PRINTNOTIFY, "RED" );
UTIL_ClientPrintAll( HUD_PRINTNOTIFY, "'s flag carrier\n" );
pk->AddPoints( TEAM_CAPTURE_CARRIER_PROTECT_BONUS, TRUE );
}
}
}
}
}
}
}
else if( pk->pev->team == BLUE )
{
while( ( ent = UTIL_FindEntityByClassname( ent, "item_flag_team2") ) != NULL )
{
// Do not defend a invisible flag
if( ent->pev->effects & EF_NODRAW )
break;
Dist = ( pk->pev->origin - ent->pev->origin ).Length();
if( Dist <= TEAM_CAPTURE_TARGET_PROTECT_RADIUS )
{
UTIL_ClientPrintAll( HUD_PRINTNOTIFY, STRING( pk->pev->netname ) );
UTIL_ClientPrintAll( HUD_PRINTNOTIFY, " defends the " );
UTIL_ClientPrintAll( HUD_PRINTNOTIFY, "RED" );
UTIL_ClientPrintAll( HUD_PRINTNOTIFY, " flag\n" );
pk->AddPoints( TEAM_CAPTURE_FLAG_DEFENSE_BONUS, TRUE );
break;
}
}
if( iRedFlagStatus == RED_FLAG_STOLEN )
{
for( int i = 1; i <= gpGlobals->maxClients; i++ )
{
CBasePlayer *pTeamMate = (CBasePlayer *)UTIL_PlayerByIndex( i );
if( pTeamMate && pTeamMate != pk )
{
if( pTeamMate->pev->team == pk->pev->team )
{
if( pTeamMate->m_bHasFlag )
{
Dist = ( pk->pev->origin - pTeamMate->pev->origin ).Length();
if( Dist <= TEAM_CAPTURE_TARGET_PROTECT_RADIUS )
{
UTIL_ClientPrintAll( HUD_PRINTNOTIFY, STRING( pk->pev->netname ) );
UTIL_ClientPrintAll( HUD_PRINTNOTIFY, " defends ");
UTIL_ClientPrintAll( HUD_PRINTNOTIFY, "RED");
UTIL_ClientPrintAll( HUD_PRINTNOTIFY, "'s flag carrier\n" );
pk->AddPoints( TEAM_CAPTURE_CARRIER_PROTECT_BONUS, TRUE );
}
}
}
}
}
}
}
}
if( pVictim->m_iRuneStatus )
{
CItemRune *pRune = (CItemRune*)CBaseEntity::Create( g_RuneEntityName[pVictim->m_iRuneStatus], pVictim->pev->origin, pVictim->pev->angles, NULL );
if( pRune )
{
pRune->pev->velocity = pVictim->pev->velocity * 1.5;
pRune->pev->angles.x = 0;
pRune->dropped = true;
UTIL_LogPrintf( "\"%s<%i><%s><%s>\" triggered \"Dropped_%s\"\n",
STRING(pVictim->pev->netname),
GETPLAYERUSERID( pVictim->edict() ),
GETPLAYERAUTHID( pVictim->edict() ),
pVictim->m_szTeamName,
g_RuneName[pVictim->m_iRuneStatus] );
}
pVictim->m_iRuneStatus = 0;
}
if( pVictim->m_ppHook )
pVictim->m_ppHook->Reset_Grapple();
MESSAGE_BEGIN( MSG_ONE, gmsgRuneStatus, NULL, pVictim->pev );
WRITE_BYTE( pVictim->m_iRuneStatus );
MESSAGE_END();
if( !m_DisableDeathPenalty )
{
CHalfLifeMultiplay::PlayerKilled( pVictim, pKiller, pInflictor );
RecountTeams();
}
}
//=========================================================
// IsTeamplay
//=========================================================
BOOL CThreeWave::IsTeamplay()
{
return TRUE;
}
BOOL CThreeWave::FPlayerCanTakeDamage( CBasePlayer *pPlayer, CBaseEntity *pAttacker )
{
if( pAttacker && PlayerRelationship( pPlayer, pAttacker ) == GR_TEAMMATE )
{
// my teammate hit me.
if( ( CVAR_GET_FLOAT( "mp_friendlyfire" ) == 0 ) && ( pAttacker != pPlayer ) )
{
// friendly fire is off, and this hit came from someone other than myself, then don't get hurt
return FALSE;
}
}
return CHalfLifeMultiplay::FPlayerCanTakeDamage( pPlayer, pAttacker );
}
//=========================================================
//=========================================================
int CThreeWave::PlayerRelationship( CBaseEntity *pPlayer, CBaseEntity *pTarget )
{
// half life multiplay has a simple concept of Player Relationships.
// you are either on another player's team, or you are not.
if( !pPlayer || !pTarget || !pTarget->IsPlayer() )
return GR_NOTTEAMMATE;
//As simple as this
if( pPlayer->pev->team == pTarget->pev->team )
{
return GR_TEAMMATE;
}
return GR_NOTTEAMMATE;
}
//=========================================================
//=========================================================
BOOL CThreeWave::ShouldAutoAim( CBasePlayer *pPlayer, edict_t *target )
{
// always autoaim, unless target is a teammate
CBaseEntity *pTgt = CBaseEntity::Instance( target );
if( pTgt && pTgt->IsPlayer() )
{
if( PlayerRelationship( pPlayer, pTgt ) == GR_TEAMMATE )
return FALSE; // don't autoaim at teammates
}
return CHalfLifeMultiplay::ShouldAutoAim( pPlayer, target );
}
//=========================================================
//=========================================================
int CThreeWave::IPointsForKill( CBasePlayer *pAttacker, CBasePlayer *pKilled )
{
if( !pKilled )
return 0;
if( !pAttacker )
return 1;
if( pAttacker != pKilled && PlayerRelationship( pAttacker, pKilled ) == GR_TEAMMATE )
return -1;
return 1;
}
//=========================================================
//=========================================================
const char *CThreeWave::GetTeamID( CBaseEntity *pEntity )
{
if( pEntity == NULL || pEntity->pev == NULL )
return "";
// return their team name
return pEntity->TeamID();
}
int CThreeWave::GetTeamIndex( const char *pTeamName )
{
if( pTeamName && *pTeamName != 0 )
{
// try to find existing team
for( int tm = 0; tm < num_teams; tm++ )
{
if( !stricmp( team_names[tm], pTeamName ) )
return tm;
}
}
return -1; // No match
}
const char *CThreeWave::GetIndexedTeamName( int teamIndex )
{
if( teamIndex < 0 || teamIndex >= num_teams )
return "";
return team_names[teamIndex];
}
BOOL CThreeWave::IsValidTeam( const char *pTeamName )
{
if( !m_teamLimit ) // Any team is valid if the teamlist isn't set
return TRUE;
return ( GetTeamIndex( pTeamName ) != -1 ) ? TRUE : FALSE;
}
void CThreeWave::GetFlagStatus( CBasePlayer *pPlayer )
{
CBaseEntity *pFlag = NULL;
int iFoundCount = 0;
int iDropped = 0;
while( ( pFlag = UTIL_FindEntityByClassname( pFlag, "carried_flag_team1" ) ) != NULL )
{
if( pFlag && !FBitSet( pFlag->pev->flags, FL_KILLME ) )
iFoundCount++;
}
if( iFoundCount >= 1 )
iRedFlagStatus = RED_FLAG_STOLEN;
if( !iFoundCount )
{
while( ( pFlag = UTIL_FindEntityByClassname( pFlag, "item_flag_team1" ) ) != NULL )
{
if( pFlag )
{
if( ( (CItemFlag*)pFlag )->Dropped )
iDropped++;
iFoundCount++;
}
}
if( iFoundCount > 1 && iDropped == 1 )
iRedFlagStatus = RED_FLAG_DROPPED;
else if( iFoundCount >= 1 && iDropped == 0 )
iRedFlagStatus = RED_FLAG_ATBASE;
}
iDropped = iFoundCount = 0;
while( ( pFlag = UTIL_FindEntityByClassname( pFlag, "carried_flag_team2" ) ) != NULL )
{
if( pFlag && !FBitSet( pFlag->pev->flags, FL_KILLME ) )
iFoundCount++;
}
if( iFoundCount >= 1 )
iBlueFlagStatus = BLUE_FLAG_STOLEN;
if( !iFoundCount )
{
while( ( pFlag = UTIL_FindEntityByClassname( pFlag, "item_flag_team2" ) ) != NULL )
{
if( pFlag )
{
if( ( (CItemFlag* )pFlag )->Dropped )
iDropped++;
iFoundCount++;
}
}
if( iFoundCount > 1 && iDropped == 1 )
iBlueFlagStatus = BLUE_FLAG_DROPPED;
else if( iFoundCount >= 1 && iDropped == 0 )
iBlueFlagStatus = BLUE_FLAG_ATBASE;
}
if( pPlayer )
{
if( pPlayer->pev->team == 0 )
{
MESSAGE_BEGIN( MSG_ONE, gmsgFlagStatus, NULL, pPlayer->edict() );
WRITE_BYTE( 0 );
WRITE_BYTE( iRedFlagStatus );
WRITE_BYTE( iBlueFlagStatus );
WRITE_BYTE( iRedTeamScore );
WRITE_BYTE( iBlueTeamScore );
MESSAGE_END();
}
else
{
MESSAGE_BEGIN( MSG_ONE, gmsgFlagStatus, NULL, pPlayer->edict() );
WRITE_BYTE( 1 );
WRITE_BYTE( iRedFlagStatus );
WRITE_BYTE( iBlueFlagStatus );
WRITE_BYTE( iRedTeamScore );
WRITE_BYTE( iBlueTeamScore );
MESSAGE_END();
}
pPlayer->m_flFlagStatusTime = 0.0;
}
else
{
MESSAGE_BEGIN( MSG_ALL, gmsgFlagStatus, NULL );
WRITE_BYTE( 1 );
WRITE_BYTE( iRedFlagStatus );
WRITE_BYTE( iBlueFlagStatus );
WRITE_BYTE( iRedTeamScore );
WRITE_BYTE( iBlueTeamScore );
MESSAGE_END();
m_flFlagStatusTime = 0.0;
}
for( int i = 1; i <= gpGlobals->maxClients; i++ )
{
CBasePlayer *plr = (CBasePlayer *)UTIL_PlayerByIndex( i );
if( plr )
{
MESSAGE_BEGIN( MSG_ALL, gmsgFlagCarrier, NULL );
WRITE_BYTE( plr->entindex() );
WRITE_BYTE( plr->m_bHasFlag );
MESSAGE_END();
}
}
}
//=========================================================
//=========================================================
void CThreeWave::RecountTeams()
{
char *pName;
char teamlist[TEAMPLAY_TEAMLISTLENGTH];
// loop through all teams, recounting everything
num_teams = 0;
// Copy all of the teams from the teamlist
// make a copy because strtok is destructive
strcpy( teamlist, m_szTeamList );
pName = teamlist;
pName = strtok( pName, ";" );
while( pName != NULL && *pName )
{
if( GetTeamIndex( pName ) < 0 )
{
strcpy( team_names[num_teams], pName );
num_teams++;
}
pName = strtok( NULL, ";" );
}
if( num_teams < 2 )
{
num_teams = 0;
m_teamLimit = FALSE;
}
// Sanity check
memset( team_scores, 0, sizeof(team_scores) );
// loop through all clients
for( int i = 1; i <= gpGlobals->maxClients; i++ )
{
CBaseEntity *plr = UTIL_PlayerByIndex( i );
if( plr )
{
const char *pTeamName = plr->TeamID();
// try add to existing team
int tm = GetTeamIndex( pTeamName );
if( tm < 0 ) // no team match found
{
if( !m_teamLimit )
{
// add to new team
tm = num_teams;
num_teams++;
team_scores[tm] = 0;
strncpy( team_names[tm], pTeamName, MAX_TEAMNAME_LENGTH );
}
}
if( tm >= 0 )
{
team_scores[tm] += plr->pev->frags;
}
}
}
}