diff options
| author | FluorescentCIAAfricanAmerican <[email protected]> | 2020-04-22 12:56:21 -0400 |
|---|---|---|
| committer | FluorescentCIAAfricanAmerican <[email protected]> | 2020-04-22 12:56:21 -0400 |
| commit | 3bf9df6b2785fa6d951086978a3e66f49427166a (patch) | |
| tree | 2c0f1f0c63c4832882bc93814ebd2c2b1c6224e5 /game/server/sdk | |
| download | archived-source-engine-2018-hl2-src-master.tar.xz archived-source-engine-2018-hl2-src-master.zip | |
Diffstat (limited to 'game/server/sdk')
| -rw-r--r-- | game/server/sdk/sdk_bot_temp.cpp | 472 | ||||
| -rw-r--r-- | game/server/sdk/sdk_bot_temp.h | 21 | ||||
| -rw-r--r-- | game/server/sdk/sdk_brushentity.cpp | 79 | ||||
| -rw-r--r-- | game/server/sdk/sdk_client.cpp | 164 | ||||
| -rw-r--r-- | game/server/sdk/sdk_env_message.cpp | 46 | ||||
| -rw-r--r-- | game/server/sdk/sdk_env_sparkler.cpp | 104 | ||||
| -rw-r--r-- | game/server/sdk/sdk_eventlog.cpp | 55 | ||||
| -rw-r--r-- | game/server/sdk/sdk_gameinterface.cpp | 29 | ||||
| -rw-r--r-- | game/server/sdk/sdk_logicalentity.cpp | 66 | ||||
| -rw-r--r-- | game/server/sdk/sdk_modelentity.cpp | 128 | ||||
| -rw-r--r-- | game/server/sdk/sdk_player.cpp | 366 | ||||
| -rw-r--r-- | game/server/sdk/sdk_player.h | 101 | ||||
| -rw-r--r-- | game/server/sdk/sdk_playermove.cpp | 89 | ||||
| -rw-r--r-- | game/server/sdk/sdk_team.cpp | 40 | ||||
| -rw-r--r-- | game/server/sdk/sdk_team.h | 38 | ||||
| -rw-r--r-- | game/server/sdk/sdk_vehicle_jeep.cpp | 1584 | ||||
| -rw-r--r-- | game/server/sdk/te_firebullets.cpp | 98 | ||||
| -rw-r--r-- | game/server/sdk/te_firebullets.h | 24 |
18 files changed, 3504 insertions, 0 deletions
diff --git a/game/server/sdk/sdk_bot_temp.cpp b/game/server/sdk/sdk_bot_temp.cpp new file mode 100644 index 0000000..cfc5764 --- /dev/null +++ b/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/game/server/sdk/sdk_bot_temp.h b/game/server/sdk/sdk_bot_temp.h new file mode 100644 index 0000000..2f3130a --- /dev/null +++ b/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/game/server/sdk/sdk_brushentity.cpp b/game/server/sdk/sdk_brushentity.cpp new file mode 100644 index 0000000..1e90c99 --- /dev/null +++ b/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/game/server/sdk/sdk_client.cpp b/game/server/sdk/sdk_client.cpp new file mode 100644 index 0000000..7b4e698 --- /dev/null +++ b/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/game/server/sdk/sdk_env_message.cpp b/game/server/sdk/sdk_env_message.cpp new file mode 100644 index 0000000..b6be3a3 --- /dev/null +++ b/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/game/server/sdk/sdk_env_sparkler.cpp b/game/server/sdk/sdk_env_sparkler.cpp new file mode 100644 index 0000000..06b1950 --- /dev/null +++ b/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/game/server/sdk/sdk_eventlog.cpp b/game/server/sdk/sdk_eventlog.cpp new file mode 100644 index 0000000..f5ce85f --- /dev/null +++ b/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/game/server/sdk/sdk_gameinterface.cpp b/game/server/sdk/sdk_gameinterface.cpp new file mode 100644 index 0000000..90ede62 --- /dev/null +++ b/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/game/server/sdk/sdk_logicalentity.cpp b/game/server/sdk/sdk_logicalentity.cpp new file mode 100644 index 0000000..4f55393 --- /dev/null +++ b/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/game/server/sdk/sdk_modelentity.cpp b/game/server/sdk/sdk_modelentity.cpp new file mode 100644 index 0000000..aad6aea --- /dev/null +++ b/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/game/server/sdk/sdk_player.cpp b/game/server/sdk/sdk_player.cpp new file mode 100644 index 0000000..b28a7eb --- /dev/null +++ b/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/game/server/sdk/sdk_player.h b/game/server/sdk/sdk_player.h new file mode 100644 index 0000000..cb93a03 --- /dev/null +++ b/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/game/server/sdk/sdk_playermove.cpp b/game/server/sdk/sdk_playermove.cpp new file mode 100644 index 0000000..c28733b --- /dev/null +++ b/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/game/server/sdk/sdk_team.cpp b/game/server/sdk/sdk_team.cpp new file mode 100644 index 0000000..5fed11a --- /dev/null +++ b/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/game/server/sdk/sdk_team.h b/game/server/sdk/sdk_team.h new file mode 100644 index 0000000..50f4c12 --- /dev/null +++ b/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/game/server/sdk/sdk_vehicle_jeep.cpp b/game/server/sdk/sdk_vehicle_jeep.cpp new file mode 100644 index 0000000..e1617cf --- /dev/null +++ b/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/game/server/sdk/te_firebullets.cpp b/game/server/sdk/te_firebullets.cpp new file mode 100644 index 0000000..274c05f --- /dev/null +++ b/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/game/server/sdk/te_firebullets.h b/game/server/sdk/te_firebullets.h new file mode 100644 index 0000000..907dfc1 --- /dev/null +++ b/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 |