mirror of https://github.com/FWGS/hlsdk-xash3d
Add new humoristic railgunarena-like multiplayer game mode "GhostBusters" from HL 25th anniversary update.
This commit is contained in:
parent
6e472815d5
commit
9a29713b66
|
@ -291,7 +291,8 @@ void CEgon::Fire( const Vector &vecOrigSrc, const Vector &vecDir )
|
|||
// multiplayer uses 1 ammo every 1/10th second
|
||||
if( gpGlobals->time >= m_flAmmoUseTime )
|
||||
{
|
||||
UseAmmo( 1 );
|
||||
if( !g_pGameRules->IsBustingGame())
|
||||
UseAmmo( 1 );
|
||||
m_flAmmoUseTime = gpGlobals->time + 0.1f;
|
||||
}
|
||||
}
|
||||
|
@ -336,7 +337,8 @@ void CEgon::Fire( const Vector &vecOrigSrc, const Vector &vecDir )
|
|||
//multiplayer uses 5 ammo/second
|
||||
if( gpGlobals->time >= m_flAmmoUseTime )
|
||||
{
|
||||
UseAmmo( 1 );
|
||||
if( !g_pGameRules->IsBustingGame())
|
||||
UseAmmo( 1 );
|
||||
m_flAmmoUseTime = gpGlobals->time + 0.2f;
|
||||
}
|
||||
}
|
||||
|
@ -497,6 +499,15 @@ void CEgon::WeaponIdle( void )
|
|||
m_deployed = TRUE;
|
||||
}
|
||||
|
||||
BOOL CEgon::CanHolster( void )
|
||||
{
|
||||
#if CLIENT_DLL
|
||||
return TRUE;
|
||||
#else
|
||||
return !g_pGameRules->IsBustingGame();
|
||||
#endif
|
||||
}
|
||||
|
||||
void CEgon::EndAttack( void )
|
||||
{
|
||||
bool bMakeNoise = false;
|
||||
|
|
|
@ -458,6 +458,7 @@ cvar_t sk_player_leg3 = { "sk_player_leg3","1" };
|
|||
// END Cvars for Skill Level settings
|
||||
|
||||
cvar_t sv_pushable_fixed_tick_fudge = { "sv_pushable_fixed_tick_fudge", "15" };
|
||||
cvar_t sv_busters = { "sv_busters", "0" };
|
||||
|
||||
// Register your console variables here
|
||||
// This gets called one time when the game is initialied
|
||||
|
@ -507,7 +508,7 @@ void GameDLLInit( void )
|
|||
CVAR_REGISTER( &multibyte_only );
|
||||
|
||||
CVAR_REGISTER( &mp_chattime );
|
||||
|
||||
CVAR_REGISTER( &sv_busters );
|
||||
|
||||
|
||||
// REGISTER CVARS FOR SKILL LEVEL STUFF
|
||||
|
|
|
@ -44,6 +44,7 @@ extern cvar_t defaultteam;
|
|||
extern cvar_t allowmonsters;
|
||||
extern cvar_t bhopcap;
|
||||
extern cvar_t sv_pushable_fixed_tick_fudge;
|
||||
extern cvar_t sv_busters;
|
||||
|
||||
// Engine Cvars
|
||||
extern cvar_t *g_psv_gravity;
|
||||
|
|
|
@ -331,6 +331,11 @@ CGameRules *InstallGameRules( void )
|
|||
g_teamplay = 1;
|
||||
return new CHalfLifeTeamplay;
|
||||
}
|
||||
if( sv_busters.value > 0 )
|
||||
{
|
||||
g_teamplay = 0;
|
||||
return new CMultiplayBusters;
|
||||
}
|
||||
if( (int)gpGlobals->deathmatch == 1 )
|
||||
{
|
||||
// vanilla deathmatch
|
||||
|
|
|
@ -162,6 +162,7 @@ public:
|
|||
|
||||
// Immediately end a multiplayer game
|
||||
virtual void EndMultiplayerGame( void ) {}
|
||||
virtual BOOL IsBustingGame( void ){ return FALSE; };
|
||||
};
|
||||
|
||||
extern CGameRules *InstallGameRules( void );
|
||||
|
@ -362,5 +363,30 @@ protected:
|
|||
void SendMOTDToClient( edict_t *client );
|
||||
};
|
||||
|
||||
bool IsPlayerBusting( CBaseEntity *pPlayer );
|
||||
BOOL BustingCanHaveItem( CBasePlayer *pPlayer, CBaseEntity *pItem );
|
||||
|
||||
class CMultiplayBusters : public CHalfLifeMultiplay
|
||||
{
|
||||
public:
|
||||
CMultiplayBusters();
|
||||
void Think();
|
||||
void PlayerSpawn( CBasePlayer *pPlayer );
|
||||
void ClientUserInfoChanged( CBasePlayer *pPlayer, char *infobuffer );
|
||||
int IPointsForKill( CBasePlayer *pAttacker, CBasePlayer *pKilled );
|
||||
void PlayerKilled( CBasePlayer *pVictim, entvars_t *pKiller, entvars_t *pInflictor );
|
||||
void DeathNotice( CBasePlayer *pVictim, entvars_t *pKiller, entvars_t *pevInflictor );
|
||||
BOOL CanHavePlayerItem( CBasePlayer *pPlayer, CBasePlayerItem *pItem );
|
||||
void PlayerGotWeapon( CBasePlayer *pPlayer, CBasePlayerItem *pWeapon );
|
||||
int WeaponShouldRespawn( CBasePlayerItem *pWeapon );
|
||||
BOOL CanHaveItem( CBasePlayer *pPlayer, CItem *pItem );
|
||||
void CheckForEgons();
|
||||
void SetPlayerModel( CBasePlayer *pPlayer, BOOL bKnownBuster );
|
||||
BOOL IsBustingGame( void ){ return TRUE; };
|
||||
|
||||
protected:
|
||||
float m_flEgonBustingCheckTime;
|
||||
};
|
||||
|
||||
extern DLL_GLOBAL CGameRules *g_pGameRules;
|
||||
#endif // GAMERULES_H
|
||||
|
|
|
@ -1723,3 +1723,219 @@ void CHalfLifeMultiplay::SendMOTDToClient( edict_t *client )
|
|||
|
||||
FREE_FILE( (void*)aFileList );
|
||||
}
|
||||
|
||||
int CMultiplayBusters::WeaponShouldRespawn( CBasePlayerItem *pWeapon )
|
||||
{
|
||||
if( pWeapon->m_iId == WEAPON_EGON )
|
||||
return GR_WEAPON_RESPAWN_NO;
|
||||
|
||||
return CHalfLifeMultiplay::WeaponShouldRespawn( pWeapon );
|
||||
}
|
||||
|
||||
BOOL CMultiplayBusters::CanHaveItem( CBasePlayer *pPlayer, CItem *pItem )
|
||||
{
|
||||
return BustingCanHaveItem( pPlayer, pItem );
|
||||
}
|
||||
|
||||
BOOL CMultiplayBusters::CanHavePlayerItem( CBasePlayer *pPlayer, CBasePlayerItem *pItem )
|
||||
{
|
||||
if( !BustingCanHaveItem( pPlayer, pItem ))
|
||||
return FALSE;
|
||||
|
||||
return CHalfLifeMultiplay::CanHavePlayerItem( pPlayer, pItem );
|
||||
}
|
||||
|
||||
int CMultiplayBusters::IPointsForKill( CBasePlayer *pAttacker, CBasePlayer *pKilled )
|
||||
{
|
||||
if( IsPlayerBusting( pAttacker ))
|
||||
return 1;
|
||||
|
||||
if( IsPlayerBusting( pKilled ))
|
||||
return 2;
|
||||
|
||||
return 0;
|
||||
}
|
||||
void CMultiplayBusters::DeathNotice( CBasePlayer *pVictim, entvars_t *pKiller, entvars_t *pevInflictor )
|
||||
{
|
||||
if( IsPlayerBusting( pVictim )
|
||||
|| IsPlayerBusting( CBaseEntity::Instance( pKiller )))
|
||||
CHalfLifeMultiplay::DeathNotice( pVictim, pKiller, pevInflictor );
|
||||
}
|
||||
|
||||
void CMultiplayBusters::PlayerKilled( CBasePlayer *pVictim, entvars_t *pKiller, entvars_t *pInflictor )
|
||||
{
|
||||
if( IsPlayerBusting( pVictim ))
|
||||
{
|
||||
UTIL_ClientPrintAll( HUD_PRINTCENTER, "The Buster is dead!!" );
|
||||
|
||||
m_flEgonBustingCheckTime = -1.0f;
|
||||
|
||||
CBasePlayer *peKiller = NULL;
|
||||
CBaseEntity *ktmp = CBaseEntity::Instance( pKiller );
|
||||
if( ktmp && ( ktmp->Classify() == CLASS_PLAYER ) )
|
||||
peKiller = (CBasePlayer*)ktmp;
|
||||
else if( ktmp && ktmp->Classify() == CLASS_VEHICLE )
|
||||
{
|
||||
CBasePlayer *pDriver = (CBasePlayer *)( (CFuncVehicle *)ktmp )->m_pDriver;
|
||||
|
||||
if( pDriver != NULL )
|
||||
{
|
||||
pKiller = pDriver->pev;
|
||||
peKiller = (CBasePlayer *)pDriver;
|
||||
}
|
||||
}
|
||||
|
||||
if( peKiller && peKiller->IsPlayer() )
|
||||
{
|
||||
UTIL_ClientPrintAll( HUD_PRINTTALK, UTIL_VarArgs( "%s has killed the Buster!", STRING( peKiller->pev->netname )));
|
||||
}
|
||||
|
||||
pVictim->pev->renderfx = 0;
|
||||
pVictim->pev->rendercolor = g_vecZero;
|
||||
}
|
||||
|
||||
CHalfLifeMultiplay::PlayerKilled( pVictim, pKiller, pInflictor );
|
||||
}
|
||||
|
||||
void CMultiplayBusters::ClientUserInfoChanged( CBasePlayer *pPlayer, char *infobuffer )
|
||||
{
|
||||
SetPlayerModel( pPlayer, FALSE );
|
||||
CHalfLifeMultiplay::ClientUserInfoChanged( pPlayer, infobuffer );
|
||||
}
|
||||
|
||||
void CMultiplayBusters::PlayerSpawn( CBasePlayer *pPlayer )
|
||||
{
|
||||
CHalfLifeMultiplay::PlayerSpawn( pPlayer );
|
||||
SetPlayerModel( pPlayer, FALSE );
|
||||
}
|
||||
|
||||
bool IsPlayerBusting( CBaseEntity *pPlayer )
|
||||
{
|
||||
if( g_pGameRules->IsBustingGame()
|
||||
&& pPlayer && pPlayer->IsPlayer()
|
||||
&& ((CBasePlayer*)pPlayer)->HasPlayerItemFromID( WEAPON_EGON ))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
BOOL BustingCanHaveItem( CBasePlayer *pPlayer, CBaseEntity *pItem )
|
||||
{
|
||||
if( IsPlayerBusting( pPlayer )
|
||||
&& !( strncmp( STRING( pItem->pev->classname ), "weapon_", 7 )
|
||||
&& strncmp( STRING( pItem->pev->classname ), "ammo_", 5 )))
|
||||
return FALSE;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
CMultiplayBusters::CMultiplayBusters()
|
||||
{
|
||||
CHalfLifeMultiplay();
|
||||
|
||||
m_flEgonBustingCheckTime = -1.0;
|
||||
}
|
||||
|
||||
void CMultiplayBusters::CheckForEgons( void )
|
||||
{
|
||||
CBaseEntity *pPlayer;
|
||||
CWeaponBox *pWeaponBox = NULL;
|
||||
CBasePlayerItem *pWeapon;
|
||||
CBasePlayer *pNewBuster = NULL;
|
||||
int i, bestfrags = 9999;
|
||||
|
||||
if( m_flEgonBustingCheckTime <= 0.0f )
|
||||
{
|
||||
m_flEgonBustingCheckTime = gpGlobals->time + 10.0f;
|
||||
return;
|
||||
}
|
||||
|
||||
if( gpGlobals->time < m_flEgonBustingCheckTime )
|
||||
return;
|
||||
|
||||
m_flEgonBustingCheckTime = -1.0f;
|
||||
|
||||
for( i = 1; i <= gpGlobals->maxClients; i++ )
|
||||
{
|
||||
pPlayer = UTIL_PlayerByIndex( i );
|
||||
if( IsPlayerBusting( pPlayer ))
|
||||
return;
|
||||
}
|
||||
|
||||
for( i = 1; i <= gpGlobals->maxClients; i++ )
|
||||
{
|
||||
pPlayer = UTIL_PlayerByIndex( i );
|
||||
|
||||
if( pPlayer && pPlayer->pev->frags < bestfrags )
|
||||
{
|
||||
pNewBuster = (CBasePlayer*)pPlayer;
|
||||
bestfrags = pPlayer->pev->frags;
|
||||
}
|
||||
}
|
||||
|
||||
if( !pNewBuster )
|
||||
return;
|
||||
|
||||
pNewBuster->GiveNamedItem( "weapon_egon" );
|
||||
|
||||
while( ( pWeaponBox = (CWeaponBox*)UTIL_FindEntityByClassname( pWeaponBox, "weaponbox" )))
|
||||
{
|
||||
// destroy weaponboxes with egons
|
||||
for( i = 0; i < MAX_ITEM_TYPES; i++ )
|
||||
{
|
||||
pWeapon = pWeaponBox->m_rgpPlayerItems[i];
|
||||
|
||||
while( pWeapon )
|
||||
{
|
||||
if( pWeapon->m_iId != WEAPON_EGON )
|
||||
{
|
||||
pWeapon = pWeapon->m_pNext;
|
||||
continue;
|
||||
}
|
||||
|
||||
pWeaponBox->Kill();
|
||||
pWeapon = 0;
|
||||
i = MAX_ITEM_TYPES;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CMultiplayBusters::Think( void )
|
||||
{
|
||||
CheckForEgons();
|
||||
CHalfLifeMultiplay::Think();
|
||||
}
|
||||
|
||||
void CMultiplayBusters::SetPlayerModel( CBasePlayer *pPlayer, BOOL bKnownBuster )
|
||||
{
|
||||
const char *pszModel = NULL;
|
||||
|
||||
if( bKnownBuster || IsPlayerBusting( pPlayer ))
|
||||
{
|
||||
pszModel = "ivan";
|
||||
}
|
||||
else
|
||||
{
|
||||
pszModel = "skeleton";
|
||||
}
|
||||
|
||||
g_engfuncs.pfnSetClientKeyValue( ENTINDEX( pPlayer->edict()), g_engfuncs.pfnGetInfoKeyBuffer( pPlayer->edict()), "model", pszModel );
|
||||
}
|
||||
|
||||
void CMultiplayBusters::PlayerGotWeapon( CBasePlayer *pPlayer, CBasePlayerItem *pWeapon )
|
||||
{
|
||||
if( pWeapon->m_iId != WEAPON_EGON )
|
||||
return;
|
||||
|
||||
pPlayer->RemoveAllItems( FALSE );
|
||||
UTIL_ClientPrintAll( HUD_PRINTCENTER, "Long live the new Buster!" );
|
||||
UTIL_ClientPrintAll( HUD_PRINTTALK, UTIL_VarArgs( "%s is busting!\n", STRING( pPlayer->pev->netname )));
|
||||
SetPlayerModel( pPlayer, TRUE );
|
||||
pPlayer->pev->health = pPlayer->pev->max_health;
|
||||
pPlayer->pev->armorvalue = MAX_NORMAL_BATTERY;
|
||||
pPlayer->pev->renderfx = kRenderFxGlowShell;
|
||||
pPlayer->pev->renderamt = 25;
|
||||
pPlayer->pev->rendercolor = Vector( 0, 75, 250 );
|
||||
pPlayer->m_rgAmmo[pWeapon->PrimaryAmmoIndex()] = pPlayer->ammo_uranium = 100;
|
||||
}
|
||||
|
|
|
@ -755,24 +755,44 @@ void CBasePlayer::PackDeadPlayerItems( void )
|
|||
iPA = 0;
|
||||
iPW = 0;
|
||||
|
||||
// pack the ammo
|
||||
while( iPackAmmo[iPA] != -1 )
|
||||
if( g_pGameRules->IsBustingGame())
|
||||
{
|
||||
pWeaponBox->PackAmmo( MAKE_STRING( CBasePlayerItem::AmmoInfoArray[iPackAmmo[iPA]].pszName ), m_rgAmmo[iPackAmmo[iPA]] );
|
||||
iPA++;
|
||||
while( rgpPackWeapons[iPW] )
|
||||
{
|
||||
// weapon unhooked from the player. Pack it into der box.
|
||||
if( FClassnameIs( rgpPackWeapons[iPW]->pev, "weapon_egon" ))
|
||||
{
|
||||
pWeaponBox->PackWeapon( rgpPackWeapons[iPW] );
|
||||
SET_MODEL( pWeaponBox->edict(), "models/w_egon.mdl" );
|
||||
pWeaponBox->pev->velocity = g_vecZero;
|
||||
pWeaponBox->pev->renderfx = kRenderFxGlowShell;
|
||||
pWeaponBox->pev->renderamt = 25;
|
||||
pWeaponBox->pev->rendercolor = Vector( 0, 75, 250 );
|
||||
break;
|
||||
}
|
||||
iPW++;
|
||||
}
|
||||
}
|
||||
|
||||
// now pack all of the items in the lists
|
||||
while( rgpPackWeapons[iPW] )
|
||||
else
|
||||
{
|
||||
// weapon unhooked from the player. Pack it into der box.
|
||||
pWeaponBox->PackWeapon( rgpPackWeapons[iPW] );
|
||||
// pack the ammo
|
||||
while( iPackAmmo[iPA] != -1 )
|
||||
{
|
||||
pWeaponBox->PackAmmo( MAKE_STRING( CBasePlayerItem::AmmoInfoArray[iPackAmmo[iPA]].pszName ), m_rgAmmo[iPackAmmo[iPA]] );
|
||||
iPA++;
|
||||
}
|
||||
|
||||
iPW++;
|
||||
// now pack all of the items in the lists
|
||||
while( rgpPackWeapons[iPW] )
|
||||
{
|
||||
// weapon unhooked from the player. Pack it into der box.
|
||||
pWeaponBox->PackWeapon( rgpPackWeapons[iPW] );
|
||||
|
||||
iPW++;
|
||||
}
|
||||
|
||||
pWeaponBox->pev->velocity = pev->velocity * 1.2;// weaponbox has player's velocity, then some.
|
||||
}
|
||||
|
||||
pWeaponBox->pev->velocity = pev->velocity * 1.2;// weaponbox has player's velocity, then some.
|
||||
|
||||
RemoveAllItems( TRUE );// now strip off everything that wasn't handled by the code above.
|
||||
}
|
||||
|
||||
|
@ -4635,6 +4655,31 @@ BOOL CBasePlayer::HasNamedPlayerItem( const char *pszItemName )
|
|||
return FALSE;
|
||||
}
|
||||
|
||||
//=========================================================
|
||||
// HasPlayerItemFromID
|
||||
//=========================================================
|
||||
BOOL CBasePlayer::HasPlayerItemFromID( int nID )
|
||||
{
|
||||
CBasePlayerItem *pItem;
|
||||
int i;
|
||||
|
||||
for( i = 0; i < MAX_ITEM_TYPES; i++ )
|
||||
{
|
||||
pItem = m_rgpPlayerItems[i];
|
||||
|
||||
while( pItem )
|
||||
{
|
||||
if( nID == pItem->m_iId )
|
||||
{
|
||||
return TRUE;
|
||||
}
|
||||
pItem = pItem->m_pNext;
|
||||
}
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
//=========================================================
|
||||
//
|
||||
//=========================================================
|
||||
|
|
|
@ -265,6 +265,7 @@ public:
|
|||
void DropPlayerItem ( char *pszItemName );
|
||||
BOOL HasPlayerItem( CBasePlayerItem *pCheckItem );
|
||||
BOOL HasNamedPlayerItem( const char *pszItemName );
|
||||
BOOL HasPlayerItemFromID( int nID );
|
||||
BOOL HasWeapons( void );// do I have ANY weapons?
|
||||
void SelectPrevItem( int iItem );
|
||||
void SelectNextItem( int iItem );
|
||||
|
|
|
@ -471,6 +471,19 @@ void CBasePlayerItem::FallThink( void )
|
|||
|
||||
Materialize();
|
||||
}
|
||||
else if( m_pPlayer )
|
||||
{
|
||||
SetThink( NULL );
|
||||
}
|
||||
|
||||
if( g_pGameRules->IsBustingGame())
|
||||
{
|
||||
if( !FNullEnt( pev->owner ))
|
||||
return;
|
||||
|
||||
if( FClassnameIs( pev, "weapon_egon" ))
|
||||
UTIL_Remove( this );
|
||||
}
|
||||
}
|
||||
|
||||
//=========================================================
|
||||
|
@ -1076,7 +1089,7 @@ void CBasePlayerAmmo::Materialize( void )
|
|||
|
||||
void CBasePlayerAmmo::DefaultTouch( CBaseEntity *pOther )
|
||||
{
|
||||
if( !pOther->IsPlayer() )
|
||||
if( !pOther->IsPlayer() || IsPlayerBusting( pOther ))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -793,13 +793,13 @@ public:
|
|||
int AddToPlayer( CBasePlayer *pPlayer );
|
||||
|
||||
BOOL Deploy( void );
|
||||
BOOL CanHolster( void );
|
||||
void Holster( int skiplocal = 0 );
|
||||
|
||||
void UpdateEffect( const Vector &startPoint, const Vector &endPoint, float timeBlend );
|
||||
|
||||
void CreateEffect ( void );
|
||||
void DestroyEffect ( void );
|
||||
|
||||
void EndAttack( void );
|
||||
void Attack( void );
|
||||
void PrimaryAttack( void );
|
||||
|
|
Loading…
Reference in New Issue