// --------------------------------------------------------------- // BubbleMod // // AUTHOR // Tyler Lund // // 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, " 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( " %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; }