Portable Half-Life SDK. GoldSource and Xash3D. Crossplatform.
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.

705 lines
18 KiB

// ---------------------------------------------------------------
// BubbleMod
//
// AUTHOR
// Tyler Lund <halflife@bubblemod.org>
//
// LICENSE
//
// Permission is granted to anyone to use this software for
// any purpose on any computer system, and to redistribute it
// in any way, subject to the following restrictions:
//
// 1. The author is not responsible for the consequences of
// use of this software, no matter how awful, even if they
// arise from defects in it.
// 2. The origin of this software must not be misrepresented,
// either by explicit claim or by omission.
// 3. Altered versions must be plainly marked as such, and
// must not be misrepresented (by explicit claim or
// omission) as being the original software.
// 3a. It would be nice if I got a copy of your improved
// version sent to halflife@bubblemod.org.
// 4. This notice must not be removed or altered.
//
// ---------------------------------------------------------------
#include "extdll.h"
#include "util.h"
#include "cbase.h"
#include "player.h"
#include "weapons.h"
#include "gamerules.h"
#include "BMOD_messaging.h"
#include "BMOD_CameraPoint.h"
#include "BMOD_player.h"
extern int gmsgCurWeapon;
extern int gmsgSetFOV;
extern int gmsgTeamInfo;
extern int gmsgSpectator;
extern void respawn(entvars_t *pev, BOOL fCopyCorpse);
extern cvar_t bm_spawnkilltime;
extern cvar_t bm_typekills;
extern cvar_t bm_bantime;
extern cvar_t bm_antispam;
extern cvar_t bm_spamlimit;
extern cvar_t bm_typecam;
// Player has become a spectator. Set it up.
// This was moved from player.cpp.
void CBasePlayer::StartObserver( Vector vecPosition, Vector vecViewAngle )
{
// ??
// clear any clientside entities attached to this player
MESSAGE_BEGIN( MSG_PAS, SVC_TEMPENTITY, pev->origin );
WRITE_BYTE( TE_KILLPLAYERATTACHMENTS );
WRITE_BYTE( (BYTE)entindex() );
MESSAGE_END();
// Holster weapon immediately, to allow it to cleanup
if (m_pActiveItem)
m_pActiveItem->Holster( );
// ?? Let go of tanks?
if ( m_pTank != NULL )
{
m_pTank->Use( this, this, USE_OFF, 0 );
m_pTank = NULL;
}
// clear out the suit message cache so we don't keep chattering
SetSuitUpdate(NULL, FALSE, 0);
// Tell Ammo Hud that the player is dead
MESSAGE_BEGIN( MSG_ONE, gmsgCurWeapon, NULL, pev );
WRITE_BYTE(0);
WRITE_BYTE(0XFF);
WRITE_BYTE(0xFF);
MESSAGE_END();
// reset FOV
m_iFOV = 0;
m_iClientFOV = -1;
pev->fov = m_iFOV;
SET_VIEW(edict(), edict());
MESSAGE_BEGIN( MSG_ONE, gmsgSetFOV, NULL, pev );
WRITE_BYTE(0);
MESSAGE_END();
// Setup flags
m_iHideHUD = (HIDEHUD_FLASHLIGHT | HIDEHUD_WEAPONS | HIDEHUD_HEALTH);
m_afPhysicsFlags |= PFLAG_OBSERVER;
pev->effects |= EF_NODRAW;
pev->view_ofs = g_vecZero;
pev->angles = pev->v_angle = vecViewAngle;
pev->fixangle = TRUE;
pev->solid = SOLID_NOT;
pev->takedamage = DAMAGE_NO;
pev->movetype = MOVETYPE_NOCLIP;
ClearBits( m_afPhysicsFlags, PFLAG_DUCKING );
ClearBits( pev->flags, FL_DUCKING );
pev->deadflag = DEAD_RESPAWNABLE;
pev->health = 1;
// Clear out the status bar
m_fInitHUD = TRUE;
// Update Team Status
// pev->team = 0;
// Remove all the player's stuff
// RemoveAllItems( FALSE );
// Move them to the new position
UTIL_SetOrigin( pev, vecPosition );
// Find a player to watch
Observer_SetMode(OBS_ROAMING);
// Tell all clients this player is now a spectator
//MESSAGE_BEGIN( MSG_ALL, gmsgSpectator );
// WRITE_BYTE( ENTINDEX( edict() ) );
// WRITE_BYTE( 1 );
//MESSAGE_END();
//MESSAGE_BEGIN( MSG_ALL, gmsgTeamInfo );
// WRITE_BYTE( ENTINDEX(edict()) );
// WRITE_STRING( "" );
//MESSAGE_END();
m_fMsgTimer = gpGlobals->time + .5;
m_bSentMsg = FALSE;
}
// Leave observer mode
void CBasePlayer::StopObserver( void )
{
// Turn off spectator
if ( pev->iuser1 || pev->iuser2 )
{
// Tell all clients this player is not a spectator anymore
//MESSAGE_BEGIN( MSG_ALL, gmsgSpectator );
// WRITE_BYTE( ENTINDEX( edict() ) );
// WRITE_BYTE( 0 );
//MESSAGE_END();
pev->iuser1 = pev->iuser2 = 0;
m_hObserverTarget = NULL;
m_iHideHUD = 0;
//MESSAGE_BEGIN( MSG_ALL, gmsgTeamInfo );
// WRITE_BYTE( ENTINDEX(edict()) );
// WRITE_STRING( m_szTeamName );
//MESSAGE_END();
}
}
// Find the next client in the game for this player to spectate
void CBasePlayer::Observer_FindNextPlayer( bool bReverse )
{
int iStart;
if ( m_hObserverTarget )
iStart = ENTINDEX( m_hObserverTarget->edict() );
else
iStart = ENTINDEX( edict() );
int iCurrent = iStart;
m_hObserverTarget = NULL;
int iDir = 1;
do
{
iCurrent += iDir;
// Loop through the clients
if (iCurrent > gpGlobals->maxClients)
iCurrent = 1;
if (iCurrent < 1)
iCurrent = gpGlobals->maxClients;
CBaseEntity *pEnt = UTIL_PlayerByIndex( iCurrent );
if ( !pEnt )
continue;
if ( pEnt == this )
continue;
// Don't spec observers or invisible players or defunct players
if ( ((CBasePlayer*)pEnt)->IsObserver()
|| (pEnt->pev->effects & EF_NODRAW)
|| (STRING(pEnt->pev->netname)[0] == 0)
|| (!((CBasePlayer*)pEnt)->m_bIsConnected)
)
continue;
// MOD AUTHORS: Add checks on target here.
m_hObserverTarget = pEnt;
break;
} while ( iCurrent != iStart );
// Did we find a target?
if ( m_hObserverTarget )
{
// Store the target in pev so the physics DLL can get to it
pev->iuser2 = ENTINDEX( m_hObserverTarget->edict() );
// Move to the target
UTIL_SetOrigin( pev, m_hObserverTarget->pev->origin );
// ClientPrint( pev, HUD_PRINTCENTER, UTIL_VarArgs ("Chase Camera: %s\n", STRING( m_hObserverTarget->pev->netname ) ) );
ALERT( at_console, "Now Tracking %s\n", STRING( m_hObserverTarget->pev->netname ) );
}
else
{
ALERT( at_console, "No observer targets.\n" );
}
}
// Handle buttons in observer mode
void CBasePlayer::Observer_HandleButtons()
{
// Slow down mouse clicks
if ( m_fMsgTimer <= gpGlobals->time )
{
// Show the observer mode instructions
if (!m_bSentMsg)
{
m_bSentMsg = TRUE;
PrintMessage( this, BMOD_CHAN_INFO, Vector (20,250,20), Vector (.5, 15, 2), "SPEC");
PrintMessage( this, BMOD_CHAN_RUNE, Vector (20,250,20), Vector (.5, 86400, 2),
"-Spectator Mode-\n FIRE=Spawn JUMP=Switch Modes ALT FIRE=Switch Targets");
}
// Check to see if the observer wants to spray their logo
if (pev->impulse == 201) {
ImpulseCommands();
}
// Jump changes modes: Chase to Roaming
if ( pev->button & IN_JUMP )
{
if ( pev->iuser1 == OBS_ROAMING )
Observer_SetMode( OBS_CHASE_FREE );
else
Observer_SetMode( OBS_ROAMING );
m_fMsgTimer = gpGlobals->time + 0.2;
}
// Attack2 cycles player targets
if ( pev->button & IN_ATTACK2 && pev->iuser1 != OBS_ROAMING )
{
Observer_FindNextPlayer( false );
m_fMsgTimer = gpGlobals->time + 0.2;
}
// Attack Spawns
// if ( m_afButtonPressed & IN_ATTACK && pev->iuser1 != OBS_ROAMING )
if ( pev->button & IN_ATTACK )
{
// g_engfuncs.pfnServerPrint( "Player spawned from Obs!\n" );
StopObserver();
m_fMsgTimer = gpGlobals->time + 0.2;
}
}
// clear attack/use commands from player
m_afButtonPressed = 0;
pev->button = 0;
m_afButtonReleased = 0;
pev->impulse = 0;
if ((m_hObserverTarget != NULL) && (m_hObserverTarget->IsPlayer()) && (pev->iuser1 == OBS_CHASE_FREE))
{
pev->origin = m_hObserverTarget->pev->origin;
pev->velocity = m_hObserverTarget->pev->velocity;
}
}
// Attempt to change the observer mode
void CBasePlayer::Observer_SetMode( int iMode )
{
// Just abort if we're changing to the mode we're already in
if ( iMode == pev->iuser1 )
return;
// Changing to Roaming?
if ( iMode == OBS_ROAMING )
{
// MOD AUTHORS: If you don't want to allow roaming observers at all in your mod, just abort here.
pev->iuser1 = OBS_ROAMING;
pev->iuser2 = 0;
m_hObserverTarget = NULL;
ClientPrint( pev, HUD_PRINTCENTER, "#Spec_Mode3" );
// pev->maxspeed = 320;
pev->maxspeed = 1000;
return;
}
// Changing to Chase Lock?
if ( iMode == OBS_CHASE_LOCKED )
{
// If changing from Roaming, or starting observing, make sure there is a target
if ( m_hObserverTarget == NULL )
Observer_FindNextPlayer( false );
if (m_hObserverTarget)
{
pev->iuser1 = OBS_CHASE_LOCKED;
pev->iuser2 = ENTINDEX( m_hObserverTarget->edict() );
ClientPrint( pev, HUD_PRINTCENTER, "#Spec_Mode1" );
pev->maxspeed = 0;
}
else
{
ClientPrint( pev, HUD_PRINTCENTER, "#Spec_NoTarget" );
Observer_SetMode(OBS_ROAMING);
}
return;
}
// Changing to Chase Freelook?
if ( iMode == OBS_CHASE_FREE )
{
// If changing from Roaming, or starting observing, make sure there is a target
// if ( m_hObserverTarget == NULL )
if ( pev->iuser1 == OBS_ROAMING )
Observer_FindNextPlayer( false );
if (m_hObserverTarget)
{
pev->iuser1 = OBS_CHASE_FREE;
pev->iuser2 = ENTINDEX( m_hObserverTarget->edict() );
// ClientPrint( pev, HUD_PRINTCENTER, "Chase-Camera Mode" );
pev->maxspeed = 0;
}
else
{
ClientPrint( pev, HUD_PRINTCENTER, "#Spec_NoTarget" );
Observer_SetMode(OBS_ROAMING);
}
return;
}
}
void CBasePlayer::BMOD_PreThink(void)
{
// Bubblemod freeze ray
if (m_flFreezeTime > 0)
{
if (m_flFreezeTime <= gpGlobals->time)
{
EnableControl(TRUE);
// pev->movetype = MOVETYPE_WALK;
pev->rendermode = kRenderNormal;
pev->renderfx = kRenderFxNone;
pev->renderamt = 0;
m_flFreezeTime = 0;
}
else
{
pev->v_angle = m_vFreezeAngle;
pev->fixangle = TRUE;
}
}
// Bubblemod spawn
if (
m_fSpawnTimeStamp &&
m_fSpawnTimeStamp + bm_spawnkilltime.value >= gpGlobals->time &&
m_iMessageFire
)
{
PrintMessage( this, BMOD_CHAN_INFO, Vector (255,0,0), Vector (.1, bm_spawnkilltime.value, .1),
UTIL_VarArgs("Spawn Protection: %d seconds", (int)(m_fSpawnTimeStamp + bm_spawnkilltime.value - gpGlobals->time))
);
}
if (m_fSpawnTimeStamp > 0 &&
((m_fSpawnTimeStamp + bm_spawnkilltime.value) <= gpGlobals->time) ) {
if (m_RuneFlags == RUNE_NONE &&
m_flFreezeTime == 0) {
pev->rendermode = kRenderNormal;
pev->renderfx = kRenderFxNone;
pev->renderamt = 0;
}
BMOD_ResetSpawnKill();
}
// Bubblemod runes
if (m_RuneFlags && (m_RuneTime < gpGlobals->time) )
{
m_RuneFlags = RUNE_NONE;
pev->rendermode = kRenderNormal;
pev->renderfx = kRenderFxNone;
pev->renderamt = 0;
}
// BubbleMod Type detection
if (pev->button & ~IN_SCORE ) {
BMOD_ResetTypeKill();
}
// Color the typer
if (BMOD_IsTyping() &&
m_iMessageFire ) {
if (!(m_iMessageCounter % 2)) {
//MESSAGE_BEGIN( MSG_PVS, SVC_TEMPENTITY, pev->origin );
// WRITE_BYTE( TE_SMOKE );
// WRITE_COORD( pev->origin.x );
// WRITE_COORD( pev->origin.y );
// WRITE_COORD( pev->origin.z - 36 );
// WRITE_SHORT( g_sModelIndexSmoke );
// WRITE_BYTE( 10 ); // scale * 10
// WRITE_BYTE( 10 ); // framerate
//MESSAGE_END();
MESSAGE_BEGIN( MSG_PVS, SVC_TEMPENTITY, pev->origin );
WRITE_BYTE( TE_SPRITE );
WRITE_COORD( pev->origin.x + RANDOM_LONG( -10, 10) );
WRITE_COORD( pev->origin.y + RANDOM_LONG( -10, 10) );
WRITE_COORD( pev->origin.z + RANDOM_LONG( -30, 30) );
WRITE_SHORT( g_sModelIndexFlare );
WRITE_BYTE( 3 ); // scale * 10
WRITE_BYTE( 255 ); // alpha
MESSAGE_END();
}
float fCos = cos( gpGlobals->time * 4.00) * 8;
float fSin = sin( gpGlobals->time * 4.00) * 8;
MESSAGE_BEGIN( MSG_PVS, SVC_TEMPENTITY, pev->origin );
WRITE_BYTE( TE_BUBBLES );
WRITE_COORD( pev->origin.x + fCos);
WRITE_COORD( pev->origin.y + fSin);
WRITE_COORD( pev->origin.z - 36 );
WRITE_COORD( pev->origin.x + fCos); // mins
WRITE_COORD( pev->origin.y + fSin);
WRITE_COORD( pev->origin.z - 36 );
WRITE_COORD( 75 ); // height
WRITE_SHORT( g_sModelIndexBubbles );
WRITE_BYTE( 3 ); // count
WRITE_COORD( -1 ); // speed
MESSAGE_END();
// Away put your weapons!
//if (m_pActiveItem) {
// ResetAutoaim( );
// m_pActiveItem->Holster( );
// m_pActiveItem = NULL;
//}
m_pLastItem = m_pActiveItem;
if (!m_bTypeMode) {
m_bTypeMode = TRUE;
// EnableControl(FALSE);
if (bm_typecam.value) {
// spawn a camera above us and use that for our view.
CCamPoint *pCam = (CCamPoint*)CBaseEntity::Create( "campoint",
pev->origin + Vector(0,0,40),
Vector(pev->angles.x + 22, pev->angles.y + 180, 0),
edict() );
if (pCam) {
pCam->m_pOwner = this;
pCam->Think();
// UTIL_ClientPrintAll( HUD_PRINTTALK, "<SERVER> Camera point created.\n");
SET_VIEW(edict(), pCam->edict());
SET_MODEL(ENT(pCam->pev), STRING(pev->model) );
pev->fov = m_iFOV = 140;
}
}
}
}
}
void CBasePlayer::BMOD_Think( void )
{
// BMOD End - Message delayer.
// Message delayer. USE THIS for general messages to players.
// counts tenths of seconds.
if (m_fMessageTimer < gpGlobals->time)
{
m_fMessageTimer = gpGlobals->time + .1;
m_iMessageCounter++;
m_iMessageFire = TRUE;
}
// Locator
if (m_LocateMode && m_iMessageFire) {
int yang = (int)pev->angles.y;
if (yang < 0)
yang += 360;
ClientPrint( pev, HUD_PRINTCENTER, UTIL_VarArgs ("Location: %dx %dy %dz, facing %d",
(int)pev->origin.x,
(int)pev->origin.y,
(int)pev->origin.z,
yang
) );
}
// Llamas!
if (m_IsLlama && m_iMessageFire && !(m_iMessageCounter%5)) {
CLIENT_COMMAND(edict(), "drop\n");
}
// Autoban
if (m_bBanMe && m_iMessageFire)
{
char cmd[81] = "";
sprintf( cmd, "banid %d %s kick\n", (int)bm_bantime.value, GETPLAYERAUTHID( edict() ));
SERVER_COMMAND(cmd);
}
// BMOD Begin - Spam Kick
if (m_iMessageFire && !(m_iMessageCounter%10) && m_iSpamSay)
{
m_iSpamSay--;
}
if (bm_antispam.value && m_iSpamSay > bm_spamlimit.value)
{
char cmd[81] = "";
sprintf( cmd, "kick # %u\n", GETPLAYERUSERID( edict() ));
SERVER_COMMAND(cmd);
UTIL_ClientPrintAll( HUD_PRINTTALK, UTIL_VarArgs( "<SERVER> %s was kicked for spamming.\n",
STRING( pev->netname )));
UTIL_LogPrintf( "\"SERVER<-1><-1><>\" say \"%s was was kicked for spamming.\"\n",
STRING( pev->netname ));
UTIL_LogPrintf( "// \"%s<%i><%s><%s>\" was kicked for spamming.\n",
STRING( pev->netname ),
GETPLAYERUSERID( edict() ),
GETPLAYERAUTHID( edict() ),
g_engfuncs.pfnInfoKeyValue( g_engfuncs.pfnGetInfoKeyBuffer( edict() ), "model" )
);
m_iSpamSay = 0;
}
// BMOD End - Spam Kick
}
void CBasePlayer::BMOD_PostThink( void )
{
}
void CBasePlayer::BMOD_Identify( void )
{
static float timer = gpGlobals->time;
static CBasePlayer *LastIdentPlayer = NULL;
TraceResult tr;
CBasePlayer *pPlayer = GetClassPtr((CBasePlayer *)pev);
Vector anglesAim = pPlayer->pev->v_angle;
UTIL_MakeVectors( anglesAim );
anglesAim.x = -anglesAim.x;
Vector vecSrc = pPlayer->GetGunPosition( ) - gpGlobals->v_up * 1;
Vector vecDir = gpGlobals->v_forward;
gpGlobals->trace_flags = FTRACE_SIMPLEBOX;
UTIL_TraceLine(vecSrc, vecSrc + vecDir * 8192, dont_ignore_monsters, ENT(pPlayer->pev), &tr);
CBaseEntity *pOther = CBaseEntity::Instance( tr.pHit );
// Do we have our nose in a wall?
if (((tr.vecEndPos - vecSrc).Length() > 40) || pOther->IsPlayer()) {
BMOD_ResetTypeKill();
}
if ( pOther->IsPlayer() &&
(
(CBasePlayer *)pOther != LastIdentPlayer ||
timer <= gpGlobals->time
)
)
{
char szExtra[81] = "\n";
if (((CBasePlayer *)pOther)->BMOD_IsASpawn()) {
strcat(szExtra, "\nFresh Spawn! DO NOT SHOOT!");
}
if (((CBasePlayer *)pOther)->BMOD_IsTyping()) {
strcat(szExtra, "\nTyping! DO NOT SHOOT!");
}
CBasePlayer *pPlayer = (CBasePlayer *)pOther;
if (IsObserver())
ClientPrint( pev, HUD_PRINTCENTER, UTIL_VarArgs ("-%s-\n(%s) %i / %i%s",
STRING( pPlayer->pev->netname ),
g_engfuncs.pfnInfoKeyValue( g_engfuncs.pfnGetInfoKeyBuffer( pPlayer->edict() ), "model" ),
(int)pPlayer->pev->health,
(int)pPlayer->pev->armorvalue,
szExtra
) );
else if ( g_pGameRules->PlayerRelationship( pOther, this ) == GR_TEAMMATE )
ClientPrint( pev, HUD_PRINTCENTER, UTIL_VarArgs ("-%s-\n%i / %i",
STRING( pPlayer->pev->netname ),
(int)pPlayer->pev->health,
(int)pPlayer->pev->armorvalue)
);
else
ClientPrint( pev, HUD_PRINTCENTER, UTIL_VarArgs ("-%s-\n(%s)%s",
STRING( pPlayer->pev->netname ),
g_engfuncs.pfnInfoKeyValue( g_engfuncs.pfnGetInfoKeyBuffer( pPlayer->edict() ), "model" ),
szExtra
) );
timer = gpGlobals->time + .5;
LastIdentPlayer = (CBasePlayer *)pOther;
}
else if (!pOther->IsPlayer()) {
LastIdentPlayer = NULL;
}
}
int CBasePlayer::BMOD_WasSpawnKilled( void )
{
if ( !IsAlive() &&
m_fSpawnTimeStamp &&
((m_fSpawnTimeStamp + bm_spawnkilltime.value) > gpGlobals->time) &&
bm_spawnkilltime.value)
return TRUE;
return FALSE;
}
int CBasePlayer::BMOD_IsASpawn( void )
{
if ( IsAlive() &&
m_fSpawnTimeStamp &&
((m_fSpawnTimeStamp + bm_spawnkilltime.value) > gpGlobals->time) &&
bm_spawnkilltime.value)
return TRUE;
return FALSE;
}
void CBasePlayer::BMOD_ResetSpawnKill( void )
{
if (m_RuneFlags == RUNE_NONE &&
m_flFreezeTime == 0) {
pev->rendermode = kRenderNormal;
pev->renderfx = kRenderFxNone;
pev->renderamt = 0;
}
m_fSpawnTimeStamp = 0;
PrintMessage( this, BMOD_CHAN_INFO, Vector (20,250,20), Vector (.1, 1, .1), "");
}
int CBasePlayer::BMOD_WasTypeKilled( void )
{
if ( !IsAlive() &&
m_flTypeKillStamp > 0 &&
m_flTypeKillStamp < gpGlobals->time &&
!bm_typekills.value )
return TRUE;
return FALSE;
}
int CBasePlayer::BMOD_IsTyping( void )
{
if ( IsAlive() &&
m_flTypeKillStamp &&
m_flTypeKillStamp < gpGlobals->time &&
!bm_typekills.value ) {
// Do we have a crowbar?
if (m_pActiveItem != NULL &&
strcmp("weapon_crowbar", STRING(m_pActiveItem->pev->classname))
)
{
BMOD_ResetTypeKill();
return FALSE;
}
return TRUE;
}
return FALSE;
}
void CBasePlayer::BMOD_ResetTypeKill( void )
{
if ( IsAlive() ) {
// make a sound if we are coming out of type mode.
if (m_bTypeMode)
{
EMIT_SOUND(ENT(pev), CHAN_VOICE, "fvox/alert.wav", 1.0, ATTN_NORM);
SET_VIEW(edict(), edict());
pev->fov = m_iFOV = 0;
}
m_bTypeMode = FALSE;
// EnableControl(TRUE);
m_flTypeKillStamp = gpGlobals->time + 4;
}
return;
}