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.
995 lines
27 KiB
995 lines
27 KiB
/* |
|
Copyright (c) 1999, Cold Ice Modification. |
|
|
|
This code has been written by SlimShady ( darcuri@optonline.net ) |
|
|
|
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 and from the Cold Ice team. |
|
|
|
Please if you use this code in any public form, please give us credit. |
|
|
|
*/ |
|
|
|
#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" |
|
|
|
extern DLL_GLOBAL CGameRules *g_pGameRules; |
|
extern DLL_GLOBAL BOOL g_fGameOver; |
|
extern int gmsgDeathMsg; // client dll messages |
|
extern int gmsgScoreInfo; |
|
extern int gmsgMOTD; |
|
|
|
#define ITEM_RESPAWN_TIME 30 |
|
#define WEAPON_RESPAWN_TIME 20 |
|
#define AMMO_RESPAWN_TIME 20 |
|
|
|
//********************************************************* |
|
// Rules for Cold Ice Railgun Arena |
|
//********************************************************* |
|
|
|
CRailArena :: CRailArena() |
|
{ |
|
RefreshSkillData(); |
|
m_flIntermissionEndTime = 0; |
|
|
|
if ( IS_DEDICATED_SERVER() ) |
|
{ |
|
// dedicated server |
|
char *servercfgfile = (char *)CVAR_GET_STRING( "servercfgfile" ); |
|
|
|
if ( servercfgfile && servercfgfile[0] ) |
|
{ |
|
char szCommand[256]; |
|
|
|
ALERT( at_console, "Executing dedicated server config file\n" ); |
|
sprintf( szCommand, "exec %s\n", servercfgfile ); |
|
SERVER_COMMAND( szCommand ); |
|
} |
|
} |
|
else |
|
{ |
|
// listen server |
|
char *lservercfgfile = (char *)CVAR_GET_STRING( "lservercfgfile" ); |
|
|
|
if ( lservercfgfile && lservercfgfile[0] ) |
|
{ |
|
char szCommand[256]; |
|
|
|
ALERT( at_console, "Executing listen server config file\n" ); |
|
sprintf( szCommand, "exec %s\n", lservercfgfile ); |
|
SERVER_COMMAND( szCommand ); |
|
} |
|
|
|
} |
|
} |
|
|
|
//========================================================= |
|
//========================================================= |
|
void CRailArena::RefreshSkillData( void ) |
|
{ |
|
CGameRules::RefreshSkillData(); |
|
|
|
// suitcharger |
|
gSkillData.suitchargerCapacity = 30; |
|
|
|
// Rocket |
|
gSkillData.plrDmgRailgun = 145; |
|
|
|
} |
|
|
|
// longest the intermission can last, in seconds |
|
#define MAX_INTERMISSION_TIME 120 |
|
|
|
//========================================================= |
|
//========================================================= |
|
void CRailArena :: Think ( void ) |
|
{ |
|
///// Check game rules ///// |
|
|
|
if ( g_fGameOver ) // someone else quit the game already |
|
{ |
|
if ( m_flIntermissionEndTime < gpGlobals->time ) |
|
{ |
|
if ( m_iEndIntermissionButtonHit // check that someone has pressed a key, or the max intermission time is over |
|
|| ((m_flIntermissionEndTime + MAX_INTERMISSION_TIME) < gpGlobals->time) ) |
|
ChangeLevel(); // intermission is over |
|
} |
|
return; |
|
} |
|
|
|
float flTimeLimit = timelimit.value * 60; |
|
float flFragLimit = fraglimit.value; |
|
|
|
if ( flTimeLimit != 0 && gpGlobals->time >= flTimeLimit ) |
|
{ |
|
GoToIntermission(); |
|
return; |
|
} |
|
|
|
if ( flFragLimit ) |
|
{ |
|
// check if any player is over the frag limit |
|
for ( int i = 1; i <= gpGlobals->maxClients; i++ ) |
|
{ |
|
CBaseEntity *pPlayer = UTIL_PlayerByIndex( i ); |
|
|
|
if ( pPlayer && pPlayer->pev->frags >= flFragLimit ) |
|
{ |
|
GoToIntermission(); |
|
return; |
|
} |
|
} |
|
} |
|
|
|
} |
|
|
|
|
|
//========================================================= |
|
//========================================================= |
|
BOOL CRailArena::IsMultiplayer( void ) |
|
{ |
|
return TRUE; |
|
} |
|
|
|
//========================================================= |
|
//========================================================= |
|
BOOL CRailArena::IsDeathmatch( void ) |
|
{ |
|
return TRUE; |
|
} |
|
|
|
//========================================================= |
|
//========================================================= |
|
BOOL CRailArena::IsRailArena( void ) |
|
{ |
|
return TRUE; |
|
} |
|
|
|
//========================================================= |
|
//========================================================= |
|
BOOL CRailArena::IsCoOp( void ) |
|
{ |
|
return gpGlobals->coop; |
|
} |
|
|
|
//========================================================= |
|
//========================================================= |
|
BOOL CRailArena::FShouldSwitchWeapon( CBasePlayer *pPlayer, CBasePlayerItem *pWeapon ) |
|
{ |
|
if ( !pWeapon->CanDeploy() ) |
|
{ |
|
// that weapon can't deploy anyway. |
|
return FALSE; |
|
} |
|
|
|
if ( !pPlayer->m_pActiveItem ) |
|
{ |
|
// player doesn't have an active item! |
|
return TRUE; |
|
} |
|
|
|
if ( !pPlayer->m_pActiveItem->CanHolster() ) |
|
{ |
|
// can't put away the active item. |
|
return FALSE; |
|
} |
|
|
|
if ( pWeapon->iWeight() > pPlayer->m_pActiveItem->iWeight() ) |
|
{ |
|
return TRUE; |
|
} |
|
|
|
return FALSE; |
|
} |
|
|
|
BOOL CRailArena :: GetNextBestWeapon( CBasePlayer *pPlayer, CBasePlayerItem *pCurrentWeapon ) |
|
{ |
|
|
|
CBasePlayerItem *pCheck; |
|
CBasePlayerItem *pBest;// this will be used in the event that we don't find a weapon in the same category. |
|
int iBestWeight; |
|
int i; |
|
|
|
iBestWeight = -1;// no weapon lower than -1 can be autoswitched to |
|
pBest = NULL; |
|
|
|
if ( !pCurrentWeapon->CanHolster() ) |
|
{ |
|
// can't put this gun away right now, so can't switch. |
|
return FALSE; |
|
} |
|
|
|
for ( i = 0 ; i < MAX_ITEM_TYPES ; i++ ) |
|
{ |
|
pCheck = pPlayer->m_rgpPlayerItems[ i ]; |
|
|
|
while ( pCheck ) |
|
{ |
|
if ( pCheck->iWeight() > -1 && pCheck->iWeight() == pCurrentWeapon->iWeight() && pCheck != pCurrentWeapon ) |
|
{ |
|
// this weapon is from the same category. |
|
if ( pCheck->CanDeploy() ) |
|
{ |
|
if ( pPlayer->SwitchWeapon( pCheck ) ) |
|
{ |
|
return TRUE; |
|
} |
|
} |
|
} |
|
else if ( pCheck->iWeight() > iBestWeight && pCheck != pCurrentWeapon )// don't reselect the weapon we're trying to get rid of |
|
{ |
|
//ALERT ( at_console, "Considering %s\n", STRING( pCheck->pev->classname ) ); |
|
// we keep updating the 'best' weapon just in case we can't find a weapon of the same weight |
|
// that the player was using. This will end up leaving the player with his heaviest-weighted |
|
// weapon. |
|
if ( pCheck->CanDeploy() ) |
|
{ |
|
// if this weapon is useable, flag it as the best |
|
iBestWeight = pCheck->iWeight(); |
|
pBest = pCheck; |
|
} |
|
} |
|
|
|
pCheck = pCheck->m_pNext; |
|
} |
|
} |
|
|
|
// if we make it here, we've checked all the weapons and found no useable |
|
// weapon in the same catagory as the current weapon. |
|
|
|
// if pBest is null, we didn't find ANYTHING. Shouldn't be possible- should always |
|
// at least get the crowbar, but ya never know. |
|
if ( !pBest ) |
|
{ |
|
return FALSE; |
|
} |
|
|
|
pPlayer->SwitchWeapon( pBest ); |
|
|
|
return TRUE; |
|
} |
|
|
|
//========================================================= |
|
//========================================================= |
|
BOOL CRailArena :: ClientConnected( edict_t *pEntity, const char *pszName, const char *pszAddress, char szRejectReason[ 128 ] ) |
|
{ |
|
return TRUE; |
|
} |
|
|
|
extern int gmsgSayText; |
|
extern int gmsgGameMode; |
|
|
|
void CRailArena :: UpdateGameMode( CBasePlayer *pPlayer ) |
|
{ |
|
MESSAGE_BEGIN( MSG_ONE, gmsgGameMode, NULL, pPlayer->edict() ); |
|
WRITE_BYTE( 0 ); // game mode none |
|
MESSAGE_END(); |
|
} |
|
|
|
void CRailArena :: InitHUD( CBasePlayer *pl ) |
|
{ |
|
// notify other clients of player joining the game |
|
UTIL_ClientPrintAll( HUD_PRINTNOTIFY, UTIL_VarArgs( "%s has joined the game\n", |
|
( pl->pev->netname && STRING(pl->pev->netname)[0] != 0 ) ? STRING(pl->pev->netname) : "unconnected" ) ); |
|
|
|
UTIL_LogPrintf( "\"%s<%i>\" has entered the game\n", STRING( pl->pev->netname ), GETPLAYERUSERID( pl->edict() ) ); |
|
|
|
UpdateGameMode( pl ); |
|
|
|
// sending just one score makes the hud scoreboard active; otherwise |
|
// it is just disabled for single play |
|
MESSAGE_BEGIN( MSG_ONE, gmsgScoreInfo, NULL, pl->edict() ); |
|
WRITE_BYTE( ENTINDEX(pl->edict()) ); |
|
WRITE_SHORT( 0 ); |
|
WRITE_SHORT( 0 ); |
|
MESSAGE_END(); |
|
|
|
SendMOTDToClient( pl->edict() ); |
|
|
|
// loop through all active players and send their score info to the new client |
|
for ( int i = 1; i <= gpGlobals->maxClients; i++ ) |
|
{ |
|
// FIXME: Probably don't need to cast this just to read m_iDeaths |
|
CBasePlayer *plr = (CBasePlayer *)UTIL_PlayerByIndex( i ); |
|
|
|
if ( plr ) |
|
{ |
|
MESSAGE_BEGIN( MSG_ONE, gmsgScoreInfo, NULL, pl->edict() ); |
|
WRITE_BYTE( i ); // client number |
|
WRITE_SHORT( plr->pev->frags ); |
|
WRITE_SHORT( plr->m_iDeaths ); |
|
MESSAGE_END(); |
|
} |
|
} |
|
|
|
if ( g_fGameOver ) |
|
{ |
|
MESSAGE_BEGIN( MSG_ONE, SVC_INTERMISSION, NULL, pl->edict() ); |
|
MESSAGE_END(); |
|
} |
|
|
|
pl->StartSpectator(); |
|
pl->m_nMenu = Menu_Spec; |
|
ShowMenu(pl, 0x3, 0, 0," Welcome to Cold Ice Beta1 2x\n\nCold-Ice Railgun Arena Mode\n\n1. Join Game\n2. Observe Game"); |
|
|
|
} |
|
|
|
//========================================================= |
|
//========================================================= |
|
void CRailArena :: ClientDisconnected( edict_t *pClient ) |
|
{ |
|
if ( pClient ) |
|
{ |
|
CBasePlayer *pPlayer = (CBasePlayer *)CBaseEntity::Instance( pClient ); |
|
|
|
if ( pPlayer ) |
|
{ |
|
FireTargets( "game_playerleave", pPlayer, pPlayer, USE_TOGGLE, 0 ); |
|
UTIL_LogPrintf( "\"%s<%i>\" left from Railgun Arena\n", STRING( pPlayer->pev->netname ), GETPLAYERUSERID( pPlayer->edict() ) ); |
|
|
|
pPlayer->RemoveAllItems( TRUE );// destroy all of the players weapons and items |
|
} |
|
} |
|
} |
|
|
|
//========================================================= |
|
//========================================================= |
|
float CRailArena :: FlPlayerFallDamage( CBasePlayer *pPlayer ) |
|
{ |
|
int iFallDamage = (int)CVAR_GET_FLOAT("mp_falldamage"); |
|
|
|
switch ( iFallDamage ) |
|
{ |
|
case 1://progressive |
|
pPlayer->m_flFallVelocity -= PLAYER_MAX_SAFE_FALL_SPEED; |
|
return pPlayer->m_flFallVelocity * DAMAGE_FOR_FALL_SPEED; |
|
break; |
|
default: |
|
case 0:// fixed |
|
return 10; |
|
break; |
|
} |
|
} |
|
|
|
//========================================================= |
|
//========================================================= |
|
BOOL CRailArena::FPlayerCanTakeDamage( CBasePlayer *pPlayer, CBaseEntity *pAttacker ) |
|
{ |
|
return TRUE; |
|
} |
|
|
|
//========================================================= |
|
//========================================================= |
|
void CRailArena :: 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; |
|
} |
|
|
|
} |
|
//========================================================= |
|
//========================================================= |
|
BOOL CRailArena :: ClientCommand( CBasePlayer *pPlayer, const char *pcmd ) |
|
{ |
|
|
|
if ( FStrEq( pcmd, "menuselect" ) ) |
|
{ |
|
|
|
int slot = atoi( CMD_ARGV(1) ); |
|
|
|
//============================================================= |
|
//============================================================= |
|
switch(pPlayer->m_nMenu) |
|
{ |
|
case Menu_Spec: |
|
if(slot == 1) |
|
pPlayer->StopSpectator(); |
|
else if (slot == 2) |
|
{ |
|
pPlayer->StartSpectator(); |
|
ShowMenu (pPlayer, 0x1, 0, 0, "Currently In Spectator Mode:\n\nHit Key 1 to exit and join the game. " ); |
|
} |
|
break; |
|
//============================================================= |
|
//============================================================= |
|
|
|
} |
|
return TRUE; |
|
} |
|
|
|
//============================================================= |
|
//============================================================= |
|
if (FStrEq(pcmd, "rune_status" )) |
|
{ |
|
|
|
if ( pPlayer->m_iPlayerRune == RUNE_SPEED ) |
|
ShowMenu (pPlayer, 0x1, 5, 0, "You Have Rune: Speed" ); |
|
else if ( pPlayer->m_iPlayerRune == RUNE_RESIST ) |
|
ShowMenu (pPlayer, 0x1, 5, 0, "You Have Rune: Resist" ); |
|
else if ( pPlayer->m_iPlayerRune == RUNE_STRENGTH ) |
|
ShowMenu (pPlayer, 0x1, 5, 0, "You Have Rune: Strength" ); |
|
else if ( pPlayer->m_iPlayerRune == RUNE_HEALTH ) |
|
ShowMenu (pPlayer, 0x1, 5, 0, "You Have Rune: Regeneration" ); |
|
else if ( pPlayer->m_iPlayerRune == RUNE_ROCKETARENA ) |
|
ShowMenu (pPlayer, 0x1, 5, 0, "You Have Rune: Rocket Arena Special" ); |
|
else |
|
ShowMenu (pPlayer, 0x1, 5, 0, "You Have No Runes." ); |
|
|
|
|
|
return TRUE; |
|
} |
|
//============================================================= |
|
//============================================================= |
|
else if ( FStrEq( pcmd, "stopobserv" ) ) |
|
{ |
|
pPlayer->StopSpectator(); |
|
return TRUE; |
|
} |
|
//============================================================= |
|
//============================================================= |
|
|
|
return FALSE; |
|
|
|
} |
|
|
|
//========================================================= |
|
//========================================================= |
|
void CRailArena :: PlayerSpawn( CBasePlayer *pPlayer ) |
|
{ |
|
BOOL addDefault; |
|
CBaseEntity *pWeaponEntity = NULL; |
|
|
|
pPlayer->pev->weapons |= (1<<WEAPON_SUIT); |
|
|
|
addDefault = TRUE; |
|
|
|
while ( pWeaponEntity = UTIL_FindEntityByClassname( pWeaponEntity, "game_player_equip" )) |
|
{ |
|
pWeaponEntity->Touch( pPlayer ); |
|
addDefault = FALSE; |
|
} |
|
|
|
if ( addDefault ) |
|
{ |
|
pPlayer->GiveNamedItem( "weapon_railgun" ); |
|
} |
|
} |
|
|
|
//========================================================= |
|
//========================================================= |
|
BOOL CRailArena :: FPlayerCanRespawn( CBasePlayer *pPlayer ) |
|
{ |
|
return pPlayer->m_fWantRespawn; |
|
} |
|
|
|
//========================================================= |
|
//========================================================= |
|
float CRailArena :: FlPlayerSpawnTime( CBasePlayer *pPlayer ) |
|
{ |
|
return gpGlobals->time;//now! |
|
} |
|
|
|
BOOL CRailArena :: AllowAutoTargetCrosshair( void ) |
|
{ |
|
return ( CVAR_GET_FLOAT( "mp_autocrosshair" ) != 0 ); |
|
} |
|
|
|
//========================================================= |
|
// IPointsForKill - how many points awarded to anyone |
|
// that kills this player? |
|
//========================================================= |
|
int CRailArena :: IPointsForKill( CBasePlayer *pAttacker, CBasePlayer *pKilled ) |
|
{ |
|
return 1; |
|
} |
|
|
|
|
|
//========================================================= |
|
// PlayerKilled - someone/something killed this player |
|
//========================================================= |
|
void CRailArena :: PlayerKilled( CBasePlayer *pVictim, entvars_t *pKiller, entvars_t *pInflictor ) |
|
{ |
|
DeathNotice( pVictim, pKiller, pInflictor ); |
|
|
|
pVictim->m_iDeaths += 1; |
|
|
|
|
|
FireTargets( "game_playerdie", pVictim, pVictim, USE_TOGGLE, 0 ); |
|
CBasePlayer *peKiller = NULL; |
|
CBaseEntity *ktmp = CBaseEntity::Instance( pKiller ); |
|
if ( ktmp && (ktmp->Classify() == CLASS_PLAYER) ) |
|
peKiller = (CBasePlayer*)ktmp; |
|
|
|
if ( pVictim->pev == pKiller ) |
|
{ // killed self |
|
pKiller->frags -= 1; |
|
} |
|
else if ( ktmp && ktmp->IsPlayer() ) |
|
{ |
|
// if a player dies in a deathmatch game and the killer is a client, award the killer some points |
|
pKiller->frags += IPointsForKill( peKiller, pVictim ); |
|
|
|
FireTargets( "game_playerkill", ktmp, ktmp, USE_TOGGLE, 0 ); |
|
} |
|
else |
|
{ // killed by the world |
|
pKiller->frags -= 1; |
|
} |
|
|
|
// update the scores |
|
// killed scores |
|
MESSAGE_BEGIN( MSG_ALL, gmsgScoreInfo ); |
|
WRITE_BYTE( ENTINDEX(pVictim->edict()) ); |
|
WRITE_SHORT( pVictim->pev->frags ); |
|
WRITE_SHORT( pVictim->m_iDeaths ); |
|
MESSAGE_END(); |
|
|
|
// killers score, if it's a player |
|
CBaseEntity *ep = CBaseEntity::Instance( pKiller ); |
|
if ( ep && ep->Classify() == CLASS_PLAYER ) |
|
{ |
|
CBasePlayer *PK = (CBasePlayer*)ep; |
|
|
|
MESSAGE_BEGIN( MSG_ALL, gmsgScoreInfo ); |
|
WRITE_BYTE( ENTINDEX(PK->edict()) ); |
|
WRITE_SHORT( PK->pev->frags ); |
|
WRITE_SHORT( PK->m_iDeaths ); |
|
MESSAGE_END(); |
|
|
|
// let the killer paint another decal as soon as he'd like. |
|
PK->m_flNextDecalTime = gpGlobals->time; |
|
} |
|
} |
|
|
|
//========================================================= |
|
// Deathnotice. |
|
//========================================================= |
|
void CRailArena::DeathNotice( CBasePlayer *pVictim, entvars_t *pKiller, entvars_t *pevInflictor ) |
|
{ |
|
// Work out what killed the player, and send a message to all clients about it |
|
CBaseEntity *Killer = CBaseEntity::Instance( pKiller ); |
|
|
|
const char *killer_weapon_name = "world"; // by default, the player is killed by the world |
|
int killer_index = 0; |
|
|
|
if ( pKiller->flags & FL_CLIENT ) |
|
{ |
|
killer_index = ENTINDEX(ENT(pKiller)); |
|
|
|
if ( pevInflictor ) |
|
{ |
|
if ( pevInflictor == pKiller ) |
|
{ |
|
// If the inflictor is the killer, then it must be their current weapon doing the damage |
|
CBasePlayer *pPlayer = (CBasePlayer*)CBaseEntity::Instance( pKiller ); |
|
|
|
if ( pPlayer->m_pActiveItem ) |
|
{ |
|
killer_weapon_name = pPlayer->m_pActiveItem->pszName(); |
|
} |
|
} |
|
else |
|
{ |
|
killer_weapon_name = STRING( pevInflictor->classname ); // it's just that easy |
|
} |
|
} |
|
} |
|
else |
|
{ |
|
killer_weapon_name = STRING( pevInflictor->classname ); |
|
} |
|
|
|
// strip the monster_* or weapon_* from the inflictor's classname |
|
if ( strncmp( killer_weapon_name, "weapon_", 7 ) == 0 ) |
|
killer_weapon_name += 7; |
|
else if ( strncmp( killer_weapon_name, "monster_", 8 ) == 0 ) |
|
killer_weapon_name += 8; |
|
else if ( strncmp( killer_weapon_name, "func_", 5 ) == 0 ) |
|
killer_weapon_name += 5; |
|
|
|
MESSAGE_BEGIN( MSG_ALL, gmsgDeathMsg ); |
|
WRITE_BYTE( killer_index ); // the killer |
|
WRITE_BYTE( ENTINDEX(pVictim->edict()) ); // the victim |
|
WRITE_STRING( killer_weapon_name ); // what they were killed by (should this be a string?) |
|
MESSAGE_END(); |
|
|
|
if ( pVictim->pev == pKiller ) |
|
{ // killed self |
|
UTIL_LogPrintf( "\"%s<%i>\" killed self with %s\n", STRING( pVictim->pev->netname ), GETPLAYERUSERID( pVictim->edict() ), killer_weapon_name ); |
|
} |
|
else if ( pKiller->flags & FL_CLIENT ) |
|
{ |
|
UTIL_LogPrintf( "\"%s<%i>\" killed \"%s<%i>\" with %s\n", STRING( pKiller->netname ), |
|
GETPLAYERUSERID( ENT(pKiller) ), |
|
STRING( pVictim->pev->netname ), |
|
GETPLAYERUSERID( pVictim->edict() ), |
|
killer_weapon_name ); |
|
} |
|
else |
|
{ // killed by the world |
|
UTIL_LogPrintf( "\"%s<%i>\" killed by world with %s\n", STRING( pVictim->pev->netname ), GETPLAYERUSERID( pVictim->edict() ), killer_weapon_name ); |
|
} |
|
|
|
return; |
|
} |
|
|
|
//========================================================= |
|
// PlayerGotWeapon - player has grabbed a weapon that was |
|
// sitting in the world |
|
//========================================================= |
|
void CRailArena :: PlayerGotWeapon( CBasePlayer *pPlayer, CBasePlayerItem *pWeapon ) |
|
{ |
|
} |
|
|
|
//========================================================= |
|
// FlWeaponRespawnTime - what is the time in the future |
|
// at which this weapon may spawn? |
|
//========================================================= |
|
float CRailArena :: FlWeaponRespawnTime( CBasePlayerItem *pWeapon ) |
|
{ |
|
return FALSE; |
|
} |
|
|
|
// when we are within this close to running out of entities, items |
|
// marked with the ITEM_FLAG_LIMITINWORLD will delay their respawn |
|
#define ENTITY_INTOLERANCE 100 |
|
|
|
//========================================================= |
|
// FlWeaponRespawnTime - Returns 0 if the weapon can respawn |
|
// now, otherwise it returns the time at which it can try |
|
// to spawn again. |
|
//========================================================= |
|
float CRailArena :: FlWeaponTryRespawn( CBasePlayerItem *pWeapon ) |
|
{ |
|
if ( pWeapon && pWeapon->m_iId ) |
|
{ |
|
return 0; |
|
} |
|
|
|
return 0; |
|
} |
|
|
|
//========================================================= |
|
// VecWeaponRespawnSpot - where should this weapon spawn? |
|
// Some game variations may choose to randomize spawn locations |
|
//========================================================= |
|
Vector CRailArena :: VecWeaponRespawnSpot( CBasePlayerItem *pWeapon ) |
|
{ |
|
return pWeapon->pev->origin; |
|
} |
|
|
|
//========================================================= |
|
// WeaponShouldRespawn - any conditions inhibiting the |
|
// respawning of this weapon? |
|
//========================================================= |
|
int CRailArena :: WeaponShouldRespawn( CBasePlayerItem *pWeapon ) |
|
{ |
|
return GR_WEAPON_RESPAWN_NO; |
|
} |
|
|
|
//========================================================= |
|
// CanHaveWeapon - returns FALSE if the player is not allowed |
|
// to pick up this weapon |
|
//========================================================= |
|
BOOL CRailArena::CanHavePlayerItem( CBasePlayer *pPlayer, CBasePlayerItem *pItem ) |
|
{ |
|
if ( CVAR_GET_FLOAT("mp_weaponstay") > 0 ) |
|
{ |
|
if ( pItem->iFlags() & ITEM_FLAG_LIMITINWORLD ) |
|
return CGameRules::CanHavePlayerItem( pPlayer, pItem ); |
|
|
|
// check if the player already has this weapon |
|
for ( int i = 0 ; i < MAX_ITEM_TYPES ; i++ ) |
|
{ |
|
CBasePlayerItem *it = pPlayer->m_rgpPlayerItems[i]; |
|
|
|
while ( it != NULL ) |
|
{ |
|
if ( it->m_iId == pItem->m_iId ) |
|
{ |
|
return FALSE; |
|
} |
|
|
|
it = it->m_pNext; |
|
} |
|
} |
|
} |
|
|
|
return CGameRules::CanHavePlayerItem( pPlayer, pItem ); |
|
} |
|
|
|
//========================================================= |
|
//========================================================= |
|
BOOL CRailArena::CanHaveItem( CBasePlayer *pPlayer, CItem *pItem ) |
|
{ |
|
return TRUE; |
|
} |
|
|
|
//========================================================= |
|
//========================================================= |
|
void CRailArena::PlayerGotItem( CBasePlayer *pPlayer, CItem *pItem ) |
|
{ |
|
} |
|
|
|
//========================================================= |
|
//========================================================= |
|
int CRailArena::ItemShouldRespawn( CItem *pItem ) |
|
{ |
|
return GR_ITEM_RESPAWN_NO; |
|
} |
|
|
|
|
|
//========================================================= |
|
// At what time in the future may this Item respawn? |
|
//========================================================= |
|
float CRailArena::FlItemRespawnTime( CItem *pItem ) |
|
{ |
|
return gpGlobals->time + ITEM_RESPAWN_TIME; |
|
} |
|
|
|
//========================================================= |
|
// Where should this item respawn? |
|
// Some game variations may choose to randomize spawn locations |
|
//========================================================= |
|
Vector CRailArena::VecItemRespawnSpot( CItem *pItem ) |
|
{ |
|
return pItem->pev->origin; |
|
} |
|
|
|
//========================================================= |
|
//========================================================= |
|
void CRailArena::PlayerGotAmmo( CBasePlayer *pPlayer, char *szName, int iCount ) |
|
{ |
|
} |
|
|
|
//========================================================= |
|
//========================================================= |
|
BOOL CRailArena::IsAllowedToSpawn( CBaseEntity *pEntity ) |
|
{ |
|
if ( pEntity->pev->flags & FL_MONSTER ) |
|
return FALSE; |
|
|
|
return TRUE; |
|
} |
|
|
|
//========================================================= |
|
//========================================================= |
|
int CRailArena::AmmoShouldRespawn( CBasePlayerAmmo *pAmmo ) |
|
{ |
|
return GR_AMMO_RESPAWN_NO; |
|
} |
|
|
|
//========================================================= |
|
//========================================================= |
|
float CRailArena::FlAmmoRespawnTime( CBasePlayerAmmo *pAmmo ) |
|
{ |
|
return gpGlobals->time + AMMO_RESPAWN_TIME; |
|
} |
|
|
|
//========================================================= |
|
//========================================================= |
|
Vector CRailArena::VecAmmoRespawnSpot( CBasePlayerAmmo *pAmmo ) |
|
{ |
|
return pAmmo->pev->origin; |
|
} |
|
|
|
//========================================================= |
|
//========================================================= |
|
float CRailArena::FlHealthChargerRechargeTime( void ) |
|
{ |
|
return 60; |
|
} |
|
|
|
|
|
float CRailArena::FlHEVChargerRechargeTime( void ) |
|
{ |
|
return 30; |
|
} |
|
|
|
//========================================================= |
|
//========================================================= |
|
int CRailArena::DeadPlayerWeapons( CBasePlayer *pPlayer ) |
|
{ |
|
return GR_PLR_DROP_GUN_ACTIVE; |
|
} |
|
//========================================================= |
|
//========================================================= |
|
int CRailArena::DeadPlayerAmmo( CBasePlayer *pPlayer ) |
|
{ |
|
return GR_PLR_DROP_AMMO_ACTIVE; |
|
} |
|
|
|
edict_t *CRailArena::GetPlayerSpawnSpot( CBasePlayer *pPlayer ) |
|
{ |
|
edict_t *pentSpawnSpot = CGameRules::GetPlayerSpawnSpot( pPlayer ); |
|
if ( IsMultiplayer() && pentSpawnSpot->v.target ) |
|
{ |
|
FireTargets( STRING(pentSpawnSpot->v.target), pPlayer, pPlayer, USE_TOGGLE, 0 ); |
|
} |
|
|
|
return pentSpawnSpot; |
|
} |
|
|
|
|
|
//========================================================= |
|
//========================================================= |
|
int CRailArena::PlayerRelationship( CBaseEntity *pPlayer, CBaseEntity *pTarget ) |
|
{ |
|
// half life deathmatch has only enemies |
|
return GR_NOTTEAMMATE; |
|
} |
|
|
|
//========================================================= |
|
//========================================================= |
|
BOOL CRailArena :: PlayFootstepSounds( CBasePlayer *pl, float fvol ) |
|
{ |
|
if ( CVAR_GET_FLOAT( "mp_footsteps" ) == 0 ) |
|
return FALSE; |
|
|
|
if ( pl->IsOnLadder() || pl->pev->velocity.Length2D() > 220 ) |
|
return TRUE; // only make step sounds in multiplayer if the player is moving fast enough |
|
|
|
return FALSE; |
|
} |
|
//========================================================= |
|
//======================================================== |
|
|
|
BOOL CRailArena :: FAllowFlashlight( void ) |
|
{ |
|
return CVAR_GET_FLOAT( "mp_flashlight" ) != 0; |
|
} |
|
|
|
//========================================================= |
|
//========================================================= |
|
|
|
BOOL CRailArena :: FAllowMonsters( void ) |
|
{ |
|
return ( CVAR_GET_FLOAT( "mp_allowmonsters" ) != 0 ); |
|
} |
|
|
|
//========================================================= |
|
//======== CRailArena private functions =========== |
|
#define INTERMISSION_TIME 6 |
|
|
|
void CRailArena :: GoToIntermission( void ) |
|
{ |
|
if ( g_fGameOver ) |
|
return; // intermission has already been triggered, so ignore. |
|
|
|
MESSAGE_BEGIN(MSG_ALL, SVC_INTERMISSION); |
|
MESSAGE_END(); |
|
|
|
m_flIntermissionEndTime = gpGlobals->time + INTERMISSION_TIME; |
|
g_fGameOver = TRUE; |
|
m_iEndIntermissionButtonHit = FALSE; |
|
} |
|
|
|
void CRailArena :: ChangeLevel( void ) |
|
{ |
|
char szNextMap[32]; |
|
char szFirstMapInList[32]; |
|
strcpy( szFirstMapInList, "hldm1" ); // the absolute default level is hldm1 |
|
|
|
// find the map to change to |
|
|
|
char *mapcfile = (char*)CVAR_GET_STRING( "mapcyclefile" ); |
|
ASSERT( mapcfile != NULL ); |
|
strcpy( szNextMap, STRING(gpGlobals->mapname) ); |
|
strcpy( szFirstMapInList, STRING(gpGlobals->mapname) ); |
|
|
|
int length; |
|
char *pFileList; |
|
char *aFileList = pFileList = (char*)LOAD_FILE_FOR_ME( mapcfile, &length ); |
|
if ( pFileList && length ) |
|
{ |
|
// the first map name in the file becomes the default |
|
sscanf( pFileList, " %32s", szNextMap ); |
|
if ( IS_MAP_VALID( szNextMap ) ) |
|
strcpy( szFirstMapInList, szNextMap ); |
|
|
|
// keep pulling mapnames out of the list until the current mapname |
|
// if the current mapname isn't found, load the first map in the list |
|
BOOL next_map_is_it = FALSE; |
|
while ( 1 ) |
|
{ |
|
while ( *pFileList && isspace( *pFileList ) ) pFileList++; // skip over any whitespace |
|
if ( !(*pFileList) ) |
|
break; |
|
|
|
char cBuf[32]; |
|
int ret = sscanf( pFileList, " %32s", cBuf ); |
|
// Check the map name is valid |
|
if ( ret != 1 || *cBuf < 13 ) |
|
break; |
|
|
|
if ( next_map_is_it ) |
|
{ |
|
// check that it is a valid map file |
|
if ( IS_MAP_VALID( cBuf ) ) |
|
{ |
|
strcpy( szNextMap, cBuf ); |
|
break; |
|
} |
|
} |
|
|
|
if ( FStrEq( cBuf, STRING(gpGlobals->mapname) ) ) |
|
{ // we've found our map; next map is the one to change to |
|
next_map_is_it = TRUE; |
|
} |
|
|
|
pFileList += strlen( cBuf ); |
|
} |
|
|
|
FREE_FILE( aFileList ); |
|
} |
|
|
|
if ( !IS_MAP_VALID(szNextMap) ) |
|
strcpy( szNextMap, szFirstMapInList ); |
|
|
|
g_fGameOver = TRUE; |
|
|
|
ALERT( at_console, "CHANGE LEVEL: %s\n", szNextMap ); |
|
|
|
CHANGE_LEVEL( szNextMap, NULL ); |
|
} |
|
|
|
#define MAX_MOTD_CHUNK 60 |
|
#define MAX_MOTD_LENGTH (MAX_MOTD_CHUNK * 4) |
|
|
|
void CRailArena :: SendMOTDToClient( edict_t *client ) |
|
{ |
|
// read from the MOTD.txt file |
|
int length, char_count = 0; |
|
char *pFileList; |
|
char *aFileList = pFileList = (char*)LOAD_FILE_FOR_ME( "rail_arena_motd.txt", &length ); |
|
|
|
// Send the message of the day |
|
// read it chunk-by-chunk, and send it in parts |
|
|
|
while ( pFileList && *pFileList && char_count < MAX_MOTD_LENGTH ) |
|
{ |
|
char chunk[MAX_MOTD_CHUNK+1]; |
|
|
|
if ( strlen( pFileList ) < MAX_MOTD_CHUNK ) |
|
{ |
|
strcpy( chunk, pFileList ); |
|
} |
|
else |
|
{ |
|
strncpy( chunk, pFileList, MAX_MOTD_CHUNK ); |
|
chunk[MAX_MOTD_CHUNK] = 0; // strncpy doesn't always append the null terminator |
|
} |
|
|
|
char_count += strlen( chunk ); |
|
if ( char_count < MAX_MOTD_LENGTH ) |
|
pFileList = aFileList + char_count; |
|
else |
|
*pFileList = 0; |
|
|
|
MESSAGE_BEGIN( MSG_ONE, gmsgMOTD, NULL, client ); |
|
WRITE_BYTE( *pFileList ? FALSE : TRUE ); // FALSE means there is still more message to come |
|
WRITE_STRING( chunk ); |
|
MESSAGE_END(); |
|
} |
|
|
|
FREE_FILE( aFileList ); |
|
} |
|
|
|
|
|
|