aboutsummaryrefslogtreecommitdiff
path: root/sp/src/game/server/sdk
diff options
context:
space:
mode:
Diffstat (limited to 'sp/src/game/server/sdk')
-rw-r--r--sp/src/game/server/sdk/sdk_bot_temp.cpp472
-rw-r--r--sp/src/game/server/sdk/sdk_bot_temp.h21
-rw-r--r--sp/src/game/server/sdk/sdk_brushentity.cpp79
-rw-r--r--sp/src/game/server/sdk/sdk_client.cpp164
-rw-r--r--sp/src/game/server/sdk/sdk_env_message.cpp46
-rw-r--r--sp/src/game/server/sdk/sdk_env_sparkler.cpp104
-rw-r--r--sp/src/game/server/sdk/sdk_eventlog.cpp55
-rw-r--r--sp/src/game/server/sdk/sdk_gameinterface.cpp29
-rw-r--r--sp/src/game/server/sdk/sdk_logicalentity.cpp66
-rw-r--r--sp/src/game/server/sdk/sdk_modelentity.cpp128
-rw-r--r--sp/src/game/server/sdk/sdk_player.cpp366
-rw-r--r--sp/src/game/server/sdk/sdk_player.h101
-rw-r--r--sp/src/game/server/sdk/sdk_playermove.cpp89
-rw-r--r--sp/src/game/server/sdk/sdk_team.cpp40
-rw-r--r--sp/src/game/server/sdk/sdk_team.h38
-rw-r--r--sp/src/game/server/sdk/sdk_vehicle_jeep.cpp1584
-rw-r--r--sp/src/game/server/sdk/te_firebullets.cpp98
-rw-r--r--sp/src/game/server/sdk/te_firebullets.h24
18 files changed, 3504 insertions, 0 deletions
diff --git a/sp/src/game/server/sdk/sdk_bot_temp.cpp b/sp/src/game/server/sdk/sdk_bot_temp.cpp
new file mode 100644
index 00000000..e8990919
--- /dev/null
+++ b/sp/src/game/server/sdk/sdk_bot_temp.cpp
@@ -0,0 +1,472 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose: Basic BOT handling.
+//
+// $Workfile: $
+// $Date: $
+//
+//-----------------------------------------------------------------------------
+// $Log: $
+//
+// $NoKeywords: $
+//=============================================================================//
+
+#include "cbase.h"
+#include "player.h"
+#include "sdk_player.h"
+#include "in_buttons.h"
+#include "movehelper_server.h"
+#include "gameinterface.h"
+
+
+class CSDKBot;
+void Bot_Think( CSDKBot *pBot );
+
+
+ConVar bot_forcefireweapon( "bot_forcefireweapon", "", 0, "Force bots with the specified weapon to fire." );
+ConVar bot_forceattack2( "bot_forceattack2", "0", 0, "When firing, use attack2." );
+ConVar bot_forceattackon( "bot_forceattackon", "0", 0, "When firing, don't tap fire, hold it down." );
+ConVar bot_flipout( "bot_flipout", "0", 0, "When on, all bots fire their guns." );
+ConVar bot_changeclass( "bot_changeclass", "0", 0, "Force all bots to change to the specified class." );
+static ConVar bot_mimic( "bot_mimic", "0", 0, "Bot uses usercmd of player by index." );
+static ConVar bot_mimic_yaw_offset( "bot_mimic_yaw_offset", "0", 0, "Offsets the bot yaw." );
+
+ConVar bot_sendcmd( "bot_sendcmd", "", 0, "Forces bots to send the specified command." );
+
+ConVar bot_crouch( "bot_crouch", "0", 0, "Bot crouches" );
+
+static int g_CurBotNumber = 1;
+
+
+// This is our bot class.
+class CSDKBot : public CSDKPlayer
+{
+public:
+ bool m_bBackwards;
+
+ float m_flNextTurnTime;
+ bool m_bLastTurnToRight;
+
+ float m_flNextStrafeTime;
+ float m_flSideMove;
+
+ QAngle m_ForwardAngle;
+ QAngle m_LastAngles;
+};
+
+LINK_ENTITY_TO_CLASS( sdk_bot, CSDKBot );
+
+class CBotManager
+{
+public:
+ static CBasePlayer* ClientPutInServerOverride_Bot( edict_t *pEdict, const char *playername )
+ {
+ // This tells it which edict to use rather than creating a new one.
+ CBasePlayer::s_PlayerEdict = pEdict;
+
+ CSDKBot *pPlayer = static_cast<CSDKBot *>( CreateEntityByName( "sdk_bot" ) );
+ if ( pPlayer )
+ {
+ pPlayer->SetPlayerName( playername );
+ }
+
+ return pPlayer;
+ }
+};
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Create a new Bot and put it in the game.
+// Output : Pointer to the new Bot, or NULL if there's no free clients.
+//-----------------------------------------------------------------------------
+CBasePlayer *BotPutInServer( bool bFrozen )
+{
+ char botname[ 64 ];
+ Q_snprintf( botname, sizeof( botname ), "Bot%02i", g_CurBotNumber );
+
+
+ // This trick lets us create a CSDKBot for this client instead of the CSDKPlayer
+ // that we would normally get when ClientPutInServer is called.
+ ClientPutInServerOverride( &CBotManager::ClientPutInServerOverride_Bot );
+ edict_t *pEdict = engine->CreateFakeClient( botname );
+ ClientPutInServerOverride( NULL );
+
+ if (!pEdict)
+ {
+ Msg( "Failed to create Bot.\n");
+ return NULL;
+ }
+
+ // Allocate a player entity for the bot, and call spawn
+ CSDKBot *pPlayer = ((CSDKBot*)CBaseEntity::Instance( pEdict ));
+
+ pPlayer->ClearFlags();
+ pPlayer->AddFlag( FL_CLIENT | FL_FAKECLIENT );
+
+ if ( bFrozen )
+ pPlayer->AddEFlags( EFL_BOT_FROZEN );
+
+ pPlayer->ChangeTeam( TEAM_UNASSIGNED );
+ pPlayer->RemoveAllItems( true );
+ pPlayer->Spawn();
+
+ g_CurBotNumber++;
+
+ return pPlayer;
+}
+
+// Handler for the "bot" command.
+CON_COMMAND_F( "bot_add", "Add a bot.", FCVAR_CHEAT )
+{
+ // Look at -count.
+ int count = args.FindArgInt( "-count", 1 );
+ count = clamp( count, 1, 16 );
+
+ // Look at -frozen.
+ bool bFrozen = !!args.FindArg( "-frozen" );
+
+ // Ok, spawn all the bots.
+ while ( --count >= 0 )
+ {
+ BotPutInServer( bFrozen );
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Run through all the Bots in the game and let them think.
+//-----------------------------------------------------------------------------
+void Bot_RunAll( void )
+{
+ for ( int i = 1; i <= gpGlobals->maxClients; i++ )
+ {
+ CSDKPlayer *pPlayer = ToSDKPlayer( UTIL_PlayerByIndex( i ) );
+
+ if ( pPlayer && (pPlayer->GetFlags() & FL_FAKECLIENT) )
+ {
+ CSDKBot *pBot = dynamic_cast< CSDKBot* >( pPlayer );
+ if ( pBot )
+ Bot_Think( pBot );
+ }
+ }
+}
+
+bool Bot_RunMimicCommand( CUserCmd& cmd )
+{
+ if ( bot_mimic.GetInt() <= 0 )
+ return false;
+
+ if ( bot_mimic.GetInt() > gpGlobals->maxClients )
+ return false;
+
+
+ CBasePlayer *pPlayer = UTIL_PlayerByIndex( bot_mimic.GetInt() );
+ if ( !pPlayer )
+ return false;
+
+ if ( !pPlayer->GetLastUserCommand() )
+ return false;
+
+ cmd = *pPlayer->GetLastUserCommand();
+ cmd.viewangles[YAW] += bot_mimic_yaw_offset.GetFloat();
+
+ if( bot_crouch.GetInt() )
+ cmd.buttons |= IN_DUCK;
+
+ return true;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Simulates a single frame of movement for a player
+// Input : *fakeclient -
+// *viewangles -
+// forwardmove -
+// m_flSideMove -
+// upmove -
+// buttons -
+// impulse -
+// msec -
+// Output : virtual void
+//-----------------------------------------------------------------------------
+static void RunPlayerMove( CSDKPlayer *fakeclient, CUserCmd &cmd, float frametime )
+{
+ if ( !fakeclient )
+ return;
+
+ // Store off the globals.. they're gonna get whacked
+ float flOldFrametime = gpGlobals->frametime;
+ float flOldCurtime = gpGlobals->curtime;
+
+ float flTimeBase = gpGlobals->curtime + gpGlobals->frametime - frametime;
+ fakeclient->SetTimeBase( flTimeBase );
+
+ MoveHelperServer()->SetHost( fakeclient );
+ fakeclient->PlayerRunCommand( &cmd, MoveHelperServer() );
+
+ // save off the last good usercmd
+ fakeclient->SetLastUserCommand( cmd );
+
+ // Clear out any fixangle that has been set
+ fakeclient->pl.fixangle = FIXANGLE_NONE;
+
+ // Restore the globals..
+ gpGlobals->frametime = flOldFrametime;
+ gpGlobals->curtime = flOldCurtime;
+}
+
+
+
+void Bot_UpdateStrafing( CSDKBot *pBot, CUserCmd &cmd )
+{
+ if ( gpGlobals->curtime >= pBot->m_flNextStrafeTime )
+ {
+ pBot->m_flNextStrafeTime = gpGlobals->curtime + 1.0f;
+
+ if ( random->RandomInt( 0, 5 ) == 0 )
+ {
+ pBot->m_flSideMove = -600.0f + 1200.0f * random->RandomFloat( 0, 2 );
+ }
+ else
+ {
+ pBot->m_flSideMove = 0;
+ }
+ cmd.sidemove = pBot->m_flSideMove;
+
+ if ( random->RandomInt( 0, 20 ) == 0 )
+ {
+ pBot->m_bBackwards = true;
+ }
+ else
+ {
+ pBot->m_bBackwards = false;
+ }
+ }
+}
+
+
+void Bot_UpdateDirection( CSDKBot *pBot )
+{
+ float angledelta = 15.0;
+ QAngle angle;
+
+ int maxtries = (int)360.0/angledelta;
+
+ if ( pBot->m_bLastTurnToRight )
+ {
+ angledelta = -angledelta;
+ }
+
+ angle = pBot->GetLocalAngles();
+
+ trace_t trace;
+ Vector vecSrc, vecEnd, forward;
+ while ( --maxtries >= 0 )
+ {
+ AngleVectors( angle, &forward );
+
+ vecSrc = pBot->GetLocalOrigin() + Vector( 0, 0, 36 );
+
+ vecEnd = vecSrc + forward * 10;
+
+ UTIL_TraceHull( vecSrc, vecEnd, VEC_HULL_MIN_SCALED( pBot ), VEC_HULL_MAX_SCALED( pBot ),
+ MASK_PLAYERSOLID, pBot, COLLISION_GROUP_NONE, &trace );
+
+ if ( trace.fraction == 1.0 )
+ {
+ if ( gpGlobals->curtime < pBot->m_flNextTurnTime )
+ {
+ break;
+ }
+ }
+
+ angle.y += angledelta;
+
+ if ( angle.y > 180 )
+ angle.y -= 360;
+ else if ( angle.y < -180 )
+ angle.y += 360;
+
+ pBot->m_flNextTurnTime = gpGlobals->curtime + 2.0;
+ pBot->m_bLastTurnToRight = random->RandomInt( 0, 1 ) == 0 ? true : false;
+
+ pBot->m_ForwardAngle = angle;
+ pBot->m_LastAngles = angle;
+ }
+
+ pBot->SetLocalAngles( angle );
+}
+
+
+void Bot_FlipOut( CSDKBot *pBot, CUserCmd &cmd )
+{
+ if ( bot_flipout.GetInt() > 0 && pBot->IsAlive() )
+ {
+ if ( bot_forceattackon.GetBool() || (RandomFloat(0.0,1.0) > 0.5) )
+ {
+ cmd.buttons |= bot_forceattack2.GetBool() ? IN_ATTACK2 : IN_ATTACK;
+ }
+
+ if ( bot_flipout.GetInt() >= 2 )
+ {
+ QAngle angOffset = RandomAngle( -1, 1 );
+
+ pBot->m_LastAngles += angOffset;
+
+ for ( int i = 0 ; i < 2; i++ )
+ {
+ if ( fabs( pBot->m_LastAngles[ i ] - pBot->m_ForwardAngle[ i ] ) > 15.0f )
+ {
+ if ( pBot->m_LastAngles[ i ] > pBot->m_ForwardAngle[ i ] )
+ {
+ pBot->m_LastAngles[ i ] = pBot->m_ForwardAngle[ i ] + 15;
+ }
+ else
+ {
+ pBot->m_LastAngles[ i ] = pBot->m_ForwardAngle[ i ] - 15;
+ }
+ }
+ }
+
+ pBot->m_LastAngles[ 2 ] = 0;
+
+ pBot->SetLocalAngles( pBot->m_LastAngles );
+ }
+ }
+}
+
+
+void Bot_HandleSendCmd( CSDKBot *pBot )
+{
+ if ( strlen( bot_sendcmd.GetString() ) > 0 )
+ {
+ //send the cmd from this bot
+ pBot->ClientCommand( bot_sendcmd.GetString() );
+
+ bot_sendcmd.SetValue("");
+ }
+}
+
+
+// If bots are being forced to fire a weapon, see if I have it
+void Bot_ForceFireWeapon( CSDKBot *pBot, CUserCmd &cmd )
+{
+ if ( bot_forcefireweapon.GetString() )
+ {
+ CBaseCombatWeapon *pWeapon = pBot->Weapon_OwnsThisType( bot_forcefireweapon.GetString() );
+ if ( pWeapon )
+ {
+ // Switch to it if we don't have it out
+ CBaseCombatWeapon *pActiveWeapon = pBot->GetActiveWeapon();
+
+ // Switch?
+ if ( pActiveWeapon != pWeapon )
+ {
+ pBot->Weapon_Switch( pWeapon );
+ }
+ else
+ {
+ // Start firing
+ // Some weapons require releases, so randomise firing
+ if ( bot_forceattackon.GetBool() || (RandomFloat(0.0,1.0) > 0.5) )
+ {
+ cmd.buttons |= bot_forceattack2.GetBool() ? IN_ATTACK2 : IN_ATTACK;
+ }
+ }
+ }
+ }
+}
+
+
+void Bot_SetForwardMovement( CSDKBot *pBot, CUserCmd &cmd )
+{
+ if ( !pBot->IsEFlagSet(EFL_BOT_FROZEN) )
+ {
+ if ( pBot->m_iHealth == 100 )
+ {
+ cmd.forwardmove = 600 * ( pBot->m_bBackwards ? -1 : 1 );
+ if ( pBot->m_flSideMove != 0.0f )
+ {
+ cmd.forwardmove *= random->RandomFloat( 0.1, 1.0f );
+ }
+ }
+ else
+ {
+ // Stop when shot
+ cmd.forwardmove = 0;
+ }
+ }
+}
+
+
+void Bot_HandleRespawn( CSDKBot *pBot, CUserCmd &cmd )
+{
+ // Wait for Reinforcement wave
+ if ( !pBot->IsAlive() )
+ {
+ // Try hitting my buttons occasionally
+ if ( random->RandomInt( 0, 100 ) > 80 )
+ {
+ // Respawn the bot
+ if ( random->RandomInt( 0, 1 ) == 0 )
+ {
+ cmd.buttons |= IN_JUMP;
+ }
+ else
+ {
+ cmd.buttons = 0;
+ }
+ }
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Run this Bot's AI for one frame.
+//-----------------------------------------------------------------------------
+void Bot_Think( CSDKBot *pBot )
+{
+ // Make sure we stay being a bot
+ pBot->AddFlag( FL_FAKECLIENT );
+
+
+ CUserCmd cmd;
+ Q_memset( &cmd, 0, sizeof( cmd ) );
+
+
+ // Finally, override all this stuff if the bot is being forced to mimic a player.
+ if ( !Bot_RunMimicCommand( cmd ) )
+ {
+ cmd.sidemove = pBot->m_flSideMove;
+
+ if ( pBot->IsAlive() && (pBot->GetSolid() == SOLID_BBOX) )
+ {
+ Bot_SetForwardMovement( pBot, cmd );
+
+ // Only turn if I haven't been hurt
+ if ( !pBot->IsEFlagSet(EFL_BOT_FROZEN) && pBot->m_iHealth == 100 )
+ {
+ Bot_UpdateDirection( pBot );
+ Bot_UpdateStrafing( pBot, cmd );
+ }
+
+ // Handle console settings.
+ Bot_ForceFireWeapon( pBot, cmd );
+ Bot_HandleSendCmd( pBot );
+ }
+ else
+ {
+ Bot_HandleRespawn( pBot, cmd );
+ }
+
+ Bot_FlipOut( pBot, cmd );
+
+ cmd.viewangles = pBot->GetLocalAngles();
+ cmd.upmove = 0;
+ cmd.impulse = 0;
+ }
+
+ float frametime = gpGlobals->frametime;
+ RunPlayerMove( pBot, cmd, frametime );
+}
+
+
diff --git a/sp/src/game/server/sdk/sdk_bot_temp.h b/sp/src/game/server/sdk/sdk_bot_temp.h
new file mode 100644
index 00000000..5af98423
--- /dev/null
+++ b/sp/src/game/server/sdk/sdk_bot_temp.h
@@ -0,0 +1,21 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================//
+
+#ifndef SDK_BOT_TEMP_H
+#define SDK_BOT_TEMP_H
+#ifdef _WIN32
+#pragma once
+#endif
+
+
+// If iTeam or iClass is -1, then a team or class is randomly chosen.
+CBasePlayer *BotPutInServer( bool bFrozen, int iTeam, int iClass );
+
+void Bot_RunAll();
+
+
+#endif // SDK_BOT_TEMP_H
diff --git a/sp/src/game/server/sdk/sdk_brushentity.cpp b/sp/src/game/server/sdk/sdk_brushentity.cpp
new file mode 100644
index 00000000..74408ee3
--- /dev/null
+++ b/sp/src/game/server/sdk/sdk_brushentity.cpp
@@ -0,0 +1,79 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose: Simple brush entity that moves when touched
+//
+//=============================================================================//
+
+#include "cbase.h"
+
+class CMyBrushEntity : public CBaseToggle
+{
+public:
+ DECLARE_CLASS( CMyBrushEntity, CBaseToggle );
+ DECLARE_DATADESC();
+
+ void Spawn( void );
+ bool CreateVPhysics( void );
+
+ void BrushTouch( CBaseEntity *pOther );
+};
+
+LINK_ENTITY_TO_CLASS( my_brush_entity, CMyBrushEntity );
+
+// Start of our data description for the class
+BEGIN_DATADESC( CMyBrushEntity )
+
+ // Declare this function as being a touch function
+ DEFINE_ENTITYFUNC( BrushTouch ),
+
+END_DATADESC()
+
+//-----------------------------------------------------------------------------
+// Purpose: Sets up the entity's initial state
+//-----------------------------------------------------------------------------
+void CMyBrushEntity::Spawn( void )
+{
+ // We want to capture touches from other entities
+ SetTouch( &CMyBrushEntity::BrushTouch );
+
+ // We should collide with physics
+ SetSolid( SOLID_VPHYSICS );
+
+ // We push things out of our way
+ SetMoveType( MOVETYPE_PUSH );
+
+ // Use our brushmodel
+ SetModel( STRING( GetModelName() ) );
+
+ // Create our physics hull information
+ CreateVPhysics();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Setup our physics information so we collide properly
+//-----------------------------------------------------------------------------
+bool CMyBrushEntity::CreateVPhysics( void )
+{
+ // For collisions with physics objects
+ VPhysicsInitShadow( false, false );
+
+ return true;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Move away from an entity that touched us
+// Input : *pOther - the entity we touched
+//-----------------------------------------------------------------------------
+void CMyBrushEntity::BrushTouch( CBaseEntity *pOther )
+{
+ // Get the collision information
+ const trace_t &tr = GetTouchTrace();
+
+ // We want to move away from the impact point along our surface
+ Vector vecPushDir = tr.plane.normal;
+ vecPushDir.Negate();
+ vecPushDir.z = 0.0f;
+
+ // Move slowly in that direction
+ LinearMove( GetAbsOrigin() + ( vecPushDir * 64.0f ), 32.0f );
+}
diff --git a/sp/src/game/server/sdk/sdk_client.cpp b/sp/src/game/server/sdk/sdk_client.cpp
new file mode 100644
index 00000000..d7329758
--- /dev/null
+++ b/sp/src/game/server/sdk/sdk_client.cpp
@@ -0,0 +1,164 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//
+//=============================================================================//
+/*
+
+===== tf_client.cpp ========================================================
+
+ HL2 client/server game specific stuff
+
+*/
+
+#include "cbase.h"
+#include "player.h"
+#include "gamerules.h"
+#include "entitylist.h"
+#include "physics.h"
+#include "game.h"
+#include "ai_network.h"
+#include "ai_node.h"
+#include "ai_hull.h"
+#include "shake.h"
+#include "player_resource.h"
+#include "engine/IEngineSound.h"
+#include "sdk_player.h"
+#include "sdk_gamerules.h"
+#include "tier0/vprof.h"
+#include "sdk_bot_temp.h"
+
+// memdbgon must be the last include file in a .cpp file!!!
+#include "tier0/memdbgon.h"
+
+
+extern CBaseEntity *FindPickerEntity( CBasePlayer *pPlayer );
+
+extern bool g_fGameOver;
+
+
+void FinishClientPutInServer( CSDKPlayer *pPlayer )
+{
+ pPlayer->InitialSpawn();
+ pPlayer->Spawn();
+
+ if (!pPlayer->IsBot())
+ {
+ // When the player first joins the server, they
+ pPlayer->m_takedamage = DAMAGE_YES;
+ pPlayer->pl.deadflag = false;
+ pPlayer->m_lifeState = LIFE_ALIVE;
+ pPlayer->RemoveEffects( EF_NODRAW );
+ pPlayer->ChangeTeam( TEAM_UNASSIGNED );
+ pPlayer->SetThink( NULL );
+ }
+
+ char sName[128];
+ Q_strncpy( sName, pPlayer->GetPlayerName(), sizeof( sName ) );
+
+ // First parse the name and remove any %'s
+ for ( char *pApersand = sName; pApersand != NULL && *pApersand != 0; pApersand++ )
+ {
+ // Replace it with a space
+ if ( *pApersand == '%' )
+ *pApersand = ' ';
+ }
+
+ // notify other clients of player joining the game
+ UTIL_ClientPrintAll( HUD_PRINTNOTIFY, "#Game_connected", sName[0] != 0 ? sName : "<unconnected>" );
+}
+
+/*
+===========
+ClientPutInServer
+
+called each time a player is spawned into the game
+============
+*/
+void ClientPutInServer( edict_t *pEdict, const char *playername )
+{
+ // Allocate a CBaseTFPlayer for pev, and call spawn
+ CSDKPlayer *pPlayer = CSDKPlayer::CreatePlayer( "player", pEdict );
+ pPlayer->SetPlayerName( playername );
+}
+
+
+void ClientActive( edict_t *pEdict, bool bLoadGame )
+{
+ // Can't load games in CS!
+ Assert( !bLoadGame );
+
+ CSDKPlayer *pPlayer = ToSDKPlayer( CBaseEntity::Instance( pEdict ) );
+ FinishClientPutInServer( pPlayer );
+}
+
+
+/*
+===============
+const char *GetGameDescription()
+
+Returns the descriptive name of this .dll. E.g., Half-Life, or Team Fortress 2
+===============
+*/
+const char *GetGameDescription()
+{
+ if ( g_pGameRules ) // this function may be called before the world has spawned, and the game rules initialized
+ return g_pGameRules->GetGameDescription();
+ else
+ return "CounterStrike";
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Precache game-specific models & sounds
+//-----------------------------------------------------------------------------
+void ClientGamePrecache( void )
+{
+ // Materials used by the client effects
+ CBaseEntity::PrecacheModel( "sprites/white.vmt" );
+ CBaseEntity::PrecacheModel( "sprites/physbeam.vmt" );
+}
+
+
+// called by ClientKill and DeadThink
+void respawn( CBaseEntity *pEdict, bool fCopyCorpse )
+{
+ if (gpGlobals->coop || gpGlobals->deathmatch)
+ {
+ if ( fCopyCorpse )
+ {
+ // make a copy of the dead body for appearances sake
+ dynamic_cast< CBasePlayer* >( pEdict )->CreateCorpse();
+ }
+
+ // respawn player
+ pEdict->Spawn();
+ }
+ else
+ { // restart the entire server
+ engine->ServerCommand("reload\n");
+ }
+}
+
+void GameStartFrame( void )
+{
+ VPROF( "GameStartFrame" );
+
+ if ( g_pGameRules )
+ g_pGameRules->Think();
+
+ if ( g_fGameOver )
+ return;
+
+ gpGlobals->teamplay = teamplay.GetInt() ? true : false;
+}
+
+//=========================================================
+// instantiate the proper game rules object
+//=========================================================
+void InstallGameRules()
+{
+ CreateGameRulesObject( "CSDKGameRules" );
+}
diff --git a/sp/src/game/server/sdk/sdk_env_message.cpp b/sp/src/game/server/sdk/sdk_env_message.cpp
new file mode 100644
index 00000000..c7116755
--- /dev/null
+++ b/sp/src/game/server/sdk/sdk_env_message.cpp
@@ -0,0 +1,46 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose: Simple entity to transmit message to the client
+//
+//=============================================================================//
+
+#include "cbase.h"
+
+class CGameMessageEntity : public CLogicalEntity
+{
+public:
+ DECLARE_CLASS( CGameMessageEntity, CLogicalEntity );
+ DECLARE_DATADESC();
+
+ CGameMessageEntity( void ) {};
+
+ void InputDisplayMessage( inputdata_t &data );
+
+ string_t m_strText;
+};
+
+LINK_ENTITY_TO_CLASS( logic_game_message, CGameMessageEntity );
+
+BEGIN_DATADESC( CGameMessageEntity )
+
+ DEFINE_KEYFIELD( m_strText, FIELD_STRING, "text" ),
+
+ DEFINE_INPUTFUNC( FIELD_VOID, "DisplayMessage", InputDisplayMessage ),
+
+END_DATADESC()
+
+void CGameMessageEntity::InputDisplayMessage( inputdata_t &data )
+{
+ // Only send this message the local player
+ CSingleUserRecipientFilter user( UTIL_PlayerByIndex(1) );
+ user.MakeReliable();
+
+ // Start the message block
+ UserMessageBegin( user, "GameMessage" );
+
+ // Send our text to the client
+ WRITE_STRING( STRING( m_strText ) );
+
+ // End the message block
+ MessageEnd();
+}
diff --git a/sp/src/game/server/sdk/sdk_env_sparkler.cpp b/sp/src/game/server/sdk/sdk_env_sparkler.cpp
new file mode 100644
index 00000000..1eda64a6
--- /dev/null
+++ b/sp/src/game/server/sdk/sdk_env_sparkler.cpp
@@ -0,0 +1,104 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose: A simple test entity for creating special effects
+//
+//=============================================================================//
+
+#include "cbase.h"
+#include "te_effect_dispatch.h"
+
+// Declare the sparkler entity for the server-side
+class CSparkler : public CBaseEntity
+{
+public:
+ DECLARE_SERVERCLASS();
+ DECLARE_CLASS( CSparkler, CBaseEntity );
+
+ void Spawn( void );
+
+ void InputToggle( inputdata_t &input ); // Input function for toggling our effect's state
+ void InputScale( inputdata_t &input );
+
+private:
+ CNetworkVar( bool, m_bEmit ); // Marks whether the effect should be active or not
+ CNetworkVar( float, m_flScale ); // The size and speed of the effect
+
+ DECLARE_DATADESC();
+};
+
+// Link our class to the "env_sparkler" entity classname
+LINK_ENTITY_TO_CLASS( env_sparkler, CSparkler );
+
+// Declare our data description for this entity
+BEGIN_DATADESC( CSparkler )
+ DEFINE_FIELD( m_bEmit, FIELD_BOOLEAN ),
+
+ DEFINE_KEYFIELD( m_flScale, FIELD_FLOAT, "scale" ),
+
+ DEFINE_INPUTFUNC( FIELD_VOID, "Toggle", InputToggle ), // Declare our toggle input function
+ DEFINE_INPUTFUNC( FIELD_FLOAT, "Scale", InputScale ),
+END_DATADESC()
+
+// Declare the data-table for server/client communication
+IMPLEMENT_SERVERCLASS_ST( CSparkler, DT_Sparkler )
+ SendPropInt( SENDINFO( m_bEmit ), 1, SPROP_UNSIGNED ), // Declare our boolean state variable
+ SendPropFloat( SENDINFO( m_flScale ), 0, SPROP_NOSCALE ),
+END_SEND_TABLE()
+
+//-----------------------------------------------------------------------------
+// Purpose: Spawn function for this entity
+//-----------------------------------------------------------------------------
+void CSparkler::Spawn( void )
+{
+ SetMoveType( MOVETYPE_NONE ); // Will not move on its own
+ SetSolid( SOLID_NONE ); // Will not collide with anything
+
+ // Set a size for culling
+ UTIL_SetSize( this, -Vector(2,2,2), Vector(2,2,2) );
+
+ // We must add this flag to receive network transmitions
+ AddEFlags( EFL_FORCE_CHECK_TRANSMIT );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Toggles the emission state of the effect
+//-----------------------------------------------------------------------------
+void CSparkler::InputToggle( inputdata_t &input )
+{
+ // Toggle our state
+ m_bEmit = !m_bEmit;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Change our scale via a float value
+//-----------------------------------------------------------------------------
+void CSparkler::InputScale( inputdata_t &input )
+{
+ // Change our scale
+ m_flScale = input.value.Float();
+}
+
+// ============================================================================
+//
+// Dispatch Effect version
+//
+// ============================================================================
+
+//-----------------------------------------------------------------------------
+// Purpose: Create a sparkle effect at the given location of the given size
+// Input : &position - Where to emit from
+// flSize - Size of the effect
+//-----------------------------------------------------------------------------
+void MakeSparkle( const Vector &origin, float flScale )
+{
+ CEffectData data;
+
+ // Send our origin
+ data.m_vOrigin = origin;
+
+ // Send our scale
+ data.m_flScale = flScale;
+
+ // Send the effect off to the client
+ DispatchEffect( "Sparkle", data );
+} \ No newline at end of file
diff --git a/sp/src/game/server/sdk/sdk_eventlog.cpp b/sp/src/game/server/sdk/sdk_eventlog.cpp
new file mode 100644
index 00000000..5b7edcd4
--- /dev/null
+++ b/sp/src/game/server/sdk/sdk_eventlog.cpp
@@ -0,0 +1,55 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//
+//=============================================================================//
+#include "cbase.h"
+#include "../EventLog.h"
+#include "KeyValues.h"
+
+class CSDKEventLog : public CEventLog
+{
+private:
+ typedef CEventLog BaseClass;
+
+public:
+ virtual ~CSDKEventLog() {};
+
+public:
+ bool PrintEvent( IGameEvent * event ) // override virtual function
+ {
+ if ( BaseClass::PrintEvent( event ) )
+ {
+ return true;
+ }
+
+ if ( Q_strcmp(event->GetName(), "sdk_") == 0 )
+ {
+ return PrintSDKEvent( event );
+ }
+
+ return false;
+ }
+
+protected:
+
+ bool PrintSDKEvent( IGameEvent * event ) // print Mod specific logs
+ {
+ //const char * name = event->GetName() + Q_strlen("sdk_"); // remove prefix
+ return false;
+ }
+
+};
+
+CSDKEventLog g_SDKEventLog;
+
+//-----------------------------------------------------------------------------
+// Singleton access
+//-----------------------------------------------------------------------------
+IGameSystem* GameLogSystem()
+{
+ return &g_SDKEventLog;
+}
+
diff --git a/sp/src/game/server/sdk/sdk_gameinterface.cpp b/sp/src/game/server/sdk/sdk_gameinterface.cpp
new file mode 100644
index 00000000..9a385100
--- /dev/null
+++ b/sp/src/game/server/sdk/sdk_gameinterface.cpp
@@ -0,0 +1,29 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+//=============================================================================//
+
+#include "cbase.h"
+#include "gameinterface.h"
+#include "mapentities.h"
+
+
+// -------------------------------------------------------------------------------------------- //
+// Mod-specific CServerGameClients implementation.
+// -------------------------------------------------------------------------------------------- //
+
+void CServerGameClients::GetPlayerLimits( int& minplayers, int& maxplayers, int &defaultMaxPlayers ) const
+{
+ minplayers = 2; // Force multiplayer.
+ maxplayers = MAX_PLAYERS;
+ defaultMaxPlayers = 32;
+}
+
+// -------------------------------------------------------------------------------------------- //
+// Mod-specific CServerGameDLL implementation.
+// -------------------------------------------------------------------------------------------- //
+
+void CServerGameDLL::LevelInit_ParseAllEntities( const char *pMapEntities )
+{
+}
diff --git a/sp/src/game/server/sdk/sdk_logicalentity.cpp b/sp/src/game/server/sdk/sdk_logicalentity.cpp
new file mode 100644
index 00000000..5cdd4a6e
--- /dev/null
+++ b/sp/src/game/server/sdk/sdk_logicalentity.cpp
@@ -0,0 +1,66 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose: Simple logical entity that counts up to a threshold value, then
+// fires an output when reached.
+//
+//=============================================================================//
+
+#include "cbase.h"
+
+class CMyLogicalEntity : public CLogicalEntity
+{
+public:
+ DECLARE_CLASS( CMyLogicalEntity , CLogicalEntity );
+ DECLARE_DATADESC();
+
+ // Constructor
+ CMyLogicalEntity ( void ) : m_nCounter( 0 ) {}
+
+ // Input function
+ void InputTick( inputdata_t &inputData );
+
+private:
+
+ int m_nThreshold; // Count at which to fire our output
+ int m_nCounter; // Internal counter
+
+ COutputEvent m_OnThreshold; // Output even when the counter reaches the threshold
+};
+
+LINK_ENTITY_TO_CLASS( my_logical_entity, CMyLogicalEntity );
+
+// Start of our data description for the class
+BEGIN_DATADESC( CMyLogicalEntity )
+
+ // For save/load
+ DEFINE_FIELD( m_nCounter, FIELD_INTEGER ),
+
+ // Links our member variable to our keyvalue from Hammer
+ DEFINE_KEYFIELD( m_nThreshold, FIELD_INTEGER, "threshold" ),
+
+ // Links our input name from Hammer to our input member function
+ DEFINE_INPUTFUNC( FIELD_VOID, "Tick", InputTick ),
+
+ // Links our output member to the output name used by Hammer
+ DEFINE_OUTPUT( m_OnThreshold, "OnThreshold" ),
+
+END_DATADESC()
+
+//-----------------------------------------------------------------------------
+// Purpose: Handle a tick input from another entity
+//-----------------------------------------------------------------------------
+void CMyLogicalEntity ::InputTick( inputdata_t &inputData )
+{
+ // Increment our counter
+ m_nCounter++;
+
+ // See if we've met or crossed our threshold value
+ if ( m_nCounter >= m_nThreshold )
+ {
+ // Fire an output event
+ m_OnThreshold.FireOutput( inputData.pActivator, this );
+
+ // Reset our counter
+ m_nCounter = 0;
+ }
+} \ No newline at end of file
diff --git a/sp/src/game/server/sdk/sdk_modelentity.cpp b/sp/src/game/server/sdk/sdk_modelentity.cpp
new file mode 100644
index 00000000..e3dca5b6
--- /dev/null
+++ b/sp/src/game/server/sdk/sdk_modelentity.cpp
@@ -0,0 +1,128 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose: Simple model entity that randomly moves and changes direction
+// when activated.
+//
+//=============================================================================//
+
+#include "cbase.h"
+
+class CMyModelEntity : public CBaseAnimating
+{
+public:
+ DECLARE_CLASS( CMyModelEntity, CBaseAnimating );
+ DECLARE_DATADESC();
+
+ void Spawn( void );
+ void Precache( void );
+
+ void MoveThink( void );
+
+ // Input function
+ void InputToggle( inputdata_t &inputData );
+
+private:
+
+ bool m_bActive;
+ float m_flNextChangeTime;
+};
+
+LINK_ENTITY_TO_CLASS( my_model_entity, CMyModelEntity );
+
+// Start of our data description for the class
+BEGIN_DATADESC( CMyModelEntity )
+
+ // Save/restore our active state
+ DEFINE_FIELD( m_bActive, FIELD_BOOLEAN ),
+ DEFINE_FIELD( m_flNextChangeTime, FIELD_TIME ),
+
+ // Links our input name from Hammer to our input member function
+ DEFINE_INPUTFUNC( FIELD_VOID, "Toggle", InputToggle ),
+
+ // Declare our think function
+ DEFINE_THINKFUNC( MoveThink ),
+
+END_DATADESC()
+
+// Name of our entity's model
+#define ENTITY_MODEL "models/gibs/airboat_broken_engine.mdl"
+
+//-----------------------------------------------------------------------------
+// Purpose: Precache assets used by the entity
+//-----------------------------------------------------------------------------
+void CMyModelEntity::Precache( void )
+{
+ PrecacheModel( ENTITY_MODEL );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Sets up the entity's initial state
+//-----------------------------------------------------------------------------
+void CMyModelEntity::Spawn( void )
+{
+ Precache();
+
+ SetModel( ENTITY_MODEL );
+ SetSolid( SOLID_BBOX );
+ UTIL_SetSize( this, -Vector(20,20,20), Vector(20,20,20) );
+
+ m_bActive = false;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Think function to randomly move the entity
+//-----------------------------------------------------------------------------
+void CMyModelEntity::MoveThink( void )
+{
+ // See if we should change direction again
+ if ( m_flNextChangeTime < gpGlobals->curtime )
+ {
+ // Randomly take a new direction and speed
+ Vector vecNewVelocity = RandomVector( -64.0f, 64.0f );
+ SetAbsVelocity( vecNewVelocity );
+
+ // Randomly change it again within one to three seconds
+ m_flNextChangeTime = gpGlobals->curtime + random->RandomFloat( 1.0f, 3.0f );
+ }
+
+ // Snap our facing to where we're heading
+ Vector velFacing = GetAbsVelocity();
+ QAngle angFacing;
+ VectorAngles( velFacing, angFacing );
+ SetAbsAngles( angFacing );
+
+ // Think every 20Hz
+ SetNextThink( gpGlobals->curtime + 0.05f );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Toggle the movement of the entity
+//-----------------------------------------------------------------------------
+void CMyModelEntity::InputToggle( inputdata_t &inputData )
+{
+ // Toggle our active state
+ if ( !m_bActive )
+ {
+ // Start thinking
+ SetThink( &CMyModelEntity::MoveThink );
+ SetNextThink( gpGlobals->curtime + 0.05f );
+
+ // Start flying
+ SetMoveType( MOVETYPE_FLY );
+
+ // Set our next time for changing our speed and direction
+ m_flNextChangeTime = gpGlobals->curtime;
+ m_bActive = true;
+ }
+ else
+ {
+ // Stop thinking
+ SetThink( NULL );
+
+ // Stop moving
+ SetAbsVelocity( vec3_origin );
+ SetMoveType( MOVETYPE_NONE );
+
+ m_bActive = false;
+ }
+}
diff --git a/sp/src/game/server/sdk/sdk_player.cpp b/sp/src/game/server/sdk/sdk_player.cpp
new file mode 100644
index 00000000..e9b33181
--- /dev/null
+++ b/sp/src/game/server/sdk/sdk_player.cpp
@@ -0,0 +1,366 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose: Player for HL1.
+//
+// $NoKeywords: $
+//=============================================================================//
+
+#include "cbase.h"
+#include "sdk_player.h"
+#include "sdk_gamerules.h"
+#include "weapon_sdkbase.h"
+#include "predicted_viewmodel.h"
+#include "iservervehicle.h"
+#include "viewport_panel_names.h"
+
+extern int gEvilImpulse101;
+
+ConVar sv_motd_unload_on_dismissal( "sv_motd_unload_on_dismissal", "0", 0, "If enabled, the MOTD contents will be unloaded when the player closes the MOTD." );
+
+#define SDK_PLAYER_MODEL "models/player/terror.mdl"
+
+
+// -------------------------------------------------------------------------------- //
+// Player animation event. Sent to the client when a player fires, jumps, reloads, etc..
+// -------------------------------------------------------------------------------- //
+
+class CTEPlayerAnimEvent : public CBaseTempEntity
+{
+public:
+ DECLARE_CLASS( CTEPlayerAnimEvent, CBaseTempEntity );
+ DECLARE_SERVERCLASS();
+
+ CTEPlayerAnimEvent( const char *name ) : CBaseTempEntity( name )
+ {
+ }
+
+ CNetworkHandle( CBasePlayer, m_hPlayer );
+ CNetworkVar( int, m_iEvent );
+ CNetworkVar( int, m_nData );
+};
+
+#define THROWGRENADE_COUNTER_BITS 3
+
+IMPLEMENT_SERVERCLASS_ST_NOBASE( CTEPlayerAnimEvent, DT_TEPlayerAnimEvent )
+ SendPropEHandle( SENDINFO( m_hPlayer ) ),
+ SendPropInt( SENDINFO( m_iEvent ), Q_log2( PLAYERANIMEVENT_COUNT ) + 1, SPROP_UNSIGNED ),
+ SendPropInt( SENDINFO( m_nData ), 32 )
+END_SEND_TABLE()
+
+static CTEPlayerAnimEvent g_TEPlayerAnimEvent( "PlayerAnimEvent" );
+
+void TE_PlayerAnimEvent( CBasePlayer *pPlayer, PlayerAnimEvent_t event, int nData )
+{
+ CPVSFilter filter( (const Vector&)pPlayer->EyePosition() );
+
+ g_TEPlayerAnimEvent.m_hPlayer = pPlayer;
+ g_TEPlayerAnimEvent.m_iEvent = event;
+ g_TEPlayerAnimEvent.m_nData = nData;
+ g_TEPlayerAnimEvent.Create( filter, 0 );
+}
+
+// -------------------------------------------------------------------------------- //
+// Tables.
+// -------------------------------------------------------------------------------- //
+BEGIN_DATADESC( CSDKPlayer )
+DEFINE_THINKFUNC( SDKPushawayThink ),
+END_DATADESC()
+
+LINK_ENTITY_TO_CLASS( player, CSDKPlayer );
+PRECACHE_REGISTER(player);
+
+BEGIN_SEND_TABLE_NOBASE( CSDKPlayer, DT_SDKLocalPlayerExclusive )
+ SendPropInt( SENDINFO( m_iShotsFired ), 8, SPROP_UNSIGNED ),
+END_SEND_TABLE()
+
+IMPLEMENT_SERVERCLASS_ST( CSDKPlayer, DT_SDKPlayer )
+ SendPropExclude( "DT_BaseAnimating", "m_flPoseParameter" ),
+ SendPropExclude( "DT_BaseAnimating", "m_flPlaybackRate" ),
+ SendPropExclude( "DT_BaseAnimating", "m_nSequence" ),
+ SendPropExclude( "DT_BaseEntity", "m_angRotation" ),
+ SendPropExclude( "DT_BaseAnimatingOverlay", "overlay_vars" ),
+
+ // playeranimstate and clientside animation takes care of these on the client
+ SendPropExclude( "DT_ServerAnimationData" , "m_flCycle" ),
+ SendPropExclude( "DT_AnimTimeMustBeFirst" , "m_flAnimTime" ),
+
+ // Data that only gets sent to the local player.
+ SendPropDataTable( "sdklocaldata", 0, &REFERENCE_SEND_TABLE(DT_SDKLocalPlayerExclusive), SendProxy_SendLocalDataTable ),
+
+ SendPropAngle( SENDINFO_VECTORELEM(m_angEyeAngles, 0), 11 ),
+ SendPropAngle( SENDINFO_VECTORELEM(m_angEyeAngles, 1), 11 ),
+ SendPropEHandle( SENDINFO( m_hRagdoll ) ),
+
+ SendPropInt( SENDINFO( m_iThrowGrenadeCounter ), THROWGRENADE_COUNTER_BITS, SPROP_UNSIGNED ),
+END_SEND_TABLE()
+
+class CSDKRagdoll : public CBaseAnimatingOverlay
+{
+public:
+ DECLARE_CLASS( CSDKRagdoll, CBaseAnimatingOverlay );
+ DECLARE_SERVERCLASS();
+
+ // Transmit ragdolls to everyone.
+ virtual int UpdateTransmitState()
+ {
+ return SetTransmitState( FL_EDICT_ALWAYS );
+ }
+
+public:
+ // In case the client has the player entity, we transmit the player index.
+ // In case the client doesn't have it, we transmit the player's model index, origin, and angles
+ // so they can create a ragdoll in the right place.
+ CNetworkHandle( CBaseEntity, m_hPlayer ); // networked entity handle
+ CNetworkVector( m_vecRagdollVelocity );
+ CNetworkVector( m_vecRagdollOrigin );
+};
+
+LINK_ENTITY_TO_CLASS( sdk_ragdoll, CSDKRagdoll );
+
+IMPLEMENT_SERVERCLASS_ST_NOBASE( CSDKRagdoll, DT_SDKRagdoll )
+ SendPropVector( SENDINFO(m_vecRagdollOrigin), -1, SPROP_COORD ),
+ SendPropEHandle( SENDINFO( m_hPlayer ) ),
+ SendPropModelIndex( SENDINFO( m_nModelIndex ) ),
+ SendPropInt ( SENDINFO(m_nForceBone), 8, 0 ),
+ SendPropVector ( SENDINFO(m_vecForce), -1, SPROP_NOSCALE ),
+ SendPropVector( SENDINFO( m_vecRagdollVelocity ) )
+END_SEND_TABLE()
+
+
+// -------------------------------------------------------------------------------- //
+
+void cc_CreatePredictionError_f()
+{
+ CBaseEntity *pEnt = CBaseEntity::Instance( 1 );
+ pEnt->SetAbsOrigin( pEnt->GetAbsOrigin() + Vector( 63, 0, 0 ) );
+}
+
+ConCommand cc_CreatePredictionError( "CreatePredictionError", cc_CreatePredictionError_f, "Create a prediction error", FCVAR_CHEAT );
+
+
+CSDKPlayer::CSDKPlayer()
+{
+ m_PlayerAnimState = CreatePlayerAnimState( this, this, LEGANIM_9WAY, true );
+
+ UseClientSideAnimation();
+ m_angEyeAngles.Init();
+
+ SetViewOffset( SDK_PLAYER_VIEW_OFFSET );
+
+ m_iThrowGrenadeCounter = 0;
+}
+
+
+CSDKPlayer::~CSDKPlayer()
+{
+ m_PlayerAnimState->Release();
+}
+
+
+CSDKPlayer *CSDKPlayer::CreatePlayer( const char *className, edict_t *ed )
+{
+ CSDKPlayer::s_PlayerEdict = ed;
+ return (CSDKPlayer*)CreateEntityByName( className );
+}
+
+void CSDKPlayer::LeaveVehicle( const Vector &vecExitPoint, const QAngle &vecExitAngles )
+{
+ BaseClass::LeaveVehicle( vecExitPoint, vecExitAngles );
+
+ //teleport physics shadow too
+ // Vector newPos = GetAbsOrigin();
+ // QAngle newAng = GetAbsAngles();
+
+ // Teleport( &newPos, &newAng, &vec3_origin );
+}
+
+void CSDKPlayer::PreThink(void)
+{
+ // Riding a vehicle?
+ if ( IsInAVehicle() )
+ {
+ // make sure we update the client, check for timed damage and update suit even if we are in a vehicle
+ UpdateClientData();
+ CheckTimeBasedDamage();
+
+ // Allow the suit to recharge when in the vehicle.
+ CheckSuitUpdate();
+
+ WaterMove();
+ return;
+ }
+
+ BaseClass::PreThink();
+}
+
+
+void CSDKPlayer::PostThink()
+{
+ BaseClass::PostThink();
+
+ QAngle angles = GetLocalAngles();
+ angles[PITCH] = 0;
+ SetLocalAngles( angles );
+
+ // Store the eye angles pitch so the client can compute its animation state correctly.
+ m_angEyeAngles = EyeAngles();
+
+ m_PlayerAnimState->Update( m_angEyeAngles[YAW], m_angEyeAngles[PITCH] );
+}
+
+
+void CSDKPlayer::Precache()
+{
+ PrecacheModel( SDK_PLAYER_MODEL );
+
+ BaseClass::Precache();
+}
+
+void CSDKPlayer::Spawn()
+{
+ SetModel( SDK_PLAYER_MODEL );
+ SetMoveType( MOVETYPE_WALK );
+ RemoveSolidFlags( FSOLID_NOT_SOLID );
+
+ m_hRagdoll = NULL;
+
+ BaseClass::Spawn();
+}
+
+void CSDKPlayer::InitialSpawn( void )
+{
+ BaseClass::InitialSpawn();
+
+ const ConVar *hostname = cvar->FindVar( "hostname" );
+ const char *title = (hostname) ? hostname->GetString() : "MESSAGE OF THE DAY";
+
+ // open info panel on client showing MOTD:
+ KeyValues *data = new KeyValues("data");
+ data->SetString( "title", title ); // info panel title
+ data->SetString( "type", "1" ); // show userdata from stringtable entry
+ data->SetString( "msg", "motd" ); // use this stringtable entry
+ data->SetInt( "cmd", TEXTWINDOW_CMD_IMPULSE101 );// exec this command if panel closed
+ data->SetBool( "unload", sv_motd_unload_on_dismissal.GetBool() );
+
+ ShowViewPortPanel( PANEL_INFO, true, data );
+
+ data->deleteThis();
+}
+
+void CSDKPlayer::Event_Killed( const CTakeDamageInfo &info )
+{
+ // Note: since we're dead, it won't draw us on the client, but we don't set EF_NODRAW
+ // because we still want to transmit to the clients in our PVS.
+
+ BaseClass::Event_Killed( info );
+
+ CreateRagdollEntity();
+}
+
+void CSDKPlayer::CreateRagdollEntity()
+{
+ // If we already have a ragdoll, don't make another one.
+ CSDKRagdoll *pRagdoll = dynamic_cast< CSDKRagdoll* >( m_hRagdoll.Get() );
+
+ if ( !pRagdoll )
+ {
+ // create a new one
+ pRagdoll = dynamic_cast< CSDKRagdoll* >( CreateEntityByName( "sdk_ragdoll" ) );
+ }
+
+ if ( pRagdoll )
+ {
+ pRagdoll->m_hPlayer = this;
+ pRagdoll->m_vecRagdollOrigin = GetAbsOrigin();
+ pRagdoll->m_vecRagdollVelocity = GetAbsVelocity();
+ pRagdoll->m_nModelIndex = m_nModelIndex;
+ pRagdoll->m_nForceBone = m_nForceBone;
+ pRagdoll->m_vecForce = Vector(0,0,0);
+ }
+
+ // ragdolls will be removed on round restart automatically
+ m_hRagdoll = pRagdoll;
+}
+
+void CSDKPlayer::DoAnimationEvent( PlayerAnimEvent_t event, int nData )
+{
+ if ( event == PLAYERANIMEVENT_THROW_GRENADE )
+ {
+ // Grenade throwing has to synchronize exactly with the player's grenade weapon going away,
+ // and events get delayed a bit, so we let CCSPlayerAnimState pickup the change to this
+ // variable.
+ m_iThrowGrenadeCounter = (m_iThrowGrenadeCounter+1) % (1<<THROWGRENADE_COUNTER_BITS);
+ }
+ else
+ {
+ m_PlayerAnimState->DoAnimationEvent( event, nData );
+ TE_PlayerAnimEvent( this, event, nData ); // Send to any clients who can see this guy.
+ }
+}
+
+CWeaponSDKBase* CSDKPlayer::GetActiveSDKWeapon() const
+{
+ return dynamic_cast< CWeaponSDKBase* >( GetActiveWeapon() );
+}
+
+void CSDKPlayer::CreateViewModel( int index /*=0*/ )
+{
+ Assert( index >= 0 && index < MAX_VIEWMODELS );
+
+ if ( GetViewModel( index ) )
+ return;
+
+ CPredictedViewModel *vm = ( CPredictedViewModel * )CreateEntityByName( "predicted_viewmodel" );
+ if ( vm )
+ {
+ vm->SetAbsOrigin( GetAbsOrigin() );
+ vm->SetOwner( this );
+ vm->SetIndex( index );
+ DispatchSpawn( vm );
+ vm->FollowEntity( this, false );
+ m_hViewModel.Set( index, vm );
+ }
+}
+
+void CSDKPlayer::CheatImpulseCommands( int iImpulse )
+{
+ if ( iImpulse != 101 )
+ {
+ BaseClass::CheatImpulseCommands( iImpulse );
+ return ;
+ }
+ gEvilImpulse101 = true;
+
+ EquipSuit();
+
+ GiveNamedItem( "weapon_mp5" );
+ GiveNamedItem( "weapon_grenade" );
+ GiveNamedItem( "weapon_shotgun" );
+
+ // Give the player everything!
+ GiveAmmo( 90, AMMO_BULLETS );
+ GiveAmmo( 3, AMMO_GRENADE );
+
+ if ( GetHealth() < 100 )
+ {
+ TakeHealth( 25, DMG_GENERIC );
+ }
+
+ gEvilImpulse101 = false;
+}
+
+
+void CSDKPlayer::FlashlightTurnOn( void )
+{
+ AddEffects( EF_DIMLIGHT );
+}
+
+void CSDKPlayer::FlashlightTurnOff( void )
+{
+ RemoveEffects( EF_DIMLIGHT );
+}
+
+int CSDKPlayer::FlashlightIsOn( void )
+{
+ return IsEffectActive( EF_DIMLIGHT );
+}
diff --git a/sp/src/game/server/sdk/sdk_player.h b/sp/src/game/server/sdk/sdk_player.h
new file mode 100644
index 00000000..efac7ec1
--- /dev/null
+++ b/sp/src/game/server/sdk/sdk_player.h
@@ -0,0 +1,101 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose: Player for SDK Game
+//
+// $NoKeywords: $
+//=============================================================================//
+
+#ifndef SDK_PLAYER_H
+#define SDK_PLAYER_H
+#pragma once
+
+
+#include "player.h"
+#include "server_class.h"
+#include "sdk_playeranimstate.h"
+#include "sdk_shareddefs.h"
+
+
+//=============================================================================
+// >> SDK Game player
+//=============================================================================
+class CSDKPlayer : public CBasePlayer, public ISDKPlayerAnimStateHelpers
+{
+public:
+ DECLARE_CLASS( CSDKPlayer, CBasePlayer );
+ DECLARE_SERVERCLASS();
+ DECLARE_PREDICTABLE();
+ DECLARE_DATADESC();
+
+ CSDKPlayer();
+ ~CSDKPlayer();
+
+ static CSDKPlayer *CreatePlayer( const char *className, edict_t *ed );
+ static CSDKPlayer* Instance( int iEnt );
+
+ // This passes the event to the client's and server's CPlayerAnimState.
+ void DoAnimationEvent( PlayerAnimEvent_t event, int nData = 0 );
+
+ virtual void FlashlightTurnOn( void );
+ virtual void FlashlightTurnOff( void );
+ virtual int FlashlightIsOn( void );
+
+ virtual void PreThink();
+ virtual void PostThink();
+ virtual void Spawn();
+ virtual void InitialSpawn();
+ virtual void Precache();
+ virtual void Event_Killed( const CTakeDamageInfo &info );
+ virtual void LeaveVehicle( const Vector &vecExitPoint, const QAngle &vecExitAngles );
+
+ CWeaponSDKBase* GetActiveSDKWeapon() const;
+ virtual void CreateViewModel( int viewmodelindex = 0 );
+
+ virtual void CheatImpulseCommands( int iImpulse );
+
+ CNetworkVar( int, m_iThrowGrenadeCounter ); // used to trigger grenade throw animations.
+ CNetworkQAngle( m_angEyeAngles ); // Copied from EyeAngles() so we can send it to the client.
+ CNetworkVar( int, m_iShotsFired ); // number of shots fired recently
+
+ // Tracks our ragdoll entity.
+ CNetworkHandle( CBaseEntity, m_hRagdoll ); // networked entity handle
+
+// In shared code.
+public:
+ // ISDKPlayerAnimState overrides.
+ virtual CWeaponSDKBase* SDKAnim_GetActiveWeapon();
+ virtual bool SDKAnim_CanMove();
+
+
+ void FireBullet(
+ Vector vecSrc,
+ const QAngle &shootAngles,
+ float vecSpread,
+ int iDamage,
+ int iBulletType,
+ CBaseEntity *pevAttacker,
+ bool bDoEffects,
+ float x,
+ float y );
+
+private:
+
+ void CreateRagdollEntity();
+
+ ISDKPlayerAnimState *m_PlayerAnimState;
+};
+
+
+inline CSDKPlayer *ToSDKPlayer( CBaseEntity *pEntity )
+{
+ if ( !pEntity || !pEntity->IsPlayer() )
+ return NULL;
+
+#ifdef _DEBUG
+ Assert( dynamic_cast<CSDKPlayer*>( pEntity ) != 0 );
+#endif
+ return static_cast< CSDKPlayer* >( pEntity );
+}
+
+
+#endif // SDK_PLAYER_H
diff --git a/sp/src/game/server/sdk/sdk_playermove.cpp b/sp/src/game/server/sdk/sdk_playermove.cpp
new file mode 100644
index 00000000..bbfd8e4e
--- /dev/null
+++ b/sp/src/game/server/sdk/sdk_playermove.cpp
@@ -0,0 +1,89 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================//
+
+#include "cbase.h"
+#include "player_command.h"
+#include "igamemovement.h"
+#include "in_buttons.h"
+#include "ipredictionsystem.h"
+#include "sdk_player.h"
+#include "iservervehicle.h"
+
+
+static CMoveData g_MoveData;
+CMoveData *g_pMoveData = &g_MoveData;
+
+IPredictionSystem *IPredictionSystem::g_pPredictionSystems = NULL;
+
+
+//-----------------------------------------------------------------------------
+// Sets up the move data for TF2
+//-----------------------------------------------------------------------------
+class CSDKPlayerMove : public CPlayerMove
+{
+DECLARE_CLASS( CSDKPlayerMove, CPlayerMove );
+
+public:
+ virtual void StartCommand( CBasePlayer *player, CUserCmd *cmd );
+ virtual void SetupMove( CBasePlayer *player, CUserCmd *ucmd, IMoveHelper *pHelper, CMoveData *move );
+ virtual void FinishMove( CBasePlayer *player, CUserCmd *ucmd, CMoveData *move );
+};
+
+// PlayerMove Interface
+static CSDKPlayerMove g_PlayerMove;
+
+//-----------------------------------------------------------------------------
+// Singleton accessor
+//-----------------------------------------------------------------------------
+CPlayerMove *PlayerMove()
+{
+ return &g_PlayerMove;
+}
+
+//-----------------------------------------------------------------------------
+// Main setup, finish
+//-----------------------------------------------------------------------------
+
+void CSDKPlayerMove::StartCommand( CBasePlayer *player, CUserCmd *cmd )
+{
+ BaseClass::StartCommand( player, cmd );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: This is called pre player movement and copies all the data necessary
+// from the player for movement. (Server-side, the client-side version
+// of this code can be found in prediction.cpp.)
+//-----------------------------------------------------------------------------
+void CSDKPlayerMove::SetupMove( CBasePlayer *player, CUserCmd *ucmd, IMoveHelper *pHelper, CMoveData *move )
+{
+ BaseClass::SetupMove( player, ucmd, pHelper, move );
+
+ IServerVehicle *pVehicle = player->GetVehicle();
+ if (pVehicle && gpGlobals->frametime != 0)
+ {
+ pVehicle->SetupMove( player, ucmd, pHelper, move );
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: This is called post player movement to copy back all data that
+// movement could have modified and that is necessary for future
+// movement. (Server-side, the client-side version of this code can
+// be found in prediction.cpp.)
+//-----------------------------------------------------------------------------
+void CSDKPlayerMove::FinishMove( CBasePlayer *player, CUserCmd *ucmd, CMoveData *move )
+{
+ // Call the default FinishMove code.
+ BaseClass::FinishMove( player, ucmd, move );
+
+ IServerVehicle *pVehicle = player->GetVehicle();
+ if (pVehicle && gpGlobals->frametime != 0)
+ {
+ pVehicle->FinishMove( player, ucmd, move );
+ }
+}
diff --git a/sp/src/game/server/sdk/sdk_team.cpp b/sp/src/game/server/sdk/sdk_team.cpp
new file mode 100644
index 00000000..27e1fdb2
--- /dev/null
+++ b/sp/src/game/server/sdk/sdk_team.cpp
@@ -0,0 +1,40 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose: Team management class. Contains all the details for a specific team
+//
+// $NoKeywords: $
+//=============================================================================//
+#include "cbase.h"
+#include "sdk_team.h"
+#include "entitylist.h"
+
+// memdbgon must be the last include file in a .cpp file!!!
+#include "tier0/memdbgon.h"
+
+
+// Datatable
+IMPLEMENT_SERVERCLASS_ST(CSDKTeam, DT_SDKTeam)
+END_SEND_TABLE()
+
+LINK_ENTITY_TO_CLASS( sdk_team_manager, CSDKTeam );
+
+//-----------------------------------------------------------------------------
+// Purpose: Get a pointer to the specified TF team manager
+//-----------------------------------------------------------------------------
+CSDKTeam *GetGlobalSDKTeam( int iIndex )
+{
+ return (CSDKTeam*)GetGlobalTeam( iIndex );
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Needed because this is an entity, but should never be used
+//-----------------------------------------------------------------------------
+void CSDKTeam::Init( const char *pName, int iNumber )
+{
+ BaseClass::Init( pName, iNumber );
+
+ // Only detect changes every half-second.
+ NetworkProp()->SetUpdateInterval( 0.75f );
+}
+
diff --git a/sp/src/game/server/sdk/sdk_team.h b/sp/src/game/server/sdk/sdk_team.h
new file mode 100644
index 00000000..c354b344
--- /dev/null
+++ b/sp/src/game/server/sdk/sdk_team.h
@@ -0,0 +1,38 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose: Team management class. Contains all the details for a specific team
+//
+// $NoKeywords: $
+//=============================================================================//
+
+#ifndef SDK_TEAM_H
+#define SDK_TEAM_H
+
+#ifdef _WIN32
+#pragma once
+#endif
+
+
+#include "utlvector.h"
+#include "team.h"
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Team Manager
+//-----------------------------------------------------------------------------
+class CSDKTeam : public CTeam
+{
+ DECLARE_CLASS( CSDKTeam, CTeam );
+ DECLARE_SERVERCLASS();
+
+public:
+
+ // Initialization
+ virtual void Init( const char *pName, int iNumber );
+};
+
+
+extern CSDKTeam *GetGlobalSDKTeam( int iIndex );
+
+
+#endif // TF_TEAM_H
diff --git a/sp/src/game/server/sdk/sdk_vehicle_jeep.cpp b/sp/src/game/server/sdk/sdk_vehicle_jeep.cpp
new file mode 100644
index 00000000..407363ec
--- /dev/null
+++ b/sp/src/game/server/sdk/sdk_vehicle_jeep.cpp
@@ -0,0 +1,1584 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================//
+
+#include "cbase.h"
+#include "vehicle_base.h"
+#include "engine/IEngineSound.h"
+#include "in_buttons.h"
+#include "ammodef.h"
+#include "IEffects.h"
+#include "beam_shared.h"
+#include "soundenvelope.h"
+#include "decals.h"
+#include "soundent.h"
+#include "te_effect_dispatch.h"
+#include "ndebugoverlay.h"
+#include "movevars_shared.h"
+#include "bone_setup.h"
+#include "ai_basenpc.h"
+#include "ai_hint.h"
+#include "globalstate.h"
+// memdbgon must be the last include file in a .cpp file!!!
+#include "tier0/memdbgon.h"
+
+#define VEHICLE_HITBOX_DRIVER 1
+#define LOCK_SPEED 10
+#define JEEP_GUN_YAW "vehicle_weapon_yaw"
+#define JEEP_GUN_PITCH "vehicle_weapon_pitch"
+#define JEEP_GUN_SPIN "gun_spin"
+#define JEEP_GUN_SPIN_RATE 20
+
+#define CANNON_MAX_UP_PITCH 20
+#define CANNON_MAX_DOWN_PITCH 20
+#define CANNON_MAX_LEFT_YAW 90
+#define CANNON_MAX_RIGHT_YAW 90
+
+#define OVERTURNED_EXIT_WAITTIME 2.0f
+
+#define JEEP_AMMOCRATE_HITGROUP 5
+#define JEEP_WHEEL_COUNT 4
+
+#define JEEP_STEERING_SLOW_ANGLE 50.0f
+#define JEEP_STEERING_FAST_ANGLE 15.0f
+
+#define JEEP_AMMO_CRATE_CLOSE_DELAY 2.0f
+
+#define JEEP_DELTA_LENGTH_MAX 12.0f // 1 foot
+#define JEEP_FRAMETIME_MIN 1e-6
+
+ConVar hud_jeephint_numentries( "hud_jeephint_numentries", "10", FCVAR_NONE );
+ConVar g_jeepexitspeed( "g_jeepexitspeed", "100", FCVAR_CHEAT );
+
+//=============================================================================
+//
+// Jeep water data.
+//
+struct JeepWaterData_t
+{
+ bool m_bWheelInWater[JEEP_WHEEL_COUNT];
+ bool m_bWheelWasInWater[JEEP_WHEEL_COUNT];
+ Vector m_vecWheelContactPoints[JEEP_WHEEL_COUNT];
+ float m_flNextRippleTime[JEEP_WHEEL_COUNT];
+ bool m_bBodyInWater;
+ bool m_bBodyWasInWater;
+
+ DECLARE_SIMPLE_DATADESC();
+};
+
+BEGIN_SIMPLE_DATADESC( JeepWaterData_t )
+ DEFINE_ARRAY( m_bWheelInWater, FIELD_BOOLEAN, JEEP_WHEEL_COUNT ),
+ DEFINE_ARRAY( m_bWheelWasInWater, FIELD_BOOLEAN, JEEP_WHEEL_COUNT ),
+ DEFINE_ARRAY( m_vecWheelContactPoints, FIELD_VECTOR, JEEP_WHEEL_COUNT ),
+ DEFINE_ARRAY( m_flNextRippleTime, FIELD_TIME, JEEP_WHEEL_COUNT ),
+ DEFINE_FIELD( m_bBodyInWater, FIELD_BOOLEAN ),
+ DEFINE_FIELD( m_bBodyWasInWater, FIELD_BOOLEAN ),
+END_DATADESC()
+
+//-----------------------------------------------------------------------------
+// Purpose: Four wheel physics vehicle server vehicle with weaponry
+//-----------------------------------------------------------------------------
+class CJeepFourWheelServerVehicle : public CFourWheelServerVehicle
+{
+ typedef CFourWheelServerVehicle BaseClass;
+// IServerVehicle
+public:
+ bool NPC_HasPrimaryWeapon( void ) { return true; }
+ void NPC_AimPrimaryWeapon( Vector vecTarget );
+ int GetExitAnimToUse( Vector &vecEyeExitEndpoint, bool &bAllPointsBlocked );
+};
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+class CPropJeep : public CPropVehicleDriveable
+{
+ DECLARE_CLASS( CPropJeep, CPropVehicleDriveable );
+
+public:
+
+ DECLARE_SERVERCLASS();
+ DECLARE_DATADESC();
+
+ CPropJeep( void );
+
+ // CPropVehicle
+ virtual void ProcessMovement( CBasePlayer *pPlayer, CMoveData *pMoveData );
+ virtual void DriveVehicle( float flFrameTime, CUserCmd *ucmd, int iButtonsDown, int iButtonsReleased );
+ virtual void SetupMove( CBasePlayer *player, CUserCmd *ucmd, IMoveHelper *pHelper, CMoveData *move );
+ virtual void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value );
+ virtual void DampenEyePosition( Vector &vecVehicleEyePos, QAngle &vecVehicleEyeAngles );
+ virtual bool AllowBlockedExit( CBasePlayer *pPlayer, int nRole ) { return false; }
+ virtual bool CanExitVehicle( CBaseEntity *pEntity );
+ virtual bool IsVehicleBodyInWater() { return m_WaterData.m_bBodyInWater; }
+
+ // CBaseEntity
+ void Think(void);
+ void Precache( void );
+ void Spawn( void );
+ void OnRestore( void );
+
+ virtual void CreateServerVehicle( void );
+ virtual Vector BodyTarget( const Vector &posSrc, bool bNoisy = true );
+ virtual void TraceAttack( const CTakeDamageInfo &info, const Vector &vecDir, trace_t *ptr );
+ virtual int OnTakeDamage( const CTakeDamageInfo &info );
+ virtual void EnterVehicle( CBasePlayer *pPlayer );
+ virtual void ExitVehicle( int nRole );
+
+ void AimGunAt( Vector *endPos, float flInterval );
+ bool TauCannonHasBeenCutOff( void ) { return m_bGunHasBeenCutOff; }
+
+ // NPC Driving
+ bool NPC_HasPrimaryWeapon( void ) { return true; }
+ void NPC_AimPrimaryWeapon( Vector vecTarget );
+
+ const char *GetTracerType( void ) { return "AR2Tracer"; }
+ void DoImpactEffect( trace_t &tr, int nDamageType );
+
+ bool HeadlightIsOn( void ) { return m_bHeadlightIsOn; }
+ void HeadlightTurnOn( void ) { m_bHeadlightIsOn = true; }
+ void HeadlightTurnOff( void ) { m_bHeadlightIsOn = false; }
+
+private:
+
+ void FireCannon( void );
+ void ChargeCannon( void );
+ void FireChargedCannon( void );
+
+ void DrawBeam( const Vector &startPos, const Vector &endPos, float width );
+ void StopChargeSound( void );
+ void GetCannonAim( Vector *resultDir );
+
+ void InitWaterData( void );
+ void HandleWater( void );
+ bool CheckWater( void );
+ void CheckWaterLevel( void );
+ void CreateSplash( const Vector &vecPosition );
+ void CreateRipple( const Vector &vecPosition );
+
+ void UpdateSteeringAngle( void );
+ void CreateDangerSounds( void );
+
+ void ComputePDControllerCoefficients( float *pCoefficientsOut, float flFrequency, float flDampening, float flDeltaTime );
+ void DampenForwardMotion( Vector &vecVehicleEyePos, QAngle &vecVehicleEyeAngles, float flFrameTime );
+ void DampenUpMotion( Vector &vecVehicleEyePos, QAngle &vecVehicleEyeAngles, float flFrameTime );
+
+ void InputStartRemoveTauCannon( inputdata_t &inputdata );
+ void InputFinishRemoveTauCannon( inputdata_t &inputdata );
+
+private:
+
+ bool m_bGunHasBeenCutOff;
+ float m_flDangerSoundTime;
+ int m_nBulletType;
+ bool m_bCannonCharging;
+ float m_flCannonTime;
+ float m_flCannonChargeStartTime;
+ Vector m_vecGunOrigin;
+ CSoundPatch *m_sndCannonCharge;
+ int m_nSpinPos;
+ float m_aimYaw;
+ float m_aimPitch;
+ float m_throttleDisableTime;
+ float m_flAmmoCrateCloseTime;
+
+ // handbrake after the fact to keep vehicles from rolling
+ float m_flHandbrakeTime;
+ bool m_bInitialHandbrake;
+
+ float m_flOverturnedTime;
+
+ Vector m_vecLastEyePos;
+ Vector m_vecLastEyeTarget;
+ Vector m_vecEyeSpeed;
+ Vector m_vecTargetSpeed;
+
+ JeepWaterData_t m_WaterData;
+
+ int m_iNumberOfEntries;
+ int m_nAmmoType;
+
+ // Seagull perching
+ float m_flPlayerExitedTime; // Time at which the player last left this vehicle
+ float m_flLastSawPlayerAt; // Time at which we last saw the player
+ EHANDLE m_hLastPlayerInVehicle;
+ bool m_bHasPoop;
+
+ CNetworkVar( bool, m_bHeadlightIsOn );
+};
+
+BEGIN_DATADESC( CPropJeep )
+ DEFINE_FIELD( m_bGunHasBeenCutOff, FIELD_BOOLEAN ),
+ DEFINE_FIELD( m_flDangerSoundTime, FIELD_TIME ),
+ DEFINE_FIELD( m_nBulletType, FIELD_INTEGER ),
+ DEFINE_FIELD( m_bCannonCharging, FIELD_BOOLEAN ),
+ DEFINE_FIELD( m_flCannonTime, FIELD_TIME ),
+ DEFINE_FIELD( m_flCannonChargeStartTime, FIELD_TIME ),
+ DEFINE_FIELD( m_vecGunOrigin, FIELD_POSITION_VECTOR ),
+ DEFINE_SOUNDPATCH( m_sndCannonCharge ),
+ DEFINE_FIELD( m_nSpinPos, FIELD_INTEGER ),
+ DEFINE_FIELD( m_aimYaw, FIELD_FLOAT ),
+ DEFINE_FIELD( m_aimPitch, FIELD_FLOAT ),
+ DEFINE_FIELD( m_throttleDisableTime, FIELD_TIME ),
+ DEFINE_FIELD( m_flHandbrakeTime, FIELD_TIME ),
+ DEFINE_FIELD( m_bInitialHandbrake, FIELD_BOOLEAN ),
+ DEFINE_FIELD( m_flOverturnedTime, FIELD_TIME ),
+ DEFINE_FIELD( m_flAmmoCrateCloseTime, FIELD_FLOAT ),
+ DEFINE_FIELD( m_vecLastEyePos, FIELD_POSITION_VECTOR ),
+ DEFINE_FIELD( m_vecLastEyeTarget, FIELD_POSITION_VECTOR ),
+ DEFINE_FIELD( m_vecEyeSpeed, FIELD_POSITION_VECTOR ),
+ DEFINE_FIELD( m_vecTargetSpeed, FIELD_POSITION_VECTOR ),
+ DEFINE_FIELD( m_bHeadlightIsOn, FIELD_BOOLEAN ),
+ DEFINE_EMBEDDED( m_WaterData ),
+
+ DEFINE_FIELD( m_iNumberOfEntries, FIELD_INTEGER ),
+ DEFINE_FIELD( m_nAmmoType, FIELD_INTEGER ),
+
+ DEFINE_FIELD( m_flPlayerExitedTime, FIELD_TIME ),
+ DEFINE_FIELD( m_flLastSawPlayerAt, FIELD_TIME ),
+ DEFINE_FIELD( m_hLastPlayerInVehicle, FIELD_EHANDLE ),
+ DEFINE_FIELD( m_bHasPoop, FIELD_BOOLEAN ),
+
+ DEFINE_INPUTFUNC( FIELD_VOID, "StartRemoveTauCannon", InputStartRemoveTauCannon ),
+ DEFINE_INPUTFUNC( FIELD_VOID, "FinishRemoveTauCannon", InputFinishRemoveTauCannon ),
+
+END_DATADESC()
+
+IMPLEMENT_SERVERCLASS_ST( CPropJeep, DT_PropJeep )
+ SendPropBool( SENDINFO( m_bHeadlightIsOn ) ),
+END_SEND_TABLE();
+
+LINK_ENTITY_TO_CLASS( prop_vehicle_jeep, CPropJeep );
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+CPropJeep::CPropJeep( void )
+{
+ m_bHasGun = true;
+ m_bGunHasBeenCutOff = false;
+ m_bCannonCharging = false;
+ m_flCannonChargeStartTime = 0;
+ m_flCannonTime = 0;
+ m_nBulletType = -1;
+ m_flOverturnedTime = 0.0f;
+ m_iNumberOfEntries = 0;
+
+ m_vecEyeSpeed.Init();
+
+ InitWaterData();
+
+ m_bUnableToFire = true;
+ m_flAmmoCrateCloseTime = 0;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CPropJeep::CreateServerVehicle( void )
+{
+ // Create our armed server vehicle
+ m_pServerVehicle = new CJeepFourWheelServerVehicle();
+ m_pServerVehicle->SetVehicle( this );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CPropJeep::Precache( void )
+{
+ UTIL_PrecacheOther( "npc_seagull" );
+
+ PrecacheScriptSound( "PropJeep.AmmoClose" );
+ PrecacheScriptSound( "PropJeep.FireCannon" );
+ PrecacheScriptSound( "PropJeep.FireChargedCannon" );
+ PrecacheScriptSound( "PropJeep.AmmoOpen" );
+
+ PrecacheScriptSound( "Jeep.GaussCharge" );
+
+// PrecacheModel( GAUSS_BEAM_SPRITE );
+
+ BaseClass::Precache();
+}
+
+//------------------------------------------------
+// Spawn
+//------------------------------------------------
+void CPropJeep::Spawn( void )
+{
+ // Setup vehicle as a real-wheels car.
+ SetVehicleType( VEHICLE_TYPE_CAR_WHEELS );
+
+ BaseClass::Spawn();
+ m_flHandbrakeTime = gpGlobals->curtime + 0.1;
+ m_bInitialHandbrake = false;
+
+ m_VehiclePhysics.SetHasBrakePedal( false );
+
+ m_flMinimumSpeedToEnterExit = LOCK_SPEED;
+
+ m_nBulletType = GetAmmoDef()->Index("GaussEnergy");
+
+ if ( m_bHasGun )
+ {
+ SetBodygroup( 1, true );
+ }
+ else
+ {
+ SetBodygroup( 1, false );
+ }
+
+ // Initialize pose parameters
+ SetPoseParameter( JEEP_GUN_YAW, 0 );
+ SetPoseParameter( JEEP_GUN_PITCH, 0 );
+ m_nSpinPos = 0;
+ SetPoseParameter( JEEP_GUN_SPIN, m_nSpinPos );
+ m_aimYaw = 0;
+ m_aimPitch = 0;
+
+ AddSolidFlags( FSOLID_NOT_STANDABLE );
+
+ CAmmoDef *pAmmoDef = GetAmmoDef();
+ m_nAmmoType = pAmmoDef->Index("GaussEnergy");
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : &tr -
+// nDamageType -
+//-----------------------------------------------------------------------------
+void CPropJeep::DoImpactEffect( trace_t &tr, int nDamageType )
+{
+ //Draw our beam
+ DrawBeam( tr.startpos, tr.endpos, 2.4 );
+
+ if ( (tr.surface.flags & SURF_SKY) == false )
+ {
+ CPVSFilter filter( tr.endpos );
+ te->GaussExplosion( filter, 0.0f, tr.endpos, tr.plane.normal, 0 );
+
+ UTIL_ImpactTrace( &tr, m_nBulletType );
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CPropJeep::TraceAttack( const CTakeDamageInfo &inputInfo, const Vector &vecDir, trace_t *ptr )
+{
+ CTakeDamageInfo info = inputInfo;
+ if ( ptr->hitbox != VEHICLE_HITBOX_DRIVER )
+ {
+ if ( inputInfo.GetDamageType() & DMG_BULLET )
+ {
+ info.ScaleDamage( 0.0001 );
+ }
+ }
+
+ BaseClass::TraceAttack( info, vecDir, ptr );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+int CPropJeep::OnTakeDamage( const CTakeDamageInfo &inputInfo )
+{
+ //Do scaled up physics damage to the car
+ CTakeDamageInfo info = inputInfo;
+ info.ScaleDamage( 25 );
+
+ // HACKHACK: Scale up grenades until we get a better explosion/pressure damage system
+ if ( inputInfo.GetDamageType() & DMG_BLAST )
+ {
+ info.SetDamageForce( inputInfo.GetDamageForce() * 10 );
+ }
+ VPhysicsTakeDamage( info );
+
+ // reset the damage
+ info.SetDamage( inputInfo.GetDamage() );
+
+ // small amounts of shock damage disrupt the car, but aren't transferred to the player
+ if ( info.GetDamageType() == DMG_SHOCK )
+ {
+ if ( info.GetDamage() <= 10 )
+ {
+ // take 10% damage and make the engine stall
+ info.ScaleDamage( 0.1 );
+ m_throttleDisableTime = gpGlobals->curtime + 2;
+ }
+ }
+
+ //Check to do damage to driver
+ if ( GetDriver() )
+ {
+ //Take no damage from physics damages
+ if ( info.GetDamageType() & DMG_CRUSH )
+ return 0;
+
+ // Take the damage (strip out the DMG_BLAST)
+ info.SetDamageType( info.GetDamageType() & (~DMG_BLAST) );
+ GetDriver()->TakeDamage( info );
+ }
+
+ return 0;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+Vector CPropJeep::BodyTarget( const Vector &posSrc, bool bNoisy )
+{
+ Vector shotPos;
+ matrix3x4_t matrix;
+
+ int eyeAttachmentIndex = LookupAttachment("vehicle_driver_eyes");
+ GetAttachment( eyeAttachmentIndex, matrix );
+ MatrixGetColumn( matrix, 3, shotPos );
+
+ if ( bNoisy )
+ {
+ shotPos[0] += random->RandomFloat( -8.0f, 8.0f );
+ shotPos[1] += random->RandomFloat( -8.0f, 8.0f );
+ shotPos[2] += random->RandomFloat( -8.0f, 8.0f );
+ }
+
+ return shotPos;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Aim Gun at a target
+//-----------------------------------------------------------------------------
+void CPropJeep::AimGunAt( Vector *endPos, float flInterval )
+{
+ Vector aimPos = *endPos;
+
+ // See if the gun should be allowed to aim
+ if ( IsOverturned() || m_bEngineLocked )
+ {
+ SetPoseParameter( JEEP_GUN_YAW, 0 );
+ SetPoseParameter( JEEP_GUN_PITCH, 0 );
+ SetPoseParameter( JEEP_GUN_SPIN, 0 );
+ return;
+
+ // Make the gun go limp and look "down"
+ Vector v_forward, v_up;
+ AngleVectors( GetLocalAngles(), NULL, &v_forward, &v_up );
+ aimPos = WorldSpaceCenter() + ( v_forward * -32.0f ) - Vector( 0, 0, 128.0f );
+ }
+
+ matrix3x4_t gunMatrix;
+ GetAttachment( LookupAttachment("gun_ref"), gunMatrix );
+
+ // transform the enemy into gun space
+ Vector localEnemyPosition;
+ VectorITransform( aimPos, gunMatrix, localEnemyPosition );
+
+ // do a look at in gun space (essentially a delta-lookat)
+ QAngle localEnemyAngles;
+ VectorAngles( localEnemyPosition, localEnemyAngles );
+
+ // convert to +/- 180 degrees
+ localEnemyAngles.x = UTIL_AngleDiff( localEnemyAngles.x, 0 );
+ localEnemyAngles.y = UTIL_AngleDiff( localEnemyAngles.y, 0 );
+
+ float targetYaw = m_aimYaw + localEnemyAngles.y;
+ float targetPitch = m_aimPitch + localEnemyAngles.x;
+
+ // Constrain our angles
+ float newTargetYaw = clamp( targetYaw, -CANNON_MAX_LEFT_YAW, CANNON_MAX_RIGHT_YAW );
+ float newTargetPitch = clamp( targetPitch, -CANNON_MAX_DOWN_PITCH, CANNON_MAX_UP_PITCH );
+
+ // If the angles have been clamped, we're looking outside of our valid range
+ if ( fabs(newTargetYaw-targetYaw) > 1e-4 || fabs(newTargetPitch-targetPitch) > 1e-4 )
+ {
+ m_bUnableToFire = true;
+ }
+
+ targetYaw = newTargetYaw;
+ targetPitch = newTargetPitch;
+
+ // Exponentially approach the target
+ float yawSpeed = 8;
+ float pitchSpeed = 8;
+
+ m_aimYaw = UTIL_Approach( targetYaw, m_aimYaw, yawSpeed );
+ m_aimPitch = UTIL_Approach( targetPitch, m_aimPitch, pitchSpeed );
+
+ SetPoseParameter( JEEP_GUN_YAW, -m_aimYaw);
+ SetPoseParameter( JEEP_GUN_PITCH, -m_aimPitch );
+
+ InvalidateBoneCache();
+
+ // read back to avoid drift when hitting limits
+ // as long as the velocity is less than the delta between the limit and 180, this is fine.
+ m_aimPitch = -GetPoseParameter( JEEP_GUN_PITCH );
+ m_aimYaw = -GetPoseParameter( JEEP_GUN_YAW );
+
+ // Now draw crosshair for actual aiming point
+ Vector vecMuzzle, vecMuzzleDir;
+ QAngle vecMuzzleAng;
+
+ GetAttachment( "Muzzle", vecMuzzle, vecMuzzleAng );
+ AngleVectors( vecMuzzleAng, &vecMuzzleDir );
+
+ trace_t tr;
+ UTIL_TraceLine( vecMuzzle, vecMuzzle + (vecMuzzleDir * MAX_TRACE_LENGTH), MASK_SHOT, this, COLLISION_GROUP_NONE, &tr );
+
+ // see if we hit something, if so, adjust endPos to hit location
+ if ( tr.fraction < 1.0 )
+ {
+ m_vecGunCrosshair = vecMuzzle + ( vecMuzzleDir * MAX_TRACE_LENGTH * tr.fraction );
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CPropJeep::InitWaterData( void )
+{
+ m_WaterData.m_bBodyInWater = false;
+ m_WaterData.m_bBodyWasInWater = false;
+
+ for ( int iWheel = 0; iWheel < JEEP_WHEEL_COUNT; ++iWheel )
+ {
+ m_WaterData.m_bWheelInWater[iWheel] = false;
+ m_WaterData.m_bWheelWasInWater[iWheel] = false;
+ m_WaterData.m_vecWheelContactPoints[iWheel].Init();
+ m_WaterData.m_flNextRippleTime[iWheel] = 0;
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CPropJeep::HandleWater( void )
+{
+ // Only check the wheels and engine in water if we have a driver (player).
+ if ( !GetDriver() )
+ return;
+
+ // Check to see if we are in water.
+ if ( CheckWater() )
+ {
+ for ( int iWheel = 0; iWheel < JEEP_WHEEL_COUNT; ++iWheel )
+ {
+ // Create an entry/exit splash!
+ if ( m_WaterData.m_bWheelInWater[iWheel] != m_WaterData.m_bWheelWasInWater[iWheel] )
+ {
+ CreateSplash( m_WaterData.m_vecWheelContactPoints[iWheel] );
+ CreateRipple( m_WaterData.m_vecWheelContactPoints[iWheel] );
+ }
+
+ // Create ripples.
+ if ( m_WaterData.m_bWheelInWater[iWheel] && m_WaterData.m_bWheelWasInWater[iWheel] )
+ {
+ if ( m_WaterData.m_flNextRippleTime[iWheel] < gpGlobals->curtime )
+ {
+ // Stagger ripple times
+ m_WaterData.m_flNextRippleTime[iWheel] = gpGlobals->curtime + RandomFloat( 0.1, 0.3 );
+ CreateRipple( m_WaterData.m_vecWheelContactPoints[iWheel] );
+ }
+ }
+ }
+ }
+
+ // Save of data from last think.
+ for ( int iWheel = 0; iWheel < JEEP_WHEEL_COUNT; ++iWheel )
+ {
+ m_WaterData.m_bWheelWasInWater[iWheel] = m_WaterData.m_bWheelInWater[iWheel];
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+bool CPropJeep::CheckWater( void )
+{
+ bool bInWater = false;
+
+ // Check all four wheels.
+ for ( int iWheel = 0; iWheel < JEEP_WHEEL_COUNT; ++iWheel )
+ {
+ // Get the current wheel and get its contact point.
+ IPhysicsObject *pWheel = m_VehiclePhysics.GetWheel( iWheel );
+ if ( !pWheel )
+ continue;
+
+ // Check to see if we hit water.
+ if ( pWheel->GetContactPoint( &m_WaterData.m_vecWheelContactPoints[iWheel], NULL ) )
+ {
+ m_WaterData.m_bWheelInWater[iWheel] = ( UTIL_PointContents( m_WaterData.m_vecWheelContactPoints[iWheel] ) & MASK_WATER ) ? true : false;
+ if ( m_WaterData.m_bWheelInWater[iWheel] )
+ {
+ bInWater = true;
+ }
+ }
+ }
+
+ // Check the body and the BONNET.
+ int iEngine = LookupAttachment( "vehicle_engine" );
+ Vector vecEnginePoint;
+ QAngle vecEngineAngles;
+ GetAttachment( iEngine, vecEnginePoint, vecEngineAngles );
+
+ m_WaterData.m_bBodyInWater = ( UTIL_PointContents( vecEnginePoint ) & MASK_WATER ) ? true : false;
+ if ( m_WaterData.m_bBodyInWater )
+ {
+ if ( m_bHasPoop )
+ {
+ RemoveAllDecals();
+ m_bHasPoop = false;
+ }
+
+ if ( !m_VehiclePhysics.IsEngineDisabled() )
+ {
+ m_VehiclePhysics.SetDisableEngine( true );
+ }
+ }
+ else
+ {
+ if ( m_VehiclePhysics.IsEngineDisabled() )
+ {
+ m_VehiclePhysics.SetDisableEngine( false );
+ }
+ }
+
+ if ( bInWater )
+ {
+ // Check the player's water level.
+ CheckWaterLevel();
+ }
+
+ return bInWater;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CPropJeep::CheckWaterLevel( void )
+{
+ CBaseEntity *pEntity = GetDriver();
+ if ( pEntity && pEntity->IsPlayer() )
+ {
+ CBasePlayer *pPlayer = static_cast<CBasePlayer*>( pEntity );
+
+ Vector vecAttachPoint;
+ QAngle vecAttachAngles;
+
+ // Check eyes. (vehicle_driver_eyes point)
+ int iAttachment = LookupAttachment( "vehicle_driver_eyes" );
+ GetAttachment( iAttachment, vecAttachPoint, vecAttachAngles );
+
+ // Add the jeep's Z view offset
+ Vector vecUp;
+ AngleVectors( vecAttachAngles, NULL, NULL, &vecUp );
+ vecUp.z = clamp( vecUp.z, 0.0f, vecUp.z );
+ vecAttachPoint.z += r_JeepViewZHeight.GetFloat() * vecUp.z;
+
+ bool bEyes = ( UTIL_PointContents( vecAttachPoint ) & MASK_WATER ) ? true : false;
+ if ( bEyes )
+ {
+ pPlayer->SetWaterLevel( WL_Eyes );
+ return;
+ }
+
+ // Check waist. (vehicle_engine point -- see parent function).
+ if ( m_WaterData.m_bBodyInWater )
+ {
+ pPlayer->SetWaterLevel( WL_Waist );
+ return;
+ }
+
+ // Check feet. (vehicle_feet_passenger0 point)
+ iAttachment = LookupAttachment( "vehicle_feet_passenger0" );
+ GetAttachment( iAttachment, vecAttachPoint, vecAttachAngles );
+ bool bFeet = ( UTIL_PointContents( vecAttachPoint ) & MASK_WATER ) ? true : false;
+ if ( bFeet )
+ {
+ pPlayer->SetWaterLevel( WL_Feet );
+ return;
+ }
+
+ // Not in water.
+ pPlayer->SetWaterLevel( WL_NotInWater );
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CPropJeep::CreateSplash( const Vector &vecPosition )
+{
+ // Splash data.
+ CEffectData data;
+ data.m_fFlags = 0;
+ data.m_vOrigin = vecPosition;
+ data.m_vNormal.Init( 0.0f, 0.0f, 1.0f );
+ VectorAngles( data.m_vNormal, data.m_vAngles );
+ data.m_flScale = 10.0f + random->RandomFloat( 0, 2 );
+
+ // Create the splash..
+ DispatchEffect( "watersplash", data );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CPropJeep::CreateRipple( const Vector &vecPosition )
+{
+ // Ripple data.
+ CEffectData data;
+ data.m_fFlags = 0;
+ data.m_vOrigin = vecPosition;
+ data.m_vNormal.Init( 0.0f, 0.0f, 1.0f );
+ VectorAngles( data.m_vNormal, data.m_vAngles );
+ data.m_flScale = 10.0f + random->RandomFloat( 0, 2 );
+ if ( GetWaterType() & CONTENTS_SLIME )
+ {
+ data.m_fFlags |= FX_WATER_IN_SLIME;
+ }
+
+ // Create the ripple.
+ DispatchEffect( "waterripple", data );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CPropJeep::Think(void)
+{
+ BaseClass::Think();
+
+/*
+ CBasePlayer *pPlayer = UTIL_GetLocalPlayer();
+
+ if ( m_bEngineLocked )
+ {
+ m_bUnableToFire = true;
+
+ if ( pPlayer != NULL )
+ {
+ pPlayer->m_Local.m_iHideHUD |= HIDEHUD_VEHICLE_CROSSHAIR;
+ }
+ }
+ else
+ {
+ // Start this as false and update it again each frame
+ m_bUnableToFire = false;
+
+ if ( pPlayer != NULL )
+ {
+ pPlayer->m_Local.m_iHideHUD &= ~HIDEHUD_VEHICLE_CROSSHAIR;
+ }
+ }
+*/
+
+ // Water!?
+ HandleWater();
+
+ SetSimulationTime( gpGlobals->curtime );
+
+ SetNextThink( gpGlobals->curtime );
+ SetAnimatedEveryTick( true );
+
+ if ( !m_bInitialHandbrake ) // after initial timer expires, set the handbrake
+ {
+ m_bInitialHandbrake = true;
+ m_VehiclePhysics.SetHandbrake( true );
+ m_VehiclePhysics.Think();
+ }
+
+ // Check overturned status.
+ if ( !IsOverturned() )
+ {
+ m_flOverturnedTime = 0.0f;
+ }
+ else
+ {
+ m_flOverturnedTime += gpGlobals->frametime;
+ }
+
+ // spin gun if charging cannon
+ //FIXME: Don't bother for E3
+ if ( m_bCannonCharging )
+ {
+ m_nSpinPos += JEEP_GUN_SPIN_RATE;
+ SetPoseParameter( JEEP_GUN_SPIN, m_nSpinPos );
+ }
+
+ // Aim gun based on the player view direction.
+ if ( m_hPlayer && !m_bExitAnimOn && !m_bEnterAnimOn )
+ {
+ Vector vecEyeDir, vecEyePos;
+ m_hPlayer->EyePositionAndVectors( &vecEyePos, &vecEyeDir, NULL, NULL );
+
+ // Trace out from the player's eye point.
+ Vector vecEndPos = vecEyePos + ( vecEyeDir * MAX_TRACE_LENGTH );
+ trace_t trace;
+ UTIL_TraceLine( vecEyePos, vecEndPos, MASK_SHOT, this, COLLISION_GROUP_NONE, &trace );
+
+ // See if we hit something, if so, adjust end position to hit location.
+ if ( trace.fraction < 1.0 )
+ {
+ vecEndPos = vecEyePos + ( vecEyeDir * MAX_TRACE_LENGTH * trace.fraction );
+ }
+
+ //m_vecLookCrosshair = vecEndPos;
+ AimGunAt( &vecEndPos, 0.1f );
+ }
+
+ StudioFrameAdvance();
+
+ // If the enter or exit animation has finished, tell the server vehicle
+ if ( IsSequenceFinished() && (m_bExitAnimOn || m_bEnterAnimOn) )
+ {
+ if ( m_bEnterAnimOn )
+ {
+ m_VehiclePhysics.ReleaseHandbrake();
+ StartEngine();
+
+ // HACKHACK: This forces the jeep to play a sound when it gets entered underwater
+ if ( m_VehiclePhysics.IsEngineDisabled() )
+ {
+ CBaseServerVehicle *pServerVehicle = dynamic_cast<CBaseServerVehicle *>(GetServerVehicle());
+ if ( pServerVehicle )
+ {
+ pServerVehicle->SoundStartDisabled();
+ }
+ }
+
+ // The first few time we get into the jeep, print the jeep help
+ if ( m_iNumberOfEntries < hud_jeephint_numentries.GetInt() )
+ {
+ UTIL_HudHintText( m_hPlayer, "#Valve_Hint_JeepKeys" );
+ m_iNumberOfEntries++;
+ }
+ }
+
+ // If we're exiting and have had the tau cannon removed, we don't want to reset the animation
+ GetServerVehicle()->HandleEntryExitFinish( m_bExitAnimOn, true );
+ }
+
+ // See if the ammo crate needs to close
+ if ( ( m_flAmmoCrateCloseTime < gpGlobals->curtime ) && ( GetSequence() == LookupSequence( "ammo_open" ) ) )
+ {
+ m_flAnimTime = gpGlobals->curtime;
+ m_flPlaybackRate = 0.0;
+ SetCycle( 0 );
+ ResetSequence( LookupSequence( "ammo_close" ) );
+ }
+ else if ( ( GetSequence() == LookupSequence( "ammo_close" ) ) && IsSequenceFinished() )
+ {
+ m_flAnimTime = gpGlobals->curtime;
+ m_flPlaybackRate = 0.0;
+ SetCycle( 0 );
+ ResetSequence( LookupSequence( "idle" ) );
+
+ CPASAttenuationFilter sndFilter( this, "PropJeep.AmmoClose" );
+ EmitSound( sndFilter, entindex(), "PropJeep.AmmoClose" );
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : &startPos -
+// &endPos -
+// width -
+// useMuzzle -
+//-----------------------------------------------------------------------------
+void CPropJeep::DrawBeam( const Vector &startPos, const Vector &endPos, float width )
+{
+ /*
+ //Tracer down the middle
+ UTIL_Tracer( startPos, endPos, 0, TRACER_DONT_USE_ATTACHMENT, 6500, false, "GaussTracer" );
+
+ //Draw the main beam shaft
+ CBeam *pBeam = CBeam::BeamCreate( GAUSS_BEAM_SPRITE, 0.5 );
+
+ pBeam->SetStartPos( startPos );
+ pBeam->PointEntInit( endPos, this );
+ pBeam->SetEndAttachment( LookupAttachment("Muzzle") );
+ pBeam->SetWidth( width );
+ pBeam->SetEndWidth( 0.05f );
+ pBeam->SetBrightness( 255 );
+ pBeam->SetColor( 255, 185+random->RandomInt( -16, 16 ), 40 );
+ pBeam->RelinkBeam();
+ pBeam->LiveForTime( 0.1f );
+
+ //Draw electric bolts along shaft
+ pBeam = CBeam::BeamCreate( GAUSS_BEAM_SPRITE, 3.0f );
+
+ pBeam->SetStartPos( startPos );
+ pBeam->PointEntInit( endPos, this );
+ pBeam->SetEndAttachment( LookupAttachment("Muzzle") );
+
+ pBeam->SetBrightness( random->RandomInt( 64, 255 ) );
+ pBeam->SetColor( 255, 255, 150+random->RandomInt( 0, 64 ) );
+ pBeam->RelinkBeam();
+ pBeam->LiveForTime( 0.1f );
+ pBeam->SetNoise( 1.6f );
+ pBeam->SetEndWidth( 0.1f ); */
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CPropJeep::FireCannon( void )
+{
+ //Don't fire again if it's been too soon
+ if ( m_flCannonTime > gpGlobals->curtime )
+ return;
+
+ if ( m_bUnableToFire )
+ return;
+
+ m_flCannonTime = gpGlobals->curtime + 0.2f;
+ m_bCannonCharging = false;
+
+ //Find the direction the gun is pointing in
+ Vector aimDir;
+ GetCannonAim( &aimDir );
+
+ FireBulletsInfo_t info( 1, m_vecGunOrigin, aimDir, VECTOR_CONE_1DEGREES, MAX_TRACE_LENGTH, m_nAmmoType );
+
+ info.m_nFlags = FIRE_BULLETS_ALLOW_WATER_SURFACE_IMPACTS;
+ info.m_pAttacker = m_hPlayer;
+
+ FireBullets( info );
+
+ // Register a muzzleflash for the AI
+ if ( m_hPlayer )
+ {
+ m_hPlayer->SetMuzzleFlashTime( gpGlobals->curtime + 0.5 );
+ }
+
+ CPASAttenuationFilter sndFilter( this, "PropJeep.FireCannon" );
+ EmitSound( sndFilter, entindex(), "PropJeep.FireCannon" );
+
+ // make cylinders of gun spin a bit
+ m_nSpinPos += JEEP_GUN_SPIN_RATE;
+ //SetPoseParameter( JEEP_GUN_SPIN, m_nSpinPos ); //FIXME: Don't bother with this for E3, won't look right
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CPropJeep::FireChargedCannon( void )
+{
+/* bool penetrated = false;
+
+ m_bCannonCharging = false;
+ m_flCannonTime = gpGlobals->curtime + 0.5f;
+
+ StopChargeSound();
+
+ CPASAttenuationFilter sndFilter( this, "PropJeep.FireChargedCannon" );
+ EmitSound( sndFilter, entindex(), "PropJeep.FireChargedCannon" );
+
+ //Find the direction the gun is pointing in
+ Vector aimDir;
+ GetCannonAim( &aimDir );
+
+ Vector endPos = m_vecGunOrigin + ( aimDir * MAX_TRACE_LENGTH );
+
+ //Shoot a shot straight out
+ trace_t tr;
+ UTIL_TraceLine( m_vecGunOrigin, endPos, MASK_SHOT, this, COLLISION_GROUP_NONE, &tr );
+
+ ClearMultiDamage();
+
+ //Find how much damage to do
+ float flChargeAmount = ( gpGlobals->curtime - m_flCannonChargeStartTime ) / MAX_GAUSS_CHARGE_TIME;
+
+ //Clamp this
+ if ( flChargeAmount > 1.0f )
+ {
+ flChargeAmount = 1.0f;
+ }
+
+ //Determine the damage amount
+ //FIXME: Use ConVars!
+ float flDamage = 15 + ( ( 250 - 15 ) * flChargeAmount );
+
+ CBaseEntity *pHit = tr.m_pEnt;
+
+ //Look for wall penetration
+ if ( tr.DidHitWorld() && !(tr.surface.flags & SURF_SKY) )
+ {
+ //Try wall penetration
+ UTIL_ImpactTrace( &tr, m_nBulletType, "ImpactJeep" );
+ UTIL_DecalTrace( &tr, "RedGlowFade" );
+
+ CPVSFilter filter( tr.endpos );
+ te->GaussExplosion( filter, 0.0f, tr.endpos, tr.plane.normal, 0 );
+
+ Vector testPos = tr.endpos + ( aimDir * 48.0f );
+
+ UTIL_TraceLine( testPos, tr.endpos, MASK_SHOT, GetDriver(), COLLISION_GROUP_NONE, &tr );
+
+ if ( tr.allsolid == false )
+ {
+ UTIL_DecalTrace( &tr, "RedGlowFade" );
+
+ penetrated = true;
+ }
+ }
+ else if ( pHit != NULL )
+ {
+ CTakeDamageInfo dmgInfo( this, GetDriver(), flDamage, DMG_SHOCK );
+ CalculateBulletDamageForce( &dmgInfo, GetAmmoDef()->Index("GaussEnergy"), aimDir, tr.endpos, 1.0f + flChargeAmount * 4.0f );
+
+ //Do direct damage to anything in our path
+ pHit->DispatchTraceAttack( dmgInfo, aimDir, &tr );
+ }
+
+ ApplyMultiDamage();
+
+ //Kick up an effect
+ if ( !(tr.surface.flags & SURF_SKY) )
+ {
+ UTIL_ImpactTrace( &tr, m_nBulletType, "ImpactJeep" );
+
+ //Do a gauss explosion
+ CPVSFilter filter( tr.endpos );
+ te->GaussExplosion( filter, 0.0f, tr.endpos, tr.plane.normal, 0 );
+ }
+
+ //Show the effect
+ DrawBeam( m_vecGunOrigin, tr.endpos, 9.6 );
+
+ // Register a muzzleflash for the AI
+ if ( m_hPlayer )
+ {
+ m_hPlayer->SetMuzzleFlashTime( gpGlobals->curtime + 0.5f );
+ }
+
+ //Rock the car
+ IPhysicsObject *pObj = VPhysicsGetObject();
+
+ if ( pObj != NULL )
+ {
+ Vector shoveDir = aimDir * -( flDamage * 500.0f );
+
+ pObj->ApplyForceOffset( shoveDir, m_vecGunOrigin );
+ }
+
+ //Do radius damage if we didn't penetrate the wall
+ if ( penetrated == true )
+ {
+ RadiusDamage( CTakeDamageInfo( this, this, flDamage, DMG_SHOCK ), tr.endpos, 200.0f, CLASS_NONE, NULL );
+ } */
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CPropJeep::ChargeCannon( void )
+{
+ //Don't fire again if it's been too soon
+ if ( m_flCannonTime > gpGlobals->curtime )
+ return;
+
+ //See if we're starting a charge
+ if ( m_bCannonCharging == false )
+ {
+ m_flCannonChargeStartTime = gpGlobals->curtime;
+ m_bCannonCharging = true;
+
+ //Start charging sound
+ CPASAttenuationFilter filter( this );
+ m_sndCannonCharge = (CSoundEnvelopeController::GetController()).SoundCreate( filter, entindex(), CHAN_STATIC, "Jeep.GaussCharge", ATTN_NORM );
+
+ assert(m_sndCannonCharge!=NULL);
+ if ( m_sndCannonCharge != NULL )
+ {
+ (CSoundEnvelopeController::GetController()).Play( m_sndCannonCharge, 1.0f, 50 );
+ (CSoundEnvelopeController::GetController()).SoundChangePitch( m_sndCannonCharge, 250, 3.0f );
+ }
+
+ return;
+ }
+
+ //TODO: Add muzzle effect?
+
+ //TODO: Check for overcharge and have the weapon simply fire or instead "decharge"?
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CPropJeep::StopChargeSound( void )
+{
+ if ( m_sndCannonCharge != NULL )
+ {
+ (CSoundEnvelopeController::GetController()).SoundFadeOut( m_sndCannonCharge, 0.1f );
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Finds the true aiming position of the gun (looks at what player
+// is looking at and adjusts)
+// Input : &resultDir - direction to be calculated
+//-----------------------------------------------------------------------------
+void CPropJeep::GetCannonAim( Vector *resultDir )
+{
+ Vector muzzleOrigin;
+ QAngle muzzleAngles;
+
+ GetAttachment( LookupAttachment("gun_ref"), muzzleOrigin, muzzleAngles );
+
+ AngleVectors( muzzleAngles, resultDir );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: If the player uses the jeep while at the back, he gets ammo from the crate instead
+//-----------------------------------------------------------------------------
+void CPropJeep::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value )
+{
+ CBasePlayer *pPlayer = ToBasePlayer( pActivator );
+
+ if ( pPlayer == NULL)
+ return;
+
+ // Find out if the player's looking at our ammocrate hitbox
+ Vector vecForward;
+ pPlayer->EyeVectors( &vecForward, NULL, NULL );
+
+ trace_t tr;
+ Vector vecStart = pPlayer->EyePosition();
+ UTIL_TraceLine( vecStart, vecStart + vecForward * 1024, MASK_SOLID | CONTENTS_DEBRIS | CONTENTS_HITBOX, pPlayer, COLLISION_GROUP_NONE, &tr );
+
+ if ( tr.m_pEnt == this && tr.hitgroup == JEEP_AMMOCRATE_HITGROUP )
+ {
+ // Player's using the crate.
+ // Fill up his SMG ammo.
+ pPlayer->GiveAmmo( 300, "SMG1");
+
+ if ( ( GetSequence() != LookupSequence( "ammo_open" ) ) && ( GetSequence() != LookupSequence( "ammo_close" ) ) )
+ {
+ // Open the crate
+ m_flAnimTime = gpGlobals->curtime;
+ m_flPlaybackRate = 0.0;
+ SetCycle( 0 );
+ ResetSequence( LookupSequence( "ammo_open" ) );
+
+ CPASAttenuationFilter sndFilter( this, "PropJeep.AmmoOpen" );
+ EmitSound( sndFilter, entindex(), "PropJeep.AmmoOpen" );
+ }
+
+ m_flAmmoCrateCloseTime = gpGlobals->curtime + JEEP_AMMO_CRATE_CLOSE_DELAY;
+ return;
+ }
+
+ // Fall back and get in the vehicle instead
+ BaseClass::Use( pActivator, pCaller, useType, value );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+bool CPropJeep::CanExitVehicle( CBaseEntity *pEntity )
+{
+ return ( !m_bEnterAnimOn && !m_bExitAnimOn && !m_bLocked && (m_nSpeed <= g_jeepexitspeed.GetFloat() ) );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CPropJeep::DampenEyePosition( Vector &vecVehicleEyePos, QAngle &vecVehicleEyeAngles )
+{
+ // Get the frametime. (Check to see if enough time has passed to warrent dampening).
+ float flFrameTime = gpGlobals->frametime;
+ if ( flFrameTime < JEEP_FRAMETIME_MIN )
+ {
+ vecVehicleEyePos = m_vecLastEyePos;
+ DampenUpMotion( vecVehicleEyePos, vecVehicleEyeAngles, 0.0f );
+ return;
+ }
+
+ // Keep static the sideways motion.
+
+ // Dampen forward/backward motion.
+ DampenForwardMotion( vecVehicleEyePos, vecVehicleEyeAngles, flFrameTime );
+
+ // Blend up/down motion.
+ DampenUpMotion( vecVehicleEyePos, vecVehicleEyeAngles, flFrameTime );
+}
+
+//-----------------------------------------------------------------------------
+// Use the controller as follows:
+// speed += ( pCoefficientsOut[0] * ( targetPos - currentPos ) + pCoefficientsOut[1] * ( targetSpeed - currentSpeed ) ) * flDeltaTime;
+//-----------------------------------------------------------------------------
+void CPropJeep::ComputePDControllerCoefficients( float *pCoefficientsOut,
+ float flFrequency, float flDampening,
+ float flDeltaTime )
+{
+ float flKs = 9.0f * flFrequency * flFrequency;
+ float flKd = 4.5f * flFrequency * flDampening;
+
+ float flScale = 1.0f / ( 1.0f + flKd * flDeltaTime + flKs * flDeltaTime * flDeltaTime );
+
+ pCoefficientsOut[0] = flKs * flScale;
+ pCoefficientsOut[1] = ( flKd + flKs * flDeltaTime ) * flScale;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CPropJeep::DampenForwardMotion( Vector &vecVehicleEyePos, QAngle &vecVehicleEyeAngles, float flFrameTime )
+{
+ // Get forward vector.
+ Vector vecForward;
+ AngleVectors( vecVehicleEyeAngles, &vecForward);
+
+ // Simulate the eye position forward based on the data from last frame
+ // (assumes no acceleration - it will get that from the "spring").
+ Vector vecCurrentEyePos = m_vecLastEyePos + m_vecEyeSpeed * flFrameTime;
+
+ // Calculate target speed based on the current vehicle eye position and the last vehicle eye position and frametime.
+ Vector vecVehicleEyeSpeed = ( vecVehicleEyePos - m_vecLastEyeTarget ) / flFrameTime;
+ m_vecLastEyeTarget = vecVehicleEyePos;
+
+ // Calculate the speed and position deltas.
+ Vector vecDeltaSpeed = vecVehicleEyeSpeed - m_vecEyeSpeed;
+ Vector vecDeltaPos = vecVehicleEyePos - vecCurrentEyePos;
+
+ // Clamp.
+ if ( vecDeltaPos.Length() > JEEP_DELTA_LENGTH_MAX )
+ {
+ float flSign = vecForward.Dot( vecVehicleEyeSpeed ) >= 0.0f ? -1.0f : 1.0f;
+ vecVehicleEyePos += flSign * ( vecForward * JEEP_DELTA_LENGTH_MAX );
+ m_vecLastEyePos = vecVehicleEyePos;
+ m_vecEyeSpeed = vecVehicleEyeSpeed;
+ return;
+ }
+
+ // Generate an updated (dampening) speed for use in next frames position extrapolation.
+ float flCoefficients[2];
+ ComputePDControllerCoefficients( flCoefficients, r_JeepViewDampenFreq.GetFloat(), r_JeepViewDampenDamp.GetFloat(), flFrameTime );
+ m_vecEyeSpeed += ( ( flCoefficients[0] * vecDeltaPos + flCoefficients[1] * vecDeltaSpeed ) * flFrameTime );
+
+ // Save off data for next frame.
+ m_vecLastEyePos = vecCurrentEyePos;
+
+ // Move eye forward/backward.
+ Vector vecForwardOffset = vecForward * ( vecForward.Dot( vecDeltaPos ) );
+ vecVehicleEyePos -= vecForwardOffset;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CPropJeep::DampenUpMotion( Vector &vecVehicleEyePos, QAngle &vecVehicleEyeAngles, float flFrameTime )
+{
+ // Get up vector.
+ Vector vecUp;
+ AngleVectors( vecVehicleEyeAngles, NULL, NULL, &vecUp );
+ vecUp.z = clamp( vecUp.z, 0.0f, vecUp.z );
+ vecVehicleEyePos.z += r_JeepViewZHeight.GetFloat() * vecUp.z;
+
+ // NOTE: Should probably use some damped equation here.
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CPropJeep::SetupMove( CBasePlayer *player, CUserCmd *ucmd, IMoveHelper *pHelper, CMoveData *move )
+{
+ // If we are overturned and hit any key - leave the vehicle (IN_USE is already handled!).
+ if ( m_flOverturnedTime > OVERTURNED_EXIT_WAITTIME )
+ {
+ if ( (ucmd->buttons & (IN_FORWARD|IN_BACK|IN_MOVELEFT|IN_MOVERIGHT|IN_SPEED|IN_JUMP|IN_ATTACK|IN_ATTACK2) ) && !m_bExitAnimOn )
+ {
+ // Can't exit yet? We're probably still moving. Swallow the keys.
+ if ( !CanExitVehicle(player) )
+ return;
+
+ if ( !GetServerVehicle()->HandlePassengerExit( m_hPlayer ) && ( m_hPlayer != NULL ) )
+ {
+ m_hPlayer->PlayUseDenySound();
+ }
+ return;
+ }
+ }
+
+ // If the throttle is disabled or we're upside-down, don't allow throttling (including turbo)
+ CUserCmd tmp;
+ if ( ( m_throttleDisableTime > gpGlobals->curtime ) || ( IsOverturned() ) )
+ {
+ m_bUnableToFire = true;
+
+ tmp = (*ucmd);
+ tmp.buttons &= ~(IN_FORWARD|IN_BACK|IN_SPEED);
+ ucmd = &tmp;
+ }
+
+ BaseClass::SetupMove( player, ucmd, pHelper, move );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CPropJeep::DriveVehicle( float flFrameTime, CUserCmd *ucmd, int iButtonsDown, int iButtonsReleased )
+{
+ int iButtons = ucmd->buttons;
+
+ //Adrian: No headlights on Superfly.
+/* if ( ucmd->impulse == 100 )
+ {
+ if (HeadlightIsOn())
+ {
+ HeadlightTurnOff();
+ }
+ else
+ {
+ HeadlightTurnOn();
+ }
+ }*/
+
+ // If we're holding down an attack button, update our state
+ if ( IsOverturned() == false )
+ {
+ if ( iButtons & IN_ATTACK )
+ {
+ if ( m_bCannonCharging )
+ {
+ FireChargedCannon();
+ }
+ else
+ {
+ FireCannon();
+ }
+ }
+ else if ( iButtons & IN_ATTACK2 )
+ {
+ ChargeCannon();
+ }
+ }
+
+ // If we've released our secondary button, fire off our cannon
+ if ( ( iButtonsReleased & IN_ATTACK2 ) && ( m_bCannonCharging ) )
+ {
+ FireChargedCannon();
+ }
+
+ BaseClass::DriveVehicle( flFrameTime, ucmd, iButtonsDown, iButtonsReleased );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : *pPlayer -
+// *pMoveData -
+//-----------------------------------------------------------------------------
+void CPropJeep::ProcessMovement( CBasePlayer *pPlayer, CMoveData *pMoveData )
+{
+ BaseClass::ProcessMovement( pPlayer, pMoveData );
+
+ // Update the steering angles based on speed.
+ UpdateSteeringAngle();
+
+ // Create dangers sounds in front of the vehicle.
+ CreateDangerSounds();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CPropJeep::UpdateSteeringAngle( void )
+{
+ float flMaxSpeed = m_VehiclePhysics.GetMaxSpeed();
+ float flSpeed = m_VehiclePhysics.GetSpeed();
+
+ float flRatio = 1.0f - ( flSpeed / flMaxSpeed );
+ float flSteeringDegrees = JEEP_STEERING_FAST_ANGLE + ( ( JEEP_STEERING_SLOW_ANGLE - JEEP_STEERING_FAST_ANGLE ) * flRatio );
+ flSteeringDegrees = clamp( flSteeringDegrees, JEEP_STEERING_FAST_ANGLE, JEEP_STEERING_SLOW_ANGLE );
+ m_VehiclePhysics.SetSteeringDegrees( flSteeringDegrees );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Create danger sounds in front of the vehicle.
+//-----------------------------------------------------------------------------
+void CPropJeep::CreateDangerSounds( void )
+{
+ QAngle dummy;
+ GetAttachment( "Muzzle", m_vecGunOrigin, dummy );
+
+ if ( m_flDangerSoundTime > gpGlobals->curtime )
+ return;
+
+ QAngle vehicleAngles = GetLocalAngles();
+ Vector vecStart = GetAbsOrigin();
+ Vector vecDir, vecRight;
+
+ GetVectors( &vecDir, &vecRight, NULL );
+
+ const float soundDuration = 0.25;
+ float speed = m_VehiclePhysics.GetHLSpeed();
+ // Make danger sounds ahead of the jeep
+ if ( fabs(speed) > 120 )
+ {
+ Vector vecSpot;
+
+ float steering = m_VehiclePhysics.GetSteering();
+ if ( steering != 0 )
+ {
+ if ( speed > 0 )
+ {
+ vecDir += vecRight * steering * 0.5;
+ }
+ else
+ {
+ vecDir -= vecRight * steering * 0.5;
+ }
+ VectorNormalize(vecDir);
+ }
+ const float radius = speed * 0.4;
+ // 0.3 seconds ahead of the jeep
+ vecSpot = vecStart + vecDir * (speed * 0.3f);
+ CSoundEnt::InsertSound( SOUND_DANGER, vecSpot, radius, soundDuration, this, 0 );
+ CSoundEnt::InsertSound( SOUND_PHYSICS_DANGER, vecSpot, radius, soundDuration, this, 1 );
+ //NDebugOverlay::Box(vecSpot, Vector(-radius,-radius,-radius),Vector(radius,radius,radius), 255, 0, 255, 0, soundDuration);
+
+#if 0
+ trace_t tr;
+ // put sounds a bit to left and right but slightly closer to Jeep to make a "cone" of sound
+ // in front of it
+ vecSpot = vecStart + vecDir * (speed * 0.5f) - vecRight * speed * 0.5;
+ UTIL_TraceLine( vecStart, vecSpot, MASK_SHOT, this, COLLISION_GROUP_NONE, &tr );
+ CSoundEnt::InsertSound( SOUND_DANGER, vecSpot, 400, soundDuration, this, 1 );
+
+ vecSpot = vecStart + vecDir * (speed * 0.5f) + vecRight * speed * 0.5;
+ UTIL_TraceLine( vecStart, vecSpot, MASK_SHOT, this, COLLISION_GROUP_NONE, &tr );
+ CSoundEnt::InsertSound( SOUND_DANGER, vecSpot, 400, soundDuration, this, 2);
+#endif
+ }
+
+ m_flDangerSoundTime = gpGlobals->curtime + 0.1;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CPropJeep::EnterVehicle( CBasePlayer *pPlayer )
+{
+ if ( !pPlayer )
+ return;
+
+ CheckWater();
+ BaseClass::EnterVehicle( pPlayer );
+
+ // Start looking for seagulls to land
+ m_hLastPlayerInVehicle = m_hPlayer;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CPropJeep::ExitVehicle( int nRole )
+{
+ HeadlightTurnOff();
+
+ BaseClass::ExitVehicle( nRole );
+
+ //If the player has exited, stop charging
+ StopChargeSound();
+ m_bCannonCharging = false;
+
+ // Remember when we last saw the player
+ m_flPlayerExitedTime = gpGlobals->curtime;
+ m_flLastSawPlayerAt = gpGlobals->curtime;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CPropJeep::InputStartRemoveTauCannon( inputdata_t &inputdata )
+{
+ // Start the gun removal animation
+ m_flAnimTime = gpGlobals->curtime;
+ m_flPlaybackRate = 0.0;
+ SetCycle( 0 );
+ ResetSequence( LookupSequence( "tau_levitate" ) );
+
+ m_bGunHasBeenCutOff = true;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CPropJeep::InputFinishRemoveTauCannon( inputdata_t &inputdata )
+{
+ // Remove & hide the gun
+ SetBodygroup( 1, false );
+ m_bHasGun = false;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CPropJeep::OnRestore( void )
+{
+ IServerVehicle *pServerVehicle = GetServerVehicle();
+ if ( pServerVehicle != NULL )
+ {
+ // Restore the passenger information we're holding on to
+ pServerVehicle->RestorePassengerInfo();
+ }
+}
+
+//========================================================================================================================================
+// JEEP FOUR WHEEL PHYSICS VEHICLE SERVER VEHICLE
+//========================================================================================================================================
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CJeepFourWheelServerVehicle::NPC_AimPrimaryWeapon( Vector vecTarget )
+{
+ ((CPropJeep*)m_pVehicle)->AimGunAt( &vecTarget, 0.1f );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : &vecEyeExitEndpoint -
+// Output : int
+//-----------------------------------------------------------------------------
+int CJeepFourWheelServerVehicle::GetExitAnimToUse( Vector &vecEyeExitEndpoint, bool &bAllPointsBlocked )
+{
+ bAllPointsBlocked = false;
+
+ if ( !m_bParsedAnimations )
+ {
+ // Load the entry/exit animations from the vehicle
+ ParseEntryExitAnims();
+ m_bParsedAnimations = true;
+ }
+
+ CBaseAnimating *pAnimating = dynamic_cast<CBaseAnimating *>(m_pVehicle);
+ // If we don't have the gun anymore, we want to get out using the "gun-less" animation
+ if ( pAnimating )
+ {
+ // HACK: We know the tau-cannon removed exit anim uses the first upright anim's exit details
+ trace_t tr;
+ Vector vehicleExitOrigin;
+ QAngle vehicleExitAngles;
+
+ // Ensure the endpoint is clear by dropping a point down from above
+ pAnimating->GetAttachment( m_ExitAnimations[0].iAttachment, vehicleExitOrigin, vehicleExitAngles );
+ vehicleExitOrigin -= VEC_VIEW;
+ Vector vecMove = Vector(0,0,64);
+ Vector vecStart = vehicleExitOrigin + vecMove;
+ Vector vecEnd = vehicleExitOrigin - vecMove;
+ UTIL_TraceHull( vecStart, vecEnd, VEC_HULL_MIN, VEC_HULL_MAX, MASK_SOLID, NULL, COLLISION_GROUP_NONE, &tr );
+
+ Assert( !tr.startsolid && tr.fraction < 1.0 );
+ m_vecCurrentExitEndPoint = vecStart + ((vecEnd - vecStart) * tr.fraction);
+ vecEyeExitEndpoint = m_vecCurrentExitEndPoint + VEC_VIEW;
+ m_iCurrentExitAnim = 0;
+ return pAnimating->LookupSequence( "exit_tauremoved" );
+ }
+
+ return BaseClass::GetExitAnimToUse( vecEyeExitEndpoint, bAllPointsBlocked );
+}
diff --git a/sp/src/game/server/sdk/te_firebullets.cpp b/sp/src/game/server/sdk/te_firebullets.cpp
new file mode 100644
index 00000000..c842707c
--- /dev/null
+++ b/sp/src/game/server/sdk/te_firebullets.cpp
@@ -0,0 +1,98 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $Workfile: $
+// $Date: $
+//
+//-----------------------------------------------------------------------------
+// $Log: $
+//
+// $NoKeywords: $
+//=============================================================================//
+#include "cbase.h"
+#include "basetempentity.h"
+
+
+#define NUM_BULLET_SEED_BITS 8
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Display's a blood sprite
+//-----------------------------------------------------------------------------
+class CTEFireBullets : public CBaseTempEntity
+{
+public:
+ DECLARE_CLASS( CTEFireBullets, CBaseTempEntity );
+ DECLARE_SERVERCLASS();
+
+ CTEFireBullets( const char *name );
+ virtual ~CTEFireBullets( void );
+
+public:
+ CNetworkVar( int, m_iPlayer ); // player who fired
+ CNetworkVector( m_vecOrigin ); // firing origin
+ CNetworkQAngle( m_vecAngles ); // firing angle
+ CNetworkVar( int, m_iWeaponID ); // weapon ID
+ CNetworkVar( int, m_iMode ); // primary or secondary fire ?
+ CNetworkVar( int, m_iSeed ); // shared random seed
+ CNetworkVar( float, m_flSpread ); // bullets spread
+
+};
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : *name -
+//-----------------------------------------------------------------------------
+CTEFireBullets::CTEFireBullets( const char *name ) :
+ CBaseTempEntity( name )
+{
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+CTEFireBullets::~CTEFireBullets( void )
+{
+}
+
+IMPLEMENT_SERVERCLASS_ST_NOBASE(CTEFireBullets, DT_TEFireBullets)
+ SendPropVector( SENDINFO(m_vecOrigin), -1, SPROP_COORD ),
+ SendPropAngle( SENDINFO_VECTORELEM( m_vecAngles, 0 ), 13, 0 ),
+ SendPropAngle( SENDINFO_VECTORELEM( m_vecAngles, 1 ), 13, 0 ),
+ SendPropInt( SENDINFO( m_iWeaponID ), 5, SPROP_UNSIGNED ), // max 31 weapons
+ SendPropInt( SENDINFO( m_iMode ), 1, SPROP_UNSIGNED ),
+ SendPropInt( SENDINFO( m_iSeed ), NUM_BULLET_SEED_BITS, SPROP_UNSIGNED ),
+ SendPropInt( SENDINFO( m_iPlayer ), 6, SPROP_UNSIGNED ), // max 64 players, see MAX_PLAYERS
+ SendPropFloat( SENDINFO( m_flSpread ), 10, 0, 0, 1 ),
+END_SEND_TABLE()
+
+
+// Singleton
+static CTEFireBullets g_TEFireBullets( "Shotgun Shot" );
+
+
+void TE_FireBullets(
+ int iPlayerIndex,
+ const Vector &vOrigin,
+ const QAngle &vAngles,
+ int iWeaponID,
+ int iMode,
+ int iSeed,
+ float flSpread )
+{
+ CPASFilter filter( vOrigin );
+ filter.UsePredictionRules();
+
+ g_TEFireBullets.m_iPlayer = iPlayerIndex-1;
+ g_TEFireBullets.m_vecOrigin = vOrigin;
+ g_TEFireBullets.m_vecAngles = vAngles;
+ g_TEFireBullets.m_iSeed = iSeed;
+ g_TEFireBullets.m_flSpread = flSpread;
+ g_TEFireBullets.m_iMode = iMode;
+ g_TEFireBullets.m_iWeaponID = iWeaponID;
+
+ Assert( iSeed < (1 << NUM_BULLET_SEED_BITS) );
+
+ g_TEFireBullets.Create( filter, 0 );
+}
diff --git a/sp/src/game/server/sdk/te_firebullets.h b/sp/src/game/server/sdk/te_firebullets.h
new file mode 100644
index 00000000..2124aa4a
--- /dev/null
+++ b/sp/src/game/server/sdk/te_firebullets.h
@@ -0,0 +1,24 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+//=============================================================================//
+
+#ifndef TE_FIREBULLETS_H
+#define TE_FIREBULLETS_H
+#ifdef _WIN32
+#pragma once
+#endif
+
+
+void TE_FireBullets(
+ int iPlayerIndex,
+ const Vector &vOrigin,
+ const QAngle &vAngles,
+ int iWeaponID,
+ int iMode,
+ int iSeed,
+ float flSpread
+ );
+
+#endif // TE_FIREBULLETS_H