hlsdk-xash3d/dlls/3wave/threewave_gamerules.cpp

3274 lines
83 KiB
C++

/***
*
* 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
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"
extern int gmsgCTFMsgs;
extern int gmsgShowMenu;
extern int gmsgFlagStatus;
extern int gmsgRuneStatus;
extern int gmsgFlagCarrier;
extern int gmsgScoreInfo;
unsigned short g_usHook;
unsigned short g_usCable;
unsigned short g_usCarried;
unsigned short g_usFlagSpawn;
static char team_names[MAX_TEAMS][MAX_TEAMNAME_LENGTH];
static int team_scores[MAX_TEAMS];
static int num_teams = 0;
bool g_bSpawnedRunes;
void SpawnRunes( void );
extern edict_t *EntSelectSpawnPoint( CBaseEntity *pPlayer, bool bCheckDM );
extern edict_t *RuneSelectSpawnPoint( void );
// Standard Scoring
#define TEAM_CAPTURE_CAPTURE_BONUS 5 // what you get for capture
#define TEAM_CAPTURE_TEAM_BONUS 10 // what your team gets for capture
#define TEAM_CAPTURE_RECOVERY_BONUS 1 // what you get for recovery
#define TEAM_CAPTURE_FLAG_BONUS 0 // what you get for picking up enemy flag
#define TEAM_CAPTURE_FRAG_CARRIER_BONUS 2 // what you get for fragging a enemy flag carrier
#define TEAM_CAPTURE_FLAG_RETURN_TIME 40 // seconds until auto return
// bonuses
#define TEAM_CAPTURE_CARRIER_DANGER_PROTECT_BONUS 2 // bonus for fraggin someone
// who has recently hurt your flag carrier
#define TEAM_CAPTURE_CARRIER_PROTECT_BONUS 1 // bonus for fraggin someone while
// either you or your target are near your flag carrier
#define TEAM_CAPTURE_FLAG_DEFENSE_BONUS 1 // bonus for fraggin someone while
// either you or your target are near your flag
#define TEAM_CAPTURE_RETURN_FLAG_ASSIST_BONUS 1 // awarded for returning a flag that causes a
// capture to happen almost immediately
#define TEAM_CAPTURE_FRAG_CARRIER_ASSIST_BONUS 2 // award for fragging a flag carrier if a
// capture happens almost immediately
// Radius
#define TEAM_CAPTURE_TARGET_PROTECT_RADIUS 550 // the radius around an object being
// defended where a target will be worth extra frags
#define TEAM_CAPTURE_ATTACKER_PROTECT_RADIUS 550 // the radius around an object being
// defended where an attacker will get extra frags when making kills
// timeouts
#define TEAM_CAPTURE_CARRIER_DANGER_PROTECT_TIMEOUT 4
#define TEAM_CAPTURE_CARRIER_FLAG_SINCE_TIMEOUT 2
#define TEAM_CAPTURE_FRAG_CARRIER_ASSIST_TIMEOUT 6
#define TEAM_CAPTURE_RETURN_FLAG_ASSIST_TIMEOUT 4
class CThreeWaveGameMgrHelper : public IVoiceGameMgrHelper
{
public:
virtual bool CanPlayerHearPlayer(CBasePlayer *pPlayer1, CBasePlayer *pPlayer2)
{
return stricmp(pPlayer1->TeamID(), pPlayer2->TeamID()) == 0;
}
};
static CThreeWaveGameMgrHelper g_GameMgrHelper;
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;
}
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 )
{
if ( pPlayer->pev->team == iTeam )
return;
if ( pPlayer->m_flNextTeamChange > gpGlobals->time )
return;
pPlayer->m_flNextTeamChange = gpGlobals->time + 5;
if ( pPlayer->pev->team == 0 )
{
ChangePlayerTeam( pPlayer, iTeam );
RecountTeams();
pPlayer->Spawn();
}
else
{
ChangePlayerTeam( pPlayer, iTeam );
RecountTeams();
}
}
int CThreeWave::TeamWithFewestPlayers( void )
{
CBaseEntity *pPlayer = NULL;
CBasePlayer *player = NULL;
int iNumRed, iNumBlue;
int iTeam;
// Initialize the player counts..
iNumRed = iNumBlue = 0;
pPlayer = UTIL_FindEntityByClassname ( pPlayer, "player" );
while ( (pPlayer != NULL) && (!FNullEnt(pPlayer->edict())) )
{
if (pPlayer->pev->flags != FL_DORMANT)
{
player = GetClassPtr((CBasePlayer *)pPlayer->pev);
if ( player->pev->team == RED )
iNumRed += 1;
else if ( player->pev->team == BLUE )
iNumBlue += 1;
}
pPlayer = UTIL_FindEntityByClassname ( pPlayer, "player" );
}
if ( iNumRed == iNumBlue )
{
switch ( RANDOM_LONG( 0, 1 ) )
{
case 0: iTeam = RED; break;
case 1: iTeam = BLUE; break;
}
}
else if ( iNumRed == 0 && iNumBlue == 0)
{
switch ( RANDOM_LONG( 0, 1 ) )
{
case 0: iTeam = RED; break;
case 1: iTeam = BLUE; break;
}
}
else if ( iNumRed > iNumBlue )
iTeam = BLUE;
else if ( iNumRed < iNumBlue )
iTeam = RED;
return iTeam;
}
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 ( FStrEq( pcmd, "menuselect" ) )
{
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:
switch ( slot )
{
case 1:
JoinTeam( pPlayer, RED );
break;
case 2:
JoinTeam( pPlayer, BLUE );
break;
case 5:
JoinTeam( pPlayer, TeamWithFewestPlayers() );
break;
}
break;
case Team_Menu_IG:
switch ( slot )
{
case 1:
JoinTeam( pPlayer, RED );
break;
case 2:
JoinTeam( pPlayer, BLUE );
break;
case 5:
JoinTeam( pPlayer, TeamWithFewestPlayers() );
break;
default:
return TRUE;
}
break;
}
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 )
{
edict_t *pentSpawnSpot;
if ( FBitSet( pPlayer->m_afPhysicsFlags, PFLAG_OBSERVER ) || pPlayer->pev->team == 0 )
pentSpawnSpot = EntSelectSpawnPoint( pPlayer, FALSE );
else
{
if ( RANDOM_LONG ( 1, 7 ) < 3 )
pentSpawnSpot= EntSelectSpawnPoint( pPlayer, TRUE );
else
pentSpawnSpot= EntSelectSpawnPoint( pPlayer, FALSE );
}
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" );
pPlayer->m_iQuakeItems |= ( IT_SHOTGUN | IT_AXE | 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, 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 damageFlags = DMG_GENERIC;
int clientIndex = pPlayer->entindex();
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;
if ( pPlayer->pev->team == RED )
{
strncpy( pPlayer->m_szTeamName, "RED", TEAM_NAME_LENGTH );
g_engfuncs.pfnSetClientKeyValue( clientIndex, g_engfuncs.pfnGetInfoKeyBuffer( pPlayer->edict() ), "model", "red" );
g_engfuncs.pfnSetClientKeyValue( clientIndex, g_engfuncs.pfnGetInfoKeyBuffer( pPlayer->edict() ), "topcolor", UTIL_VarArgs( "%d", 255 ) );
}
else if ( pPlayer->pev->team == BLUE )
{
strncpy( pPlayer->m_szTeamName, "BLUE", TEAM_NAME_LENGTH );
g_engfuncs.pfnSetClientKeyValue( clientIndex, g_engfuncs.pfnGetInfoKeyBuffer( pPlayer->edict() ), "model", "blue" );
g_engfuncs.pfnSetClientKeyValue( clientIndex, g_engfuncs.pfnGetInfoKeyBuffer( pPlayer->edict() ), "topcolor", UTIL_VarArgs( "%d", 153 ) );
}
// 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();
if ( pPlayer->pev->team == RED )
{
g_engfuncs.pfnSetClientKeyValue( clientIndex, g_engfuncs.pfnGetInfoKeyBuffer( pPlayer->edict() ), "topcolor", UTIL_VarArgs( "%d", 255 ) );
g_engfuncs.pfnSetClientKeyValue( clientIndex, g_engfuncs.pfnGetInfoKeyBuffer( pPlayer->edict() ), "model", "red" );
}
else if ( pPlayer->pev->team == BLUE )
{
g_engfuncs.pfnSetClientKeyValue( clientIndex, g_engfuncs.pfnGetInfoKeyBuffer( pPlayer->edict() ), "topcolor", UTIL_VarArgs( "%d", 153 ) );
g_engfuncs.pfnSetClientKeyValue( clientIndex, g_engfuncs.pfnGetInfoKeyBuffer( pPlayer->edict() ), "model", "blue" );
}
}
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;
//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
CBaseEntity *pRune;
char * runeName;
switch ( pPlayer->m_iRuneStatus )
{
case ITEM_RUNE1_FLAG:
pRune = CBaseEntity::Create( "item_rune1", pPlayer->pev->origin, pPlayer->pev->angles, NULL );
pRune->pev->velocity = pPlayer->pev->velocity * 1.5;
pRune->pev->angles.x = 0;
((CResistRune*)pRune)->dropped = true;
runeName = "ResistRune";
break;
case ITEM_RUNE2_FLAG:
pRune = CBaseEntity::Create( "item_rune2", pPlayer->pev->origin, pPlayer->pev->angles, NULL );
pRune->pev->velocity = pPlayer->pev->velocity * 1.5;
pRune->pev->angles.x = 0;
((CStrengthRune*)pRune)->dropped = true;
runeName = "StrengthRune";
break;
case ITEM_RUNE3_FLAG:
pRune = CBaseEntity::Create( "item_rune3", pPlayer->pev->origin, pPlayer->pev->angles, NULL );
pRune->pev->velocity = pPlayer->pev->velocity * 1.5;
pRune->pev->angles.x = 0;
((CHasteRune*)pRune)->dropped = true;
runeName = "HasteRune";
break;
case ITEM_RUNE4_FLAG:
pRune = CBaseEntity::Create( "item_rune4", pPlayer->pev->origin, pPlayer->pev->angles, NULL );
pRune->pev->velocity = pPlayer->pev->velocity * 1.5;
pRune->pev->angles.x = 0;
((CRegenRune*)pRune)->dropped = true;
runeName = "RegenRune";
break;
default:
runeName = "Unknown";
break;
}
if ( pPlayer->m_iRuneStatus )
{
pPlayer->m_iRuneStatus = 0;
UTIL_LogPrintf( "\"%s<%i><%s><%s>\" triggered \"Dropped_%s\"\n",
STRING(pPlayer->pev->netname),
GETPLAYERUSERID( pPlayer->edict() ),
GETPLAYERAUTHID( pPlayer->edict() ),
pPlayer->m_szTeamName,
runeName );
}
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;
//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 );
}
}
}
}
}
}
}
}
CBaseEntity *pRune;
char * runeName;
switch ( pVictim->m_iRuneStatus )
{
case ITEM_RUNE1_FLAG:
pRune = CBaseEntity::Create( "item_rune1", pVictim->pev->origin, pVictim->pev->angles, NULL );
pRune->pev->velocity = pVictim->pev->velocity * 1.5;
pRune->pev->angles.x = 0;
((CResistRune*)pRune)->dropped = true;
runeName = "ResistRune";
break;
case ITEM_RUNE2_FLAG:
pRune = CBaseEntity::Create( "item_rune2", pVictim->pev->origin, pVictim->pev->angles, NULL );
pRune->pev->velocity = pVictim->pev->velocity * 1.5;
pRune->pev->angles.x = 0;
((CStrengthRune*)pRune)->dropped = true;
runeName = "StrengthRune";
break;
case ITEM_RUNE3_FLAG:
pRune = CBaseEntity::Create( "item_rune3", pVictim->pev->origin, pVictim->pev->angles, NULL );
pRune->pev->velocity = pVictim->pev->velocity * 1.5;
pRune->pev->angles.x = 0;
((CHasteRune*)pRune)->dropped = true;
runeName = "HasteRune";
break;
case ITEM_RUNE4_FLAG:
pRune = CBaseEntity::Create( "item_rune4", pVictim->pev->origin, pVictim->pev->angles, NULL );
pRune->pev->velocity = pVictim->pev->velocity * 1.5;
pRune->pev->angles.x = 0;
((CRegenRune*)pRune)->dropped = true;
runeName = "RegenRune";
break;
default:
runeName = "Unknown";
break;
}
if ( pVictim->m_iRuneStatus )
{
UTIL_LogPrintf( "\"%s<%i><%s><%s>\" triggered \"Dropped_%s\"\n",
STRING(pVictim->pev->netname),
GETPLAYERUSERID( pVictim->edict() ),
GETPLAYERAUTHID( pVictim->edict() ),
pVictim->m_szTeamName,
runeName );
}
if ( pVictim->m_ppHook )
(( CGrapple *)pVictim->m_ppHook)->Reset_Grapple();
pVictim->m_iRuneStatus = 0;
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( void )
{
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++ )
{
CBaseEntity *plr = UTIL_PlayerByIndex( i );
if ( plr )
{
if ( ((CBasePlayer *)plr)->m_bHasFlag )
{
MESSAGE_BEGIN( MSG_ALL, gmsgFlagCarrier, NULL );
WRITE_BYTE( plr->entindex() );
WRITE_BYTE( 1 );
MESSAGE_END();
}
else
{
MESSAGE_BEGIN( MSG_ALL, gmsgFlagCarrier, NULL );
WRITE_BYTE( plr->entindex() );
WRITE_BYTE( 0 );
MESSAGE_END();
}
}
}
}
//=========================================================
//=========================================================
void CThreeWave::RecountTeams( void )
{
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;
}
}
}
}
/*****************************************************
******************************************************
THREEWAVE CTF FLAG CODE
******************************************************
*****************************************************/
enum Flag_Anims
{
ON_GROUND = 0,
NOT_CARRIED,
CARRIED,
WAVE_IDLE,
FLAG_POSITION
};
void CItemFlag::Spawn ( void )
{
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( &CItemFlag::FlagThink );
SetTouch( &CItemFlag::FlagTouch );
pev->nextthink = gpGlobals->time + 0.3;
//Set the Skin based on the team.
pev->skin = pev->team;
Dropped = FALSE;
m_flDroppedTime = 0.0;
pev->sequence = NOT_CARRIED;
pev->framerate = 1.0;
// if ( !DROP_TO_FLOOR(ENT(pev)) )
// ResetFlag( pev->team );
}
void CItemFlag::FlagTouch ( CBaseEntity *pToucher )
{
if ( !pToucher )
return;
if ( !pToucher->IsPlayer() )
return;
if ( FBitSet( pev->effects, EF_NODRAW ) )
return;
if ( pToucher->pev->health <= 0 )
return;
if ( pToucher->pev->team == 0 )
return;
CBasePlayer *pPlayer = (CBasePlayer *)pToucher;
//Same team as the flag
if ( pev->team == pToucher->pev->team )
{
//Flag is dropped, let's return it
if ( Dropped )
{
Dropped = FALSE;
pPlayer->AddPoints( TEAM_CAPTURE_RECOVERY_BONUS, TRUE );
if ( pPlayer->pev->team == RED )
{
UTIL_LogPrintf( "\"%s<%i><%s><%s>\" triggered \"Returned_Red_Flag\"\n",
STRING( pPlayer->pev->netname ),
GETPLAYERUSERID( pPlayer->edict() ),
GETPLAYERAUTHID( pPlayer->edict() ),
GetTeamName( pPlayer->pev->team ) );
if ( ((CThreeWave *) g_pGameRules)->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->pFlagReturner = pPlayer;
pTeamMate->m_flFlagReturnTime = gpGlobals->time + TEAM_CAPTURE_RETURN_FLAG_ASSIST_TIMEOUT;
}
}
}
}
}
if ( pPlayer->pev->team == BLUE )
{
UTIL_LogPrintf( "\"%s<%i><%s><%s>\" triggered \"Returned_Blue_Flag\"\n",
STRING( pPlayer->pev->netname ),
GETPLAYERUSERID( pPlayer->edict() ),
GETPLAYERAUTHID( pPlayer->edict() ),
GetTeamName( pPlayer->pev->team ) );
if ( ((CThreeWave *) g_pGameRules)->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->pFlagReturner = pPlayer;
pTeamMate->m_flFlagReturnTime = gpGlobals->time + TEAM_CAPTURE_RETURN_FLAG_ASSIST_TIMEOUT;
}
}
}
}
}
//Back at home!
ResetFlag( pev->team );
MESSAGE_BEGIN ( MSG_ALL, gmsgCTFMsgs, NULL );
if ( pev->team == RED )
WRITE_BYTE( RED_FLAG_RETURNED_PLAYER );
else if ( pev->team == BLUE )
WRITE_BYTE( BLUE_FLAG_RETURNED_PLAYER );
WRITE_STRING( STRING(pToucher->pev->netname) );
MESSAGE_END();
//Remove this one
UTIL_Remove( this );
return;
}
//Not Dropped, means it's the one in our base
else if ( !Dropped )
{
//We have the enemy flag!
//Capture it!
if ( pPlayer->m_bHasFlag )
{
if ( pev->team == RED )
Capture( pPlayer, BLUE );
else if ( pev->team == BLUE )
Capture( pPlayer, RED );
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 );
return;
}
}
}
else
{
if ( Dropped )
{
MESSAGE_BEGIN ( MSG_ALL, gmsgCTFMsgs, NULL );
if ( pev->team == RED )
WRITE_BYTE( RED_FLAG_STOLEN );
else if ( pev->team == BLUE )
WRITE_BYTE( BLUE_FLAG_STOLEN );
WRITE_STRING( STRING(pToucher->pev->netname) );
MESSAGE_END();
pPlayer->m_bHasFlag = TRUE;
CBaseEntity *pEnt = NULL;
if ( pev->team == RED )
{
pEnt = CBaseEntity::Create( "carried_flag_team1", pPlayer->pev->origin, pPlayer->pev->angles, pPlayer->edict() );
UTIL_LogPrintf( "\"%s<%i><%s><%s>\" triggered \"Picked_Up_Red_Flag\"\n",
STRING( pPlayer->pev->netname ),
GETPLAYERUSERID( pPlayer->edict() ),
GETPLAYERAUTHID( pPlayer->edict() ),
GetTeamName( pPlayer->pev->team ) );
}
else if ( pev->team == BLUE )
{
pEnt = CBaseEntity::Create( "carried_flag_team2", pPlayer->pev->origin, pPlayer->pev->angles, pPlayer->edict() );
UTIL_LogPrintf( "\"%s<%i><%s><%s>\" triggered \"Picked_Up_Blue_Flag\"\n",
STRING( pPlayer->pev->netname ),
GETPLAYERUSERID( pPlayer->edict() ),
GETPLAYERAUTHID( pPlayer->edict() ),
GetTeamName( pPlayer->pev->team ) );
}
CCarriedFlag *pCarriedFlag = (CCarriedFlag *)pEnt;
pCarriedFlag->Owner = pPlayer;
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, 0, 0 );
UTIL_Remove( this );
}
else
{
pev->effects |= EF_NODRAW;
MESSAGE_BEGIN ( MSG_ALL, gmsgCTFMsgs, NULL );
if ( pev->team == RED )
WRITE_BYTE( RED_FLAG_STOLEN );
else if ( pev->team == BLUE )
WRITE_BYTE( BLUE_FLAG_STOLEN );
WRITE_STRING( STRING(pToucher->pev->netname) );
MESSAGE_END();
pPlayer->m_bHasFlag = TRUE;
pPlayer->m_flCarrierPickupTime = gpGlobals->time + TEAM_CAPTURE_CARRIER_FLAG_SINCE_TIMEOUT;
CBaseEntity *pEnt = NULL;
if ( pev->team == RED )
{
pEnt = CBaseEntity::Create( "carried_flag_team1", pev->origin, pev->angles, pPlayer->edict() );
UTIL_LogPrintf( "\"%s<%i><%s><%s>\" triggered \"Stole_Red_Flag\"\n",
STRING( pPlayer->pev->netname ),
GETPLAYERUSERID( pPlayer->edict() ),
GETPLAYERAUTHID( pPlayer->edict() ),
GetTeamName( pPlayer->pev->team ) );
}
else if ( pev->team == BLUE )
{
pEnt = CBaseEntity::Create( "carried_flag_team2", pev->origin, pev->angles, pPlayer->edict() );
UTIL_LogPrintf( "\"%s<%i><%s><%s>\" triggered \"Stole_Blue_Flag\"\n",
STRING( pPlayer->pev->netname ),
GETPLAYERUSERID( pPlayer->edict() ),
GETPLAYERAUTHID( pPlayer->edict() ),
GetTeamName( pPlayer->pev->team ) );
}
CCarriedFlag *pCarriedFlag = (CCarriedFlag *)pEnt;
pCarriedFlag->Owner = pPlayer;
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, 0, 0 );
}
((CThreeWave *) g_pGameRules)->m_flFlagStatusTime = gpGlobals->time + 0.1;
}
}
void CItemFlag::Capture(CBasePlayer *pPlayer, int iTeam )
{
CBaseEntity *pFlag1 = NULL;
MESSAGE_BEGIN ( MSG_ALL, gmsgCTFMsgs, NULL );
if ( iTeam == RED )
WRITE_BYTE( RED_FLAG_CAPTURED );
else if ( iTeam == BLUE )
WRITE_BYTE( BLUE_FLAG_CAPTURED );
WRITE_STRING( STRING( pPlayer->pev->netname) );
MESSAGE_END();
if ( pPlayer->pFlagCarrierKiller )
{
if ( pPlayer->m_flFlagCarrierKillTime > gpGlobals->time )
{
UTIL_ClientPrintAll( HUD_PRINTNOTIFY, STRING( pPlayer->pFlagCarrierKiller->pev->netname ) );
UTIL_ClientPrintAll( HUD_PRINTNOTIFY, " gets an assist for fragging the flag carrier!\n");
pPlayer->pFlagCarrierKiller->AddPoints( TEAM_CAPTURE_FRAG_CARRIER_ASSIST_BONUS, TRUE );
pPlayer->pFlagCarrierKiller = NULL;
pPlayer->m_flFlagCarrierKillTime = 0.0;
}
}
if ( pPlayer->pFlagReturner )
{
if ( pPlayer->m_flFlagReturnTime > gpGlobals->time )
{
UTIL_ClientPrintAll( HUD_PRINTNOTIFY, STRING( pPlayer->pFlagReturner->pev->netname ) );
UTIL_ClientPrintAll( HUD_PRINTNOTIFY, " gets an assist for returning his flag!\n");
pPlayer->pFlagReturner->AddPoints( TEAM_CAPTURE_RETURN_FLAG_ASSIST_BONUS, TRUE );
pPlayer->pFlagReturner = NULL;
pPlayer->m_flFlagReturnTime = 0.0;
}
}
if ( iTeam != pPlayer->pev->team )
{
if ( iTeam == RED )
{
UTIL_LogPrintf( "\"%s<%i><%s><%s>\" triggered \"Captured_Red_Flag\"\n",
STRING( pPlayer->pev->netname ),
GETPLAYERUSERID( pPlayer->edict() ),
GETPLAYERAUTHID( pPlayer->edict() ),
GetTeamName( pPlayer->pev->team ) );
}
else
{
UTIL_LogPrintf( "\"%s<%i><%s><%s>\" triggered \"Captured_Blue_Flag\"\n",
STRING( pPlayer->pev->netname ),
GETPLAYERUSERID( pPlayer->edict() ),
GETPLAYERAUTHID( pPlayer->edict() ),
GetTeamName( pPlayer->pev->team ) );
}
}
if ( iTeam == RED )
{
((CThreeWave *) g_pGameRules)->iBlueTeamScore++;
while((pFlag1 = UTIL_FindEntityByClassname( pFlag1, "carried_flag_team1")) != NULL)
{
if ( pFlag1 )
UTIL_Remove( pFlag1 );
}
}
else if ( iTeam == BLUE )
{
((CThreeWave *) g_pGameRules)->iRedTeamScore++;
while((pFlag1 = UTIL_FindEntityByClassname( pFlag1, "carried_flag_team2")) != NULL)
{
if ( pFlag1 )
UTIL_Remove( pFlag1 );
}
}
pPlayer->m_bHasFlag = FALSE;
pPlayer->AddPoints( TEAM_CAPTURE_CAPTURE_BONUS, TRUE );
for ( int i = 1; i <= gpGlobals->maxClients; i++ )
{
CBaseEntity *pTeamMate = UTIL_PlayerByIndex( i );
if ( pTeamMate )
{
if ( pTeamMate->pev->team == pPlayer->pev->team )
pTeamMate->AddPoints( TEAM_CAPTURE_TEAM_BONUS, TRUE );
}
}
ResetFlag( iTeam );
}
void CItemFlag::Materialize( void )
{
if ( pev->effects & EF_NODRAW )
{
pev->effects &= ~EF_NODRAW;
pev->effects |= EF_MUZZLEFLASH;
}
PLAYBACK_EVENT_FULL( FEV_GLOBAL | FEV_RELIABLE,
edict(), g_usFlagSpawn, 0, (float *)&g_vecZero, (float *)&g_vecZero,
0.0, 0.0, pev->team, 0, 0, 0 );
Dropped = FALSE;
SetTouch( &CItemFlag::FlagTouch );
SetThink( &CItemFlag::FlagThink );
}
void CItemFlag::ResetFlag( int iTeam )
{
CBaseEntity *pFlag1 = NULL;
if ( iTeam == BLUE )
{
while((pFlag1 = UTIL_FindEntityByClassname( pFlag1, "item_flag_team2")) != NULL)
{
CItemFlag *pFlag2 = (CItemFlag *)pFlag1;
if ( pFlag2->Dropped )
continue;
if ( pFlag2->pev->effects & EF_NODRAW)
pFlag2->Materialize();
}
}
else if ( iTeam == RED )
{
while((pFlag1 = UTIL_FindEntityByClassname( pFlag1, "item_flag_team1")) != NULL)
{
CItemFlag *pFlag2 = (CItemFlag *)pFlag1;
if ( pFlag2->Dropped )
continue;
if ( pFlag2->pev->effects & EF_NODRAW)
pFlag2->Materialize();
}
}
((CThreeWave *) g_pGameRules)->m_flFlagStatusTime = gpGlobals->time + 0.1;
}
void CItemFlag::FlagThink( void )
{
if ( Dropped )
{
if ( m_flDroppedTime <= gpGlobals->time )
{
ResetFlag( pev->team );
MESSAGE_BEGIN ( MSG_ALL, gmsgCTFMsgs, NULL );
if ( pev->team == RED )
WRITE_BYTE( RED_FLAG_RETURNED );
else if ( pev->team == BLUE )
WRITE_BYTE( BLUE_FLAG_RETURNED );
WRITE_STRING( "" );
MESSAGE_END();
UTIL_Remove( this );
return;
}
}
//Using 0.2 just in case we might lag the server.
pev->nextthink = gpGlobals->time + 0.2;
}
void CItemFlag::Precache( void )
{
PRECACHE_MODEL ("models/flag.mdl");
PRECACHE_SOUND ("ctf/flagcap.wav");
PRECACHE_SOUND ("ctf/flagtk.wav");
PRECACHE_SOUND ("ctf/flagret.wav");
}
class CItemFlagTeam1 : public CItemFlag
{
void Spawn( void )
{
pev->classname = MAKE_STRING( "item_flag_team1" );
pev->team = RED;
CItemFlag::Spawn( );
}
};
class CItemFlagTeam2 : public CItemFlag
{
void Spawn( void )
{
pev->classname = MAKE_STRING( "item_flag_team2" );
pev->team = BLUE;
CItemFlag::Spawn( );
}
};
LINK_ENTITY_TO_CLASS( item_flag_team1, CItemFlagTeam1 )
LINK_ENTITY_TO_CLASS( ctf_redflag, CItemFlagTeam1 )
LINK_ENTITY_TO_CLASS( item_flag_team2, CItemFlagTeam2 )
LINK_ENTITY_TO_CLASS( ctf_blueflag, CItemFlagTeam2 )
void CCarriedFlag ::Spawn()
{
Precache( );
SET_MODEL(ENT(pev), "models/flag.mdl");
UTIL_SetOrigin( pev, pev->origin );
pev->movetype = MOVETYPE_NONE;
pev->solid = SOLID_NOT;
pev->effects |= EF_NODRAW;
pev->sequence = WAVE_IDLE;
pev->framerate = 1.0;
if ( pev->team == RED )
pev->skin = 1;
else if ( pev->team == BLUE )
pev->skin = 2;
m_iOwnerOldVel = 0;
SetThink( &CCarriedFlag::FlagThink );
pev->nextthink = gpGlobals->time + 0.1;
}
void CCarriedFlag::Precache( )
{
PRECACHE_MODEL ("models/flag.mdl");
}
void CCarriedFlag::FlagThink( )
{
//Make it visible
pev->effects &= ~EF_NODRAW;
//And let if follow
pev->aiment = ENT(Owner->pev);
pev->movetype = MOVETYPE_FOLLOW;
//Remove if owner is death
if (!Owner->IsAlive())
UTIL_Remove( this );
//If owner lost flag, remove
if ( !Owner->m_bHasFlag )
UTIL_Remove( this );
else
{
//If owners speed is low, go in idle mode
if (Owner->pev->velocity.Length() <= 75 && pev->sequence != WAVE_IDLE)
{
pev->sequence = WAVE_IDLE;
}
//Else let the flag go wild
else if (Owner->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 CCarriedFlagTeam1 : public CCarriedFlag
{
void Spawn( void )
{
pev->team = RED;
CCarriedFlag::Spawn( );
}
};
class CCarriedFlagTeam2 : public CCarriedFlag
{
void Spawn( void )
{
pev->team = BLUE;
CCarriedFlag::Spawn( );
}
};
LINK_ENTITY_TO_CLASS( carried_flag_team1, CCarriedFlagTeam1 );
LINK_ENTITY_TO_CLASS( carried_flag_team2, CCarriedFlagTeam2 );
/***************************************
****************************************
RUNES
****************************************
***************************************/
/*----------------------------------------------------------------------
The Rune Game modes
Rune 1 - Earth Magic
resistance
Rune 2 - Black Magic
strength
Rune 3 - Hell Magic
haste
Rune 4 - Elder Magic
regeneration
----------------------------------------------------------------------*/
BOOL IsRuneSpawnPointValid( CBaseEntity *pSpot )
{
CBaseEntity *ent = NULL;
while ( (ent = UTIL_FindEntityInSphere( ent, pSpot->pev->origin, 128 )) != NULL )
{
//Try not to spawn it near other runes.
if ( !strcmp( STRING( ent->pev->classname ), "item_rune1") ||
!strcmp( STRING( ent->pev->classname ), "item_rune2") ||
!strcmp( STRING( ent->pev->classname ), "item_rune3") ||
!strcmp( STRING( ent->pev->classname ), "item_rune4") )
return FALSE;
}
return TRUE;
}
edict_t *RuneSelectSpawnPoint( void )
{
CBaseEntity *pSpot;
pSpot = NULL;
// Randomize the start spot
for ( int i = RANDOM_LONG(1,5); i > 0; i-- )
pSpot = UTIL_FindEntityByClassname( pSpot, "info_player_deathmatch" );
if ( !pSpot ) // skip over the null point
pSpot = UTIL_FindEntityByClassname( pSpot, "info_player_deathmatch" );
CBaseEntity *pFirstSpot = pSpot;
do
{
if ( pSpot )
{
if ( IsRuneSpawnPointValid( pSpot ) )
{
if ( pSpot->pev->origin == Vector( 0, 0, 0 ) )
{
pSpot = UTIL_FindEntityByClassname( pSpot, "info_player_deathmatch" );
continue;
}
// if so, go to pSpot
goto ReturnSpot;
}
}
// increment pSpot
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 ( pSpot )
goto ReturnSpot;
// If startspot is set, (re)spawn there.
if ( FStringNull( gpGlobals->startspot ) || !strlen(STRING(gpGlobals->startspot)))
{
pSpot = UTIL_FindEntityByClassname(NULL, "info_player_start");
if ( pSpot )
goto ReturnSpot;
}
else
{
pSpot = UTIL_FindEntityByTargetname( NULL, STRING(gpGlobals->startspot) );
if ( pSpot )
goto ReturnSpot;
}
ReturnSpot:
if ( !pSpot )
{
ALERT(at_error, "PutClientInServer: no info_player_start on level");
return INDEXENT(0);
}
return pSpot->edict();
}
void VectorScale (const float *in, float scale, float *out)
{
out[0] = in[0]*scale;
out[1] = in[1]*scale;
out[2] = in[2]*scale;
}
void G_ProjectSource (vec3_t point, vec3_t distance, vec3_t forward, vec3_t right, vec3_t result)
{
result[0] = point[0] + forward[0] * distance[0] + right[0] * distance[1];
result[1] = point[1] + forward[1] * distance[0] + right[1] * distance[1];
result[2] = point[2] + forward[2] * distance[0] + right[2] * distance[1] + distance[2];
}
#define VectorSet(v, x, y, z) (v[0]=(x), v[1]=(y), v[2]=(z))
void DropRune ( CBasePlayer *pPlayer )
{
TraceResult tr;
// do they even have a rune?
if ( pPlayer->m_iRuneStatus == 0 )
return;
// Make Sure there's enough room to drop the rune here
// This is so hacky ( the reason why we are doing this), and I hate it to death.
UTIL_MakeVectors ( pPlayer->pev->v_angle );
Vector vecSrc = pPlayer->GetGunPosition( );
Vector vecEnd = vecSrc + gpGlobals->v_forward * 32;
UTIL_TraceHull( vecSrc, vecEnd, dont_ignore_monsters, human_hull, ENT( pPlayer->pev ), &tr );
if (tr.flFraction != 1)
{
ClientPrint( pPlayer->pev, HUD_PRINTCENTER, "Not enough room to drop the rune here." );
return;
}
CBaseEntity *pRune = NULL;
char * runeName;
if ( pPlayer->m_iRuneStatus == ITEM_RUNE1_FLAG )
{
pRune = CBaseEntity::Create( "item_rune1", pPlayer->pev->origin, pPlayer->pev->angles, pPlayer->edict() );
runeName = "ResistRune";
if ( pRune )
((CResistRune*)pRune)->dropped = true;
}
else if ( pPlayer->m_iRuneStatus == ITEM_RUNE2_FLAG )
{
pRune = CBaseEntity::Create( "item_rune2", pPlayer->pev->origin, pPlayer->pev->angles, pPlayer->edict() );
runeName = "StrengthRune";
if ( pRune )
((CStrengthRune*)pRune)->dropped = true;
}
else if ( pPlayer->m_iRuneStatus == ITEM_RUNE3_FLAG )
{
pRune = CBaseEntity::Create( "item_rune3", pPlayer->pev->origin, pPlayer->pev->angles, pPlayer->edict() );
runeName = "HasteRune";
if ( pRune )
((CHasteRune*)pRune)->dropped = true;
}
else if ( pPlayer->m_iRuneStatus == ITEM_RUNE4_FLAG )
{
pRune = CBaseEntity::Create( "item_rune4", pPlayer->pev->origin, pPlayer->pev->angles, pPlayer->edict() );
runeName = "RegenRune";
if ( pRune )
((CRegenRune*)pRune)->dropped = true;
}
else
{
runeName = "Unknown";
}
if ( pPlayer->m_iRuneStatus == ITEM_RUNE3_FLAG )
g_engfuncs.pfnSetClientMaxspeed( ENT( pPlayer->pev ), PLAYER_MAX_SPEED ); //Reset Haste player speed to normal
pPlayer->m_iRuneStatus = 0;
UTIL_LogPrintf( "\"%s<%i><%s><%s>\" triggered \"Dropped_%s\"\n",
STRING(pPlayer->pev->netname),
GETPLAYERUSERID( pPlayer->edict() ),
GETPLAYERAUTHID( pPlayer->edict() ),
pPlayer->m_szTeamName,
runeName );
MESSAGE_BEGIN( MSG_ONE, gmsgRuneStatus, NULL, pPlayer->pev);
WRITE_BYTE( pPlayer->m_iRuneStatus );
MESSAGE_END();
}
void CResistRune::RuneTouch ( CBaseEntity *pOther )
{
//No toucher?
if ( !pOther )
return;
//Not a player?
if ( !pOther->IsPlayer() )
return;
//DEAD?!
if ( pOther->pev->health <= 0 )
return;
//Spectating?
if ( pOther->pev->movetype == MOVETYPE_NOCLIP )
return;
//Only one per customer
if ( ((CBasePlayer *)pOther)->m_iRuneStatus )
{
ClientPrint( pOther->pev, HUD_PRINTCENTER, "You already have a rune!\n" );
return;
}
if ( !m_bTouchable )
return;
((CBasePlayer *)pOther)->m_iRuneStatus = m_iRuneFlag; //Add me the rune flag
ClientPrint( pOther->pev, HUD_PRINTCENTER, "You got the rune of Resistance!\n" );
UTIL_LogPrintf( "\"%s<%i><%s><%s>\" triggered \"Found_ResistRune\"\n",
STRING(pOther->pev->netname),
GETPLAYERUSERID( pOther->edict() ),
GETPLAYERAUTHID( pOther->edict() ),
((CBasePlayer *)pOther)->m_szTeamName );
EMIT_SOUND( ENT(pev), CHAN_ITEM, "weapons/lock4.wav", 1, ATTN_NORM );
//Update my client side rune hud thingy.
MESSAGE_BEGIN( MSG_ONE, gmsgRuneStatus, NULL, pOther->pev);
WRITE_BYTE( ((CBasePlayer *)pOther)->m_iRuneStatus );
MESSAGE_END();
//And Remove this entity
UTIL_Remove( this );
}
void CResistRune::RuneRespawn ( void )
{
edict_t *pentSpawnSpot;
vec3_t vOrigin;
pentSpawnSpot = RuneSelectSpawnPoint();
vOrigin = VARS(pentSpawnSpot)->origin;
UTIL_SetOrigin( pev, vOrigin );
if ( dropped )
UTIL_LogPrintf( "\"<-1><><>\" triggered triggered \"Respawn_ResistRune\"\n" );
Spawn();
}
void CResistRune::MakeTouchable ( void )
{
m_bTouchable = TRUE;
pev->nextthink = gpGlobals->time + 120; // if no one touches it in two minutes,
// respawn it somewhere else, so inaccessible
// ones will come 'back'
SetThink ( &CResistRune::RuneRespawn );
}
void CResistRune::Spawn ( void )
{
SET_MODEL( ENT(pev), "models/rune_resist.mdl");
m_bTouchable = FALSE;
m_iRuneFlag = ITEM_RUNE1_FLAG;
dropped = false;
pev->movetype = MOVETYPE_TOSS;
pev->solid = SOLID_TRIGGER;
vec3_t forward, right, up;
UTIL_SetSize( pev, Vector(-15, -15, -15), Vector(15, 15, 15) );
pev->angles.z = pev->angles.x = 0;
pev->angles.y = RANDOM_LONG ( 0, 360 );
//If we got an owner, it means we are either dropping the flag or diying and letting it go.
if ( pev->owner )
g_engfuncs.pfnAngleVectors ( pev->owner->v.angles, forward, right, up );
else
g_engfuncs.pfnAngleVectors ( pev->angles, forward, right, up);
UTIL_SetOrigin( pev, pev->origin );
pev->velocity = ( forward * 400 ) + ( up * 200 );
if ( pev->owner == NULL )
{
pev->origin.z += 16;
pev->velocity.z = 300;
}
pev->owner = NULL;
SetTouch( &CResistRune::RuneTouch );
pev->nextthink = gpGlobals->time + 1;
SetThink ( &CResistRune::MakeTouchable );
}
LINK_ENTITY_TO_CLASS( item_rune1, CResistRune );
void CStrengthRune::MakeTouchable ( void )
{
m_bTouchable = TRUE;
pev->nextthink = gpGlobals->time + 120; // if no one touches it in two minutes,
// respawn it somewhere else, so inaccessible
// ones will come 'back'
SetThink ( &CStrengthRune::RuneRespawn );
}
void CStrengthRune::RuneTouch ( CBaseEntity *pOther )
{
//No toucher?
if ( !pOther )
return;
//Not a player?
if ( !pOther->IsPlayer() )
return;
//DEAD?!
if ( pOther->pev->health <= 0 )
return;
//Spectating?
if ( pOther->pev->movetype == MOVETYPE_NOCLIP )
return;
//Only one per customer
if ( ((CBasePlayer *)pOther)->m_iRuneStatus )
{
ClientPrint( pOther->pev, HUD_PRINTCENTER, "You already have a rune!\n" );
return;
}
if ( !m_bTouchable )
return;
((CBasePlayer *)pOther)->m_iRuneStatus = m_iRuneFlag; //Add me the rune flag
ClientPrint( pOther->pev, HUD_PRINTCENTER, "You got the rune of Strength!\n" );
UTIL_LogPrintf( "\"%s<%i><%s><%s>\" triggered \"Found_StrengthRune\"\n",
STRING(pOther->pev->netname),
GETPLAYERUSERID( pOther->edict() ),
GETPLAYERAUTHID( pOther->edict() ),
((CBasePlayer *)pOther)->m_szTeamName );
EMIT_SOUND( ENT(pev), CHAN_ITEM, "weapons/lock4.wav", 1, ATTN_NORM );
//Update my client side rune hud thingy.
MESSAGE_BEGIN( MSG_ONE, gmsgRuneStatus, NULL, pOther->pev);
WRITE_BYTE( ((CBasePlayer *)pOther)->m_iRuneStatus );
MESSAGE_END();
//And Remove this entity
UTIL_Remove( this );
}
void CStrengthRune::RuneRespawn ( void )
{
edict_t *pentSpawnSpot;
vec3_t vOrigin;
pentSpawnSpot = RuneSelectSpawnPoint();
vOrigin = VARS(pentSpawnSpot)->origin;
UTIL_SetOrigin( pev, vOrigin );
if ( dropped )
UTIL_LogPrintf( "\"<-1><><>\" triggered triggered \"Respawn_StrengthRune\"\n" );
Spawn();
}
void CStrengthRune::Spawn ( void )
{
SET_MODEL( ENT(pev), "models/rune_strength.mdl");
m_bTouchable = FALSE;
m_iRuneFlag = ITEM_RUNE2_FLAG;
dropped = false;
pev->movetype = MOVETYPE_TOSS;
pev->solid = SOLID_TRIGGER;
vec3_t forward, right, up;
UTIL_SetSize( pev, Vector(-15, -15, -15), Vector(15, 15, 15) );
pev->angles.z = pev->angles.x = 0;
pev->angles.y = RANDOM_LONG ( 0, 360 );
//If we got an owner, it means we are either dropping the flag or diying and letting it go.
if ( pev->owner )
g_engfuncs.pfnAngleVectors ( pev->owner->v.angles, forward, right, up);
else
g_engfuncs.pfnAngleVectors ( pev->angles, forward, right, up);
UTIL_SetOrigin( pev, pev->origin );
pev->velocity = ( forward * 400 ) + ( up * 200 );
if ( pev->owner == NULL )
{
pev->origin.z += 16;
pev->velocity.z = 300;
}
pev->owner = NULL;
SetTouch( &CStrengthRune::RuneTouch );
pev->nextthink = gpGlobals->time + 1;
SetThink ( &CStrengthRune::MakeTouchable );
}
LINK_ENTITY_TO_CLASS( item_rune2, CStrengthRune );
void CHasteRune::MakeTouchable ( void )
{
m_bTouchable = TRUE;
pev->nextthink = gpGlobals->time + 120; // if no one touches it in two minutes,
// respawn it somewhere else, so inaccessible
// ones will come 'back'
SetThink ( &CHasteRune::RuneRespawn );
}
void CHasteRune::RuneTouch ( CBaseEntity *pOther )
{
//No toucher?
if ( !pOther )
return;
//Not a player?
if ( !pOther->IsPlayer() )
return;
//DEAD?!
if ( pOther->pev->health <= 0 )
return;
//Spectating?
if ( pOther->pev->movetype == MOVETYPE_NOCLIP )
return;
//Only one per customer
if ( ((CBasePlayer *)pOther)->m_iRuneStatus )
{
ClientPrint( pOther->pev, HUD_PRINTCENTER, "You already have a rune!\n" );
return;
}
if ( !m_bTouchable )
return;
((CBasePlayer *)pOther)->m_iRuneStatus = m_iRuneFlag; //Add me the rune flag
ClientPrint( pOther->pev, HUD_PRINTCENTER, "You got the rune of Haste!\n" );
UTIL_LogPrintf( "\"%s<%i><%s><%s>\" triggered \"Found_HasteRune\"\n",
STRING(pOther->pev->netname),
GETPLAYERUSERID( pOther->edict() ),
GETPLAYERAUTHID( pOther->edict() ),
((CBasePlayer *)pOther)->m_szTeamName );
g_engfuncs.pfnSetClientMaxspeed( ENT( pOther->pev ), ( PLAYER_MAX_SPEED * 1.25 ) ); //25% more speed
EMIT_SOUND( ENT(pev), CHAN_ITEM, "weapons/lock4.wav", 1, ATTN_NORM );
//Update my client side rune hud thingy.
MESSAGE_BEGIN( MSG_ONE, gmsgRuneStatus, NULL, pOther->pev);
WRITE_BYTE( ((CBasePlayer *)pOther)->m_iRuneStatus );
MESSAGE_END();
//And Remove this entity
UTIL_Remove( this );
}
void CHasteRune::RuneRespawn ( void )
{
edict_t *pentSpawnSpot;
vec3_t vOrigin;
pentSpawnSpot = RuneSelectSpawnPoint();
vOrigin = VARS(pentSpawnSpot)->origin;
UTIL_SetOrigin( pev, vOrigin );
if ( dropped )
UTIL_LogPrintf( "\"<-1><><>\" triggered triggered \"Respawn_HasteRune\"\n" );
Spawn();
}
void CHasteRune::Spawn ( void )
{
SET_MODEL( ENT(pev), "models/rune_haste.mdl");
m_bTouchable = FALSE;
m_iRuneFlag = ITEM_RUNE3_FLAG;
dropped = false;
pev->movetype = MOVETYPE_TOSS;
pev->solid = SOLID_TRIGGER;
vec3_t forward, right, up;
UTIL_SetSize( pev, Vector(-15, -15, -15), Vector(15, 15, 15) );
pev->angles.z = pev->angles.x = 0;
pev->angles.y = RANDOM_LONG ( 0, 360 );
//If we got an owner, it means we are either dropping the flag or diying and letting it go.
if ( pev->owner )
g_engfuncs.pfnAngleVectors ( pev->owner->v.angles, forward, right, up);
else
g_engfuncs.pfnAngleVectors ( pev->angles, forward, right, up);
UTIL_SetOrigin( pev, pev->origin );
pev->velocity = ( forward * 400 ) + ( up * 200 );
if ( pev->owner == NULL )
{
pev->origin.z += 16;
pev->velocity.z = 300;
}
pev->owner = NULL;
SetTouch( &CHasteRune::RuneTouch );
pev->nextthink = gpGlobals->time + 1; // if no one touches it in two minutes,
// respawn it somewhere else, so inaccessible
// ones will come 'back'
SetThink ( &CHasteRune::MakeTouchable );
}
LINK_ENTITY_TO_CLASS( item_rune3, CHasteRune );
void CRegenRune::MakeTouchable ( void )
{
m_bTouchable = TRUE;
pev->nextthink = gpGlobals->time + 120; // if no one touches it in two minutes,
// respawn it somewhere else, so inaccessible
// ones will come 'back'
SetThink ( &CRegenRune::RuneRespawn );
}
void CRegenRune::RuneTouch ( CBaseEntity *pOther )
{
//No toucher?
if ( !pOther )
return;
//Not a player?
if ( !pOther->IsPlayer() )
return;
//DEAD?!
if ( pOther->pev->health <= 0 )
return;
//Spectating?
if ( pOther->pev->movetype == MOVETYPE_NOCLIP )
return;
//Only one per customer
if ( ((CBasePlayer *)pOther)->m_iRuneStatus )
{
ClientPrint( pOther->pev, HUD_PRINTCENTER, "You already have a rune!\n" );
return;
}
if ( !m_bTouchable )
return;
((CBasePlayer *)pOther)->m_iRuneStatus = m_iRuneFlag; //Add me the rune flag
ClientPrint( pOther->pev, HUD_PRINTCENTER, "You got the rune of Regeneration!\n" );
UTIL_LogPrintf( "\"%s<%i><%s><%s>\" triggered \"Found_RegenRune\"\n",
STRING(pOther->pev->netname),
GETPLAYERUSERID( pOther->edict() ),
GETPLAYERAUTHID( pOther->edict() ),
((CBasePlayer *)pOther)->m_szTeamName );
EMIT_SOUND( ENT(pev), CHAN_ITEM, "weapons/lock4.wav", 1, ATTN_NORM );
//Update my client side rune hud thingy.
MESSAGE_BEGIN( MSG_ONE, gmsgRuneStatus, NULL, pOther->pev);
WRITE_BYTE( ((CBasePlayer *)pOther)->m_iRuneStatus );
MESSAGE_END();
//And Remove this entity
UTIL_Remove( this );
}
void CRegenRune::RuneRespawn ( void )
{
edict_t *pentSpawnSpot;
vec3_t vOrigin;
pentSpawnSpot = RuneSelectSpawnPoint();
vOrigin = VARS(pentSpawnSpot)->origin;
UTIL_SetOrigin( pev, vOrigin );
if ( dropped )
UTIL_LogPrintf( "\"<-1><><>\" triggered triggered \"Respawn_RegenRune\"\n" );
Spawn();
}
void CRegenRune::Spawn ( void )
{
SET_MODEL( ENT(pev), "models/rune_regen.mdl" );
m_bTouchable = FALSE;
m_iRuneFlag = ITEM_RUNE4_FLAG;
dropped = false;
pev->movetype = MOVETYPE_TOSS;
pev->solid = SOLID_TRIGGER;
vec3_t forward, right, up;
UTIL_SetSize( pev, Vector(-15, -15, -15), Vector(15, 15, 15) );
pev->angles.z = pev->angles.x = 0;
pev->angles.y = RANDOM_LONG ( 0, 360 );
//If we got an owner, it means we are either dropping the flag or diying and letting it go.
if ( pev->owner )
g_engfuncs.pfnAngleVectors ( pev->owner->v.angles, forward, right, up);
else
g_engfuncs.pfnAngleVectors ( pev->angles, forward, right, up);
UTIL_SetOrigin( pev, pev->origin );
pev->velocity = ( forward * 400 ) + ( up * 200 );
if ( pev->owner == NULL )
{
pev->origin.z += 16;
pev->velocity.z = 300;
}
pev->owner = NULL;
SetTouch( &CRegenRune::RuneTouch );
pev->nextthink = gpGlobals->time + 1; // if no one touches it in two minutes,
// respawn it somewhere else, so inaccessible
// ones will come 'back'
SetThink ( &CRegenRune::MakeTouchable );
}
LINK_ENTITY_TO_CLASS( item_rune4, CRegenRune );
/*
================
SpawnRunes
spawn all the runes
self is the entity that was created for us, we remove it
================
*/
void SpawnRunes( void )
{
if ( g_bSpawnedRunes )
return;
edict_t *pentSpawnSpot;
pentSpawnSpot = RuneSelectSpawnPoint();
CBaseEntity::Create( "item_rune1", VARS(pentSpawnSpot)->origin, VARS(pentSpawnSpot)->angles, NULL );
pentSpawnSpot = RuneSelectSpawnPoint();
CBaseEntity::Create( "item_rune2", VARS(pentSpawnSpot)->origin, VARS(pentSpawnSpot)->angles, NULL );
pentSpawnSpot = RuneSelectSpawnPoint();
CBaseEntity::Create( "item_rune3", VARS(pentSpawnSpot)->origin, VARS(pentSpawnSpot)->angles, NULL );
pentSpawnSpot = RuneSelectSpawnPoint();
CBaseEntity::Create( "item_rune4", VARS(pentSpawnSpot)->origin, VARS(pentSpawnSpot)->angles, NULL );
g_bSpawnedRunes = TRUE;
}
/***********************************************
************************************************
GRAPPLE
************************************************
***********************************************/
void CGrapple::Reset_Grapple ( void )
{
CBaseEntity *pOwner = CBaseEntity::Instance( pev->owner );
((CBasePlayer *)pOwner)->m_bOn_Hook = FALSE;
((CBasePlayer *)pOwner)->m_bHook_Out = FALSE;
PLAYBACK_EVENT_FULL( FEV_GLOBAL | FEV_RELIABLE,
((CBasePlayer *)pOwner)->edict(), g_usCable, 0, (float *)&g_vecZero, (float *)&g_vecZero,
0.0, 0.0, entindex(), pev->team, 1, 0 );
STOP_SOUND( edict(), CHAN_WEAPON, "weapons/grhang.wav" );
STOP_SOUND( ((CBasePlayer *)pOwner)->edict(), CHAN_WEAPON, "weapons/grfire.wav" );
STOP_SOUND( ((CBasePlayer *)pOwner)->edict(), CHAN_WEAPON, "weapons/grpull.wav" );
((CBasePlayer *)pOwner)->m_ppHook = NULL;
pev->enemy = NULL;
UTIL_Remove ( this );
}
void CGrapple::GrappleTouch ( CBaseEntity *pOther )
{
CBaseEntity *pOwner = CBaseEntity::Instance( pev->owner );
if ( pOther == pOwner )
return;
// DO NOT allow the grapple to hook to any projectiles, no matter WHAT!
// if you create new types of projectiles, make sure you use one of the
// classnames below or write code to exclude your new classname so
// grapples will not stick to them.
if ( FClassnameIs( pOther->pev, "grenade" )||
FClassnameIs( pOther->pev, "spike" ) ||
FClassnameIs( pOther->pev, "hook" ) )
return;
if ( FClassnameIs( pOther->pev, "player" ) )
{
// glance off of teammates
if ( pOther->pev->team == pOwner->pev->team )
return;
// sound (self, CHAN_WEAPON, "player/axhit1.wav", 1, ATTN_NORM);
//TakeDamage( pOther->pev, pOwner->pev, 10, DMG_GENERIC );
// make hook invisible since we will be pulling directly
// towards the player the hook hit. Quakeworld makes it
// too quirky to try to match hook's velocity with that of
// the client that it hit.
// setmodel (self, "");
pev->velocity = Vector(0,0,0);
UTIL_SetOrigin( pev, pOther->pev->origin);
}
else if ( !FClassnameIs( pOther->pev, "player" ) )
{
// sound (self, CHAN_WEAPON, "player/axhit2.wav", 1, ATTN_NORM);
// One point of damage inflicted upon impact. Subsequent
// damage will only be done to PLAYERS... this way secret
// doors and triggers will only be damaged once.
if ( pOther->pev->takedamage )
TakeDamage( pOther->pev, pOwner->pev, 1, DMG_GENERIC );
pev->velocity = Vector(0,0,0);
EMIT_SOUND( ENT( pev ), CHAN_WEAPON, "weapons/grhit.wav", 1, ATTN_NORM);
//No sparks underwater
if ( pev->waterlevel == 0 )
UTIL_Sparks( pev->origin );
}
// conveniently clears the sound channel of the CHAIN1 sound,
// which is a looping sample and would continue to play. Tink1 is
// the least offensive choice, ass NULL.WAV loops and clogs the
// channel with silence
// sound (self.owner, CHAN_NO_PHS_ADD+CHAN_WEAPON, "weapons/tink1.wav", 1, ATTN_NORM);
if ( !(pOwner->pev->button & IN_ATTACK) )
{
if ( ((CBasePlayer*)pOwner)->m_bOn_Hook )
{
Reset_Grapple();
return;
}
}
if ( pOwner->pev->flags & FL_ONGROUND)
{
pOwner->pev->flags &= ~FL_ONGROUND;
// setorigin(self.owner,self.owner.origin + '0 0 1');
}
((CBasePlayer*)pOwner)->m_bOn_Hook = TRUE;
// sound (self.owner, CHAN_WEAPON, "weapons/chain2.wav", 1, ATTN_NORM);
// CHAIN2 is a looping sample. Use LEFTY as a flag so that client.qc
// will know to only play the tink sound ONCE to clear the weapons
// sound channel. (Lefty is a leftover from AI.QC, so I reused it to
// avoid adding a field)
//self.owner.lefty = TRUE;
STOP_SOUND( ((CBasePlayer *)pOwner)->edict(), CHAN_WEAPON, "weapons/grfire.wav" );
pev->enemy = pOther->edict();// remember this guy!
SetThink ( &CGrapple::Grapple_Track );
pev->nextthink = gpGlobals->time;
m_flNextIdleTime = gpGlobals->time + 0.1;
pev->solid = SOLID_NOT;
SetTouch ( NULL );
};
bool CanSee ( CBaseEntity *pEnemy, CBaseEntity *pOwner )
{
TraceResult tr;
UTIL_TraceLine ( pOwner->pev->origin, pEnemy->pev->origin, ignore_monsters, ENT( pOwner->pev ), &tr);
if ( tr.flFraction == 1 )
return TRUE;
UTIL_TraceLine ( pOwner->pev->origin, pEnemy->pev->origin + Vector( 15, 15, 0 ), ignore_monsters, ENT( pOwner->pev ), &tr);
if ( tr.flFraction == 1 )
return TRUE;
UTIL_TraceLine ( pOwner->pev->origin, pEnemy->pev->origin + Vector( -15, -15, 0 ), ignore_monsters, ENT( pOwner->pev ), &tr);
if ( tr.flFraction == 1 )
return TRUE;
UTIL_TraceLine ( pOwner->pev->origin, pEnemy->pev->origin + Vector( -15, 15, 0 ), ignore_monsters, ENT( pOwner->pev ), &tr);
if ( tr.flFraction == 1 )
return TRUE;
UTIL_TraceLine ( pOwner->pev->origin, pEnemy->pev->origin + Vector( 15, -15, 0 ), ignore_monsters, ENT( pOwner->pev ), &tr);
if ( tr.flFraction == 1 )
return TRUE;
return FALSE;
}
void CGrapple::Grapple_Track ( void )
{
CBaseEntity *pOwner = CBaseEntity::Instance( pev->owner );
CBaseEntity *pEnemy = CBaseEntity::Instance( pev->enemy );
// Release dead targets
if ( FClassnameIs( pEnemy->pev, "player" ) && pEnemy->pev->health <= 0)
Reset_Grapple();
// drop the hook if owner is dead or has released the button
if ( !((CBasePlayer*)pOwner)->m_bOn_Hook|| ((CBasePlayer*)pOwner)->pev->health <= 0)
{
Reset_Grapple();
return;
}
if ( !(pOwner->pev->button & IN_ATTACK) )
{
if ( ((CBasePlayer*)pOwner)->m_iQuakeWeapon == IT_EXTRA_WEAPON )
{
Reset_Grapple();
return;
}
}
// bring the pAiN!
if ( FClassnameIs( pEnemy->pev, "player" ) )
{
if ( !CanSee( pEnemy, pOwner ) )
{
Reset_Grapple();
return;
}
// move the hook along with the player. It's invisible, but
// we need this to make the sound come from the right spot
UTIL_SetOrigin( pev, pEnemy->pev->origin);
//sound (self, CHAN_WEAPON, "blob/land1.wav", 1, ATTN_NORM);
SpawnBlood( pEnemy->pev->origin, BLOOD_COLOR_RED, 1 );
((CBasePlayer *)pEnemy)->TakeDamage( pev, pOwner->pev, 1, DMG_GENERIC );
}
// If the hook is not attached to the player, constantly copy
// copy the target's velocity. Velocity copying DOES NOT work properly
// for a hooked client.
if ( !FClassnameIs( pEnemy->pev, "player" ) )
pev->velocity = pEnemy->pev->velocity;
pev->nextthink = gpGlobals->time + 0.1;
};
void CBasePlayer::Service_Grapple ( void )
{
Vector hook_dir;
CBaseEntity *pEnemy = CBaseEntity::Instance( pev->enemy );
// drop the hook if player lets go of button
if ( !(pev->button & IN_ATTACK) )
{
if ( m_iQuakeWeapon == IT_EXTRA_WEAPON )
{
((CGrapple *)m_ppHook)->Reset_Grapple();
return;
}
}
if ( m_ppHook->pev->enemy != NULL )
{
// If hooked to a player, track them directly!
if ( FClassnameIs( pEnemy->pev, "player" ) )
{
pEnemy = CBaseEntity::Instance( pev->enemy );
hook_dir = ( pEnemy->pev->origin - pev->origin );
}
// else, track to hook
else if ( !FClassnameIs( pEnemy->pev, "player" ) )
hook_dir = ( m_ppHook->pev->origin - pev->origin );
pev->velocity = ( (hook_dir).Normalize() * 750 );
pev->speed = 750;
if ( ((CGrapple *)m_ppHook)->m_flNextIdleTime <= gpGlobals->time && (hook_dir).Length() <= 50 )
{
//No sparks underwater
if ( m_ppHook->pev->waterlevel == 0 )
UTIL_Sparks( m_ppHook->pev->origin );
STOP_SOUND( edict(), CHAN_WEAPON, "weapons/grpull.wav" );
EMIT_SOUND( ENT( m_ppHook->pev ), CHAN_WEAPON, "weapons/grhang.wav", 1, ATTN_NORM);
((CGrapple *)m_ppHook)->m_flNextIdleTime = gpGlobals->time + RANDOM_LONG( 1, 3 );
PLAYBACK_EVENT_FULL( FEV_GLOBAL | FEV_RELIABLE,
edict(), g_usCable, 0, (float *)&g_vecZero, (float *)&g_vecZero,
0.0, 0.0, m_ppHook->entindex(), pev->team, 1, 0 );
}
else if ( ((CGrapple *)m_ppHook)->m_flNextIdleTime <= gpGlobals->time )
{
//No sparks underwater
if ( m_ppHook->pev->waterlevel == 0 )
UTIL_Sparks( m_ppHook->pev->origin );
STOP_SOUND( edict(), CHAN_WEAPON, "weapons/grfire.wav" );
EMIT_SOUND( ENT( pev ), CHAN_WEAPON, "weapons/grpull.wav", 1, ATTN_NORM);
((CGrapple *)m_ppHook)->m_flNextIdleTime = gpGlobals->time + RANDOM_LONG( 1, 3 );
}
}
};
void CGrapple::OnAirThink ( void )
{
TraceResult tr;
CBaseEntity *pOwner = CBaseEntity::Instance( pev->owner );
if ( !(pOwner->pev->button & IN_ATTACK) )
{
Reset_Grapple();
return;
}
UTIL_TraceLine ( pev->origin, pOwner->pev->origin, ignore_monsters, ENT(pev), &tr);
if ( tr.flFraction < 1.0 )
{
Reset_Grapple();
return;
}
pev->nextthink = gpGlobals->time + 0.5;
}
void CGrapple::Spawn ( void )
{
pev->movetype = MOVETYPE_FLYMISSILE;
pev->solid = SOLID_BBOX;
SET_MODEL ( ENT(pev),"models/hook.mdl");
SetTouch ( &CGrapple::GrappleTouch );
SetThink ( &CGrapple::OnAirThink );
pev->nextthink = gpGlobals->time + 0.1;
}
LINK_ENTITY_TO_CLASS( hook, CGrapple );
void CBasePlayer::Throw_Grapple ( void )
{
if ( m_bHook_Out )
return;
CBaseEntity *pHookCBEnt = NULL;
pHookCBEnt = CBaseEntity::Create( "hook", pev->origin, pev->angles, NULL );
if ( pHookCBEnt )
{
m_ppHook = pHookCBEnt;
m_ppHook->pev->owner = edict();
UTIL_MakeVectors ( pev->v_angle);
UTIL_SetOrigin ( m_ppHook->pev , pev->origin + gpGlobals->v_forward * 16 + Vector( 0, 0, 16 ) );
UTIL_SetSize( m_ppHook->pev, Vector(0,0,0) , Vector(0,0,0) );
EMIT_SOUND( ENT( pev ), CHAN_WEAPON, "weapons/grfire.wav", 1, ATTN_NORM);
//Make if fly forward
m_ppHook->pev->velocity = gpGlobals->v_forward * 1000;
//And make the hook face forward too!
m_ppHook->pev->angles = UTIL_VecToAngles ( gpGlobals->v_forward );
m_ppHook->pev->fixangle = TRUE;
PLAYBACK_EVENT_FULL( FEV_GLOBAL | FEV_RELIABLE,
edict(), g_usCable, 0, (float *)&g_vecZero, (float *)&g_vecZero,
0.0, 0.0, m_ppHook->entindex(), pev->team, 0, 0 );
m_bHook_Out = TRUE;
}
};