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.
1512 lines
38 KiB
1512 lines
38 KiB
8 years ago
|
//++ BulliT - with ideas from http://www.planethalflife.com/whenitsdone/
|
||
|
|
||
|
#include "extdll.h"
|
||
|
#include "util.h"
|
||
|
#include "cbase.h"
|
||
|
#include "player.h"
|
||
|
#include "weapons.h"
|
||
|
#include "gamerules.h"
|
||
|
|
||
|
#include "aggamerules.h"
|
||
|
#include "agglobal.h"
|
||
|
#include "agctf.h"
|
||
|
|
||
|
//////////////////////////////////////////////////////////////////////
|
||
|
// Construction/Destruction
|
||
|
//////////////////////////////////////////////////////////////////////
|
||
|
|
||
|
extern int gmsgCTFSound;
|
||
|
extern int gmsgCTFFlag;
|
||
|
extern int gmsgCountdown;
|
||
|
|
||
|
enum CTFSound
|
||
|
{
|
||
|
YouHaveFlag = 0,
|
||
|
TeamHaveFlag,
|
||
|
EnemyHaveFlag,
|
||
|
BlueFlagReturned,
|
||
|
RedFlagReturned,
|
||
|
BlueScores,
|
||
|
RedScores,
|
||
|
BlueFlagStolen,
|
||
|
RedFlagStolen,
|
||
|
//not used...
|
||
|
BlueLeads,
|
||
|
RedLeads,
|
||
|
TeamsTied,
|
||
|
SuddenDeath,
|
||
|
Stolen,
|
||
|
Capture,
|
||
|
};
|
||
|
|
||
|
FILE_GLOBAL int s_iTeam1Captures;
|
||
|
FILE_GLOBAL int s_iTeam2Captures;
|
||
|
|
||
|
DLL_GLOBAL bool g_bTeam1FlagStolen;
|
||
|
DLL_GLOBAL bool g_bTeam2FlagStolen;
|
||
|
|
||
|
DLL_GLOBAL bool g_bTeam1FlagLost;
|
||
|
DLL_GLOBAL bool g_bTeam2FlagLost;
|
||
|
FILE_GLOBAL int s_iPlayerFlag1;
|
||
|
FILE_GLOBAL int s_iPlayerFlag2;
|
||
|
|
||
|
extern int gmsgTeamScore;
|
||
|
|
||
|
AgCTF::AgCTF()
|
||
|
{
|
||
|
m_iTeam1Captures = 0;
|
||
|
m_iTeam2Captures = 0;
|
||
|
s_iTeam1Captures = s_iTeam2Captures = 0;
|
||
|
g_bTeam1FlagStolen = g_bTeam2FlagStolen = false;
|
||
|
g_bTeam1FlagLost = g_bTeam2FlagLost = false;
|
||
|
s_iPlayerFlag1 = 0;
|
||
|
s_iPlayerFlag2 = 0;
|
||
|
m_iPlayerFlag1 = 0;
|
||
|
m_iPlayerFlag2= 0;
|
||
|
m_fNextCountdown = 0.0;
|
||
|
m_fMatchStart = 0.0;
|
||
|
|
||
|
if (ag_ctf_roundbased.value)
|
||
|
m_Status = Waiting;
|
||
|
else
|
||
|
m_Status = Playing;
|
||
|
}
|
||
|
|
||
|
AgCTF::~AgCTF()
|
||
|
{
|
||
|
|
||
|
}
|
||
|
|
||
|
void AgCTF::PlayerInitHud(CBasePlayer* pPlayer)
|
||
|
{
|
||
|
ASSERT(NULL != pPlayer);
|
||
|
if (!pPlayer)
|
||
|
return;
|
||
|
ASSERT(NULL != pPlayer->pev);
|
||
|
if (!pPlayer->pev)
|
||
|
return;
|
||
|
|
||
|
MESSAGE_BEGIN( MSG_ONE, gmsgTeamScore, NULL, pPlayer->pev );
|
||
|
WRITE_STRING( CTF_TEAM1_NAME);
|
||
|
WRITE_SHORT( m_iTeam1Captures );
|
||
|
WRITE_SHORT( 0 );
|
||
|
MESSAGE_END();
|
||
|
|
||
|
MESSAGE_BEGIN( MSG_ONE, gmsgTeamScore, NULL, pPlayer->pev );
|
||
|
WRITE_STRING( CTF_TEAM2_NAME);
|
||
|
WRITE_SHORT( m_iTeam2Captures );
|
||
|
WRITE_SHORT( 0 );
|
||
|
MESSAGE_END();
|
||
|
}
|
||
|
|
||
|
bool AgCTF::CaptureLimit()
|
||
|
{
|
||
|
if (ag_ctf_capture_limit.value > 1
|
||
|
&& ( s_iTeam1Captures == ag_ctf_capture_limit.value
|
||
|
||s_iTeam2Captures == ag_ctf_capture_limit.value))
|
||
|
return true;
|
||
|
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
void AgCTF::SendCaptures(CBasePlayer* pPlayer)
|
||
|
{
|
||
|
ASSERT(NULL != pPlayer);
|
||
|
if (!pPlayer)
|
||
|
return;
|
||
|
ASSERT(NULL != pPlayer->pev);
|
||
|
if (!pPlayer->pev)
|
||
|
return;
|
||
|
|
||
|
MESSAGE_BEGIN( MSG_ONE, gmsgTeamScore, NULL, pPlayer->pev );
|
||
|
WRITE_STRING( CTF_TEAM1_NAME);
|
||
|
WRITE_SHORT( s_iTeam1Captures );
|
||
|
WRITE_SHORT( 0 );
|
||
|
MESSAGE_END();
|
||
|
|
||
|
MESSAGE_BEGIN( MSG_ONE, gmsgTeamScore, NULL, pPlayer->pev );
|
||
|
WRITE_STRING( CTF_TEAM2_NAME);
|
||
|
WRITE_SHORT( s_iTeam2Captures );
|
||
|
WRITE_SHORT( 0 );
|
||
|
MESSAGE_END();
|
||
|
|
||
|
}
|
||
|
|
||
|
void AgCTF::ResetScore(bool bResetCaptures)
|
||
|
{
|
||
|
m_iTeam1Captures = -1;
|
||
|
m_iTeam2Captures = -1;
|
||
|
s_iTeam1Captures = s_iTeam2Captures = 0;
|
||
|
m_Status = Playing;
|
||
|
|
||
|
if (bResetCaptures)
|
||
|
ResetCaptures();
|
||
|
}
|
||
|
|
||
|
void AgCTF::ResetCaptures()
|
||
|
{
|
||
|
g_bTeam1FlagStolen = g_bTeam2FlagStolen = false;
|
||
|
|
||
|
//Reset flag carrier.
|
||
|
for ( int i = 1; i <= gpGlobals->maxClients; i++ )
|
||
|
{
|
||
|
CBasePlayer* pPlayerLoop = AgPlayerByIndex(i);
|
||
|
if (pPlayerLoop)
|
||
|
{
|
||
|
pPlayerLoop->m_bFlagTeam1 = false;
|
||
|
pPlayerLoop->m_bFlagTeam2 = false;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//Remove carried flag
|
||
|
CBaseEntity* pEntity = NULL;
|
||
|
pEntity = NULL;
|
||
|
while ((pEntity = UTIL_FindEntityByClassname( pEntity, "carried_flag_team1" )) != NULL)
|
||
|
UTIL_Remove(pEntity);
|
||
|
|
||
|
pEntity = NULL;
|
||
|
while ((pEntity = UTIL_FindEntityByClassname( pEntity, "carried_flag_team2" )) != NULL)
|
||
|
UTIL_Remove(pEntity);
|
||
|
|
||
|
//Remove dropped flag
|
||
|
pEntity = NULL;
|
||
|
while ((pEntity = UTIL_FindEntityByClassname( pEntity, "item_flag_team1" )) != NULL)
|
||
|
{
|
||
|
if (((AgCTFFlag*)pEntity)->m_bDropped)
|
||
|
UTIL_Remove(pEntity);
|
||
|
}
|
||
|
|
||
|
pEntity = NULL;
|
||
|
while ((pEntity = UTIL_FindEntityByClassname( pEntity, "item_flag_team2" )) != NULL)
|
||
|
{
|
||
|
if (((AgCTFFlag*)pEntity)->m_bDropped)
|
||
|
UTIL_Remove(pEntity);
|
||
|
}
|
||
|
|
||
|
//Reset base flag
|
||
|
AgCTFFlag::ResetFlag(CTF_TEAM1_NAME);
|
||
|
AgCTFFlag::ResetFlag(CTF_TEAM2_NAME);
|
||
|
}
|
||
|
|
||
|
void AgCTF::Think()
|
||
|
{
|
||
|
if (!g_pGameRules)
|
||
|
return;
|
||
|
|
||
|
if (m_iTeam1Captures != s_iTeam1Captures
|
||
|
||m_iTeam2Captures != s_iTeam2Captures)
|
||
|
{
|
||
|
m_iTeam1Captures = s_iTeam1Captures;
|
||
|
|
||
|
//Send new team score to all clients.
|
||
|
MESSAGE_BEGIN( MSG_ALL, gmsgTeamScore );
|
||
|
WRITE_STRING( CTF_TEAM1_NAME);
|
||
|
WRITE_SHORT( s_iTeam1Captures );
|
||
|
WRITE_SHORT( 0 );
|
||
|
MESSAGE_END();
|
||
|
|
||
|
m_iTeam2Captures = s_iTeam2Captures;
|
||
|
|
||
|
//Send new team score to all clients.
|
||
|
MESSAGE_BEGIN( MSG_ALL, gmsgTeamScore );
|
||
|
WRITE_STRING( CTF_TEAM2_NAME);
|
||
|
WRITE_SHORT( s_iTeam2Captures );
|
||
|
WRITE_SHORT( 0 );
|
||
|
MESSAGE_END();
|
||
|
}
|
||
|
|
||
|
if (m_iPlayerFlag1 != s_iPlayerFlag1
|
||
|
||m_iPlayerFlag2 != s_iPlayerFlag2)
|
||
|
{
|
||
|
m_iPlayerFlag1 = s_iPlayerFlag1;
|
||
|
m_iPlayerFlag2 = s_iPlayerFlag2;
|
||
|
|
||
|
//Send new flag status to all clients.
|
||
|
MESSAGE_BEGIN( MSG_ALL, gmsgCTFFlag );
|
||
|
WRITE_BYTE( m_iPlayerFlag1 );
|
||
|
WRITE_BYTE( m_iPlayerFlag2 );
|
||
|
MESSAGE_END();
|
||
|
}
|
||
|
|
||
|
m_FileItemCache.Init();
|
||
|
|
||
|
RoundBasedThink();
|
||
|
}
|
||
|
|
||
|
void AgCTF::RoundBasedThink()
|
||
|
{
|
||
|
//We only update status once every second.
|
||
|
if (m_fNextCountdown > gpGlobals->time)
|
||
|
return;
|
||
|
m_fNextCountdown = gpGlobals->time + 1.0;
|
||
|
|
||
|
//Handle the status
|
||
|
if (Waiting == m_Status)
|
||
|
{
|
||
|
g_bPaused = true;
|
||
|
m_Status = Countdown;
|
||
|
m_fMatchStart = gpGlobals->time + 8.0;
|
||
|
m_fNextCountdown = gpGlobals->time + 3.0;
|
||
|
|
||
|
//Write waiting message
|
||
|
MESSAGE_BEGIN( MSG_ALL, gmsgCountdown);
|
||
|
WRITE_BYTE( 50 );
|
||
|
WRITE_BYTE( 1 );
|
||
|
WRITE_STRING( m_sWinner.c_str() );
|
||
|
WRITE_STRING( "" );
|
||
|
MESSAGE_END();
|
||
|
}
|
||
|
else if (Countdown == m_Status)
|
||
|
{
|
||
|
if (m_fMatchStart < gpGlobals->time)
|
||
|
{
|
||
|
//Clear out the map
|
||
|
AgResetMap();
|
||
|
|
||
|
//Reset CTF items
|
||
|
ResetCaptures();
|
||
|
|
||
|
m_Status = Spawning;
|
||
|
m_sWinner = "";
|
||
|
|
||
|
//Time to start playing.
|
||
|
for ( int i = 1; i <= gpGlobals->maxClients; i++ )
|
||
|
{
|
||
|
CBasePlayer* pPlayerLoop = AgPlayerByIndex(i);
|
||
|
if (pPlayerLoop && pPlayerLoop->m_bReady)
|
||
|
{
|
||
|
if (!pPlayerLoop->IsSpectator())
|
||
|
pPlayerLoop->RespawnMatch();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
m_Status = Playing;
|
||
|
|
||
|
//Stop countdown
|
||
|
MESSAGE_BEGIN( MSG_ALL, gmsgCountdown);
|
||
|
WRITE_BYTE( -1 );
|
||
|
WRITE_BYTE( 0 );
|
||
|
WRITE_STRING( "" );
|
||
|
WRITE_STRING( "" );
|
||
|
MESSAGE_END();
|
||
|
|
||
|
g_bPaused = false;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
//Write countdown message.
|
||
|
MESSAGE_BEGIN( MSG_ALL, gmsgCountdown);
|
||
|
WRITE_BYTE( (int)(m_fMatchStart - gpGlobals->time) );
|
||
|
WRITE_BYTE( 1 );
|
||
|
WRITE_STRING( "" );
|
||
|
WRITE_STRING( "" );
|
||
|
MESSAGE_END();
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void AgCTF::RoundOver(const char* pszWinner)
|
||
|
{
|
||
|
m_sWinner = pszWinner;
|
||
|
m_Status = Waiting;
|
||
|
}
|
||
|
|
||
|
|
||
|
void AgCTF::ClientConnected(CBasePlayer* pPlayer)
|
||
|
{
|
||
|
ASSERT(NULL != pPlayer);
|
||
|
if (!pPlayer)
|
||
|
return;
|
||
|
ASSERT(NULL != pPlayer->pev);
|
||
|
if (!pPlayer->pev)
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
|
||
|
void AgCTF::ClientDisconnected(CBasePlayer* pPlayer)
|
||
|
{
|
||
|
ASSERT(NULL != pPlayer);
|
||
|
if (!pPlayer)
|
||
|
return;
|
||
|
ASSERT(NULL != pPlayer->pev);
|
||
|
if (!pPlayer->pev)
|
||
|
return;
|
||
|
|
||
|
PlayerDropFlag(pPlayer);
|
||
|
}
|
||
|
|
||
|
void AgCTF::PlayerKilled(CBasePlayer* pPlayer,entvars_t *pKiller)
|
||
|
{
|
||
|
ASSERT(NULL != pPlayer);
|
||
|
if (!pPlayer)
|
||
|
return;
|
||
|
ASSERT(NULL != pPlayer->pev);
|
||
|
if (!pPlayer->pev)
|
||
|
return;
|
||
|
|
||
|
CBaseEntity* pKillerBE = CBaseEntity::Instance(pKiller);
|
||
|
if (pKillerBE && CLASS_PLAYER == pKillerBE->Classify())
|
||
|
{
|
||
|
CBasePlayer* pKillerPlayer = ((CBasePlayer*)pKillerBE);
|
||
|
AddPointsForKill(pKillerPlayer,pPlayer);
|
||
|
}
|
||
|
|
||
|
bool bReturnDirectly = (0 == strcmp(STRING(pKiller->classname),"trigger_hurt"));
|
||
|
|
||
|
if (bReturnDirectly)
|
||
|
{
|
||
|
if (pPlayer->m_bFlagTeam1)
|
||
|
{
|
||
|
CBaseEntity* pEntity = NULL;
|
||
|
pEntity = NULL;
|
||
|
while ((pEntity = UTIL_FindEntityByClassname( pEntity, "carried_flag_team1" )) != NULL)
|
||
|
UTIL_Remove(pEntity);
|
||
|
pPlayer->m_bFlagTeam1 = false;
|
||
|
AgCTFFlag::ResetFlag(CTF_TEAM1_NAME);
|
||
|
|
||
|
char szText[201];
|
||
|
sprintf(szText, "%s flag returned!", CTF_TEAM1_NAME);
|
||
|
AgConsole(szText);
|
||
|
UTIL_ClientPrintAll( HUD_PRINTCENTER, szText );
|
||
|
|
||
|
MESSAGE_BEGIN( MSG_ALL, gmsgCTFSound );
|
||
|
WRITE_BYTE( BlueFlagReturned );
|
||
|
MESSAGE_END();
|
||
|
}
|
||
|
else if (pPlayer->m_bFlagTeam2)
|
||
|
{
|
||
|
CBaseEntity* pEntity = NULL;
|
||
|
pEntity = NULL;
|
||
|
while ((pEntity = UTIL_FindEntityByClassname( pEntity, "carried_flag_team2" )) != NULL)
|
||
|
UTIL_Remove(pEntity);
|
||
|
pPlayer->m_bFlagTeam2 = false;
|
||
|
AgCTFFlag::ResetFlag(CTF_TEAM2_NAME);
|
||
|
|
||
|
char szText[201];
|
||
|
sprintf(szText, "%s flag returned!", CTF_TEAM2_NAME);
|
||
|
AgConsole(szText);
|
||
|
UTIL_ClientPrintAll( HUD_PRINTCENTER, szText );
|
||
|
|
||
|
MESSAGE_BEGIN( MSG_ALL, gmsgCTFSound );
|
||
|
WRITE_BYTE( RedFlagReturned );
|
||
|
MESSAGE_END();
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
PlayerDropFlag(pPlayer);
|
||
|
}
|
||
|
|
||
|
void AgCTF::AddPointsForKill(CBasePlayer *pAttacker, CBasePlayer *pKilled)
|
||
|
{
|
||
|
if ( pAttacker != pKilled && g_pGameRules->PlayerRelationship( pAttacker, pKilled ) == GR_TEAMMATE )
|
||
|
return; //Killed his team m8.
|
||
|
|
||
|
if (FStrEq(CTF_TEAM1_NAME, pKilled->m_szTeamName) && pKilled->m_bFlagTeam2
|
||
|
||FStrEq(CTF_TEAM2_NAME, pKilled->m_szTeamName) && pKilled->m_bFlagTeam1)
|
||
|
{
|
||
|
//He killed the flag carrier.
|
||
|
pAttacker->AddPoints(ag_ctf_carrierkillpoints.value, TRUE);
|
||
|
}
|
||
|
|
||
|
//Check if he is 192 units within his own flag (defending)
|
||
|
edict_t* pFind = NULL;
|
||
|
if (FStrEq(CTF_TEAM1_NAME, pAttacker->m_szTeamName))
|
||
|
pFind = FIND_ENTITY_BY_CLASSNAME(NULL,"item_flag_team1");
|
||
|
else if (FStrEq(CTF_TEAM2_NAME, pAttacker->m_szTeamName))
|
||
|
pFind = FIND_ENTITY_BY_CLASSNAME( NULL, "item_flag_team2" );
|
||
|
if (pFind)
|
||
|
{
|
||
|
Vector vtFlag = pFind->v.origin;
|
||
|
Vector vtPlayer = pKilled->pev->origin;
|
||
|
float fDistance = (vtFlag - vtPlayer).Length();
|
||
|
if (fDistance < 192)
|
||
|
//Add points for defending.
|
||
|
pAttacker->AddPoints(ag_ctf_defendpoints.value, TRUE);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
void AgCTF::PlayerDropFlag(CBasePlayer* pPlayer, bool bPlayerDrop)
|
||
|
{
|
||
|
ASSERT(NULL != pPlayer);
|
||
|
if (!pPlayer)
|
||
|
return;
|
||
|
ASSERT(NULL != pPlayer->pev);
|
||
|
if (!pPlayer->pev)
|
||
|
return;
|
||
|
|
||
|
//When carrying a flag, drop it!
|
||
|
if (pPlayer->m_bFlagTeam1 || pPlayer->m_bFlagTeam2)
|
||
|
{
|
||
|
char szText [201];
|
||
|
|
||
|
CBaseEntity *pEnt = NULL;
|
||
|
|
||
|
if (bPlayerDrop)
|
||
|
UTIL_MakeVectors ( pPlayer->pev->angles );
|
||
|
|
||
|
if (pPlayer->m_bFlagTeam1)
|
||
|
{
|
||
|
pEnt = CBaseEntity::Create( "item_flag_team1", bPlayerDrop? (pPlayer->pev->origin + gpGlobals->v_forward * 10) : pPlayer->pev->origin, pPlayer->pev->angles, pPlayer->edict() );
|
||
|
sprintf(szText, "%s lost the %s flag!", STRING(pPlayer->pev->netname), CTF_TEAM1_NAME);
|
||
|
AgConsole(szText);
|
||
|
UTIL_ClientPrintAll( HUD_PRINTCENTER, szText );
|
||
|
g_bTeam1FlagLost = true;
|
||
|
}
|
||
|
else if (pPlayer->m_bFlagTeam2)
|
||
|
{
|
||
|
pEnt = CBaseEntity::Create( "item_flag_team2", bPlayerDrop? (pPlayer->pev->origin + gpGlobals->v_forward * 10) : pPlayer->pev->origin, pPlayer->pev->angles, pPlayer->edict() );
|
||
|
sprintf(szText, "%s lost the %s flag!", STRING(pPlayer->pev->netname), CTF_TEAM2_NAME);
|
||
|
AgConsole(szText);
|
||
|
UTIL_ClientPrintAll( HUD_PRINTCENTER, szText );
|
||
|
g_bTeam2FlagLost = true;
|
||
|
}
|
||
|
|
||
|
if (bPlayerDrop)
|
||
|
{
|
||
|
pEnt->pev->velocity = gpGlobals->v_forward * 300 + gpGlobals->v_forward * 100;
|
||
|
pEnt->pev->angles.z = 0;
|
||
|
}
|
||
|
else
|
||
|
pEnt->pev->velocity = pPlayer->pev->velocity * 1.2;
|
||
|
pEnt->pev->angles.x = 0;
|
||
|
|
||
|
AgCTFFlag *pFlag = (AgCTFFlag *)pEnt;
|
||
|
|
||
|
if (bPlayerDrop)
|
||
|
pFlag->m_fNextTouch = gpGlobals->time + 0.5; //Gotta give the flag a bit of time to fly away from player before it can be picked up again.
|
||
|
pFlag->m_bDropped = true;
|
||
|
|
||
|
pFlag->m_fNextReset = gpGlobals->time + ag_ctf_flag_resettime.value;
|
||
|
|
||
|
pPlayer->m_bFlagTeam1 = false;
|
||
|
pPlayer->m_bFlagTeam2 = false;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
extern int gmsgItemPickup;
|
||
|
|
||
|
enum Flag_Animations
|
||
|
{
|
||
|
ON_GROUND = 0,
|
||
|
NOT_CARRIED,
|
||
|
CARRIED,
|
||
|
WAVE_IDLE,
|
||
|
FLAG_POSITION
|
||
|
};
|
||
|
|
||
|
void AgCTFFlag::Spawn ( void )
|
||
|
{
|
||
|
m_fNextTouch = 0;
|
||
|
|
||
|
Precache( );
|
||
|
SET_MODEL(ENT(pev), "models/flag.mdl");
|
||
|
|
||
|
pev->movetype = MOVETYPE_TOSS;
|
||
|
pev->solid = SOLID_TRIGGER;
|
||
|
UTIL_SetOrigin( pev, pev->origin );
|
||
|
UTIL_SetSize(pev, Vector(-16, -16, 0), Vector(16, 16, 16));
|
||
|
|
||
|
SetThink( &AgCTFFlag::Think );
|
||
|
SetTouch( &AgCTFFlag::FlagTouch );
|
||
|
|
||
|
pev->nextthink = gpGlobals->time + 0.1;
|
||
|
|
||
|
if (FStrEq(CTF_TEAM1_NAME, m_szTeamName))
|
||
|
pev->skin = 1;
|
||
|
else if (FStrEq(CTF_TEAM2_NAME, m_szTeamName))
|
||
|
pev->skin = 2;
|
||
|
|
||
|
m_bDropped = false;
|
||
|
|
||
|
pev->sequence = NOT_CARRIED;
|
||
|
pev->framerate = 1.0;
|
||
|
|
||
|
if (FStrEq(CTF_TEAM1_NAME, m_szTeamName))
|
||
|
{
|
||
|
pev->rendercolor.x = 0;
|
||
|
pev->rendercolor.y = 0;
|
||
|
pev->rendercolor.z = 128;
|
||
|
}
|
||
|
else if (FStrEq(CTF_TEAM2_NAME, m_szTeamName))
|
||
|
{
|
||
|
pev->rendercolor.x = 128;
|
||
|
pev->rendercolor.y = 0;
|
||
|
pev->rendercolor.z = 0;
|
||
|
}
|
||
|
pev->renderamt = 50;
|
||
|
pev->renderfx = kRenderFxGlowShell;
|
||
|
}
|
||
|
|
||
|
void AgCTFFlag::Precache( void )
|
||
|
{
|
||
|
PRECACHE_MODEL ("models/flag.mdl");
|
||
|
}
|
||
|
|
||
|
void AgCTFFlag::Capture(CBasePlayer *pPlayer, const char *m_szTeamName)
|
||
|
{
|
||
|
char szText[201];
|
||
|
|
||
|
sprintf(szText, "%s captured the %s flag!", STRING(pPlayer->pev->netname), m_szTeamName);
|
||
|
AgConsole(szText);
|
||
|
UTIL_ClientPrintAll( HUD_PRINTCENTER, szText );
|
||
|
|
||
|
//Give the player the points
|
||
|
pPlayer->AddPoints(ag_ctf_capturepoints.value, TRUE);
|
||
|
pPlayer->AddPointsToTeam(ag_ctf_teamcapturepoints.value, TRUE);
|
||
|
|
||
|
//And give the team a capture
|
||
|
if (FStrEq(CTF_TEAM1_NAME, m_szTeamName))
|
||
|
{
|
||
|
MESSAGE_BEGIN( MSG_ALL, gmsgCTFSound );
|
||
|
WRITE_BYTE( RedScores );
|
||
|
MESSAGE_END();
|
||
|
|
||
|
s_iTeam2Captures++;
|
||
|
UTIL_LogPrintf("Team \"%s\" triggered \"Capture\" (%s \"%d\") (%s \"%d\")\n",CTF_TEAM2_NAME,CTF_TEAM1_NAME,s_iTeam1Captures,CTF_TEAM2_NAME,s_iTeam2Captures);
|
||
|
|
||
|
if (ag_ctf_roundbased.value)
|
||
|
g_pGameRules->m_CTF.RoundOver(CTF_TEAM2_NAME);
|
||
|
}
|
||
|
else if (FStrEq(CTF_TEAM2_NAME, m_szTeamName))
|
||
|
{
|
||
|
MESSAGE_BEGIN( MSG_ALL, gmsgCTFSound );
|
||
|
WRITE_BYTE( BlueScores );
|
||
|
MESSAGE_END();
|
||
|
|
||
|
s_iTeam1Captures++;
|
||
|
UTIL_LogPrintf("Team \"%s\" triggered \"Capture\" (%s \"%d\") (%s \"%d\")\n",CTF_TEAM1_NAME,CTF_TEAM1_NAME,s_iTeam1Captures,CTF_TEAM2_NAME,s_iTeam2Captures);
|
||
|
|
||
|
if (ag_ctf_roundbased.value)
|
||
|
g_pGameRules->m_CTF.RoundOver(CTF_TEAM1_NAME);
|
||
|
}
|
||
|
|
||
|
ResetFlag( m_szTeamName );
|
||
|
}
|
||
|
|
||
|
void AgCTFFlag::ResetFlag()
|
||
|
{
|
||
|
AgCTFFlag::ResetFlag(m_szTeamName);
|
||
|
|
||
|
char szText[201];
|
||
|
sprintf(szText, "%s flag returned!", m_szTeamName);
|
||
|
AgConsole(szText);
|
||
|
UTIL_ClientPrintAll( HUD_PRINTCENTER, szText );
|
||
|
|
||
|
if (FStrEq(CTF_TEAM1_NAME, m_szTeamName))
|
||
|
{
|
||
|
MESSAGE_BEGIN( MSG_ALL, gmsgCTFSound );
|
||
|
WRITE_BYTE( BlueFlagReturned );
|
||
|
MESSAGE_END();
|
||
|
}
|
||
|
else if (FStrEq(CTF_TEAM2_NAME, m_szTeamName))
|
||
|
{
|
||
|
MESSAGE_BEGIN( MSG_ALL, gmsgCTFSound );
|
||
|
WRITE_BYTE( RedFlagReturned );
|
||
|
MESSAGE_END();
|
||
|
}
|
||
|
|
||
|
if (m_bDropped)
|
||
|
UTIL_Remove( this );
|
||
|
}
|
||
|
|
||
|
void AgCTFFlag::ResetFlag(const char *szTeamName)
|
||
|
{
|
||
|
edict_t *pFind;
|
||
|
|
||
|
if (FStrEq(CTF_TEAM1_NAME, szTeamName))
|
||
|
{
|
||
|
pFind = FIND_ENTITY_BY_CLASSNAME( NULL, "item_flag_team1" );
|
||
|
g_bTeam1FlagStolen = false;
|
||
|
g_bTeam1FlagLost = false;
|
||
|
}
|
||
|
else if (FStrEq(CTF_TEAM2_NAME, szTeamName))
|
||
|
{
|
||
|
pFind = FIND_ENTITY_BY_CLASSNAME( NULL, "item_flag_team2" );
|
||
|
g_bTeam2FlagStolen = false;
|
||
|
g_bTeam2FlagLost = false;
|
||
|
}
|
||
|
else
|
||
|
return;
|
||
|
|
||
|
while ( !FNullEnt( pFind ) )
|
||
|
{
|
||
|
CBaseEntity *pEnt = CBaseEntity::Instance( pFind );
|
||
|
AgCTFFlag *pFlag = (AgCTFFlag *)pEnt;
|
||
|
|
||
|
pFlag->Materialize( );
|
||
|
|
||
|
if (FStrEq(CTF_TEAM1_NAME, szTeamName))
|
||
|
pFind = FIND_ENTITY_BY_CLASSNAME( pFind, "item_flag_team1" );
|
||
|
else if (FStrEq(CTF_TEAM2_NAME, szTeamName))
|
||
|
pFind = FIND_ENTITY_BY_CLASSNAME( pFind, "item_flag_team2" );
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void AgCTFFlag::FlagTouch( CBaseEntity *pOther )
|
||
|
{
|
||
|
if (m_fNextTouch > gpGlobals->time)
|
||
|
return;
|
||
|
|
||
|
// if it's not a player, ignore
|
||
|
if ( !pOther->IsPlayer() )
|
||
|
return;
|
||
|
|
||
|
if ( !pOther->IsAlive() )
|
||
|
return;
|
||
|
|
||
|
|
||
|
CBasePlayer *pPlayer = (CBasePlayer *)pOther;
|
||
|
|
||
|
if (MyTouch( pPlayer ))
|
||
|
{
|
||
|
SUB_UseTargets( pOther, USE_TOGGLE, 0 );
|
||
|
SetTouch( NULL );
|
||
|
SetThink( NULL );
|
||
|
|
||
|
//if it's a dropped flag, remove. Else make it invisible
|
||
|
if (m_bDropped)
|
||
|
UTIL_Remove( this );
|
||
|
else
|
||
|
pev->effects |= EF_NODRAW;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void AgCTFFlag::Materialize( void )
|
||
|
{
|
||
|
if ( pev->effects & EF_NODRAW )
|
||
|
{
|
||
|
// changing from invisible state to visible.
|
||
|
EMIT_SOUND_DYN( ENT(pev), CHAN_WEAPON, "items/suitchargeok1.wav", 1, ATTN_NORM, 0, 150 );
|
||
|
pev->effects &= ~EF_NODRAW;
|
||
|
pev->effects |= EF_MUZZLEFLASH;
|
||
|
}
|
||
|
|
||
|
SetTouch( &AgCTFFlag::FlagTouch );
|
||
|
SetThink( &AgCTFFlag::Think );
|
||
|
}
|
||
|
|
||
|
BOOL AgCTFFlag::MyTouch( CBasePlayer *pPlayer )
|
||
|
{
|
||
|
char szText[201];
|
||
|
|
||
|
// Can only carry one flag and can not pickup own flag
|
||
|
if (FStrEq(CTF_TEAM1_NAME, m_szTeamName))
|
||
|
{
|
||
|
//if client has other teams flag and it isn't a dropped flag, then there is a capture!
|
||
|
if ( pPlayer->m_bFlagTeam2 && !m_bDropped)
|
||
|
{
|
||
|
pPlayer->m_bFlagTeam2 = false;
|
||
|
|
||
|
UTIL_SendDirectorMessage( pPlayer->edict(), this->edict(), 10 | DRC_FLAG_DRAMATIC);
|
||
|
Capture(pPlayer, CTF_TEAM2_NAME);
|
||
|
return FALSE;
|
||
|
}
|
||
|
else if ( pPlayer->m_bFlagTeam1 )
|
||
|
{
|
||
|
return FALSE;
|
||
|
}
|
||
|
else if (FStrEq(pPlayer->m_szTeamName, CTF_TEAM1_NAME))
|
||
|
{
|
||
|
//if dropped, return flag
|
||
|
if (m_bDropped)
|
||
|
{
|
||
|
ResetFlag(CTF_TEAM1_NAME);
|
||
|
sprintf(szText, "%s returned the %s flag!", STRING(pPlayer->pev->netname), m_szTeamName);
|
||
|
AgConsole(szText);
|
||
|
UTIL_ClientPrintAll( HUD_PRINTCENTER, szText );
|
||
|
UTIL_Remove( this );
|
||
|
|
||
|
pPlayer->AddPoints(ag_ctf_returnpoints.value, TRUE);
|
||
|
|
||
|
MESSAGE_BEGIN( MSG_ALL, gmsgCTFSound );
|
||
|
WRITE_BYTE( BlueFlagReturned );
|
||
|
MESSAGE_END();
|
||
|
}
|
||
|
//but don't pick it up!
|
||
|
return FALSE;
|
||
|
}
|
||
|
}
|
||
|
else if (FStrEq(CTF_TEAM2_NAME, m_szTeamName))
|
||
|
{
|
||
|
//if client has other teams flag and it isn't a dropped flag, then there is a capture!
|
||
|
if ( pPlayer->m_bFlagTeam1 && !m_bDropped)
|
||
|
{
|
||
|
pPlayer->m_bFlagTeam1 = false;
|
||
|
|
||
|
UTIL_SendDirectorMessage( pPlayer->edict(), this->edict(), 10 | DRC_FLAG_DRAMATIC);
|
||
|
Capture(pPlayer, CTF_TEAM1_NAME);
|
||
|
|
||
|
return FALSE;
|
||
|
}
|
||
|
else if ( pPlayer->m_bFlagTeam2 )
|
||
|
{
|
||
|
return FALSE;
|
||
|
}
|
||
|
else if (FStrEq(pPlayer->m_szTeamName, CTF_TEAM2_NAME))
|
||
|
{
|
||
|
//if dropped, return flag
|
||
|
if (m_bDropped)
|
||
|
{
|
||
|
ResetFlag(CTF_TEAM2_NAME);
|
||
|
sprintf(szText, "%s returned the %s flag!", STRING(pPlayer->pev->netname), m_szTeamName);
|
||
|
AgConsole(szText);
|
||
|
UTIL_ClientPrintAll( HUD_PRINTCENTER, szText );
|
||
|
UTIL_Remove( this );
|
||
|
|
||
|
MESSAGE_BEGIN( MSG_ALL, gmsgCTFSound );
|
||
|
WRITE_BYTE( RedFlagReturned );
|
||
|
MESSAGE_END();
|
||
|
|
||
|
pPlayer->AddPoints(ag_ctf_returnpoints.value, TRUE);
|
||
|
}
|
||
|
//but don't pick it up!
|
||
|
return FALSE;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if ( ( pPlayer->pev->weapons & (1<<WEAPON_SUIT) ) )
|
||
|
{
|
||
|
if (FStrEq(CTF_TEAM1_NAME, m_szTeamName))
|
||
|
{
|
||
|
pPlayer->m_bFlagTeam1 = true;
|
||
|
// player is now carrying the flag of team1, so give him the flag
|
||
|
|
||
|
CBaseEntity *pEnt = CBaseEntity::Create( "carried_flag_team1", pev->origin, pev->angles, pPlayer->edict() );
|
||
|
AgCTFPlayerFlag *pCarriedFlag = (AgCTFPlayerFlag *)pEnt;
|
||
|
pCarriedFlag->m_pOwner = pPlayer;
|
||
|
s_iPlayerFlag1 = pPlayer->entindex();
|
||
|
|
||
|
/*
|
||
|
//Glow blue
|
||
|
pCarriedFlag->pev->renderfx = kRenderFxGlowShell;
|
||
|
pCarriedFlag->pev->rendercolor = Vector( 0, 0, 255 ); // RGB
|
||
|
pCarriedFlag->pev->renderamt = 100; // Shell size
|
||
|
*/
|
||
|
}
|
||
|
else if (FStrEq(CTF_TEAM2_NAME, m_szTeamName))
|
||
|
{
|
||
|
pPlayer->m_bFlagTeam2 = true;
|
||
|
// player is now carrying the flag of team2, so give him the flag
|
||
|
CBaseEntity *pEnt = CBaseEntity::Create( "carried_flag_team2", pev->origin, pev->angles, pPlayer->edict() );
|
||
|
AgCTFPlayerFlag *pCarriedFlag = (AgCTFPlayerFlag *)pEnt;
|
||
|
pCarriedFlag->m_pOwner = pPlayer;
|
||
|
s_iPlayerFlag2 = pPlayer->entindex();
|
||
|
/*
|
||
|
//Glow red
|
||
|
pCarriedFlag->pev->renderfx = kRenderFxGlowShell;
|
||
|
pCarriedFlag->pev->rendercolor = Vector( 255, 0, 0 ); // RGB
|
||
|
pCarriedFlag->pev->renderamt = 100; // Shell size
|
||
|
*/
|
||
|
}
|
||
|
MESSAGE_BEGIN( MSG_ONE, gmsgItemPickup, NULL, pPlayer->pev );
|
||
|
WRITE_STRING( STRING(pev->classname) );
|
||
|
MESSAGE_END();
|
||
|
|
||
|
//Let all players hear and read that the flag is gone
|
||
|
char szText[201];
|
||
|
|
||
|
if (FStrEq(CTF_TEAM1_NAME, m_szTeamName))
|
||
|
{
|
||
|
if (!g_bTeam1FlagLost)
|
||
|
pPlayer->AddPoints(ag_ctf_stealpoints.value, TRUE);
|
||
|
sprintf(szText, "%s got the %s flag!\n", STRING(pPlayer->pev->netname), CTF_TEAM1_NAME);
|
||
|
}
|
||
|
else if (FStrEq(CTF_TEAM2_NAME, m_szTeamName))
|
||
|
{
|
||
|
if (!g_bTeam2FlagLost)
|
||
|
pPlayer->AddPoints(ag_ctf_stealpoints.value, TRUE);
|
||
|
sprintf(szText, "%s got the %s flag!\n", STRING(pPlayer->pev->netname), CTF_TEAM2_NAME);
|
||
|
}
|
||
|
|
||
|
AgConsole(szText);
|
||
|
UTIL_ClientPrintAll( HUD_PRINTCENTER, szText );
|
||
|
|
||
|
for ( int i = 1; i <= gpGlobals->maxClients; i++ )
|
||
|
{
|
||
|
CBasePlayer* pPlayerLoop = AgPlayerByIndex(i);
|
||
|
if (pPlayerLoop)
|
||
|
{
|
||
|
if (pPlayer != pPlayerLoop)
|
||
|
{
|
||
|
if (pPlayerLoop->IsSpectator() || pPlayerLoop->IsProxy())
|
||
|
{
|
||
|
if (!m_bDropped)
|
||
|
{
|
||
|
if (FStrEq(m_szTeamName, CTF_TEAM1_NAME))
|
||
|
{
|
||
|
MESSAGE_BEGIN( MSG_ONE, gmsgCTFSound, NULL, pPlayerLoop->pev );
|
||
|
WRITE_BYTE(BlueFlagStolen);
|
||
|
MESSAGE_END();
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
MESSAGE_BEGIN( MSG_ONE, gmsgCTFSound, NULL, pPlayerLoop->pev );
|
||
|
WRITE_BYTE(RedFlagStolen);
|
||
|
MESSAGE_END();
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
else if (FStrEq(pPlayerLoop->m_szTeamName, m_szTeamName))
|
||
|
{
|
||
|
MESSAGE_BEGIN( MSG_ONE, gmsgCTFSound, NULL, pPlayerLoop->pev );
|
||
|
WRITE_BYTE(EnemyHaveFlag);
|
||
|
MESSAGE_END();
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
MESSAGE_BEGIN( MSG_ONE, gmsgCTFSound, NULL, pPlayerLoop->pev );
|
||
|
WRITE_BYTE(TeamHaveFlag);
|
||
|
MESSAGE_END();
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
MESSAGE_BEGIN( MSG_ONE, gmsgCTFSound, NULL, pPlayerLoop->pev );
|
||
|
WRITE_BYTE(YouHaveFlag);
|
||
|
MESSAGE_END();
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
int iPowerUp = 0;
|
||
|
|
||
|
if (FStrEq(CTF_TEAM1_NAME, m_szTeamName))
|
||
|
{
|
||
|
g_bTeam1FlagStolen = true;
|
||
|
g_bTeam1FlagLost = false;
|
||
|
|
||
|
|
||
|
//Glow red
|
||
|
pPlayer->pev->renderfx = kRenderFxGlowShell;
|
||
|
pPlayer->pev->rendercolor = Vector( 128, 0, 0 ); // RGB
|
||
|
pPlayer->pev->renderamt = 50; // Shell size
|
||
|
|
||
|
iPowerUp = 2;
|
||
|
}
|
||
|
else if (FStrEq(CTF_TEAM2_NAME, m_szTeamName))
|
||
|
{
|
||
|
g_bTeam2FlagStolen = true;
|
||
|
g_bTeam2FlagLost = false;
|
||
|
|
||
|
//Glow blue
|
||
|
pPlayer->pev->renderfx = kRenderFxGlowShell;
|
||
|
pPlayer->pev->rendercolor = Vector( 0, 0, 128 ); // RGB
|
||
|
pPlayer->pev->renderamt = 50; // Shell size
|
||
|
|
||
|
iPowerUp = 2;
|
||
|
}
|
||
|
|
||
|
UTIL_SendDirectorMessage( pPlayer->edict(), this->edict(), 8 | DRC_FLAG_DRAMATIC);
|
||
|
|
||
|
return TRUE;
|
||
|
}
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
void AgCTFFlag::Think( void )
|
||
|
{
|
||
|
if (m_bDropped && m_fNextReset <= gpGlobals->time)
|
||
|
{
|
||
|
//Let all players know that the flag has been returned
|
||
|
char szText[201];
|
||
|
|
||
|
if (FStrEq(CTF_TEAM1_NAME, m_szTeamName))
|
||
|
{
|
||
|
sprintf(szText, "The %s flag has returned.\n", CTF_TEAM1_NAME);
|
||
|
ResetFlag(CTF_TEAM1_NAME);
|
||
|
|
||
|
MESSAGE_BEGIN( MSG_ALL, gmsgCTFSound );
|
||
|
WRITE_BYTE( BlueFlagReturned );
|
||
|
MESSAGE_END();
|
||
|
}
|
||
|
else if (FStrEq(CTF_TEAM2_NAME, m_szTeamName))
|
||
|
{
|
||
|
sprintf(szText, "The %s flag has returned.\n", CTF_TEAM2_NAME);
|
||
|
ResetFlag(CTF_TEAM2_NAME);
|
||
|
|
||
|
MESSAGE_BEGIN( MSG_ALL, gmsgCTFSound );
|
||
|
WRITE_BYTE( RedFlagReturned );
|
||
|
MESSAGE_END();
|
||
|
}
|
||
|
|
||
|
AgConsole(szText);
|
||
|
UTIL_ClientPrintAll( HUD_PRINTCENTER, szText );
|
||
|
UTIL_Remove( this );
|
||
|
return;
|
||
|
}
|
||
|
pev->frame += pev->framerate;
|
||
|
if (pev->frame < 0.0 || pev->frame >= 256.0)
|
||
|
{
|
||
|
pev->frame -= (int)(pev->frame / 256.0) * 256.0;
|
||
|
}
|
||
|
pev->nextthink = gpGlobals->time + 0.1;
|
||
|
}
|
||
|
|
||
|
class AgCTFFlagTeam1 : public AgCTFFlag
|
||
|
{
|
||
|
void Spawn( void )
|
||
|
{
|
||
|
pev->classname = MAKE_STRING("item_flag_team1"); //CCTF map compatibility hack
|
||
|
strcpy( m_szTeamName, CTF_TEAM1_NAME );
|
||
|
|
||
|
AgCTFFlag::Spawn( );
|
||
|
}
|
||
|
};
|
||
|
|
||
|
#ifndef AG_NO_CLIENT_DLL
|
||
|
LINK_ENTITY_TO_CLASS( item_flag_team1, AgCTFFlagTeam1 );
|
||
|
LINK_ENTITY_TO_CLASS( ctf_blueflag, AgCTFFlagTeam1 ); //CCTF map compatibility hack
|
||
|
#endif
|
||
|
|
||
|
class AgCTFFlagTeam2 : public AgCTFFlag
|
||
|
{
|
||
|
void Spawn( void )
|
||
|
{
|
||
|
pev->classname = MAKE_STRING("item_flag_team2"); //CCTF map compatibility hack
|
||
|
strcpy( m_szTeamName, CTF_TEAM2_NAME );
|
||
|
|
||
|
AgCTFFlag::Spawn( );
|
||
|
}
|
||
|
};
|
||
|
|
||
|
#ifndef AG_NO_CLIENT_DLL
|
||
|
LINK_ENTITY_TO_CLASS( item_flag_team2, AgCTFFlagTeam2 );
|
||
|
LINK_ENTITY_TO_CLASS( ctf_redflag, AgCTFFlagTeam2 ); //CCTF map compatibility hack
|
||
|
#endif
|
||
|
|
||
|
class AgCTFFlagTeamOP4 : public AgCTFFlag
|
||
|
{
|
||
|
int m_iTeam;
|
||
|
void KeyValue( KeyValueData *pkvd )
|
||
|
{
|
||
|
if (FStrEq(pkvd->szKeyName, "goal_no"))
|
||
|
{
|
||
|
m_iTeam = atoi(pkvd->szValue);
|
||
|
pkvd->fHandled = TRUE;
|
||
|
}
|
||
|
else if (FStrEq(pkvd->szKeyName, "ctf_flag")) //HLE map compatibility hack
|
||
|
{
|
||
|
if (1 == atoi(pkvd->szValue))
|
||
|
m_iTeam = 2;
|
||
|
else if (2 == atoi(pkvd->szValue))
|
||
|
m_iTeam = 1;
|
||
|
|
||
|
pkvd->fHandled = TRUE;
|
||
|
}
|
||
|
else
|
||
|
AgCTFFlag::KeyValue( pkvd );
|
||
|
}
|
||
|
|
||
|
void Spawn( void )
|
||
|
{
|
||
|
if (1 == m_iTeam)
|
||
|
{
|
||
|
pev->classname = MAKE_STRING("item_flag_team1");
|
||
|
strcpy( m_szTeamName, CTF_TEAM1_NAME );
|
||
|
}
|
||
|
else if (2 == m_iTeam)
|
||
|
{
|
||
|
pev->classname = MAKE_STRING("item_flag_team2");
|
||
|
strcpy( m_szTeamName, CTF_TEAM2_NAME );
|
||
|
}
|
||
|
|
||
|
AgCTFFlag::Spawn( );
|
||
|
}
|
||
|
};
|
||
|
#ifndef AG_NO_CLIENT_DLL
|
||
|
LINK_ENTITY_TO_CLASS( item_ctfflag, AgCTFFlagTeamOP4 ); //OP4CTF map compatibility hack.
|
||
|
LINK_ENTITY_TO_CLASS( info_flag_ctf, AgCTFFlagTeamOP4 ); //HLE map compatibility hack
|
||
|
#endif
|
||
|
|
||
|
|
||
|
|
||
|
//=========================================================
|
||
|
// Carried Flag
|
||
|
//
|
||
|
// This is a complete new entity because it doesn't behave
|
||
|
// as a flag. It just sits on the back of the player and
|
||
|
// removes itself at the right time. (When player is gone
|
||
|
// or death or lost the flag.)
|
||
|
//=========================================================
|
||
|
void AgCTFPlayerFlag ::Spawn( )
|
||
|
{
|
||
|
Precache( );
|
||
|
|
||
|
SET_MODEL(ENT(pev), "models/flag.mdl");
|
||
|
UTIL_SetOrigin( pev, pev->origin );
|
||
|
|
||
|
pev->movetype = MOVETYPE_NONE;
|
||
|
pev->solid = SOLID_NOT;
|
||
|
|
||
|
//HACKHACKHACK: Overcome the attachment with no owner yet model "hop" by making it invisible
|
||
|
pev->effects |= EF_NODRAW;
|
||
|
|
||
|
pev->sequence = WAVE_IDLE;
|
||
|
pev->framerate = 1.0;
|
||
|
|
||
|
if (FStrEq(CTF_TEAM1_NAME, m_szTeamName))
|
||
|
pev->skin = 1;
|
||
|
else if (FStrEq(CTF_TEAM2_NAME, m_szTeamName))
|
||
|
pev->skin = 2;
|
||
|
|
||
|
SetThink( &AgCTFPlayerFlag::Think );
|
||
|
pev->nextthink = gpGlobals->time + 0.1;
|
||
|
}
|
||
|
|
||
|
void AgCTFPlayerFlag::UpdateOnRemove( void )
|
||
|
{
|
||
|
if (FStrEq(CTF_TEAM1_NAME, m_szTeamName))
|
||
|
s_iPlayerFlag1 = 0;
|
||
|
else if (FStrEq(CTF_TEAM2_NAME, m_szTeamName))
|
||
|
s_iPlayerFlag2 = 0;
|
||
|
}
|
||
|
|
||
|
|
||
|
void AgCTFPlayerFlag::Precache( )
|
||
|
{
|
||
|
PRECACHE_MODEL ("models/flag.mdl");
|
||
|
}
|
||
|
|
||
|
void AgCTFPlayerFlag::Think( )
|
||
|
{
|
||
|
//Make it visible
|
||
|
pev->effects &= ~EF_NODRAW;
|
||
|
|
||
|
//And let if follow
|
||
|
pev->aiment = ENT(m_pOwner->pev);
|
||
|
pev->movetype = MOVETYPE_FOLLOW;
|
||
|
|
||
|
//Remove if owner is death
|
||
|
if (!m_pOwner->IsAlive())
|
||
|
UTIL_Remove( this );
|
||
|
|
||
|
//If owner lost flag, remove
|
||
|
if ( !m_pOwner->m_bFlagTeam1 && !m_pOwner->m_bFlagTeam2)
|
||
|
{
|
||
|
UTIL_Remove( this );
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
//If owners speed is low, go in idle mode
|
||
|
if (m_pOwner->pev->velocity.Length() <= 75 && pev->sequence != WAVE_IDLE)
|
||
|
{
|
||
|
pev->sequence = WAVE_IDLE;
|
||
|
}
|
||
|
//Else let the flag go wild
|
||
|
else if (m_pOwner->pev->velocity.Length() >= 75 && pev->sequence != CARRIED)
|
||
|
{
|
||
|
pev->sequence = CARRIED;
|
||
|
}
|
||
|
pev->frame += pev->framerate;
|
||
|
if (pev->frame < 0.0 || pev->frame >= 256.0)
|
||
|
{
|
||
|
pev->frame -= (int)(pev->frame / 256.0) * 256.0;
|
||
|
}
|
||
|
pev->nextthink = gpGlobals->time + 0.1;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
class AgCTFPlayerFlagTeam1 : public AgCTFPlayerFlag
|
||
|
{
|
||
|
void Spawn( void )
|
||
|
{
|
||
|
strcpy( m_szTeamName, CTF_TEAM1_NAME );
|
||
|
|
||
|
AgCTFPlayerFlag::Spawn( );
|
||
|
}
|
||
|
};
|
||
|
|
||
|
#ifndef AG_NO_CLIENT_DLL
|
||
|
LINK_ENTITY_TO_CLASS( carried_flag_team1, AgCTFPlayerFlagTeam1 );
|
||
|
#endif
|
||
|
|
||
|
class AgCTFPlayerFlagTeam2 : public AgCTFPlayerFlag
|
||
|
{
|
||
|
void Spawn( void )
|
||
|
{
|
||
|
strcpy( m_szTeamName, CTF_TEAM2_NAME );
|
||
|
|
||
|
AgCTFPlayerFlag::Spawn( );
|
||
|
}
|
||
|
};
|
||
|
|
||
|
#ifndef AG_NO_CLIENT_DLL
|
||
|
LINK_ENTITY_TO_CLASS( carried_flag_team2, AgCTFPlayerFlagTeam2 );
|
||
|
#endif
|
||
|
|
||
|
class AgCTFDetect : public CBaseEntity
|
||
|
{
|
||
|
void Spawn( void )
|
||
|
{
|
||
|
UTIL_SetOrigin( pev, pev->origin );
|
||
|
pev->solid = SOLID_NOT;
|
||
|
pev->effects = EF_NODRAW;
|
||
|
|
||
|
AgString sGametype = CVAR_GET_STRING("sv_ag_gametype");
|
||
|
if (sGametype != "ctf")
|
||
|
CVAR_SET_STRING("sv_ag_gamemode","ctf");
|
||
|
}
|
||
|
void KeyValue( KeyValueData* pkvd)
|
||
|
{
|
||
|
pkvd->fHandled = FALSE;
|
||
|
}
|
||
|
};
|
||
|
#ifndef AG_NO_CLIENT_DLL
|
||
|
LINK_ENTITY_TO_CLASS( info_hmctfdetect, AgCTFDetect );
|
||
|
LINK_ENTITY_TO_CLASS( info_ctfdetect, AgCTFDetect ); //OP4 CTF detect
|
||
|
LINK_ENTITY_TO_CLASS( game_mode_ctf, AgCTFDetect ); //HLE CTF detect
|
||
|
#endif
|
||
|
|
||
|
/*
|
||
|
============
|
||
|
EntSelectCTFSpawnPoint
|
||
|
|
||
|
Returns the CTF entity to spawn at
|
||
|
|
||
|
USES AND SETS GLOBAL g_pLastSpawn
|
||
|
============
|
||
|
*/
|
||
|
extern CBaseEntity *g_pLastSpawn;
|
||
|
BOOL IsSpawnPointValid( CBaseEntity *pPlayer, CBaseEntity *pSpot);
|
||
|
inline int FNullEnt( CBaseEntity *ent ) { return (ent == NULL) || FNullEnt( ent->edict() ); }
|
||
|
|
||
|
|
||
|
edict_t *EntSelectCTFSpawnPoint( CBaseEntity *pPlayer )
|
||
|
{
|
||
|
CBaseEntity *pSpot;
|
||
|
edict_t *player;
|
||
|
|
||
|
player = pPlayer->edict();
|
||
|
CBasePlayer *cbPlayer = (CBasePlayer *)pPlayer; //we need a CBasePlayer
|
||
|
|
||
|
pSpot = g_pLastSpawn;
|
||
|
// Randomize the start spot
|
||
|
for ( int i = RANDOM_LONG(1,5); i > 0; i-- )
|
||
|
{
|
||
|
if (FStrEq(cbPlayer->m_szTeamName, CTF_TEAM1_NAME))
|
||
|
pSpot = UTIL_FindEntityByClassname( pSpot, "info_player_team1" );
|
||
|
else if (FStrEq(cbPlayer->m_szTeamName, CTF_TEAM2_NAME))
|
||
|
pSpot = UTIL_FindEntityByClassname( pSpot, "info_player_team2" );
|
||
|
else
|
||
|
pSpot = UTIL_FindEntityByClassname( pSpot, "info_player_deathmatch" );
|
||
|
}
|
||
|
if ( FNullEnt( pSpot ) ) // skip over the null point
|
||
|
{
|
||
|
if (FStrEq(cbPlayer->m_szTeamName, CTF_TEAM1_NAME))
|
||
|
pSpot = UTIL_FindEntityByClassname( pSpot, "info_player_team1" );
|
||
|
else if (FStrEq(cbPlayer->m_szTeamName, CTF_TEAM2_NAME))
|
||
|
pSpot = UTIL_FindEntityByClassname( pSpot, "info_player_team2" );
|
||
|
else
|
||
|
pSpot = UTIL_FindEntityByClassname( pSpot, "info_player_deathmatch" );
|
||
|
}
|
||
|
|
||
|
CBaseEntity *pFirstSpot = pSpot;
|
||
|
|
||
|
do
|
||
|
{
|
||
|
if ( pSpot )
|
||
|
{
|
||
|
// check if pSpot is valid
|
||
|
if ( IsSpawnPointValid( pPlayer, pSpot ) )
|
||
|
{
|
||
|
if ( pSpot->pev->origin == Vector( 0, 0, 0 ) )
|
||
|
{
|
||
|
if (FStrEq(cbPlayer->m_szTeamName, CTF_TEAM1_NAME))
|
||
|
pSpot = UTIL_FindEntityByClassname( pSpot, "info_player_team1" );
|
||
|
else if (FStrEq(cbPlayer->m_szTeamName, CTF_TEAM2_NAME))
|
||
|
pSpot = UTIL_FindEntityByClassname( pSpot, "info_player_team2" );
|
||
|
else
|
||
|
pSpot = UTIL_FindEntityByClassname( pSpot, "info_player_deathmatch" );
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
// valid pSpot, so it can be returned
|
||
|
goto ReturnSpot;
|
||
|
}
|
||
|
}
|
||
|
// increment pSpot
|
||
|
if (FStrEq(cbPlayer->m_szTeamName, CTF_TEAM1_NAME))
|
||
|
pSpot = UTIL_FindEntityByClassname( pSpot, "info_player_team1" );
|
||
|
else if (FStrEq(cbPlayer->m_szTeamName, CTF_TEAM2_NAME))
|
||
|
pSpot = UTIL_FindEntityByClassname( pSpot, "info_player_team2" );
|
||
|
else
|
||
|
pSpot = UTIL_FindEntityByClassname( pSpot, "info_player_deathmatch" );
|
||
|
} while ( pSpot != pFirstSpot ); // loop if we're not back to the start
|
||
|
|
||
|
// we haven't found a place to spawn yet, so kill any guy at the first spawn point and spawn there
|
||
|
if ( !FNullEnt( pSpot ) )
|
||
|
{
|
||
|
CBaseEntity *ent = NULL;
|
||
|
while ( (ent = UTIL_FindEntityInSphere( ent, pSpot->pev->origin, 128 )) != NULL )
|
||
|
{
|
||
|
// if ent is a client, kill em (unless they are ourselves)
|
||
|
if ( ent->IsPlayer() && !(ent->edict() == player) )
|
||
|
ent->TakeDamage( VARS(INDEXENT(0)), VARS(INDEXENT(0)), 300, DMG_GENERIC );
|
||
|
}
|
||
|
goto ReturnSpot;
|
||
|
}
|
||
|
|
||
|
ReturnSpot:
|
||
|
if ( FNullEnt( pSpot ) )
|
||
|
{
|
||
|
ALERT(at_error, "PutClientInServer: no info_player_team1,info_player_team2 on level");
|
||
|
ClientPrint(pPlayer->pev,HUD_PRINTCENTER, "This is not a valid CTF map!" );
|
||
|
pSpot = UTIL_FindEntityByClassname( pSpot, "info_player_deathmatch" );
|
||
|
if (FNullEnt( pSpot ))
|
||
|
return INDEXENT(0);
|
||
|
}
|
||
|
|
||
|
g_pLastSpawn = pSpot;
|
||
|
return pSpot->edict();
|
||
|
}
|
||
|
|
||
|
|
||
|
class AgCTFSpawn : public CPointEntity
|
||
|
{
|
||
|
int m_iTeam;
|
||
|
public:
|
||
|
void KeyValue( KeyValueData *pkvd );
|
||
|
BOOL IsTriggered( CBaseEntity *pEntity );
|
||
|
void Spawn( void );
|
||
|
|
||
|
private:
|
||
|
};
|
||
|
|
||
|
void AgCTFSpawn::KeyValue( KeyValueData *pkvd )
|
||
|
{
|
||
|
if (FStrEq(pkvd->szKeyName, "master"))
|
||
|
{
|
||
|
pev->netname = ALLOC_STRING(pkvd->szValue);
|
||
|
pkvd->fHandled = TRUE;
|
||
|
}
|
||
|
//OP4 map compatibility
|
||
|
else if (FStrEq(pkvd->szKeyName, "team_no"))
|
||
|
{
|
||
|
m_iTeam = atoi(pkvd->szValue);
|
||
|
pkvd->fHandled = TRUE;
|
||
|
}
|
||
|
else
|
||
|
CPointEntity::KeyValue( pkvd );
|
||
|
}
|
||
|
|
||
|
BOOL AgCTFSpawn::IsTriggered( CBaseEntity *pEntity )
|
||
|
{
|
||
|
BOOL master = UTIL_IsMasterTriggered( pev->netname, pEntity );
|
||
|
|
||
|
return master;
|
||
|
}
|
||
|
|
||
|
void AgCTFSpawn :: Spawn( void )
|
||
|
{
|
||
|
//CCTF map compatibility
|
||
|
if (FStrEq(STRING(pev->classname), "ctf_bluespawn"))
|
||
|
pev->classname = MAKE_STRING("info_player_team1");
|
||
|
else if (FStrEq(STRING(pev->classname), "ctf_redspawn"))
|
||
|
pev->classname = MAKE_STRING("info_player_team2");
|
||
|
//HLE map compatibility
|
||
|
else if (FStrEq(STRING(pev->classname), "info_player_ctf_blue"))
|
||
|
pev->classname = MAKE_STRING("info_player_team1");
|
||
|
else if (FStrEq(STRING(pev->classname), "info_player_ctf_red"))
|
||
|
pev->classname = MAKE_STRING("info_player_team2");
|
||
|
//OP4 map compatibility
|
||
|
else if (1 == m_iTeam)
|
||
|
pev->classname = MAKE_STRING("info_player_team1");
|
||
|
else if (2 == m_iTeam)
|
||
|
pev->classname = MAKE_STRING("info_player_team2");
|
||
|
pev->solid = SOLID_NOT;
|
||
|
|
||
|
|
||
|
}
|
||
|
|
||
|
#ifndef AG_NO_CLIENT_DLL
|
||
|
LINK_ENTITY_TO_CLASS(info_player_team1,AgCTFSpawn);
|
||
|
LINK_ENTITY_TO_CLASS(ctf_bluespawn,AgCTFSpawn); //CCTF map compatibility
|
||
|
LINK_ENTITY_TO_CLASS(info_player_team2,AgCTFSpawn);
|
||
|
LINK_ENTITY_TO_CLASS(ctf_redspawn,AgCTFSpawn); //CCTF map compatibility
|
||
|
LINK_ENTITY_TO_CLASS(info_ctfspawn,AgCTFSpawn); //OP4 CTF map compatibility
|
||
|
LINK_ENTITY_TO_CLASS(info_player_ctf_blue,AgCTFSpawn); //HLE CTF map compatibility
|
||
|
LINK_ENTITY_TO_CLASS(info_player_ctf_red,AgCTFSpawn); //HLE CTF map compatibility
|
||
|
#endif
|
||
|
|
||
|
|
||
|
|
||
|
#include "vector.h"
|
||
|
|
||
|
class AgCTFFileItemCache;
|
||
|
|
||
|
|
||
|
AgCTFFileItem::AgCTFFileItem()
|
||
|
{
|
||
|
m_vOrigin = Vector(0,0,0);
|
||
|
m_vAngles = Vector(0,0,0);
|
||
|
m_szName[0] = '\0';
|
||
|
}
|
||
|
|
||
|
AgCTFFileItem::~AgCTFFileItem()
|
||
|
{
|
||
|
|
||
|
}
|
||
|
|
||
|
void AgCTFFileItem::Show()
|
||
|
{
|
||
|
CLaserSpot* pSpot = CLaserSpot::CreateSpot();
|
||
|
UTIL_SetOrigin( pSpot->pev, m_vOrigin );
|
||
|
pSpot->LiveForTime(5.0);
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
AgCTFFileItemCache::AgCTFFileItemCache()
|
||
|
{
|
||
|
m_bInitDone = false;
|
||
|
Load();
|
||
|
}
|
||
|
|
||
|
AgCTFFileItemCache::~AgCTFFileItemCache()
|
||
|
{
|
||
|
//Delete all.
|
||
|
for (AgCTFFileItemList::iterator itrFileItems = m_lstFileItems.begin() ;itrFileItems != m_lstFileItems.end(); ++itrFileItems)
|
||
|
delete *itrFileItems;
|
||
|
m_lstFileItems.clear();
|
||
|
}
|
||
|
|
||
|
void AgCTFFileItemCache::Add(const AgString& sFileItem,CBasePlayer* pPlayer)
|
||
|
{
|
||
|
ASSERT(NULL != pPlayer);
|
||
|
if (!pPlayer)
|
||
|
return;
|
||
|
ASSERT(NULL != pPlayer->pev);
|
||
|
if (!pPlayer->pev)
|
||
|
return;
|
||
|
|
||
|
if (0 == sFileItem.size())
|
||
|
return;
|
||
|
|
||
|
AgCTFFileItem* pFileItem = new AgCTFFileItem;
|
||
|
strcpy(pFileItem->m_szName,sFileItem.c_str());
|
||
|
pFileItem->m_vOrigin = pPlayer->pev->origin;
|
||
|
pFileItem->m_vAngles = pPlayer->pev->angles;
|
||
|
|
||
|
m_lstFileItems.push_back(pFileItem);
|
||
|
pFileItem->Show();
|
||
|
|
||
|
Save(pPlayer);
|
||
|
|
||
|
AgConsole(UTIL_VarArgs("Added item %s.",(const char*)sFileItem.c_str()),pPlayer);
|
||
|
}
|
||
|
|
||
|
void AgCTFFileItemCache::Del(CBasePlayer* pPlayer)
|
||
|
{
|
||
|
ASSERT(NULL != pPlayer);
|
||
|
if (!pPlayer)
|
||
|
return;
|
||
|
ASSERT(NULL != pPlayer->pev);
|
||
|
if (!pPlayer->pev)
|
||
|
return;
|
||
|
|
||
|
if (0 == m_lstFileItems.size())
|
||
|
return;
|
||
|
|
||
|
AgCTFFileItem* pFileItem = m_lstFileItems.back();
|
||
|
AgConsole(UTIL_VarArgs("Deleted last item - %s.",pFileItem->m_szName,pPlayer));
|
||
|
m_lstFileItems.pop_back();
|
||
|
Save(pPlayer);
|
||
|
}
|
||
|
|
||
|
void AgCTFFileItemCache::List(CBasePlayer* pPlayer)
|
||
|
{
|
||
|
ASSERT(NULL != pPlayer);
|
||
|
if (!pPlayer)
|
||
|
return;
|
||
|
ASSERT(NULL != pPlayer->pev);
|
||
|
if (!pPlayer->pev)
|
||
|
return;
|
||
|
|
||
|
for (AgCTFFileItemList::iterator itrFileItems = m_lstFileItems.begin() ;itrFileItems != m_lstFileItems.end(); ++itrFileItems)
|
||
|
{
|
||
|
AgConsole(UTIL_VarArgs("%s",(const char*)(*itrFileItems)->m_szName),pPlayer);
|
||
|
(*itrFileItems)->Show();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void AgCTFFileItemCache::Load(CBasePlayer* pPlayer)
|
||
|
{
|
||
|
for (AgCTFFileItemList::iterator itrFileItems = m_lstFileItems.begin() ;itrFileItems != m_lstFileItems.end(); ++itrFileItems)
|
||
|
delete *itrFileItems;
|
||
|
m_lstFileItems.clear();
|
||
|
|
||
|
|
||
|
char szFile[MAX_PATH];
|
||
|
char szData[20000];
|
||
|
sprintf(szFile, "%s/ctf/%s.ctf", AgGetDirectory(),STRING(gpGlobals->mapname));
|
||
|
FILE* pFile = fopen(szFile,"r");
|
||
|
if (!pFile)
|
||
|
{
|
||
|
// file error
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
int iRead = fread(szData,sizeof(char),sizeof(szData)-2,pFile);
|
||
|
fclose(pFile);
|
||
|
if (0 >= iRead)
|
||
|
return;
|
||
|
szData[iRead] = '\0';
|
||
|
|
||
|
char* pszCTFString = strtok( szData, "\n");
|
||
|
while (pszCTFString != NULL)
|
||
|
{
|
||
|
AgCTFFileItem* pFileItem = new AgCTFFileItem;
|
||
|
sscanf(pszCTFString,"%s %f %f %f %f %f %f\n",pFileItem->m_szName,&pFileItem->m_vOrigin.x,&pFileItem->m_vOrigin.y,&pFileItem->m_vOrigin.z,&pFileItem->m_vAngles.x,&pFileItem->m_vAngles.y,&pFileItem->m_vAngles.z);
|
||
|
m_lstFileItems.push_back(pFileItem);
|
||
|
pszCTFString = strtok( NULL, "\n");
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void AgCTFFileItemCache::Save(CBasePlayer* pPlayer)
|
||
|
{
|
||
|
if (0 == m_lstFileItems.size())
|
||
|
return;
|
||
|
|
||
|
char szFile[MAX_PATH];
|
||
|
sprintf(szFile, "%s/ctf/%s.ctf", AgGetDirectory(),STRING(gpGlobals->mapname));
|
||
|
FILE* pFile = fopen(szFile,"wb");
|
||
|
if (!pFile)
|
||
|
{
|
||
|
// file error
|
||
|
AgConsole(UTIL_VarArgs("Couldn't create/save FileItem file %s.",szFile),pPlayer);
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
//Loop and write the file.
|
||
|
for (AgCTFFileItemList::iterator itrFileItems = m_lstFileItems.begin() ;itrFileItems != m_lstFileItems.end(); ++itrFileItems)
|
||
|
{
|
||
|
//Append.
|
||
|
AgCTFFileItem* pFileItem = *itrFileItems;
|
||
|
fprintf(pFile,"%s %f %f %f %f %f %f\n",pFileItem->m_szName,pFileItem->m_vOrigin.x,pFileItem->m_vOrigin.y,pFileItem->m_vOrigin.z,pFileItem->m_vAngles.x,pFileItem->m_vAngles.y,pFileItem->m_vAngles.z);
|
||
|
}
|
||
|
|
||
|
fflush(pFile);
|
||
|
fclose(pFile);
|
||
|
}
|
||
|
|
||
|
|
||
|
void AgCTFFileItemCache::Init()
|
||
|
{
|
||
|
if (m_bInitDone)
|
||
|
return;
|
||
|
m_bInitDone = true;
|
||
|
|
||
|
for (AgCTFFileItemList::iterator itrFileItems = m_lstFileItems.begin() ;itrFileItems != m_lstFileItems.end(); ++itrFileItems)
|
||
|
{
|
||
|
AgCTFFileItem* pFileItem = *itrFileItems;
|
||
|
|
||
|
if (g_pGameRules->IsAllowedToSpawn(pFileItem->m_szName))
|
||
|
CBaseEntity::Create(pFileItem->m_szName, pFileItem->m_vOrigin, pFileItem->m_vAngles, INDEXENT(0));
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//-- Martin Webrant
|
||
|
|