diff --git a/dlls/egon.cpp b/dlls/egon.cpp index d315e26f..ab6fe24c 100644 --- a/dlls/egon.cpp +++ b/dlls/egon.cpp @@ -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; diff --git a/dlls/game.cpp b/dlls/game.cpp index 26a4d481..93cc7eb2 100644 --- a/dlls/game.cpp +++ b/dlls/game.cpp @@ -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 diff --git a/dlls/game.h b/dlls/game.h index 069324bb..8a0f6d34 100644 --- a/dlls/game.h +++ b/dlls/game.h @@ -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; diff --git a/dlls/gamerules.cpp b/dlls/gamerules.cpp index bfbbf59e..2499a67d 100644 --- a/dlls/gamerules.cpp +++ b/dlls/gamerules.cpp @@ -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 diff --git a/dlls/gamerules.h b/dlls/gamerules.h index 781ef447..0d86ce02 100644 --- a/dlls/gamerules.h +++ b/dlls/gamerules.h @@ -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 diff --git a/dlls/multiplay_gamerules.cpp b/dlls/multiplay_gamerules.cpp index 49e24ab3..1578ec13 100644 --- a/dlls/multiplay_gamerules.cpp +++ b/dlls/multiplay_gamerules.cpp @@ -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; +} diff --git a/dlls/player.cpp b/dlls/player.cpp index 7f5df559..3b1d57af 100644 --- a/dlls/player.cpp +++ b/dlls/player.cpp @@ -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; +} + //========================================================= // //========================================================= diff --git a/dlls/player.h b/dlls/player.h index f86d25b4..90dd62e1 100644 --- a/dlls/player.h +++ b/dlls/player.h @@ -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 ); diff --git a/dlls/weapons.cpp b/dlls/weapons.cpp index 0443d271..3ff1a15f 100644 --- a/dlls/weapons.cpp +++ b/dlls/weapons.cpp @@ -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; } diff --git a/dlls/weapons.h b/dlls/weapons.h index ca1ec3b7..fae0889d 100644 --- a/dlls/weapons.h +++ b/dlls/weapons.h @@ -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 );