diff options
Diffstat (limited to 'game/shared/hl1')
28 files changed, 8742 insertions, 0 deletions
diff --git a/game/shared/hl1/hl1_basecombatweapon_shared.cpp b/game/shared/hl1/hl1_basecombatweapon_shared.cpp new file mode 100644 index 0000000..e51b434 --- /dev/null +++ b/game/shared/hl1/hl1_basecombatweapon_shared.cpp @@ -0,0 +1,230 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=============================================================================// + +#include "cbase.h" +#include "hl1_basecombatweapon_shared.h" + +#include "hl1_player_shared.h" + +LINK_ENTITY_TO_CLASS( basehl1combatweapon, CBaseHL1CombatWeapon ); + +IMPLEMENT_NETWORKCLASS_ALIASED( BaseHL1CombatWeapon , DT_BaseHL1CombatWeapon ) + +BEGIN_NETWORK_TABLE( CBaseHL1CombatWeapon , DT_BaseHL1CombatWeapon ) +END_NETWORK_TABLE() + +BEGIN_PREDICTION_DATA( CBaseHL1CombatWeapon ) +END_PREDICTION_DATA() + + +void CBaseHL1CombatWeapon::Spawn( void ) +{ + Precache(); + + SetSolid( SOLID_BBOX ); + m_flNextEmptySoundTime = 0.0f; + + // Weapons won't show up in trace calls if they are being carried... + RemoveEFlags( EFL_USE_PARTITION_WHEN_NOT_SOLID ); + + m_iState = WEAPON_NOT_CARRIED; + // Assume + m_nViewModelIndex = 0; + + // If I use clips, set my clips to the default + if ( UsesClipsForAmmo1() ) + { + m_iClip1 = GetDefaultClip1(); + } + else + { + SetPrimaryAmmoCount( GetDefaultClip1() ); + m_iClip1 = WEAPON_NOCLIP; + } + if ( UsesClipsForAmmo2() ) + { + m_iClip2 = GetDefaultClip2(); + } + else + { + SetSecondaryAmmoCount( GetDefaultClip2() ); + m_iClip2 = WEAPON_NOCLIP; + } + + SetModel( GetWorldModel() ); + +#if !defined( CLIENT_DLL ) + FallInit(); + SetCollisionGroup( COLLISION_GROUP_WEAPON ); + + m_takedamage = DAMAGE_EVENTS_ONLY; + + SetBlocksLOS( false ); + + // Default to non-removeable, because we don't want the + // game_weapon_manager entity to remove weapons that have + // been hand-placed by level designers. We only want to remove + // weapons that have been dropped by NPC's. + SetRemoveable( false ); +#endif + + //Make weapons easier to pick up in MP. + if ( g_pGameRules->IsMultiplayer() ) + { + CollisionProp()->UseTriggerBounds( true, 36 ); + } + else + { + CollisionProp()->UseTriggerBounds( true, 24 ); + } + + // Use more efficient bbox culling on the client. Otherwise, it'll setup bones for most + // characters even when they're not in the frustum. + AddEffects( EF_BONEMERGE_FASTCULL ); +} + +#if defined( CLIENT_DLL ) + +#define HL1_BOB_CYCLE_MIN 1.0f +#define HL1_BOB_CYCLE_MAX 0.45f +#define HL1_BOB 0.002f +#define HL1_BOB_UP 0.5f + +float g_lateralBob; +float g_verticalBob; + +static ConVar cl_bobcycle( "cl_bobcycle","0.8" ); +static ConVar cl_bob( "cl_bob","0.002" ); +static ConVar cl_bobup( "cl_bobup","0.5" ); + +// Register these cvars if needed for easy tweaking +static ConVar v_iyaw_cycle( "v_iyaw_cycle", "2"/*, FCVAR_UNREGISTERED*/ ); +static ConVar v_iroll_cycle( "v_iroll_cycle", "0.5"/*, FCVAR_UNREGISTERED*/ ); +static ConVar v_ipitch_cycle( "v_ipitch_cycle", "1"/*, FCVAR_UNREGISTERED*/ ); +static ConVar v_iyaw_level( "v_iyaw_level", "0.3"/*, FCVAR_UNREGISTERED*/ ); +static ConVar v_iroll_level( "v_iroll_level", "0.1"/*, FCVAR_UNREGISTERED*/ ); +static ConVar v_ipitch_level( "v_ipitch_level", "0.3"/*, FCVAR_UNREGISTERED*/ ); + +//----------------------------------------------------------------------------- +// Purpose: +// Output : float +//----------------------------------------------------------------------------- +float CBaseHL1CombatWeapon::CalcViewmodelBob( void ) +{ + static float bobtime; + static float lastbobtime; + float cycle; + + CBasePlayer *player = ToBasePlayer( GetOwner() ); + //Assert( player ); + + //NOTENOTE: For now, let this cycle continue when in the air, because it snaps badly without it + + if ( ( !gpGlobals->frametime ) || ( player == NULL ) ) + { + //NOTENOTE: We don't use this return value in our case (need to restructure the calculation function setup!) + return 0.0f;// just use old value + } + + //Find the speed of the player + float speed = player->GetLocalVelocity().Length2D(); + + //FIXME: This maximum speed value must come from the server. + // MaxSpeed() is not sufficient for dealing with sprinting - jdw + + speed = clamp( speed, -320, 320 ); + + float bob_offset = RemapVal( speed, 0, 320, 0.0f, 1.0f ); + + bobtime += ( gpGlobals->curtime - lastbobtime ) * bob_offset; + lastbobtime = gpGlobals->curtime; + + //Calculate the vertical bob + cycle = bobtime - (int)(bobtime/HL1_BOB_CYCLE_MAX)*HL1_BOB_CYCLE_MAX; + cycle /= HL1_BOB_CYCLE_MAX; + + if ( cycle < HL1_BOB_UP ) + { + cycle = M_PI * cycle / HL1_BOB_UP; + } + else + { + cycle = M_PI + M_PI*(cycle-HL1_BOB_UP)/(1.0 - HL1_BOB_UP); + } + + g_verticalBob = speed*0.005f; + g_verticalBob = g_verticalBob*0.3 + g_verticalBob*0.7*sin(cycle); + + g_verticalBob = clamp( g_verticalBob, -7.0f, 4.0f ); + + //Calculate the lateral bob + cycle = bobtime - (int)(bobtime/HL1_BOB_CYCLE_MAX*2)*HL1_BOB_CYCLE_MAX*2; + cycle /= HL1_BOB_CYCLE_MAX*2; + + if ( cycle < HL1_BOB_UP ) + { + cycle = M_PI * cycle / HL1_BOB_UP; + } + else + { + cycle = M_PI + M_PI*(cycle-HL1_BOB_UP)/(1.0 - HL1_BOB_UP); + } + + g_lateralBob = speed*0.005f; + g_lateralBob = g_lateralBob*0.3 + g_lateralBob*0.7*sin(cycle); + g_lateralBob = clamp( g_lateralBob, -7.0f, 4.0f ); + + //NOTENOTE: We don't use this return value in our case (need to restructure the calculation function setup!) + return 0.0f; +} + +//----------------------------------------------------------------------------- +// Purpose: +// Input : &origin - +// &angles - +// viewmodelindex - +//----------------------------------------------------------------------------- +void CBaseHL1CombatWeapon::AddViewmodelBob( CBaseViewModel *viewmodel, Vector &origin, QAngle &angles ) +{ + Vector forward, right; + AngleVectors( angles, &forward, &right, NULL ); + + CalcViewmodelBob(); + + // Apply bob, but scaled down to 40% + VectorMA( origin, g_verticalBob * 0.1f, forward, origin ); + + // Z bob a bit more + origin[2] += g_verticalBob * 0.1f; + + // bob the angles + angles[ ROLL ] += g_verticalBob * 0.5f; + angles[ PITCH ] -= g_verticalBob * 0.4f; + + angles[ YAW ] -= g_lateralBob * 0.3f; + + VectorMA( origin, g_lateralBob * 0.8f, right, origin ); +} + + +#else + +Vector CBaseHL1CombatWeapon::GetSoundEmissionOrigin() const +{ + if ( gpGlobals->maxClients == 1 || !GetOwner() ) + return CBaseCombatWeapon::GetSoundEmissionOrigin(); + +// Vector vecOwner = GetOwner()->GetSoundEmissionOrigin(); +// Vector vecThis = WorldSpaceCenter(); +// DevMsg("SoundEmissionOrigin: Owner: %4.1f,%4.1f,%4.1f Default:%4.1f,%4.1f,%4.1f\n", +// vecOwner.x, vecOwner.y, vecOwner.z, +// vecThis.x, vecThis.y, vecThis.z ); + + // TEMP fix for HL1MP... sounds are sometimes beeing emitted underneath the ground + return GetOwner()->GetSoundEmissionOrigin(); +} + +#endif
\ No newline at end of file diff --git a/game/shared/hl1/hl1_basecombatweapon_shared.h b/game/shared/hl1/hl1_basecombatweapon_shared.h new file mode 100644 index 0000000..48d209d --- /dev/null +++ b/game/shared/hl1/hl1_basecombatweapon_shared.h @@ -0,0 +1,50 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=============================================================================// + +#include "basecombatweapon_shared.h" + +#ifndef BASEHLCOMBATWEAPON_SHARED_H +#define BASEHLCOMBATWEAPON_SHARED_H +#ifdef _WIN32 +#pragma once +#endif + +#if defined( CLIENT_DLL ) +#define CBaseHL1CombatWeapon C_BaseHL1CombatWeapon +#endif + +class CBaseHL1CombatWeapon : public CBaseCombatWeapon +{ + DECLARE_CLASS( CBaseHL1CombatWeapon, CBaseCombatWeapon ); +public: + DECLARE_NETWORKCLASS(); + DECLARE_PREDICTABLE(); + +public: + void Spawn( void ); + +public: +// Server Only Methods +#if !defined( CLIENT_DLL ) + DECLARE_DATADESC(); + + virtual void Precache(); + + void FallInit( void ); // prepare to fall to the ground + virtual void FallThink( void ); // make the weapon fall to the ground after spawning + + void EjectShell( CBaseEntity *pPlayer, int iType ); + + Vector GetSoundEmissionOrigin() const; +#else + + virtual void AddViewmodelBob( CBaseViewModel *viewmodel, Vector &origin, QAngle &angles ); + virtual float CalcViewmodelBob( void ); + +#endif +}; + +#endif // BASEHLCOMBATWEAPON_SHARED_H diff --git a/game/shared/hl1/hl1_gamemovement.cpp b/game/shared/hl1/hl1_gamemovement.cpp new file mode 100644 index 0000000..d968e36 --- /dev/null +++ b/game/shared/hl1/hl1_gamemovement.cpp @@ -0,0 +1,305 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +//========= Copyright � 1996-2001, Valve LLC, All rights reserved. ============ +// +// Purpose: +// +// $NoKeywords: $ +//============================================================================= +#include "cbase.h" +#include "gamemovement.h" +#include "in_buttons.h" +#include <stdarg.h> +#include "movevars_shared.h" +#include "engine/IEngineTrace.h" +#include "SoundEmitterSystem/isoundemittersystembase.h" +#include "decals.h" +#include "tier0/vprof.h" +#include "hl1_gamemovement.h" + + +// Expose our interface. +static CHL1GameMovement g_GameMovement; +IGameMovement *g_pGameMovement = ( IGameMovement * )&g_GameMovement; + +EXPOSE_SINGLE_INTERFACE_GLOBALVAR( CGameMovement, IGameMovement, INTERFACENAME_GAMEMOVEMENT, g_GameMovement ); + +#ifdef CLIENT_DLL +#include "hl1/c_hl1mp_player.h" +#else +#include "hl1mp_player.h" +#endif + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +bool CHL1GameMovement::CheckJumpButton( void ) +{ + m_pHL1Player = ToHL1Player( player ); + + Assert( m_pHL1Player ); + + if (m_pHL1Player->pl.deadflag) + { + mv->m_nOldButtons |= IN_JUMP ; // don't jump again until released + return false; + } + + // See if we are waterjumping. If so, decrement count and return. + if (m_pHL1Player->m_flWaterJumpTime) + { + m_pHL1Player->m_flWaterJumpTime -= gpGlobals->frametime; + if (m_pHL1Player->m_flWaterJumpTime < 0) + m_pHL1Player->m_flWaterJumpTime = 0; + + return false; + } + + // If we are in the water most of the way... + if ( m_pHL1Player->GetWaterLevel() >= 2 ) + { + // swimming, not jumping + SetGroundEntity( NULL ); + + if(m_pHL1Player->GetWaterType() == CONTENTS_WATER) // We move up a certain amount + mv->m_vecVelocity[2] = 100; + else if (m_pHL1Player->GetWaterType() == CONTENTS_SLIME) + mv->m_vecVelocity[2] = 80; + + // play swiming sound + if ( m_pHL1Player->m_flSwimSoundTime <= 0 ) + { + // Don't play sound again for 1 second + m_pHL1Player->m_flSwimSoundTime = 1000; + PlaySwimSound(); + } + + return false; + } + + // No more effect + if (m_pHL1Player->GetGroundEntity() == NULL) + { + mv->m_nOldButtons |= IN_JUMP; + return false; // in air, so no effect + } + + if ( mv->m_nOldButtons & IN_JUMP ) + return false; // don't pogo stick + + // In the air now. + SetGroundEntity( NULL ); + + m_pHL1Player->PlayStepSound( (Vector &)mv->GetAbsOrigin(), player->GetSurfaceData(), 1.0, true ); + + MoveHelper()->PlayerSetAnimation( PLAYER_JUMP ); + + float flGroundFactor = 1.0f; + if ( player->GetSurfaceData() ) + { + flGroundFactor = 1.0;//player->GetSurfaceData()->game.jumpFactor; + } + + // Acclerate upward + // If we are ducking... + float startz = mv->m_vecVelocity[2]; + if ( ( m_pHL1Player->m_Local.m_bDucking ) || ( m_pHL1Player->GetFlags() & FL_DUCKING ) ) + { + // d = 0.5 * g * t^2 - distance traveled with linear accel + // t = sqrt(2.0 * 45 / g) - how long to fall 45 units + // v = g * t - velocity at the end (just invert it to jump up that high) + // v = g * sqrt(2.0 * 45 / g ) + // v^2 = g * g * 2.0 * 45 / g + // v = sqrt( g * 2.0 * 45 ) + + // Adjust for super long jump module + // UNDONE -- note this should be based on forward angles, not current velocity. + if ( m_pHL1Player->m_bHasLongJump && + ( mv->m_nButtons & IN_DUCK ) && + ( m_pHL1Player->m_Local.m_flDucktime > 0 ) && + mv->m_vecVelocity.Length() > 50 ) + { + m_pHL1Player->m_Local.m_vecPunchAngle.Set( PITCH, -5 ); + + mv->m_vecVelocity = m_vecForward * PLAYER_LONGJUMP_SPEED * 1.6; + mv->m_vecVelocity.z = sqrt(2 * 800 * 56.0); + } + else + { + mv->m_vecVelocity[2] = flGroundFactor * sqrt(2 * 800 * 45.0); // 2 * gravity * height + } + } + else + { + mv->m_vecVelocity[2] += flGroundFactor * sqrt(2 * 800 * 45.0); // 2 * gravity * height + } + FinishGravity(); + + mv->m_outWishVel.z += mv->m_vecVelocity[2] - startz; + mv->m_outStepHeight += 0.1f; + + if ( gpGlobals->maxClients > 1 ) +#ifdef CLIENT_DLL + (dynamic_cast<C_HL1MP_Player*>(m_pHL1Player))->DoAnimationEvent( PLAYERANIMEVENT_JUMP ); +#else + (dynamic_cast<CHL1MP_Player*>(m_pHL1Player))->DoAnimationEvent( PLAYERANIMEVENT_JUMP ); +#endif + + // Flag that we jumped. + mv->m_nOldButtons |= IN_JUMP; // don't jump again until released + return true; +} + +//----------------------------------------------------------------------------- +// Purpose: See if duck button is pressed and do the appropriate things +//----------------------------------------------------------------------------- +void CHL1GameMovement::Duck( void ) +{ + int buttonsChanged = ( mv->m_nOldButtons ^ mv->m_nButtons ); // These buttons have changed this frame + int buttonsPressed = buttonsChanged & mv->m_nButtons; // The changed ones still down are "pressed" + int buttonsReleased = buttonsChanged & mv->m_nOldButtons; // The changed ones which were previously down are "released" + + // Check to see if we are in the air. + bool bInAir = ( player->GetGroundEntity() == NULL ); + bool bInDuck = ( player->GetFlags() & FL_DUCKING ) ? true : false; + + if ( mv->m_nButtons & IN_DUCK ) + { + mv->m_nOldButtons |= IN_DUCK; + } + else + { + mv->m_nOldButtons &= ~IN_DUCK; + } + + // Handle death. + if ( IsDead() ) + { + if ( bInDuck ) + { + // Unduck + FinishUnDuck(); + } + return; + } + + HandleDuckingSpeedCrop(); + + // If the player is holding down the duck button, the player is in duck transition, ducking, or duck-jumping. + if ( ( mv->m_nButtons & IN_DUCK ) || player->m_Local.m_bDucking || bInDuck ) + { + if ( ( mv->m_nButtons & IN_DUCK ) ) + { + // Have the duck button pressed, but the player currently isn't in the duck position. + if ( ( buttonsPressed & IN_DUCK ) && !bInDuck ) + { + // Use 1 second so super long jump will work + player->m_Local.m_flDucktime = GAMEMOVEMENT_DUCK_TIME; + player->m_Local.m_bDucking = true; + } + + // The player is in duck transition and not duck-jumping. + if ( player->m_Local.m_bDucking ) + { + float flDuckMilliseconds = MAX( 0.0f, GAMEMOVEMENT_DUCK_TIME - ( float )player->m_Local.m_flDucktime ); + float flDuckSeconds = flDuckMilliseconds / GAMEMOVEMENT_DUCK_TIME; + + // Finish in duck transition when transition time is over, in "duck", in air. + if ( ( flDuckSeconds > TIME_TO_DUCK ) || bInDuck || bInAir ) + { + FinishDuck(); + } + else + { + // Calc parametric time + float flDuckFraction = SimpleSpline( flDuckSeconds / TIME_TO_DUCK ); + SetDuckedEyeOffset( flDuckFraction ); + } + } + } + else + { + // Try to unduck unless automovement is not allowed + // NOTE: When not onground, you can always unduck + if ( player->m_Local.m_bAllowAutoMovement || bInAir ) + { + if ( ( buttonsReleased & IN_DUCK ) && bInDuck ) + { + // Use 1 second so super long jump will work + player->m_Local.m_flDucktime = GAMEMOVEMENT_DUCK_TIME; + } + + // Check to see if we are capable of unducking. + if ( CanUnduck() ) + { + // or unducking + if ( ( player->m_Local.m_bDucking || player->m_Local.m_bDucked ) ) + { + float flDuckMilliseconds = MAX( 0.0f, GAMEMOVEMENT_DUCK_TIME - (float)player->m_Local.m_flDucktime ); + float flDuckSeconds = flDuckMilliseconds / GAMEMOVEMENT_DUCK_TIME; + + // Finish ducking immediately if duck time is over or not on ground + if ( flDuckSeconds > TIME_TO_UNDUCK || ( bInAir ) ) + { + FinishUnDuck(); + } + else + { + // Calc parametric time + float flDuckFraction = SimpleSpline( 1.0f - ( flDuckSeconds / TIME_TO_UNDUCK ) ); + SetDuckedEyeOffset( flDuckFraction ); + player->m_Local.m_bDucking = true; + } + } + } + else + { + // Still under something where we can't unduck, so make sure we reset this timer so + // that we'll unduck once we exit the tunnel, etc. + player->m_Local.m_flDucktime = GAMEMOVEMENT_DUCK_TIME; + SetDuckedEyeOffset( 1.0f ); + } + } + } + } +} + +void CHL1GameMovement::HandleDuckingSpeedCrop() +{ + if ( !( m_iSpeedCropped & SPEED_CROPPED_DUCK ) ) + { + if ( player->GetFlags() & FL_DUCKING ) + { + float frac = 0.33333333f; + mv->m_flForwardMove *= frac; + mv->m_flSideMove *= frac; + mv->m_flUpMove *= frac; + m_iSpeedCropped |= SPEED_CROPPED_DUCK; + } + } +} + +void CHL1GameMovement::CheckParameters( void ) +{ + if ( mv->m_nButtons & IN_SPEED ) + { + mv->m_flClientMaxSpeed = 100; + } + else + { + mv->m_flClientMaxSpeed = mv->m_flMaxSpeed; + } + + CHL1_Player* pHL1Player = dynamic_cast<CHL1_Player*>(player); + if( pHL1Player && pHL1Player->IsPullingObject() ) + { + mv->m_flClientMaxSpeed = mv->m_flMaxSpeed * 0.5f; + } + + BaseClass::CheckParameters(); +} diff --git a/game/shared/hl1/hl1_gamemovement.h b/game/shared/hl1/hl1_gamemovement.h new file mode 100644 index 0000000..d685c54 --- /dev/null +++ b/game/shared/hl1/hl1_gamemovement.h @@ -0,0 +1,42 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=============================================================================// + +#ifndef C_HL1_GAMEMOVEMENT_H +#define C_HL1_GAMEMOVEMENT_H +#ifdef _WIN32 +#pragma once +#endif + +#ifdef CLIENT_DLL + #include "hl1/hl1_c_player.h" +#else + #include "hl1_player.h" +#endif + +#if defined( CLIENT_DLL ) + class CHL1_Player; + #define CHL1_Player C_HL1_Player +#endif + +#define PLAYER_LONGJUMP_SPEED 350 // how fast we longjump + +class CHL1GameMovement : public CGameMovement +{ +public: + DECLARE_CLASS( CHL1GameMovement, CGameMovement ); + + virtual bool CheckJumpButton( void ); + + // Duck + virtual void Duck( void ); + virtual void HandleDuckingSpeedCrop(); + virtual void CheckParameters( void ); + +protected: + CHL1_Player *m_pHL1Player; +}; + +#endif //C_HL1_GAMEMOVEMENT_H
\ No newline at end of file diff --git a/game/shared/hl1/hl1_gamerules.cpp b/game/shared/hl1/hl1_gamerules.cpp new file mode 100644 index 0000000..f9b9ecc --- /dev/null +++ b/game/shared/hl1/hl1_gamerules.cpp @@ -0,0 +1,741 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: The Half-Life 1 game rules, such as the relationship tables and ammo +// damage cvars. +// +// $NoKeywords: $ +//=============================================================================// + +#include "cbase.h" +#include "hl1_gamerules.h" +#include "ammodef.h" + + +#ifdef CLIENT_DLL + +#else + + #include "player.h" + #include "game.h" + #include "gamerules.h" + #include "teamplay_gamerules.h" + #include "hl1_player.h" + #include "voice_gamemgr.h" + #include "hl1mp_weapon_satchel.h" +#endif + + +REGISTER_GAMERULES_CLASS( CHalfLife1 ); + + +ConVar sk_plr_dmg_crowbar ( "sk_plr_dmg_crowbar", "0", FCVAR_REPLICATED ); + +ConVar sk_npc_dmg_9mm_bullet ( "sk_npc_dmg_9mm_bullet", "0", FCVAR_REPLICATED ); +ConVar sk_plr_dmg_9mm_bullet ( "sk_plr_dmg_9mm_bullet", "0", FCVAR_REPLICATED ); +ConVar sk_max_9mm_bullet ( "sk_max_9mm_bullet", "0", FCVAR_REPLICATED ); + +ConVar sk_npc_dmg_9mmAR_bullet ( "sk_npc_dmg_9mmAR_bullet", "0", FCVAR_REPLICATED ); + +ConVar sk_plr_dmg_357_bullet ( "sk_plr_dmg_357_bullet", "0", FCVAR_REPLICATED ); +ConVar sk_max_357_bullet ( "sk_max_357_bullet", "0", FCVAR_REPLICATED ); + +ConVar sk_plr_dmg_buckshot ( "sk_plr_dmg_buckshot", "0", FCVAR_REPLICATED ); +ConVar sk_max_buckshot ( "sk_max_buckshot", "0", FCVAR_REPLICATED ); + +ConVar sk_plr_dmg_mp5_grenade ( "sk_plr_dmg_mp5_grenade", "0", FCVAR_REPLICATED ); +ConVar sk_max_mp5_grenade ( "sk_max_mp5_grenade", "0", FCVAR_REPLICATED ); +ConVar sk_mp5_grenade_radius ( "sk_mp5_grenade_radius", "0", FCVAR_REPLICATED ); + +ConVar sk_plr_dmg_rpg ( "sk_plr_dmg_rpg", "0", FCVAR_REPLICATED ); +ConVar sk_max_rpg_rocket ( "sk_max_rpg_rocket", "0", FCVAR_REPLICATED ); + +ConVar sk_plr_dmg_xbow_bolt_plr ( "sk_plr_dmg_xbow_bolt_plr", "0", FCVAR_REPLICATED ); +ConVar sk_plr_dmg_xbow_bolt_npc ( "sk_plr_dmg_xbow_bolt_npc", "0", FCVAR_REPLICATED ); +ConVar sk_max_xbow_bolt ( "sk_max_xbow_bolt", "0", FCVAR_REPLICATED ); + +ConVar sk_plr_dmg_egon_narrow ( "sk_plr_dmg_egon_narrow", "0", FCVAR_REPLICATED ); +ConVar sk_plr_dmg_egon_wide ( "sk_plr_dmg_egon_wide", "0", FCVAR_REPLICATED ); +ConVar sk_max_uranium ( "sk_max_uranium", "0", FCVAR_REPLICATED ); + +ConVar sk_plr_dmg_gauss ( "sk_plr_dmg_gauss", "0", FCVAR_REPLICATED ); + +ConVar sk_plr_dmg_grenade ( "sk_plr_dmg_grenade", "0", FCVAR_REPLICATED ); +ConVar sk_max_grenade ( "sk_max_grenade", "0", FCVAR_REPLICATED ); + +ConVar sk_plr_dmg_hornet ( "sk_plr_dmg_hornet", "0", FCVAR_REPLICATED ); +ConVar sk_npc_dmg_hornet ( "sk_npc_dmg_hornet", "0", FCVAR_REPLICATED ); +ConVar sk_max_hornet ( "sk_max_hornet", "0", FCVAR_REPLICATED ); + +ConVar sk_max_snark ( "sk_max_snark", "0", FCVAR_REPLICATED ); + +ConVar sk_plr_dmg_tripmine ( "sk_plr_dmg_tripmine", "0", FCVAR_REPLICATED ); +ConVar sk_max_tripmine ( "sk_max_tripmine", "0", FCVAR_REPLICATED ); + +ConVar sk_plr_dmg_satchel ( "sk_plr_dmg_satchel", "0", FCVAR_REPLICATED ); +ConVar sk_max_satchel ( "sk_max_satchel", "0", FCVAR_REPLICATED ); + +ConVar sk_npc_dmg_12mm_bullet ( "sk_npc_dmg_12mm_bullet", "0", FCVAR_REPLICATED ); + +ConVar sk_mp_dmg_multiplier ( "sk_mp_dmg_multiplier", "2.0" ); + +// Damage Queries. + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +int CHalfLife1::Damage_GetShowOnHud( void ) +{ + int iDamage = (DMG_POISON | DMG_ACID | DMG_DISSOLVE/*DMG_FREEZE | DMG_SLOWFREEZE*/ | DMG_DROWN | DMG_BURN | DMG_SLOWBURN | DMG_NERVEGAS | DMG_RADIATION | DMG_SHOCK); + return iDamage; +} + +#ifndef CLIENT_DLL + + extern bool g_fGameOver; + + const char *CHalfLife1::GetGameDescription( void ) + { + if ( IsMultiplayer() ) + { + return "Half-Life 1: Deathmatch"; + } + else + { + return "Half-Life 1"; + } + } + + class CVoiceGameMgrHelper : public IVoiceGameMgrHelper + { + public: + virtual bool CanPlayerHearPlayer( CBasePlayer *pListener, CBasePlayer *pTalker, bool &bProximity ) + { + return true; + } + }; + CVoiceGameMgrHelper g_VoiceGameMgrHelper; + IVoiceGameMgrHelper *g_pVoiceGameMgrHelper = &g_VoiceGameMgrHelper; + + //----------------------------------------------------------------------------- + // Purpose: + // Input : + // Output : + //----------------------------------------------------------------------------- + CHalfLife1::CHalfLife1() + { + } + + //----------------------------------------------------------------------------- + // Purpose: called each time a player uses a "cmd" command + // Input : *pEdict - the player who issued the command + // Use engine.Cmd_Argv, engine.Cmd_Argv, and engine.Cmd_Argc to get + // pointers the character string command. + //----------------------------------------------------------------------------- + bool CHalfLife1::ClientCommand( CBaseEntity *pEdict, const CCommand &args ) + { + if( BaseClass::ClientCommand( pEdict, args ) ) + return true; + + CHL1_Player *pPlayer = (CHL1_Player *) pEdict; + + if ( pPlayer->ClientCommand( args ) ) + return true; + + return false; + } + + //----------------------------------------------------------------------------- + // Purpose: Player has just spawned. Equip them. + //----------------------------------------------------------------------------- + void CHalfLife1::PlayerSpawn( CBasePlayer *pPlayer ) + { + // pPlayer->EquipSuit(); + } + + + //----------------------------------------------------------------------------- + // Purpose: MULTIPLAYER BODY QUE HANDLING + //----------------------------------------------------------------------------- + class CCorpse : public CBaseAnimating + { + DECLARE_CLASS( CCorpse, CBaseAnimating ); + public: + + DECLARE_SERVERCLASS(); + + virtual int ObjectCaps( void ) { return FCAP_DONT_SAVE; } + + public: + CNetworkVar( int, m_nReferencePlayer ); + }; + + IMPLEMENT_SERVERCLASS_ST(CCorpse, DT_Corpse) + SendPropInt( SENDINFO(m_nReferencePlayer), 10, SPROP_UNSIGNED ) + END_SEND_TABLE() + + LINK_ENTITY_TO_CLASS( bodyque, CCorpse ); + + + CCorpse *g_pBodyQueueHead; + + void InitBodyQue(void) + { + CCorpse *pEntity = ( CCorpse * )CreateEntityByName( "bodyque" ); + pEntity->AddEFlags( EFL_KEEP_ON_RECREATE_ENTITIES ); + g_pBodyQueueHead = pEntity; + CCorpse *p = g_pBodyQueueHead; + + // Reserve 3 more slots for dead bodies + for ( int i = 0; i < 3; i++ ) + { + CCorpse *next = ( CCorpse * )CreateEntityByName( "bodyque" ); + next->AddEFlags( EFL_KEEP_ON_RECREATE_ENTITIES ); + p->SetOwnerEntity( next ); + p = next; + } + + p->SetOwnerEntity( g_pBodyQueueHead ); + } + + //----------------------------------------------------------------------------- + // Purpose: make a body que entry for the given ent so the ent can be respawned elsewhere + // GLOBALS ASSUMED SET: g_eoBodyQueueHead + //----------------------------------------------------------------------------- + void CopyToBodyQue( CBaseAnimating *pCorpse ) + { + if ( pCorpse->IsEffectActive( EF_NODRAW ) ) + return; + + CCorpse *pHead = g_pBodyQueueHead; + + pHead->CopyAnimationDataFrom( pCorpse ); + + pHead->SetMoveType( MOVETYPE_FLYGRAVITY ); + pHead->SetAbsVelocity( pCorpse->GetAbsVelocity() ); + pHead->ClearFlags(); + pHead->m_nReferencePlayer = ENTINDEX( pCorpse ); + + pHead->SetLocalAngles( pCorpse->GetAbsAngles() ); + UTIL_SetOrigin(pHead, pCorpse->GetAbsOrigin()); + + UTIL_SetSize(pHead, pCorpse->WorldAlignMins(), pCorpse->WorldAlignMaxs()); + g_pBodyQueueHead = (CCorpse *)pHead->GetOwnerEntity(); + } + + //------------------------------------------------------------------------------ + // Purpose : Initialize all default class relationships + // Input : + // Output : + //------------------------------------------------------------------------------ + void CHalfLife1::InitDefaultAIRelationships( void ) + { + int i, j; + + // Allocate memory for default relationships + CBaseCombatCharacter::AllocateDefaultRelationships(); + + // -------------------------------------------------------------- + // First initialize table so we can report missing relationships + // -------------------------------------------------------------- + for (i=0;i<NUM_AI_CLASSES;i++) + { + for (j=0;j<NUM_AI_CLASSES;j++) + { + // By default all relationships are neutral of priority zero + CBaseCombatCharacter::SetDefaultRelationship( (Class_T)i, (Class_T)j, D_NU, 0 ); + } + } + + + // ------------------------------------------------------------ + // > CLASS_NONE + // ------------------------------------------------------------ + CBaseCombatCharacter::SetDefaultRelationship( CLASS_NONE, CLASS_NONE, D_NU, 0 ); + CBaseCombatCharacter::SetDefaultRelationship( CLASS_NONE, CLASS_PLAYER, D_NU, 0 ); + CBaseCombatCharacter::SetDefaultRelationship( CLASS_NONE, CLASS_HUMAN_PASSIVE, D_NU, 0 ); + CBaseCombatCharacter::SetDefaultRelationship( CLASS_NONE, CLASS_PLAYER_ALLY, D_NU, 0 ); + CBaseCombatCharacter::SetDefaultRelationship( CLASS_NONE, CLASS_ALIEN_PREY, D_NU, 0 ); + CBaseCombatCharacter::SetDefaultRelationship( CLASS_NONE, CLASS_ALIEN_MILITARY, D_NU, 0 ); + CBaseCombatCharacter::SetDefaultRelationship( CLASS_NONE, CLASS_ALIEN_MONSTER, D_NU, 0 ); + CBaseCombatCharacter::SetDefaultRelationship( CLASS_NONE, CLASS_ALIEN_PREDATOR, D_NU, 0 ); + CBaseCombatCharacter::SetDefaultRelationship( CLASS_NONE, CLASS_HUMAN_MILITARY, D_NU, 0 ); + CBaseCombatCharacter::SetDefaultRelationship( CLASS_NONE, CLASS_MACHINE, D_NU, 0 ); + CBaseCombatCharacter::SetDefaultRelationship( CLASS_NONE, CLASS_ALIEN_BIOWEAPON, D_NU, 0 ); + CBaseCombatCharacter::SetDefaultRelationship( CLASS_NONE, CLASS_PLAYER_BIOWEAPON, D_NU, 0 ); + CBaseCombatCharacter::SetDefaultRelationship( CLASS_NONE, CLASS_INSECT, D_NU, 0 ); + + + // ------------------------------------------------------------ + // > CLASS_HUMAN_PASSIVE + // ------------------------------------------------------------ + CBaseCombatCharacter::SetDefaultRelationship( CLASS_HUMAN_PASSIVE, CLASS_NONE, D_NU, 0 ); + CBaseCombatCharacter::SetDefaultRelationship( CLASS_HUMAN_PASSIVE, CLASS_PLAYER, D_LI, 0 ); + CBaseCombatCharacter::SetDefaultRelationship( CLASS_HUMAN_PASSIVE, CLASS_HUMAN_PASSIVE, D_LI, 0 ); + CBaseCombatCharacter::SetDefaultRelationship( CLASS_HUMAN_PASSIVE, CLASS_PLAYER_ALLY, D_LI, 0 ); + CBaseCombatCharacter::SetDefaultRelationship( CLASS_HUMAN_PASSIVE, CLASS_ALIEN_PREY, D_FR, 0 ); + CBaseCombatCharacter::SetDefaultRelationship( CLASS_HUMAN_PASSIVE, CLASS_ALIEN_MILITARY, D_FR, 0 ); + CBaseCombatCharacter::SetDefaultRelationship( CLASS_HUMAN_PASSIVE, CLASS_ALIEN_MONSTER, D_HT, 0 ); + CBaseCombatCharacter::SetDefaultRelationship( CLASS_HUMAN_PASSIVE, CLASS_ALIEN_PREDATOR, D_FR, 0 ); + CBaseCombatCharacter::SetDefaultRelationship( CLASS_HUMAN_PASSIVE, CLASS_HUMAN_MILITARY, D_HT, 0 ); + CBaseCombatCharacter::SetDefaultRelationship( CLASS_HUMAN_PASSIVE, CLASS_MACHINE, D_NU, 0 ); + CBaseCombatCharacter::SetDefaultRelationship( CLASS_HUMAN_PASSIVE, CLASS_ALIEN_BIOWEAPON, D_NU, 0 ); + CBaseCombatCharacter::SetDefaultRelationship( CLASS_HUMAN_PASSIVE, CLASS_PLAYER_BIOWEAPON, D_NU, 0 ); + CBaseCombatCharacter::SetDefaultRelationship( CLASS_HUMAN_PASSIVE, CLASS_INSECT, D_NU, 0 ); + + + + // ------------------------------------------------------------ + // > CLASS_PLAYER + // ------------------------------------------------------------ + CBaseCombatCharacter::SetDefaultRelationship( CLASS_PLAYER, CLASS_NONE, D_NU, 0 ); + CBaseCombatCharacter::SetDefaultRelationship( CLASS_PLAYER, CLASS_PLAYER, D_LI, 0 ); + CBaseCombatCharacter::SetDefaultRelationship( CLASS_PLAYER, CLASS_HUMAN_PASSIVE, D_LI, 0 ); + CBaseCombatCharacter::SetDefaultRelationship( CLASS_PLAYER, CLASS_PLAYER_ALLY, D_LI, 0 ); + CBaseCombatCharacter::SetDefaultRelationship( CLASS_PLAYER, CLASS_ALIEN_PREY, D_HT, 0 ); + CBaseCombatCharacter::SetDefaultRelationship( CLASS_PLAYER, CLASS_ALIEN_MILITARY, D_HT, 0 ); + CBaseCombatCharacter::SetDefaultRelationship( CLASS_PLAYER, CLASS_ALIEN_MONSTER, D_HT, 0 ); + CBaseCombatCharacter::SetDefaultRelationship( CLASS_PLAYER, CLASS_ALIEN_PREDATOR, D_HT, 0 ); + CBaseCombatCharacter::SetDefaultRelationship( CLASS_PLAYER, CLASS_HUMAN_MILITARY, D_HT, 0 ); + CBaseCombatCharacter::SetDefaultRelationship( CLASS_PLAYER, CLASS_MACHINE, D_HT, 0 ); + CBaseCombatCharacter::SetDefaultRelationship( CLASS_PLAYER, CLASS_ALIEN_BIOWEAPON, D_HT, 0 ); + CBaseCombatCharacter::SetDefaultRelationship( CLASS_PLAYER, CLASS_PLAYER_BIOWEAPON, D_HT, 0 ); + CBaseCombatCharacter::SetDefaultRelationship( CLASS_PLAYER, CLASS_INSECT, D_NU, 0 ); + + // ------------------------------------------------------------ + // > CLASS_PLAYER_ALLY + // ------------------------------------------------------------ + CBaseCombatCharacter::SetDefaultRelationship( CLASS_PLAYER_ALLY, CLASS_NONE, D_NU, 0 ); + CBaseCombatCharacter::SetDefaultRelationship( CLASS_PLAYER_ALLY, CLASS_PLAYER, D_LI, 0 ); + CBaseCombatCharacter::SetDefaultRelationship( CLASS_PLAYER_ALLY, CLASS_HUMAN_PASSIVE, D_LI, 0 ); + CBaseCombatCharacter::SetDefaultRelationship( CLASS_PLAYER_ALLY, CLASS_PLAYER_ALLY, D_LI, 0 ); + CBaseCombatCharacter::SetDefaultRelationship( CLASS_PLAYER_ALLY, CLASS_ALIEN_PREY, D_HT, 0 ); + CBaseCombatCharacter::SetDefaultRelationship( CLASS_PLAYER_ALLY, CLASS_ALIEN_MILITARY, D_HT, 0 ); + CBaseCombatCharacter::SetDefaultRelationship( CLASS_PLAYER_ALLY, CLASS_ALIEN_MONSTER, D_HT, 0 ); + CBaseCombatCharacter::SetDefaultRelationship( CLASS_PLAYER_ALLY, CLASS_ALIEN_PREDATOR, D_HT, 0 ); + CBaseCombatCharacter::SetDefaultRelationship( CLASS_PLAYER_ALLY, CLASS_HUMAN_MILITARY, D_HT, 0 ); + CBaseCombatCharacter::SetDefaultRelationship( CLASS_PLAYER_ALLY, CLASS_MACHINE, D_HT, 0 ); + CBaseCombatCharacter::SetDefaultRelationship( CLASS_PLAYER_ALLY, CLASS_ALIEN_BIOWEAPON, D_NU, 0 ); + CBaseCombatCharacter::SetDefaultRelationship( CLASS_PLAYER_ALLY, CLASS_PLAYER_BIOWEAPON, D_NU, 0 ); + CBaseCombatCharacter::SetDefaultRelationship( CLASS_PLAYER_ALLY, CLASS_INSECT, D_NU, 0 ); + + // ------------------------------------------------------------ + // > CLASS_ALIEN_PREY + // ------------------------------------------------------------ + CBaseCombatCharacter::SetDefaultRelationship( CLASS_ALIEN_PREY, CLASS_NONE, D_NU, 0 ); + CBaseCombatCharacter::SetDefaultRelationship( CLASS_ALIEN_PREY, CLASS_PLAYER, D_HT, 0 ); + CBaseCombatCharacter::SetDefaultRelationship( CLASS_ALIEN_PREY, CLASS_PLAYER_ALLY, D_HT, 0 ); + CBaseCombatCharacter::SetDefaultRelationship( CLASS_ALIEN_PREY, CLASS_HUMAN_PASSIVE, D_HT, 0 ); + CBaseCombatCharacter::SetDefaultRelationship( CLASS_ALIEN_PREY, CLASS_ALIEN_PREY, D_NU, 0 ); + CBaseCombatCharacter::SetDefaultRelationship( CLASS_ALIEN_PREY, CLASS_ALIEN_MILITARY, D_NU, 0 ); + CBaseCombatCharacter::SetDefaultRelationship( CLASS_ALIEN_PREY, CLASS_ALIEN_MONSTER, D_NU, 0 ); + CBaseCombatCharacter::SetDefaultRelationship( CLASS_ALIEN_PREY, CLASS_ALIEN_PREDATOR, D_FR, 0 ); + CBaseCombatCharacter::SetDefaultRelationship( CLASS_ALIEN_PREY, CLASS_HUMAN_MILITARY, D_HT, 0 ); + CBaseCombatCharacter::SetDefaultRelationship( CLASS_ALIEN_PREY, CLASS_MACHINE, D_NU, 0 ); + CBaseCombatCharacter::SetDefaultRelationship( CLASS_ALIEN_PREY, CLASS_ALIEN_BIOWEAPON, D_NU, 0 ); + CBaseCombatCharacter::SetDefaultRelationship( CLASS_ALIEN_PREY, CLASS_PLAYER_BIOWEAPON, D_NU, 0 ); + CBaseCombatCharacter::SetDefaultRelationship( CLASS_ALIEN_PREY, CLASS_INSECT, D_NU, 0 ); + + // ------------------------------------------------------------ + // > CLASS_ALIEN_MILITARY + // ------------------------------------------------------------ + CBaseCombatCharacter::SetDefaultRelationship( CLASS_ALIEN_MILITARY, CLASS_NONE, D_NU, 0 ); + CBaseCombatCharacter::SetDefaultRelationship( CLASS_ALIEN_MILITARY, CLASS_PLAYER, D_HT, 0 ); + CBaseCombatCharacter::SetDefaultRelationship( CLASS_ALIEN_MILITARY, CLASS_PLAYER_ALLY, D_HT, 0 ); + CBaseCombatCharacter::SetDefaultRelationship( CLASS_ALIEN_MILITARY, CLASS_HUMAN_PASSIVE, D_HT, 0 ); + CBaseCombatCharacter::SetDefaultRelationship( CLASS_ALIEN_MILITARY, CLASS_ALIEN_PREY, D_NU, 0 ); + CBaseCombatCharacter::SetDefaultRelationship( CLASS_ALIEN_MILITARY, CLASS_ALIEN_MILITARY, D_NU, 0 ); + CBaseCombatCharacter::SetDefaultRelationship( CLASS_ALIEN_MILITARY, CLASS_ALIEN_MONSTER, D_NU, 0 ); + CBaseCombatCharacter::SetDefaultRelationship( CLASS_ALIEN_MILITARY, CLASS_ALIEN_PREDATOR, D_NU, 0 ); + CBaseCombatCharacter::SetDefaultRelationship( CLASS_ALIEN_MILITARY, CLASS_HUMAN_MILITARY, D_HT, 0 ); + CBaseCombatCharacter::SetDefaultRelationship( CLASS_ALIEN_MILITARY, CLASS_MACHINE, D_HT, 0 ); + CBaseCombatCharacter::SetDefaultRelationship( CLASS_ALIEN_MILITARY, CLASS_ALIEN_BIOWEAPON, D_NU, 0 ); + CBaseCombatCharacter::SetDefaultRelationship( CLASS_ALIEN_MILITARY, CLASS_PLAYER_BIOWEAPON, D_NU, 0 ); + CBaseCombatCharacter::SetDefaultRelationship( CLASS_ALIEN_MILITARY, CLASS_INSECT, D_NU, 0 ); + + // ------------------------------------------------------------ + // > CLASS_ALIEN_MONSTER + // ------------------------------------------------------------ + CBaseCombatCharacter::SetDefaultRelationship( CLASS_ALIEN_MONSTER, CLASS_NONE, D_NU, 0 ); + CBaseCombatCharacter::SetDefaultRelationship( CLASS_ALIEN_MONSTER, CLASS_PLAYER, D_HT, 0 ); + CBaseCombatCharacter::SetDefaultRelationship( CLASS_ALIEN_MONSTER, CLASS_PLAYER_ALLY, D_HT, 0 ); + CBaseCombatCharacter::SetDefaultRelationship( CLASS_ALIEN_MONSTER, CLASS_HUMAN_PASSIVE, D_HT, 0 ); + CBaseCombatCharacter::SetDefaultRelationship( CLASS_ALIEN_MONSTER, CLASS_ALIEN_PREY, D_NU, 0 ); + CBaseCombatCharacter::SetDefaultRelationship( CLASS_ALIEN_MONSTER, CLASS_ALIEN_MILITARY, D_NU, 0 ); + CBaseCombatCharacter::SetDefaultRelationship( CLASS_ALIEN_MONSTER, CLASS_ALIEN_MONSTER, D_NU, 0 ); + CBaseCombatCharacter::SetDefaultRelationship( CLASS_ALIEN_MONSTER, CLASS_ALIEN_PREDATOR, D_NU, 0 ); + CBaseCombatCharacter::SetDefaultRelationship( CLASS_ALIEN_MONSTER, CLASS_HUMAN_MILITARY, D_HT, 0 ); + CBaseCombatCharacter::SetDefaultRelationship( CLASS_ALIEN_MONSTER, CLASS_MACHINE, D_HT, 0 ); + CBaseCombatCharacter::SetDefaultRelationship( CLASS_ALIEN_MONSTER, CLASS_ALIEN_BIOWEAPON, D_NU, 0 ); + CBaseCombatCharacter::SetDefaultRelationship( CLASS_ALIEN_MONSTER, CLASS_PLAYER_BIOWEAPON, D_NU, 0 ); + CBaseCombatCharacter::SetDefaultRelationship( CLASS_ALIEN_MONSTER, CLASS_INSECT, D_NU, 0 ); + + // ------------------------------------------------------------ + // > CLASS_ALIEN_PREDATOR + // ------------------------------------------------------------ + CBaseCombatCharacter::SetDefaultRelationship( CLASS_ALIEN_PREDATOR, CLASS_NONE, D_NU, 0 ); + CBaseCombatCharacter::SetDefaultRelationship( CLASS_ALIEN_PREDATOR, CLASS_PLAYER, D_HT, 0 ); + CBaseCombatCharacter::SetDefaultRelationship( CLASS_ALIEN_PREDATOR, CLASS_PLAYER_ALLY, D_HT, 0 ); + CBaseCombatCharacter::SetDefaultRelationship( CLASS_ALIEN_PREDATOR, CLASS_HUMAN_PASSIVE, D_HT, 0 ); + CBaseCombatCharacter::SetDefaultRelationship( CLASS_ALIEN_PREDATOR, CLASS_ALIEN_PREY, D_HT, 0 ); + CBaseCombatCharacter::SetDefaultRelationship( CLASS_ALIEN_PREDATOR, CLASS_ALIEN_MILITARY, D_NU, 0 ); + CBaseCombatCharacter::SetDefaultRelationship( CLASS_ALIEN_PREDATOR, CLASS_ALIEN_MONSTER, D_NU, 0 ); + CBaseCombatCharacter::SetDefaultRelationship( CLASS_ALIEN_PREDATOR, CLASS_ALIEN_PREDATOR, D_NU, 0 ); + CBaseCombatCharacter::SetDefaultRelationship( CLASS_ALIEN_PREDATOR, CLASS_HUMAN_MILITARY, D_HT, 0 ); + CBaseCombatCharacter::SetDefaultRelationship( CLASS_ALIEN_PREDATOR, CLASS_MACHINE, D_NU, 0 ); + CBaseCombatCharacter::SetDefaultRelationship( CLASS_ALIEN_PREDATOR, CLASS_ALIEN_BIOWEAPON, D_NU, 0 ); + CBaseCombatCharacter::SetDefaultRelationship( CLASS_ALIEN_PREDATOR, CLASS_PLAYER_BIOWEAPON, D_NU, 0 ); + CBaseCombatCharacter::SetDefaultRelationship( CLASS_ALIEN_PREDATOR, CLASS_INSECT, D_NU, 0 ); + + // ------------------------------------------------------------ + // > CLASS_HUMAN_MILITARY + // ------------------------------------------------------------ + CBaseCombatCharacter::SetDefaultRelationship( CLASS_HUMAN_MILITARY, CLASS_NONE, D_NU, 0 ); + CBaseCombatCharacter::SetDefaultRelationship( CLASS_HUMAN_MILITARY, CLASS_PLAYER, D_HT, 0 ); + CBaseCombatCharacter::SetDefaultRelationship( CLASS_HUMAN_MILITARY, CLASS_PLAYER_ALLY, D_HT, 0 ); + CBaseCombatCharacter::SetDefaultRelationship( CLASS_HUMAN_MILITARY, CLASS_HUMAN_PASSIVE, D_HT, 0 ); + CBaseCombatCharacter::SetDefaultRelationship( CLASS_HUMAN_MILITARY, CLASS_ALIEN_PREY, D_HT, 0 ); + CBaseCombatCharacter::SetDefaultRelationship( CLASS_HUMAN_MILITARY, CLASS_ALIEN_MILITARY, D_HT, 0 ); + CBaseCombatCharacter::SetDefaultRelationship( CLASS_HUMAN_MILITARY, CLASS_ALIEN_MONSTER, D_HT, 0 ); + CBaseCombatCharacter::SetDefaultRelationship( CLASS_HUMAN_MILITARY, CLASS_ALIEN_PREDATOR, D_HT, 0 ); + CBaseCombatCharacter::SetDefaultRelationship( CLASS_HUMAN_MILITARY, CLASS_HUMAN_MILITARY, D_NU, 0 ); + CBaseCombatCharacter::SetDefaultRelationship( CLASS_HUMAN_MILITARY, CLASS_MACHINE, D_NU, 0 ); + CBaseCombatCharacter::SetDefaultRelationship( CLASS_HUMAN_MILITARY, CLASS_ALIEN_BIOWEAPON, D_NU, 0 ); + CBaseCombatCharacter::SetDefaultRelationship( CLASS_HUMAN_MILITARY, CLASS_PLAYER_BIOWEAPON, D_NU, 0 ); + CBaseCombatCharacter::SetDefaultRelationship( CLASS_HUMAN_MILITARY, CLASS_INSECT, D_NU, 0 ); + + // ------------------------------------------------------------ + // > CLASS_MACHINE + // ------------------------------------------------------------ + CBaseCombatCharacter::SetDefaultRelationship( CLASS_MACHINE, CLASS_NONE, D_NU, 0 ); + CBaseCombatCharacter::SetDefaultRelationship( CLASS_MACHINE, CLASS_MACHINE, D_NU, 0 ); + CBaseCombatCharacter::SetDefaultRelationship( CLASS_MACHINE, CLASS_PLAYER, D_HT, 0 ); + CBaseCombatCharacter::SetDefaultRelationship( CLASS_MACHINE, CLASS_HUMAN_PASSIVE, D_HT, 0 ); + CBaseCombatCharacter::SetDefaultRelationship( CLASS_MACHINE, CLASS_HUMAN_MILITARY, D_NU, 0 ); + CBaseCombatCharacter::SetDefaultRelationship( CLASS_MACHINE, CLASS_ALIEN_MILITARY, D_HT, 0 ); + CBaseCombatCharacter::SetDefaultRelationship( CLASS_MACHINE, CLASS_ALIEN_MONSTER, D_HT, 0 ); + CBaseCombatCharacter::SetDefaultRelationship( CLASS_MACHINE, CLASS_ALIEN_PREY, D_HT, 0 ); + CBaseCombatCharacter::SetDefaultRelationship( CLASS_MACHINE, CLASS_ALIEN_PREDATOR, D_HT, 0 ); + CBaseCombatCharacter::SetDefaultRelationship( CLASS_MACHINE, CLASS_PLAYER_ALLY, D_HT, 0 ); + CBaseCombatCharacter::SetDefaultRelationship( CLASS_MACHINE, CLASS_ALIEN_BIOWEAPON, D_HT, 0 ); + CBaseCombatCharacter::SetDefaultRelationship( CLASS_MACHINE, CLASS_PLAYER_BIOWEAPON, D_HT, 0 ); + CBaseCombatCharacter::SetDefaultRelationship( CLASS_MACHINE, CLASS_INSECT, D_NU, 0 ); + + // ------------------------------------------------------------ + // > CLASS_ALIEN_BIOWEAPON + // ------------------------------------------------------------ + CBaseCombatCharacter::SetDefaultRelationship( CLASS_ALIEN_BIOWEAPON, CLASS_NONE, D_NU, 0 ); + CBaseCombatCharacter::SetDefaultRelationship( CLASS_ALIEN_BIOWEAPON, CLASS_MACHINE, D_NU, 0 ); + CBaseCombatCharacter::SetDefaultRelationship( CLASS_ALIEN_BIOWEAPON, CLASS_PLAYER, D_HT, 0 ); + CBaseCombatCharacter::SetDefaultRelationship( CLASS_ALIEN_BIOWEAPON, CLASS_HUMAN_PASSIVE, D_HT, 0 ); + CBaseCombatCharacter::SetDefaultRelationship( CLASS_ALIEN_BIOWEAPON, CLASS_HUMAN_MILITARY, D_HT, 0 ); + CBaseCombatCharacter::SetDefaultRelationship( CLASS_ALIEN_BIOWEAPON, CLASS_ALIEN_MILITARY, D_LI, 0 ); + CBaseCombatCharacter::SetDefaultRelationship( CLASS_ALIEN_BIOWEAPON, CLASS_ALIEN_MONSTER, D_HT, 0 ); + CBaseCombatCharacter::SetDefaultRelationship( CLASS_ALIEN_BIOWEAPON, CLASS_ALIEN_PREY, D_HT, 0 ); + CBaseCombatCharacter::SetDefaultRelationship( CLASS_ALIEN_BIOWEAPON, CLASS_ALIEN_PREDATOR, D_NU, 0 ); + CBaseCombatCharacter::SetDefaultRelationship( CLASS_ALIEN_BIOWEAPON, CLASS_PLAYER_ALLY, D_HT, 0 ); + CBaseCombatCharacter::SetDefaultRelationship( CLASS_ALIEN_BIOWEAPON, CLASS_ALIEN_BIOWEAPON, D_NU, 0 ); + CBaseCombatCharacter::SetDefaultRelationship( CLASS_ALIEN_BIOWEAPON, CLASS_PLAYER_BIOWEAPON, D_HT, 0 ); + CBaseCombatCharacter::SetDefaultRelationship( CLASS_ALIEN_BIOWEAPON, CLASS_INSECT, D_NU, 0 ); + + // ------------------------------------------------------------ + // > CLASS_PLAYER_BIOWEAPON + // ------------------------------------------------------------ + CBaseCombatCharacter::SetDefaultRelationship( CLASS_PLAYER_BIOWEAPON, CLASS_NONE, D_NU, 0 ); + CBaseCombatCharacter::SetDefaultRelationship( CLASS_PLAYER_BIOWEAPON, CLASS_MACHINE, D_NU, 0 ); + CBaseCombatCharacter::SetDefaultRelationship( CLASS_PLAYER_BIOWEAPON, CLASS_PLAYER, D_HT, 0 ); + CBaseCombatCharacter::SetDefaultRelationship( CLASS_PLAYER_BIOWEAPON, CLASS_HUMAN_PASSIVE, D_HT, 0 ); + CBaseCombatCharacter::SetDefaultRelationship( CLASS_PLAYER_BIOWEAPON, CLASS_HUMAN_MILITARY, D_HT, 0 ); + CBaseCombatCharacter::SetDefaultRelationship( CLASS_PLAYER_BIOWEAPON, CLASS_ALIEN_MILITARY, D_HT, 0 ); + CBaseCombatCharacter::SetDefaultRelationship( CLASS_PLAYER_BIOWEAPON, CLASS_ALIEN_MONSTER, D_HT, 0 ); + CBaseCombatCharacter::SetDefaultRelationship( CLASS_PLAYER_BIOWEAPON, CLASS_ALIEN_PREY, D_HT, 0 ); + CBaseCombatCharacter::SetDefaultRelationship( CLASS_PLAYER_BIOWEAPON, CLASS_ALIEN_PREDATOR, D_HT, 0 ); + CBaseCombatCharacter::SetDefaultRelationship( CLASS_PLAYER_BIOWEAPON, CLASS_PLAYER_ALLY, D_HT, 0 ); + CBaseCombatCharacter::SetDefaultRelationship( CLASS_PLAYER_BIOWEAPON, CLASS_ALIEN_BIOWEAPON, D_HT, 0 ); + CBaseCombatCharacter::SetDefaultRelationship( CLASS_PLAYER_BIOWEAPON, CLASS_PLAYER_BIOWEAPON, D_NU, 0 ); + CBaseCombatCharacter::SetDefaultRelationship( CLASS_PLAYER_BIOWEAPON, CLASS_INSECT, D_NU, 0 ); + + + // ------------------------------------------------------------ + // > CLASS_INSECT + // ------------------------------------------------------------ + CBaseCombatCharacter::SetDefaultRelationship( CLASS_INSECT, CLASS_NONE, D_FR, 0 ); + CBaseCombatCharacter::SetDefaultRelationship( CLASS_INSECT, CLASS_MACHINE, D_FR, 0 ); + CBaseCombatCharacter::SetDefaultRelationship( CLASS_INSECT, CLASS_PLAYER, D_FR, 0 ); + CBaseCombatCharacter::SetDefaultRelationship( CLASS_INSECT, CLASS_HUMAN_PASSIVE, D_FR, 0 ); + CBaseCombatCharacter::SetDefaultRelationship( CLASS_INSECT, CLASS_HUMAN_MILITARY, D_FR, 0 ); + CBaseCombatCharacter::SetDefaultRelationship( CLASS_INSECT, CLASS_ALIEN_MILITARY, D_NU, 0 ); + CBaseCombatCharacter::SetDefaultRelationship( CLASS_INSECT, CLASS_ALIEN_MONSTER, D_FR, 0 ); + CBaseCombatCharacter::SetDefaultRelationship( CLASS_INSECT, CLASS_ALIEN_PREY, D_FR, 0 ); + CBaseCombatCharacter::SetDefaultRelationship( CLASS_INSECT, CLASS_ALIEN_PREDATOR, D_FR, 0 ); + CBaseCombatCharacter::SetDefaultRelationship( CLASS_INSECT, CLASS_PLAYER_ALLY, D_FR, 0 ); + CBaseCombatCharacter::SetDefaultRelationship( CLASS_INSECT, CLASS_ALIEN_BIOWEAPON, D_NU, 0 ); + CBaseCombatCharacter::SetDefaultRelationship( CLASS_INSECT, CLASS_PLAYER_BIOWEAPON, D_NU, 0 ); + CBaseCombatCharacter::SetDefaultRelationship( CLASS_INSECT, CLASS_INSECT, D_NU, 0 ); + } + + //------------------------------------------------------------------------------ + // Purpose : Return classify text for classify type + // Input : + // Output : + //------------------------------------------------------------------------------ + const char* CHalfLife1::AIClassText(int classType) + { + switch (classType) + { + case CLASS_NONE: return "CLASS_NONE"; + case CLASS_HUMAN_PASSIVE: return "CLASS_HUMAN_PASSIVE"; + case CLASS_PLAYER_ALLY: return "CLASS_PLAYER_ALLY"; + case CLASS_PLAYER: return "CLASS_PLAYER"; + case CLASS_ALIEN_PREY: return "CLASS_ALIEN_PREY"; + case CLASS_ALIEN_MILITARY: return "CLASS_ALIEN_MILITARY"; + case CLASS_ALIEN_MONSTER: return "CLASS_ALIEN_MONSTER"; + case CLASS_ALIEN_PREDATOR: return "CLASS_ALIEN_PREDATOR"; + case CLASS_HUMAN_MILITARY: return "CLASS_HUMAN_MILITARY"; + case CLASS_MACHINE: return "CLASS_MACHINE"; + case CLASS_ALIEN_BIOWEAPON: return "CLASS_ALIEN_BIOWEAPON"; + case CLASS_PLAYER_BIOWEAPON: return "CLASS_PLAYER_BIOWEAPON"; + + default: return "MISSING CLASS in ClassifyText()"; + } + } + + + void CHalfLife1::PlayerThink( CBasePlayer *pPlayer ) + { + } + + + bool CHalfLife1::CanHavePlayerItem( CBasePlayer *pPlayer, CBaseCombatWeapon *pWeapon ) + { + if ( FClassnameIs( pWeapon, "weapon_satchel" ) ) + { + CWeaponSatchel *satchel = static_cast< CWeaponSatchel * >( pPlayer->Weapon_OwnsThisType( "weapon_satchel" ) ); + if ( satchel ) + { + if ( satchel->HasChargeDeployed() ) + { + return false; + } + } + } + + return true; + } + + + float CHalfLife1::FlPlayerFallDamage( CBasePlayer *pPlayer ) + { + CBaseEntity *pGroundEntity = pPlayer->GetGroundEntity(); + + if( pGroundEntity && pGroundEntity->ClassMatches( "func_breakable" ) ) + { + // FIXME touchtrace will be wrong. + pGroundEntity->Touch( pPlayer ); + + if( pGroundEntity->m_iHealth <= 0 ) + { + // The breakable broke when we hit it, don't take falling damage + return 0; + } + } + + return BaseClass::FlPlayerFallDamage( pPlayer ); + } + + + class CTraceFilterHitAllExcept : public CTraceFilter + { + public: + // It does have a base, but we'll never network anything below here.. + DECLARE_CLASS_NOBASE( CTraceFilterHitAllExcept ); + + CTraceFilterHitAllExcept( const IHandleEntity *passedict ) + { + m_pPassEnt = passedict; + } + + bool ShouldHitEntity( IHandleEntity *pServerEntity, int contentsMask ) + { + if ( m_pPassEnt && ( m_pPassEnt == pServerEntity ) ) + { + return false; + } + + return true; + } + + private: + const IHandleEntity *m_pPassEnt; + }; + + void CHalfLife1::RadiusDamage( const CTakeDamageInfo &info, const Vector &vecSrcIn, float flRadius, int iClassIgnore ) + { + CBaseEntity *pEntity = NULL; + trace_t tr; + float flAdjustedDamage, falloff; + Vector vecSpot; + + Vector vecSrc = vecSrcIn; + + if ( flRadius ) + falloff = info.GetDamage() / flRadius; + else + falloff = 1.0; + + int bInWater = (UTIL_PointContents ( vecSrc ) & MASK_WATER) ? true : false; + + vecSrc.z += 1;// in case grenade is lying on the ground + + // iterate on all entities in the vicinity. + for ( CEntitySphereQuery sphere( vecSrc, flRadius ); ( pEntity = sphere.GetCurrentEntity() ) != NULL; sphere.NextEntity() ) + { + if ( pEntity->m_takedamage != DAMAGE_NO ) + { + // UNDONE: this should check a damage mask, not an ignore + if ( iClassIgnore != CLASS_NONE && pEntity->Classify() == iClassIgnore ) + {// houndeyes don't hurt other houndeyes with their attack + continue; + } + + // blast's don't tavel into or out of water + if (bInWater && pEntity->GetWaterLevel() == 0) + continue; + if (!bInWater && pEntity->GetWaterLevel() == 3) + continue; + + // radius damage can only be blocked by the world + vecSpot = pEntity->BodyTarget( vecSrc ); + + CTraceFilterHitAllExcept traceFilter( info.GetInflictor() ); + UTIL_TraceLine( vecSrc, vecSpot, CONTENTS_SOLID, &traceFilter, &tr ); + + if ( tr.fraction == 1.0 || tr.m_pEnt == pEntity ) + {// the explosion can 'see' this entity, so hurt them! + if (tr.startsolid) + { + // if we're stuck inside them, fixup the position and distance + tr.endpos = vecSrc; + tr.fraction = 0.0; + } + + // decrease damage for an ent that's farther from the bomb. + flAdjustedDamage = ( vecSrc - tr.endpos ).Length() * falloff; + flAdjustedDamage = info.GetDamage() - flAdjustedDamage; + + if ( flAdjustedDamage > 0 ) + { + CTakeDamageInfo adjustedInfo = info; + adjustedInfo.SetDamage( flAdjustedDamage ); + + Vector vecDir = vecSpot - vecSrc; + VectorNormalize( vecDir ); + + // If we don't have a damage force, manufacture one + if ( adjustedInfo.GetDamagePosition() == vec3_origin || adjustedInfo.GetDamageForce() == vec3_origin ) + { + CalculateExplosiveDamageForce( &adjustedInfo, vecDir, vecSrc ); + } + else + { + // Assume the force passed in is the maximum force. Decay it based on falloff. + float flForce = adjustedInfo.GetDamageForce().Length() * falloff; + adjustedInfo.SetDamageForce( vecDir * flForce ); + adjustedInfo.SetDamagePosition( vecSrc ); + } + + if (tr.fraction != 1.0) + { + ClearMultiDamage( ); + Vector dir = tr.endpos - vecSrc; + VectorNormalize( dir ); + pEntity->DispatchTraceAttack( adjustedInfo, dir, &tr ); + ApplyMultiDamage(); + } + else + { + pEntity->TakeDamage( adjustedInfo ); + } + // Now hit all triggers along the way that respond to damage... + Vector dir = tr.endpos - vecSrc; + pEntity->TraceAttackToTriggers( adjustedInfo, vecSrc, tr.endpos, dir ); + } + } + } + } + } +#endif + + + +// ------------------------------------------------------------------------------------- // +// CHalfLife1 shared implementation. +// ------------------------------------------------------------------------------------- // + +bool CHalfLife1::ShouldCollide( int collisionGroup0, int collisionGroup1 ) +{ + // HL2 treats movement and tracing against players the same, so just remap here + if ( collisionGroup0 == COLLISION_GROUP_PLAYER_MOVEMENT ) + { + collisionGroup0 = COLLISION_GROUP_PLAYER; + } + + if( collisionGroup1 == COLLISION_GROUP_PLAYER_MOVEMENT ) + { + collisionGroup1 = COLLISION_GROUP_PLAYER; + } + + if ( collisionGroup0 > collisionGroup1 ) + { + // swap so that lowest is always first + int tmp = collisionGroup0; + collisionGroup0 = collisionGroup1; + collisionGroup1 = tmp; + } + + return BaseClass::ShouldCollide( collisionGroup0, collisionGroup1 ); +} + +// ------------------------------------------------------------------------------------- // +// Global functions. +// ------------------------------------------------------------------------------------- // + +// shared ammo definition +// JAY: Trying to make a more physical bullet response +#define BULLET_MASS_GRAINS_TO_LB(grains) (0.002285*(grains)/16.0f) +#define BULLET_MASS_GRAINS_TO_KG(grains) lbs2kg(BULLET_MASS_GRAINS_TO_LB(grains)) + +// exaggerate all of the forces, but use real numbers to keep them consistent +#define BULLET_IMPULSE_EXAGGERATION 3 + +// convert a velocity in ft/sec and a mass in grains to an impulse in kg in/s +#define BULLET_IMPULSE(grains, ftpersec) ((ftpersec)*12*BULLET_MASS_GRAINS_TO_KG(grains)*BULLET_IMPULSE_EXAGGERATION) + +CAmmoDef *GetAmmoDef() +{ + static CAmmoDef def; + static bool bInitted = false; + + if ( !bInitted ) + { + bInitted = true; + + def.AddAmmoType( "9mmRound", DMG_BULLET | DMG_NEVERGIB, TRACER_LINE, "sk_plr_dmg_9mm_bullet", "sk_npc_dmg_9mm_bullet","sk_max_9mm_bullet", BULLET_IMPULSE(500, 1325), 0 ); + def.AddAmmoType( "357Round", DMG_BULLET | DMG_NEVERGIB, TRACER_NONE, "sk_plr_dmg_357_bullet", NULL, "sk_max_357_bullet", BULLET_IMPULSE(650, 6000), 0 ); + def.AddAmmoType( "Buckshot", DMG_BULLET | DMG_BUCKSHOT, TRACER_LINE, "sk_plr_dmg_buckshot", NULL, "sk_max_buckshot", BULLET_IMPULSE(200, 1200), 0 ); + def.AddAmmoType( "XBowBolt", DMG_BULLET | DMG_NEVERGIB, TRACER_LINE, "sk_plr_dmg_xbow_bolt_plr",NULL, "sk_max_xbow_bolt", BULLET_IMPULSE( 200, 1200), 0 ); + def.AddAmmoType( "MP5_Grenade", DMG_BURN | DMG_BLAST, TRACER_NONE, "sk_plr_dmg_mp5_grenade", NULL, "sk_max_mp5_grenade", 0, 0 ); + def.AddAmmoType( "RPG_Rocket", DMG_BURN | DMG_BLAST, TRACER_NONE, "sk_plr_dmg_rpg", NULL, "sk_max_rpg_rocket", 0, 0 ); + def.AddAmmoType( "Uranium", DMG_ENERGYBEAM, TRACER_NONE, NULL, NULL, "sk_max_uranium", 0, 0 ); + def.AddAmmoType( "Grenade", DMG_BURN | DMG_BLAST, TRACER_NONE, "sk_plr_dmg_grenade", NULL, "sk_max_grenade", 0, 0 ); + def.AddAmmoType( "Hornet", DMG_BULLET, TRACER_NONE, "sk_plr_dmg_hornet", "sk_npc_dmg_hornet", "sk_max_hornet", BULLET_IMPULSE(100, 1200), 0 ); + def.AddAmmoType( "Snark", DMG_SLASH, TRACER_NONE, "sk_snark_dmg_bite", NULL, "sk_max_snark", 0, 0 ); + def.AddAmmoType( "TripMine", DMG_BURN | DMG_BLAST, TRACER_NONE, "sk_plr_dmg_tripmine", NULL, "sk_max_tripmine", 0, 0 ); + def.AddAmmoType( "Satchel", DMG_BURN | DMG_BLAST, TRACER_NONE, "sk_plr_dmg_satchel", NULL, "sk_max_satchel", 0, 0 ); + + def.AddAmmoType( "12mmRound", DMG_BULLET | DMG_NEVERGIB, TRACER_LINE, NULL, "sk_npc_dmg_12mm_bullet",NULL, BULLET_IMPULSE(300, 1200), 0 ); + + def.AddAmmoType( "Gravity", DMG_CRUSH, TRACER_NONE, 0, 0, 8, 0, 0 ); + } + + return &def; +} diff --git a/game/shared/hl1/hl1_gamerules.h b/game/shared/hl1/hl1_gamerules.h new file mode 100644 index 0000000..a31f688 --- /dev/null +++ b/game/shared/hl1/hl1_gamerules.h @@ -0,0 +1,65 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: The HL2 Game rules object +// +// $Workfile: $ +// $Date: $ +// +//----------------------------------------------------------------------------- +// $Log: $ +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef HL1_GAMERULES_H +#define HL1_GAMERULES_H +#pragma once + +#include "gamerules.h" +#include "singleplay_gamerules.h" + + +#ifdef CLIENT_DLL + #define CHalfLife1 C_HalfLife1 +#endif + + +class CHalfLife1 : public CSingleplayRules +{ +public: + + DECLARE_CLASS( CHalfLife1, CSingleplayRules ); + + // Damage Queries. + virtual int Damage_GetShowOnHud( void ); + + // Client/server shared implementation. + virtual bool ShouldCollide( int collisionGroup0, int collisionGroup1 ); + + +#ifndef CLIENT_DLL + + CHalfLife1(); + virtual ~CHalfLife1() {} + + virtual bool ClientCommand( CBaseEntity *pEdict, const CCommand &args ); + virtual void PlayerSpawn( CBasePlayer *pPlayer ); + + virtual void InitDefaultAIRelationships( void ); + virtual const char * AIClassText(int classType); + virtual const char * GetGameDescription( void ); + virtual float FlPlayerFallDamage( CBasePlayer *pPlayer ); + + // Ammo + virtual void PlayerThink( CBasePlayer *pPlayer ); + bool CanHavePlayerItem( CBasePlayer *pPlayer, CBaseCombatWeapon *pWeapon ); + + void RadiusDamage( const CTakeDamageInfo &info, const Vector &vecSrc, float flRadius, int iClassIgnore ); + + int DefaultFOV( void ) { return 90; } + +#endif + +}; + +#endif // HL1_GAMERULES_H diff --git a/game/shared/hl1/hl1_player_shared.cpp b/game/shared/hl1/hl1_player_shared.cpp new file mode 100644 index 0000000..2d74018 --- /dev/null +++ b/game/shared/hl1/hl1_player_shared.cpp @@ -0,0 +1,373 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +// +//=============================================================================// +#include "cbase.h" +#include "tier0/vprof.h" + +#ifdef CLIENT_DLL +#include "hl1_player_shared.h" +#include "hl1/c_hl1mp_player.h" +//#define CRecipientFilter C_RecipientFilter +#else +#include "hl1mp_player.h" +#endif + +// When moving this fast, he plays run anim. +#define ARBITRARY_RUN_SPEED 175.0f + +#define MAX_STANDING_RUN_SPEED 320 +#define MAX_CROUCHED_RUN_SPEED 110 + + +// ------------------------------------------------------------------------------------------------ // +// CPlayerAnimState declaration. +// ------------------------------------------------------------------------------------------------ // + +class CPlayerAnimState : public IHL1MPPlayerAnimState, public CBasePlayerAnimState +{ +public: + + DECLARE_CLASS( CPlayerAnimState, CBasePlayerAnimState ); + + CPlayerAnimState(); + void Init( CHL1MP_Player *pPlayer ); + + // This is called by both the client and the server in the same way to trigger events for + // players firing, jumping, throwing grenades, etc. + virtual void DoAnimationEvent( PlayerAnimEvent_t event, int nData ); + virtual int CalcAimLayerSequence( float *flCycle, float *flAimSequenceWeight, bool bForceIdle ); + virtual float SetOuterBodyYaw( float flValue ); + virtual Activity CalcMainActivity(); + virtual float GetCurrentMaxGroundSpeed(); + virtual void ClearAnimationState(); + virtual bool ShouldUpdateAnimState(); + virtual int SelectWeightedSequence( Activity activity ) ; + + float CalcMovementPlaybackRate( bool *bIsMoving ); + + virtual void ComputePoseParam_BodyPitch( CStudioHdr *pStudioHdr ); + + +private: + + const char* GetWeaponSuffix(); + bool HandleJumping(); + bool HandleDeath( Activity *deathActivity ); + + +private: + + CHL1MP_Player *m_pOuter; + + bool m_bJumping; + bool m_bFirstJumpFrame; + float m_flJumpStartTime; + + bool m_bFiring; + float m_flFireStartTime; + + bool m_bDying; + Activity m_DeathActivity; +}; + + +IHL1MPPlayerAnimState* CreatePlayerAnimState( CHL1MP_Player *pPlayer ) +{ + CPlayerAnimState *pRet = new CPlayerAnimState; + pRet->Init( pPlayer ); + return pRet; +} + + +// ----------------------------------------------------------------------------- // +// CPlayerAnimState implementation. +// ----------------------------------------------------------------------------- // + +CPlayerAnimState::CPlayerAnimState() +{ + m_pOuter = NULL; + m_bJumping = false; + m_bFirstJumpFrame = false; + m_bFiring = false; +} + + +void CPlayerAnimState::Init( CHL1MP_Player *pPlayer ) +{ + m_pOuter = pPlayer; + + CModAnimConfig config; + config.m_flMaxBodyYawDegrees = 90; + config.m_LegAnimType = LEGANIM_GOLDSRC; + config.m_bUseAimSequences = true; + + BaseClass::Init( pPlayer, config ); +} + + +const char* CPlayerAnimState::GetWeaponSuffix() +{ + CBaseCombatWeapon *pWeapon = m_pOuter->GetActiveWeapon(); + if ( pWeapon ) + return pWeapon->GetWpnData().szAnimationPrefix; + else + return "shotgun"; +} + + +int CPlayerAnimState::CalcAimLayerSequence( float *flCycle, float *flAimSequenceWeight, bool bForceIdle ) +{ + const char *pWeaponSuffix = GetWeaponSuffix(); + if ( !pWeaponSuffix ) + return 0; + + if ( strcmp( pWeaponSuffix, "glock" ) == 0 ) + pWeaponSuffix = "onehanded"; + + // Are we aiming or firing? + const char *pAimOrShoot = "aim"; + if ( m_bFiring ) + pAimOrShoot = "shoot"; + + // Are we standing or crouching? + int iSequence = 0; + const char *pPrefix = "ref"; + if ( m_bDying ) + { + // While dying, only play the main sequence.. don't layer this one on top. + *flAimSequenceWeight = 0; + } + else + { + switch ( GetCurrentMainSequenceActivity() ) + { + case ACT_CROUCHIDLE: + case ACT_RUN_CROUCH: + pPrefix = "crouch"; + break; + } + } + + iSequence = CalcSequenceIndex( "%s_%s_%s", pPrefix, pAimOrShoot, pWeaponSuffix ); + + // Check if we're done firing. + if ( m_bFiring ) + { + float dur = m_pOuter->SequenceDuration( iSequence ); + *flCycle = (gpGlobals->curtime - m_flFireStartTime) / dur; + if ( *flCycle >= 1 ) + { + *flCycle = 1; + m_bFiring = false; + } + } + + return iSequence; +} + + +void CPlayerAnimState::DoAnimationEvent( PlayerAnimEvent_t event, int nData ) +{ + if ( event == PLAYERANIMEVENT_JUMP ) + { + // Main animation goes to ACT_HOP. + m_bJumping = true; + m_bFirstJumpFrame = true; + m_flJumpStartTime = gpGlobals->curtime; + } + else if ( event == PLAYERANIMEVENT_FIRE_GUN ) + { + // The middle part of the aim layer sequence becomes "shoot" until that animation is complete. + m_bFiring = true; + m_flFireStartTime = gpGlobals->curtime; + } +} + + +float CPlayerAnimState::SetOuterBodyYaw( float flValue ) +{ +// m_pOuter->SetBoneController( 0, flValue ); + + float fAcc = flValue / 4; + + for ( int i = 0; i < 4; i++ ) + { + m_pOuter->SetBoneController( i, fAcc ); + } + + return flValue; +} + + +bool CPlayerAnimState::HandleJumping() +{ + if ( m_bJumping ) + { + if ( m_bFirstJumpFrame ) + { + m_bFirstJumpFrame = false; + RestartMainSequence(); // Reset the animation. + } + + // Don't check if he's on the ground for a sec.. sometimes the client still has the + // on-ground flag set right when the message comes in. + if ( gpGlobals->curtime - m_flJumpStartTime > 0.2f ) + { + if ( m_pOuter->GetFlags() & FL_ONGROUND ) + { + m_bJumping = false; + RestartMainSequence(); // Reset the animation. + } + } + } + + // Are we still jumping? If so, keep playing the jump animation. + return m_bJumping; +} + +int CPlayerAnimState::SelectWeightedSequence( Activity activity ) +{ + return m_pOuter->m_iRealSequence; +} + +bool CPlayerAnimState::HandleDeath( Activity *deathActivity ) +{ + if ( m_bDying ) + { + if ( m_pOuter->IsAlive() ) + { + m_bDying = false; + } + else + { + *deathActivity = m_DeathActivity; + } + } + return m_bDying; +} + + +Activity CPlayerAnimState::CalcMainActivity() +{ + Activity deathActivity = ACT_IDLE; + if ( HandleDeath( &deathActivity ) ) + { + return deathActivity; + } + else if ( HandleJumping() ) + { + return ACT_HOP; + } + else + { + Activity idealActivity = ACT_IDLE; + float flOuterSpeed = GetOuterXYSpeed(); + + if ( m_pOuter->GetFlags() & FL_DUCKING ) + { + if ( flOuterSpeed > 0.1f ) + idealActivity = ACT_RUN_CROUCH; + else + idealActivity = ACT_CROUCHIDLE; + } + else + { + if ( flOuterSpeed > 0.1f ) + { + if ( flOuterSpeed > ARBITRARY_RUN_SPEED ) + idealActivity = ACT_RUN; + else + idealActivity = ACT_WALK; + } + else + { + idealActivity = ACT_IDLE; + } + } + + return idealActivity ; + } +} + + +float CPlayerAnimState::GetCurrentMaxGroundSpeed() +{ + Activity act = GetCurrentMainSequenceActivity(); + if ( act == ACT_CROUCHIDLE || act == ACT_RUN_CROUCH ) + return MAX_CROUCHED_RUN_SPEED; + else + return MAX_STANDING_RUN_SPEED; +} + + +void CPlayerAnimState::ClearAnimationState() +{ + m_bJumping = false; + m_bFiring = false; + m_bDying = false; + + BaseClass::ClearAnimationState(); +} + + +bool CPlayerAnimState::ShouldUpdateAnimState() +{ + return true; +} + +float CPlayerAnimState::CalcMovementPlaybackRate( bool *bIsMoving ) +{ + // Determine ideal playback rate + Vector vel; + GetOuterAbsVelocity( vel ); + + float flReturnValue = BaseClass::CalcMovementPlaybackRate( bIsMoving ); + + Activity eActivity = GetOuter()->GetSequenceActivity( GetOuter()->GetSequence() ) ; + + if ( eActivity == ACT_RUN || eActivity == ACT_WALK || eActivity == ACT_CROUCH ) + { + VectorNormalize( vel ); + + Vector vForward; + AngleVectors( GetOuter()->EyeAngles(), &vForward ); + + float flDot = DotProduct( vel, vForward ); + + if ( flDot < 0 ) + { + flReturnValue *= -1; + } + } + + return flReturnValue; +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CPlayerAnimState::ComputePoseParam_BodyPitch( CStudioHdr *pStudioHdr ) +{ + VPROF( "CBasePlayerAnimState::ComputePoseParam_BodyPitch" ); + + // Get pitch from v_angle + float flPitch = -m_flEyePitch; + if ( flPitch > 180.0f ) + { + flPitch -= 360.0f; + } + flPitch = clamp( flPitch, -50, 45 ); + + // See if we have a blender for pitch + int pitch = GetOuter()->LookupPoseParameter( pStudioHdr, "XR" ); + if ( pitch < 0 ) + return; + + GetOuter()->SetPoseParameter( pStudioHdr, pitch, flPitch ); + g_flLastBodyPitch = flPitch; +} + diff --git a/game/shared/hl1/hl1_player_shared.h b/game/shared/hl1/hl1_player_shared.h new file mode 100644 index 0000000..5536637 --- /dev/null +++ b/game/shared/hl1/hl1_player_shared.h @@ -0,0 +1,53 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=============================================================================// + +#ifndef HL1_PLAYER_SHARED_H +#define HL1_PLAYER_SHARED_H +#ifdef _WIN32 +#pragma once +#endif + +#include "cbase.h" +#include "base_playeranimstate.h" + +// Shared header file for players +#if defined( CLIENT_DLL ) +//#define CHL1_Player C_BaseHLPlayer //FIXME: Lovely naming job between server and client here... +class C_HL1MP_Player; +#define CHL1MP_Player C_HL1MP_Player +#else +//#include "hl1_player.h" +class CHL1MP_Player; +#endif + +#include "studio.h" + +enum PlayerAnimEvent_t +{ + PLAYERANIMEVENT_FIRE_GUN=0, + PLAYERANIMEVENT_THROW_GRENADE, + PLAYERANIMEVENT_JUMP, + PLAYERANIMEVENT_RELOAD, + PLAYERANIMEVENT_DIE, + + PLAYERANIMEVENT_COUNT +}; + +class IHL1MPPlayerAnimState : virtual public IPlayerAnimState +{ +public: + // This is called by both the client and the server in the same way to trigger events for + // players firing, jumping, throwing grenades, etc. + virtual void DoAnimationEvent( PlayerAnimEvent_t event, int nData ) = 0; +}; + +IHL1MPPlayerAnimState* CreatePlayerAnimState( CHL1MP_Player *pPlayer ); + +// If this is set, then the game code needs to make sure to send player animation events +// to the local player if he's the one being watched. +extern ConVar cl_showanimstate; + +#endif // HL1_PLAYER_SHARED_H diff --git a/game/shared/hl1/hl1_shareddefs.h b/game/shared/hl1/hl1_shareddefs.h new file mode 100644 index 0000000..4285bfe --- /dev/null +++ b/game/shared/hl1/hl1_shareddefs.h @@ -0,0 +1,20 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=============================================================================// + +#ifndef HL1_SHAREDDEFS_H +#define HL1_SHAREDDEFS_H +#ifdef _WIN32 +#pragma once +#endif + + +//-------------- +// HL1 SPECIFIC +//-------------- +#define DMG_MISSILEDEFENSE (DMG_LASTGENERICFLAG<<2) // The only kind of damage missiles take. (special missile defense) + + +#endif // HL1_SHAREDDEFS_H diff --git a/game/shared/hl1/hl1_usermessages.cpp b/game/shared/hl1/hl1_usermessages.cpp new file mode 100644 index 0000000..75744c2 --- /dev/null +++ b/game/shared/hl1/hl1_usermessages.cpp @@ -0,0 +1,42 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=============================================================================// + +#include "cbase.h" +#include "usermessages.h" +#include "shake.h" +#include "voice_gamemgr.h" +// NVNT include to register in haptic user messages +#include "haptics/haptic_msgs.h" + +void RegisterUserMessages( void ) +{ + usermessages->Register( "Geiger", 1 ); + usermessages->Register( "Train", 1 ); + usermessages->Register( "HudText", -1 ); + usermessages->Register( "SayText", -1 ); + usermessages->Register( "SayText2", -1 ); + usermessages->Register( "TextMsg", -1 ); + usermessages->Register( "HudMsg", -1 ); + usermessages->Register( "ResetHUD", 1 ); // called every respawn + usermessages->Register( "GameTitle", 0 ); + usermessages->Register( "ItemPickup", -1 ); + usermessages->Register( "ShowMenu", -1 ); + usermessages->Register( "Shake", 13 ); + usermessages->Register( "Fade", 10 ); + usermessages->Register( "VGUIMenu", -1 ); // Show VGUI menu + usermessages->Register( "Rumble", 3 ); // Send a rumble to a controller + usermessages->Register( "Battery", 2 ); + usermessages->Register( "Damage", 18 ); + usermessages->Register( "VoiceMask", VOICE_MAX_PLAYERS_DW*4 * 2 + 1 ); + usermessages->Register( "RequestState", 0 ); + usermessages->Register( "CloseCaption", -1 ); // Show a caption (by string id number)(duration in 10th of a second) + usermessages->Register( "HintText", -1 ); // Displays hint text display + usermessages->Register( "KeyHintText", -1 ); // Displays hint text display + usermessages->Register( "AmmoDenied", 2 ); + + // NVNT register haptic user messages + RegisterHapticMessages(); +}
\ No newline at end of file diff --git a/game/shared/hl1/hl1mp_basecombatweapon_shared.cpp b/game/shared/hl1/hl1mp_basecombatweapon_shared.cpp new file mode 100644 index 0000000..fe31f64 --- /dev/null +++ b/game/shared/hl1/hl1mp_basecombatweapon_shared.cpp @@ -0,0 +1,135 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// +#include "cbase.h" +#include "hl1mp_basecombatweapon_shared.h" + +#include "effect_dispatch_data.h" + +#ifdef CLIENT_DLL + #include "c_te_effect_dispatch.h" +#else + #include "te_effect_dispatch.h" +#endif + +#include "hl1_player_shared.h" + +LINK_ENTITY_TO_CLASS( basehl1mpcombatweapon, CBaseHL1MPCombatWeapon ); + +IMPLEMENT_NETWORKCLASS_ALIASED( BaseHL1MPCombatWeapon , DT_BaseHL1MPCombatWeapon ) + +BEGIN_NETWORK_TABLE( CBaseHL1MPCombatWeapon , DT_BaseHL1MPCombatWeapon ) +END_NETWORK_TABLE() + +BEGIN_PREDICTION_DATA( CBaseHL1MPCombatWeapon ) +END_PREDICTION_DATA() + + +CBaseHL1MPCombatWeapon::CBaseHL1MPCombatWeapon() +{ + SetPredictionEligible( true ); + AddSolidFlags( FSOLID_TRIGGER ); // Nothing collides with these but it gets touches. +} + + +void CBaseHL1MPCombatWeapon::EjectShell( CBaseEntity *pPlayer, int iType ) +{ + QAngle angShellAngles = pPlayer->GetAbsAngles(); + + Vector vecForward, vecRight, vecUp; + AngleVectors( angShellAngles, &vecForward, &vecRight, &vecUp ); + + Vector vecShellPosition = pPlayer->GetAbsOrigin() + pPlayer->GetViewOffset(); + switch ( iType ) + { + case 0: + default: + vecShellPosition += vecRight * 4; + vecShellPosition += vecUp * -12; + vecShellPosition += vecForward * 20; + break; + case 1: + vecShellPosition += vecRight * 6; + vecShellPosition += vecUp * -12; + vecShellPosition += vecForward * 32; + break; + } + + Vector vecShellVelocity = vec3_origin; // pPlayer->GetAbsVelocity(); + vecShellVelocity += vecRight * random->RandomFloat( 50, 70 ); + vecShellVelocity += vecUp * random->RandomFloat( 100, 150 ); + vecShellVelocity += vecForward * 25; + + angShellAngles.x = 0; + angShellAngles.z = 0; + + CEffectData data; + data.m_vStart = vecShellVelocity; + data.m_vOrigin = vecShellPosition; + data.m_vAngles = angShellAngles; + data.m_fFlags = iType; + + DispatchEffect( "HL1ShellEject", data ); +} + + +#ifdef CLIENT_DLL + +void CBaseHL1MPCombatWeapon::OnDataChanged( DataUpdateType_t type ) +{ + BaseClass::OnDataChanged( type ); + + if ( GetPredictable() && !ShouldPredict() ) + ShutdownPredictable(); +} + + +bool CBaseHL1MPCombatWeapon::ShouldPredict() +{ + if ( GetOwner() && GetOwner() == C_BasePlayer::GetLocalPlayer() ) + return true; + + return BaseClass::ShouldPredict(); +} + + +void CBaseHL1MPCombatWeapon::ApplyBoneMatrixTransform( matrix3x4_t& transform ) +{ + BaseClass::ApplyBoneMatrixTransform( transform ); +} + +#endif + + +bool CBaseHL1MPCombatWeapon::IsPredicted() const +{ + return true; +} + + +CBasePlayer* CBaseHL1MPCombatWeapon::GetPlayerOwner() const +{ + return dynamic_cast< CBasePlayer* >( GetOwner() ); +} + + +void CBaseHL1MPCombatWeapon::WeaponSound( WeaponSound_t sound_type, float soundtime /* = 0.0f */ ) +{ +#ifdef CLIENT_DLL + // If we have some sounds from the weapon classname.txt file, play a random one of them + const char *shootsound = GetWpnData().aShootSounds[ sound_type ]; + if ( !shootsound || !shootsound[0] ) + return; + + CBroadcastRecipientFilter filter; // this is client side only + if ( !te->CanPredict() ) + return; + + CBaseEntity::EmitSound( filter, GetPlayerOwner()->entindex(), shootsound, &GetPlayerOwner()->GetAbsOrigin() ); +#else + BaseClass::WeaponSound( sound_type, soundtime ); +#endif +} diff --git a/game/shared/hl1/hl1mp_basecombatweapon_shared.h b/game/shared/hl1/hl1mp_basecombatweapon_shared.h new file mode 100644 index 0000000..3e417a7 --- /dev/null +++ b/game/shared/hl1/hl1mp_basecombatweapon_shared.h @@ -0,0 +1,42 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +#include "hl1_basecombatweapon_shared.h" + +#ifndef BASEHL1MPCOMBATWEAPON_SHARED_H +#define BASEHL1MPCOMBATWEAPON_SHARED_H +#ifdef _WIN32 +#pragma once +#endif + + +#if defined( CLIENT_DLL ) +#define CBaseHL1MPCombatWeapon C_BaseHL1MPCombatWeapon +#endif + + +class CBaseHL1MPCombatWeapon : public CBaseHL1CombatWeapon +{ + DECLARE_CLASS( CBaseHL1MPCombatWeapon, CBaseHL1CombatWeapon ); +public : + CBaseHL1MPCombatWeapon(); + + DECLARE_NETWORKCLASS(); + DECLARE_PREDICTABLE(); + +public : + void EjectShell( CBaseEntity *pPlayer, int iType ); + + CBasePlayer* GetPlayerOwner() const; + virtual void WeaponSound( WeaponSound_t sound_type, float soundtime = 0.0f ); + +#ifdef CLIENT_DLL + void OnDataChanged( DataUpdateType_t type ); + bool ShouldPredict(); + + void ApplyBoneMatrixTransform( matrix3x4_t& transform ); +#endif + bool IsPredicted() const; + +}; + + +#endif // #ifndef BASEHL1MPCOMBATWEAPON_SHARED_H
\ No newline at end of file diff --git a/game/shared/hl1/hl1mp_gamerules.cpp b/game/shared/hl1/hl1mp_gamerules.cpp new file mode 100644 index 0000000..84c76d6 --- /dev/null +++ b/game/shared/hl1/hl1mp_gamerules.cpp @@ -0,0 +1,739 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +#include "cbase.h" +#include "hl1mp_gamerules.h" +#include "viewport_panel_names.h" +#include "gameeventdefs.h" +#include <KeyValues.h> +#include "ammodef.h" + +#ifdef CLIENT_DLL + +#include "hl1/c_hl1mp_player.h" + +#else + +#include "eventqueue.h" +#include "player.h" +#include "gamerules.h" +#include "game.h" +#include "items.h" +#include "entitylist.h" +#include "in_buttons.h" +#include <ctype.h> +#include "voice_gamemgr.h" +#include "iscorer.h" +#include "hl1mp_player.h" +#include "team.h" +#include "voice_gamemgr.h" + +#ifdef DEBUG +#include "hl1mp_bot_temp.h" +#endif + +ConVar sv_hl1mp_weapon_respawn_time( "sv_hl1mp_weapon_respawn_time", "20", FCVAR_GAMEDLL | FCVAR_NOTIFY ); +ConVar sv_hl1mp_item_respawn_time( "sv_hl1mp_item_respawn_time", "30", FCVAR_GAMEDLL | FCVAR_NOTIFY ); + + +extern ConVar mp_chattime; + +extern CBaseEntity *g_pLastCombineSpawn; +extern CBaseEntity *g_pLastRebelSpawn; + +//#define WEAPON_MAX_DISTANCE_FROM_SPAWN 64 + +#endif + + +REGISTER_GAMERULES_CLASS( CHL1MPRules ); + +BEGIN_NETWORK_TABLE_NOBASE( CHL1MPRules, DT_HL1MPRules ) + + #ifdef CLIENT_DLL + RecvPropBool( RECVINFO( m_bTeamPlayEnabled ) ), + #else + SendPropBool( SENDINFO( m_bTeamPlayEnabled ) ), + #endif + +END_NETWORK_TABLE() + + +LINK_ENTITY_TO_CLASS( hl1mp_gamerules, CHL1MPGameRulesProxy ); +IMPLEMENT_NETWORKCLASS_ALIASED( HL1MPGameRulesProxy, DT_HL1MPGameRulesProxy ) + + +#ifdef CLIENT_DLL + void RecvProxy_HL1MPRules( const RecvProp *pProp, void **pOut, void *pData, int objectID ) + { + CHL1MPRules *pRules = HL1MPRules(); + Assert( pRules ); + *pOut = pRules; + } + + BEGIN_RECV_TABLE( CHL1MPGameRulesProxy, DT_HL1MPGameRulesProxy ) + RecvPropDataTable( "hl1mp_gamerules_data", 0, 0, &REFERENCE_RECV_TABLE( DT_HL1MPRules ), RecvProxy_HL1MPRules ) + END_RECV_TABLE() +#else + void* SendProxy_HL1MPRules( const SendProp *pProp, const void *pStructBase, const void *pData, CSendProxyRecipients *pRecipients, int objectID ) + { + CHL1MPRules *pRules = HL1MPRules(); + Assert( pRules ); + return pRules; + } + + BEGIN_SEND_TABLE( CHL1MPGameRulesProxy, DT_HL1MPGameRulesProxy ) + SendPropDataTable( "hl1mp_gamerules_data", 0, &REFERENCE_SEND_TABLE( DT_HL1MPRules ), SendProxy_HL1MPRules ) + END_SEND_TABLE() +#endif + +#ifndef CLIENT_DLL + +#if 0 + class CVoiceGameMgrHelper : public IVoiceGameMgrHelper + { + public: + virtual bool CanPlayerHearPlayer( CBasePlayer *pListener, CBasePlayer *pTalker ) + { + return ( pListener->GetTeamNumber() == pTalker->GetTeamNumber() ); + } + }; + CVoiceGameMgrHelper g_VoiceGameMgrHelper; + IVoiceGameMgrHelper *g_pVoiceGameMgrHelper = &g_VoiceGameMgrHelper; +#endif + +#ifdef DEBUG + + // Handler for the "bot" command. + void Bot_f() + { + // Look at -count. + int count = 1; + count = clamp( count, 1, 16 ); + + int iTeam = 0; + + // Look at -frozen. + bool bFrozen = false; + + // Ok, spawn all the bots. + while ( --count >= 0 ) + { + BotPutInServer( bFrozen, iTeam ); + } + } + + + ConCommand cc_Bot( "bot", Bot_f, "Add a bot.", FCVAR_CHEAT ); + +#endif + +#endif + + + + +CHL1MPRules::CHL1MPRules() +{ +#ifndef CLIENT_DLL + m_bTeamPlayEnabled = teamplay.GetBool(); + + if ( IsTeamplay() ) + { + // Create basic server teams + + CTeam *pTeam = static_cast<CTeam*>(CreateEntityByName( "team_manager" )); + pTeam->Init( "Unassigned", 0 ); + g_Teams.AddToTail( pTeam ); + + pTeam = static_cast<CTeam*>(CreateEntityByName( "team_manager" )); + pTeam->Init( "Spectator", 1 ); + g_Teams.AddToTail( pTeam ); + + char *pName; + char szTeamlist[TEAMPLAY_TEAMLISTLENGTH]; + + // loop through all teams, recounting everything + int num_teams = 0; + + // Copy all of the teams from the teamlist + // make a copy because strtok is destructive + Q_strncpy( szTeamlist, teamlist.GetString(), sizeof(teamlist) ); + pName = szTeamlist; + pName = strtok( pName, "," ); + while ( pName != NULL && *pName ) + { + if ( GetTeamIndex( pName ) < 0 ) + { + // create team + pTeam = static_cast<CTeam*>(CreateEntityByName( "team_manager" )); + pTeam->Init( pName, num_teams + 2 ); + g_Teams.AddToTail( pTeam ); + + num_teams++; + } + pName = strtok( NULL, "," ); + } + + // Manually create teams + if ( num_teams == 0 ) + { + pTeam = static_cast<CTeam*>(CreateEntityByName( "team_manager" ) ); + pTeam->Init( "robo", num_teams + 2 ); + g_Teams.AddToTail( pTeam ); + num_teams++; + + pTeam = static_cast<CTeam*>(CreateEntityByName( "team_manager" ) ); + pTeam->Init( "hgrunt", num_teams + 2 ); + g_Teams.AddToTail( pTeam ); + num_teams++; + } + + } +#endif +} + +CHL1MPRules::~CHL1MPRules( void ) +{ +#ifndef CLIENT_DLL + // Note, don't delete each team since they are in the gEntList and will + // automatically be deleted from there, instead. + g_Teams.Purge(); +#endif +} + +void CHL1MPRules::CreateStandardEntities( void ) +{ + +#ifndef CLIENT_DLL + // Create the entity that will send our data to the client. + + BaseClass::CreateStandardEntities(); + +#ifdef _DEBUG + CBaseEntity *pEnt = +#endif + CBaseEntity::Create( "hl1mp_gamerules", vec3_origin, vec3_angle ); + Assert( pEnt ); +#endif +} + +float CHL1MPRules::GetAmmoDamage( CBaseEntity *pAttacker, CBaseEntity *pVictim, int nAmmoType ) +{ + return BaseClass::GetAmmoDamage( pAttacker, pVictim, nAmmoType ) * GetDamageMultiplier(); +} + +float CHL1MPRules::GetDamageMultiplier( void ) +{ + if ( IsMultiplayer() ) + return sk_mp_dmg_multiplier.GetFloat(); + else + return 1.0f; +} + + +bool CHL1MPRules::ClientCommand( CBaseEntity *pEdict, const CCommand &args ) +{ +#ifndef CLIENT_DLL + if( BaseClass::ClientCommand( pEdict, args ) ) + return true; + + + CHL1MP_Player *pPlayer = (CHL1MP_Player *) pEdict; + + if ( pPlayer->ClientCommand( args ) ) + return true; +#endif + + return false; +} + + +#ifdef CLIENT_DLL +#else + + +void CHL1MPRules::Think ( void ) +{ + CGameRules::Think(); + + if ( g_fGameOver ) // someone else quit the game already + { + // check to see if we should change levels now + if ( m_flIntermissionEndTime < gpGlobals->curtime ) + { + ChangeLevel(); // intermission is over + } + + return; + } + + float flTimeLimit = mp_timelimit.GetFloat() * 60; + float flFragLimit = fraglimit.GetFloat(); + + if ( flTimeLimit != 0 && gpGlobals->curtime >= flTimeLimit ) + { + GoToIntermission(); + return; + } + + if ( flFragLimit ) + { + if( IsTeamplay() == true ) + { + for (int i = TEAM_SPECTATOR+1; i < GetNumberOfTeams(); i++) + { + if ( GetGlobalTeam(i)->GetScore() >= flFragLimit ) + { + GoToIntermission(); + return; + } + } + } + else + { + // check if any player is over the frag limit + for ( int i = 1; i <= gpGlobals->maxClients; i++ ) + { + CBasePlayer *pPlayer = UTIL_PlayerByIndex( i ); + + if ( pPlayer && pPlayer->FragCount() >= flFragLimit ) + { + GoToIntermission(); + return; + } + } + } + } + +// ManageObjectRelocation(); +} + + +void CHL1MPRules::GoToIntermission() +{ +#ifndef CLIENT_DLL + if ( g_fGameOver ) + return; + + g_fGameOver = true; + + m_flIntermissionEndTime = gpGlobals->curtime + mp_chattime.GetInt(); + + for ( int i = 0; i < MAX_PLAYERS; i++ ) + { + CBasePlayer *pPlayer = UTIL_PlayerByIndex( i ); + + if ( !pPlayer ) + continue; + + pPlayer->ShowViewPortPanel( PANEL_SCOREBOARD ); + pPlayer->AddFlag( FL_FROZEN ); + } +#endif +} + + +const char * CHL1MPRules::SetDefaultPlayerTeam( CBasePlayer *pPlayer ) +{ + if ( !IsTeamplay() ) + { + CMultiplayRules::SetDefaultPlayerTeam( pPlayer ); + return ""; + } + + int clientIndex = pPlayer->entindex(); + + char szTeam[128]; + Q_FileBase( engine->GetClientConVarValue( clientIndex, "cl_playermodel" ), szTeam, 128 ); + + const char * team = szTeam; + + int iTeam = GetTeamIndex( team ); + if ( iTeam == -1 || !IsValidTeam( team ) ) + { + team = TeamWithFewestPlayers(); + iTeam = GetTeamIndex(team); + } + + pPlayer->ChangeTeam( iTeam ); + + return team; +} + + +const char * CHL1MPRules::TeamWithFewestPlayers( void ) +{ + const char * szName = ""; + int iNumPlayers = 0xFFFF; + for (int i = TEAM_SPECTATOR+1; i < GetNumberOfTeams(); i++) + { + if ( GetGlobalTeam(i)->GetNumPlayers() < iNumPlayers ) + { + szName = GetGlobalTeam(i)->GetName(); + iNumPlayers = GetGlobalTeam(i)->GetNumPlayers(); + } + } + + return szName; +} + + +void CHL1MPRules::InitHUD( CBasePlayer *pPlayer ) +{ + SetDefaultPlayerTeam( pPlayer ); + BaseClass::InitHUD( pPlayer ); +} + + +void CHL1MPRules::ChangePlayerTeam( CBasePlayer *pPlayer, const char *pTeamName, bool bKill, bool bGib ) +{ + BaseClass::ChangePlayerTeam( pPlayer, pTeamName, bKill, bGib ); +} + + +void CHL1MPRules::ClientSettingsChanged( CBasePlayer *pPlayer ) +{ + CHL1MP_Player *pHL1Player = ToHL1MPPlayer( pPlayer ); + + if ( pHL1Player == NULL ) + return; + + // strip down to just the name + char szTempCurrentModel[128]; + Q_FileBase( modelinfo->GetModelName( pPlayer->GetModel() ), szTempCurrentModel, 128 ); + const char *pCurrentModel = szTempCurrentModel; + + char szTempModelName[128]; + Q_FileBase( engine->GetClientConVarValue( engine->IndexOfEdict( pPlayer->edict() ), "cl_playermodel" ), szTempModelName, 128 ); + const char *szModelName = szTempModelName; + + //If we're different. + if ( strlen( szModelName ) > 0 && stricmp( szModelName, pCurrentModel ) ) + { + //Too soon, set the cvar back to what it was. + //Note: this will make this function be called again + //but since our models will match it'll just skip this whole dealio. + if ( pHL1Player->GetNextModelChangeTime() >= gpGlobals->curtime ) + { + char szReturnString[512]; + + Q_snprintf( szReturnString, sizeof (szReturnString ), "cl_playermodel %s\n", pCurrentModel ); + engine->ClientCommand ( pHL1Player->edict(), szReturnString ); + + Q_snprintf( szReturnString, sizeof( szReturnString ), "Please wait %d more seconds before trying to switch.\n", (int)(pHL1Player->GetNextModelChangeTime() - gpGlobals->curtime) ); + ClientPrint( pHL1Player, HUD_PRINTTALK, szReturnString ); + return; + } + + if ( HL1MPRules()->IsTeamplay() == false ) + { + pHL1Player->SetPlayerModel(); + + //const char *pszCurrentModelName = modelinfo->GetModelName( pHL1Player->GetModel() ); + + //char szReturnString[128]; + //Q_snprintf( szReturnString, sizeof( szReturnString ), "Your player model is: %s\n", pszCurrentModelName ); + + //Printing the model path for the average player is way too verbose - ml + //ClientPrint( pHL1Player, HUD_PRINTTALK, szReturnString ); + } + else + { + int iTeam = GetTeamIndex( szModelName ); + if ( iTeam == -1 || !IsValidTeam( szModelName ) ) + { + const char * team = TeamWithFewestPlayers(); + iTeam = GetTeamIndex( team ); + } + + pPlayer->ChangeTeam( iTeam ); + } + } + + BaseClass::ClientSettingsChanged( pPlayer ); +} + + +int CHL1MPRules::GetTeamIndex( const char * pName ) +{ + for ( int i = 0; i < GetNumberOfTeams(); i++ ) + { + if ( strcmp( g_Teams[i]->GetName(), pName ) == 0 ) + { + return i; + } + } + + return -1; +} + + +float CHL1MPRules::FlWeaponRespawnTime( CBaseCombatWeapon *pWeapon ) +{ + if ( weaponstay.GetInt() > 0 ) + { + // make sure it's only certain weapons + if ( !(pWeapon->GetWeaponFlags() & ITEM_FLAG_LIMITINWORLD) ) + { + return 0; + } + } + + return sv_hl1mp_weapon_respawn_time.GetInt(); +} + + +float CHL1MPRules::FlItemRespawnTime( CItem *pItem ) +{ + return sv_hl1mp_item_respawn_time.GetInt(); +} + + + +// This is a direct rip from CHalfLife1 +void CHL1MPRules::InitDefaultAIRelationships( void ) +{ + int i, j; + + // Allocate memory for default relationships + CBaseCombatCharacter::AllocateDefaultRelationships(); + + // -------------------------------------------------------------- + // First initialize table so we can report missing relationships + // -------------------------------------------------------------- + for (i=0;i<NUM_AI_CLASSES;i++) + { + for (j=0;j<NUM_AI_CLASSES;j++) + { + // By default all relationships are neutral of priority zero + CBaseCombatCharacter::SetDefaultRelationship( (Class_T)i, (Class_T)j, D_NU, 0 ); + } + } + + // ------------------------------------------------------------ + // > CLASS_NONE + // ------------------------------------------------------------ + CBaseCombatCharacter::SetDefaultRelationship( CLASS_NONE, CLASS_NONE, D_NU, 0 ); + CBaseCombatCharacter::SetDefaultRelationship( CLASS_NONE, CLASS_PLAYER, D_NU, 0 ); + CBaseCombatCharacter::SetDefaultRelationship( CLASS_NONE, CLASS_HUMAN_PASSIVE, D_NU, 0 ); + CBaseCombatCharacter::SetDefaultRelationship( CLASS_NONE, CLASS_PLAYER_ALLY, D_NU, 0 ); + CBaseCombatCharacter::SetDefaultRelationship( CLASS_NONE, CLASS_ALIEN_PREY, D_NU, 0 ); + CBaseCombatCharacter::SetDefaultRelationship( CLASS_NONE, CLASS_ALIEN_MILITARY, D_NU, 0 ); + CBaseCombatCharacter::SetDefaultRelationship( CLASS_NONE, CLASS_ALIEN_MONSTER, D_NU, 0 ); + CBaseCombatCharacter::SetDefaultRelationship( CLASS_NONE, CLASS_ALIEN_PREDATOR, D_NU, 0 ); + CBaseCombatCharacter::SetDefaultRelationship( CLASS_NONE, CLASS_HUMAN_MILITARY, D_NU, 0 ); + CBaseCombatCharacter::SetDefaultRelationship( CLASS_NONE, CLASS_MACHINE, D_NU, 0 ); + CBaseCombatCharacter::SetDefaultRelationship( CLASS_NONE, CLASS_ALIEN_BIOWEAPON, D_NU, 0 ); + CBaseCombatCharacter::SetDefaultRelationship( CLASS_NONE, CLASS_PLAYER_BIOWEAPON, D_NU, 0 ); + CBaseCombatCharacter::SetDefaultRelationship( CLASS_NONE, CLASS_INSECT, D_NU, 0 ); + + + // ------------------------------------------------------------ + // > CLASS_HUMAN_PASSIVE + // ------------------------------------------------------------ + CBaseCombatCharacter::SetDefaultRelationship( CLASS_HUMAN_PASSIVE, CLASS_NONE, D_NU, 0 ); + CBaseCombatCharacter::SetDefaultRelationship( CLASS_HUMAN_PASSIVE, CLASS_PLAYER, D_LI, 0 ); + CBaseCombatCharacter::SetDefaultRelationship( CLASS_HUMAN_PASSIVE, CLASS_HUMAN_PASSIVE, D_LI, 0 ); + CBaseCombatCharacter::SetDefaultRelationship( CLASS_HUMAN_PASSIVE, CLASS_PLAYER_ALLY, D_LI, 0 ); + CBaseCombatCharacter::SetDefaultRelationship( CLASS_HUMAN_PASSIVE, CLASS_ALIEN_PREY, D_FR, 0 ); + CBaseCombatCharacter::SetDefaultRelationship( CLASS_HUMAN_PASSIVE, CLASS_ALIEN_MILITARY, D_FR, 0 ); + CBaseCombatCharacter::SetDefaultRelationship( CLASS_HUMAN_PASSIVE, CLASS_ALIEN_MONSTER, D_HT, 0 ); + CBaseCombatCharacter::SetDefaultRelationship( CLASS_HUMAN_PASSIVE, CLASS_ALIEN_PREDATOR, D_FR, 0 ); + CBaseCombatCharacter::SetDefaultRelationship( CLASS_HUMAN_PASSIVE, CLASS_HUMAN_MILITARY, D_HT, 0 ); + CBaseCombatCharacter::SetDefaultRelationship( CLASS_HUMAN_PASSIVE, CLASS_MACHINE, D_NU, 0 ); + CBaseCombatCharacter::SetDefaultRelationship( CLASS_HUMAN_PASSIVE, CLASS_ALIEN_BIOWEAPON, D_NU, 0 ); + CBaseCombatCharacter::SetDefaultRelationship( CLASS_HUMAN_PASSIVE, CLASS_PLAYER_BIOWEAPON, D_NU, 0 ); + CBaseCombatCharacter::SetDefaultRelationship( CLASS_HUMAN_PASSIVE, CLASS_INSECT, D_NU, 0 ); + + + + // ------------------------------------------------------------ + // > CLASS_PLAYER + // ------------------------------------------------------------ + CBaseCombatCharacter::SetDefaultRelationship( CLASS_PLAYER, CLASS_NONE, D_NU, 0 ); + CBaseCombatCharacter::SetDefaultRelationship( CLASS_PLAYER, CLASS_PLAYER, D_LI, 0 ); + CBaseCombatCharacter::SetDefaultRelationship( CLASS_PLAYER, CLASS_HUMAN_PASSIVE, D_LI, 0 ); + CBaseCombatCharacter::SetDefaultRelationship( CLASS_PLAYER, CLASS_PLAYER_ALLY, D_LI, 0 ); + CBaseCombatCharacter::SetDefaultRelationship( CLASS_PLAYER, CLASS_ALIEN_PREY, D_HT, 0 ); + CBaseCombatCharacter::SetDefaultRelationship( CLASS_PLAYER, CLASS_ALIEN_MILITARY, D_HT, 0 ); + CBaseCombatCharacter::SetDefaultRelationship( CLASS_PLAYER, CLASS_ALIEN_MONSTER, D_HT, 0 ); + CBaseCombatCharacter::SetDefaultRelationship( CLASS_PLAYER, CLASS_ALIEN_PREDATOR, D_HT, 0 ); + CBaseCombatCharacter::SetDefaultRelationship( CLASS_PLAYER, CLASS_HUMAN_MILITARY, D_HT, 0 ); + CBaseCombatCharacter::SetDefaultRelationship( CLASS_PLAYER, CLASS_MACHINE, D_HT, 0 ); + CBaseCombatCharacter::SetDefaultRelationship( CLASS_PLAYER, CLASS_ALIEN_BIOWEAPON, D_HT, 0 ); + CBaseCombatCharacter::SetDefaultRelationship( CLASS_PLAYER, CLASS_PLAYER_BIOWEAPON, D_HT, 0 ); + CBaseCombatCharacter::SetDefaultRelationship( CLASS_PLAYER, CLASS_INSECT, D_NU, 0 ); + + // ------------------------------------------------------------ + // > CLASS_PLAYER_ALLY + // ------------------------------------------------------------ + CBaseCombatCharacter::SetDefaultRelationship( CLASS_PLAYER_ALLY, CLASS_NONE, D_NU, 0 ); + CBaseCombatCharacter::SetDefaultRelationship( CLASS_PLAYER_ALLY, CLASS_PLAYER, D_LI, 0 ); + CBaseCombatCharacter::SetDefaultRelationship( CLASS_PLAYER_ALLY, CLASS_HUMAN_PASSIVE, D_LI, 0 ); + CBaseCombatCharacter::SetDefaultRelationship( CLASS_PLAYER_ALLY, CLASS_PLAYER_ALLY, D_LI, 0 ); + CBaseCombatCharacter::SetDefaultRelationship( CLASS_PLAYER_ALLY, CLASS_ALIEN_PREY, D_HT, 0 ); + CBaseCombatCharacter::SetDefaultRelationship( CLASS_PLAYER_ALLY, CLASS_ALIEN_MILITARY, D_HT, 0 ); + CBaseCombatCharacter::SetDefaultRelationship( CLASS_PLAYER_ALLY, CLASS_ALIEN_MONSTER, D_HT, 0 ); + CBaseCombatCharacter::SetDefaultRelationship( CLASS_PLAYER_ALLY, CLASS_ALIEN_PREDATOR, D_HT, 0 ); + CBaseCombatCharacter::SetDefaultRelationship( CLASS_PLAYER_ALLY, CLASS_HUMAN_MILITARY, D_HT, 0 ); + CBaseCombatCharacter::SetDefaultRelationship( CLASS_PLAYER_ALLY, CLASS_MACHINE, D_HT, 0 ); + CBaseCombatCharacter::SetDefaultRelationship( CLASS_PLAYER_ALLY, CLASS_ALIEN_BIOWEAPON, D_NU, 0 ); + CBaseCombatCharacter::SetDefaultRelationship( CLASS_PLAYER_ALLY, CLASS_PLAYER_BIOWEAPON, D_NU, 0 ); + CBaseCombatCharacter::SetDefaultRelationship( CLASS_PLAYER_ALLY, CLASS_INSECT, D_NU, 0 ); + + // ------------------------------------------------------------ + // > CLASS_ALIEN_PREY + // ------------------------------------------------------------ + CBaseCombatCharacter::SetDefaultRelationship( CLASS_ALIEN_PREY, CLASS_NONE, D_NU, 0 ); + CBaseCombatCharacter::SetDefaultRelationship( CLASS_ALIEN_PREY, CLASS_PLAYER, D_HT, 0 ); + CBaseCombatCharacter::SetDefaultRelationship( CLASS_ALIEN_PREY, CLASS_PLAYER_ALLY, D_HT, 0 ); + CBaseCombatCharacter::SetDefaultRelationship( CLASS_ALIEN_PREY, CLASS_HUMAN_PASSIVE, D_HT, 0 ); + CBaseCombatCharacter::SetDefaultRelationship( CLASS_ALIEN_PREY, CLASS_ALIEN_PREY, D_NU, 0 ); + CBaseCombatCharacter::SetDefaultRelationship( CLASS_ALIEN_PREY, CLASS_ALIEN_MILITARY, D_NU, 0 ); + CBaseCombatCharacter::SetDefaultRelationship( CLASS_ALIEN_PREY, CLASS_ALIEN_MONSTER, D_NU, 0 ); + CBaseCombatCharacter::SetDefaultRelationship( CLASS_ALIEN_PREY, CLASS_ALIEN_PREDATOR, D_FR, 0 ); + CBaseCombatCharacter::SetDefaultRelationship( CLASS_ALIEN_PREY, CLASS_HUMAN_MILITARY, D_HT, 0 ); + CBaseCombatCharacter::SetDefaultRelationship( CLASS_ALIEN_PREY, CLASS_MACHINE, D_NU, 0 ); + CBaseCombatCharacter::SetDefaultRelationship( CLASS_ALIEN_PREY, CLASS_ALIEN_BIOWEAPON, D_NU, 0 ); + CBaseCombatCharacter::SetDefaultRelationship( CLASS_ALIEN_PREY, CLASS_PLAYER_BIOWEAPON, D_NU, 0 ); + CBaseCombatCharacter::SetDefaultRelationship( CLASS_ALIEN_PREY, CLASS_INSECT, D_NU, 0 ); + + // ------------------------------------------------------------ + // > CLASS_ALIEN_MILITARY + // ------------------------------------------------------------ + CBaseCombatCharacter::SetDefaultRelationship( CLASS_ALIEN_MILITARY, CLASS_NONE, D_NU, 0 ); + CBaseCombatCharacter::SetDefaultRelationship( CLASS_ALIEN_MILITARY, CLASS_PLAYER, D_HT, 0 ); + CBaseCombatCharacter::SetDefaultRelationship( CLASS_ALIEN_MILITARY, CLASS_PLAYER_ALLY, D_HT, 0 ); + CBaseCombatCharacter::SetDefaultRelationship( CLASS_ALIEN_MILITARY, CLASS_HUMAN_PASSIVE, D_HT, 0 ); + CBaseCombatCharacter::SetDefaultRelationship( CLASS_ALIEN_MILITARY, CLASS_ALIEN_PREY, D_NU, 0 ); + CBaseCombatCharacter::SetDefaultRelationship( CLASS_ALIEN_MILITARY, CLASS_ALIEN_MILITARY, D_NU, 0 ); + CBaseCombatCharacter::SetDefaultRelationship( CLASS_ALIEN_MILITARY, CLASS_ALIEN_MONSTER, D_NU, 0 ); + CBaseCombatCharacter::SetDefaultRelationship( CLASS_ALIEN_MILITARY, CLASS_ALIEN_PREDATOR, D_NU, 0 ); + CBaseCombatCharacter::SetDefaultRelationship( CLASS_ALIEN_MILITARY, CLASS_HUMAN_MILITARY, D_HT, 0 ); + CBaseCombatCharacter::SetDefaultRelationship( CLASS_ALIEN_MILITARY, CLASS_MACHINE, D_HT, 0 ); + CBaseCombatCharacter::SetDefaultRelationship( CLASS_ALIEN_MILITARY, CLASS_ALIEN_BIOWEAPON, D_NU, 0 ); + CBaseCombatCharacter::SetDefaultRelationship( CLASS_ALIEN_MILITARY, CLASS_PLAYER_BIOWEAPON, D_NU, 0 ); + CBaseCombatCharacter::SetDefaultRelationship( CLASS_ALIEN_MILITARY, CLASS_INSECT, D_NU, 0 ); + + // ------------------------------------------------------------ + // > CLASS_ALIEN_MONSTER + // ------------------------------------------------------------ + CBaseCombatCharacter::SetDefaultRelationship( CLASS_ALIEN_MONSTER, CLASS_NONE, D_NU, 0 ); + CBaseCombatCharacter::SetDefaultRelationship( CLASS_ALIEN_MONSTER, CLASS_PLAYER, D_HT, 0 ); + CBaseCombatCharacter::SetDefaultRelationship( CLASS_ALIEN_MONSTER, CLASS_PLAYER_ALLY, D_HT, 0 ); + CBaseCombatCharacter::SetDefaultRelationship( CLASS_ALIEN_MONSTER, CLASS_HUMAN_PASSIVE, D_HT, 0 ); + CBaseCombatCharacter::SetDefaultRelationship( CLASS_ALIEN_MONSTER, CLASS_ALIEN_PREY, D_NU, 0 ); + CBaseCombatCharacter::SetDefaultRelationship( CLASS_ALIEN_MONSTER, CLASS_ALIEN_MILITARY, D_NU, 0 ); + CBaseCombatCharacter::SetDefaultRelationship( CLASS_ALIEN_MONSTER, CLASS_ALIEN_MONSTER, D_NU, 0 ); + CBaseCombatCharacter::SetDefaultRelationship( CLASS_ALIEN_MONSTER, CLASS_ALIEN_PREDATOR, D_NU, 0 ); + CBaseCombatCharacter::SetDefaultRelationship( CLASS_ALIEN_MONSTER, CLASS_HUMAN_MILITARY, D_HT, 0 ); + CBaseCombatCharacter::SetDefaultRelationship( CLASS_ALIEN_MONSTER, CLASS_MACHINE, D_HT, 0 ); + CBaseCombatCharacter::SetDefaultRelationship( CLASS_ALIEN_MONSTER, CLASS_ALIEN_BIOWEAPON, D_NU, 0 ); + CBaseCombatCharacter::SetDefaultRelationship( CLASS_ALIEN_MONSTER, CLASS_PLAYER_BIOWEAPON, D_NU, 0 ); + CBaseCombatCharacter::SetDefaultRelationship( CLASS_ALIEN_MONSTER, CLASS_INSECT, D_NU, 0 ); + + // ------------------------------------------------------------ + // > CLASS_ALIEN_PREDATOR + // ------------------------------------------------------------ + CBaseCombatCharacter::SetDefaultRelationship( CLASS_ALIEN_PREDATOR, CLASS_NONE, D_NU, 0 ); + CBaseCombatCharacter::SetDefaultRelationship( CLASS_ALIEN_PREDATOR, CLASS_PLAYER, D_HT, 0 ); + CBaseCombatCharacter::SetDefaultRelationship( CLASS_ALIEN_PREDATOR, CLASS_PLAYER_ALLY, D_HT, 0 ); + CBaseCombatCharacter::SetDefaultRelationship( CLASS_ALIEN_PREDATOR, CLASS_HUMAN_PASSIVE, D_HT, 0 ); + CBaseCombatCharacter::SetDefaultRelationship( CLASS_ALIEN_PREDATOR, CLASS_ALIEN_PREY, D_HT, 0 ); + CBaseCombatCharacter::SetDefaultRelationship( CLASS_ALIEN_PREDATOR, CLASS_ALIEN_MILITARY, D_NU, 0 ); + CBaseCombatCharacter::SetDefaultRelationship( CLASS_ALIEN_PREDATOR, CLASS_ALIEN_MONSTER, D_NU, 0 ); + CBaseCombatCharacter::SetDefaultRelationship( CLASS_ALIEN_PREDATOR, CLASS_ALIEN_PREDATOR, D_NU, 0 ); + CBaseCombatCharacter::SetDefaultRelationship( CLASS_ALIEN_PREDATOR, CLASS_HUMAN_MILITARY, D_HT, 0 ); + CBaseCombatCharacter::SetDefaultRelationship( CLASS_ALIEN_PREDATOR, CLASS_MACHINE, D_NU, 0 ); + CBaseCombatCharacter::SetDefaultRelationship( CLASS_ALIEN_PREDATOR, CLASS_ALIEN_BIOWEAPON, D_NU, 0 ); + CBaseCombatCharacter::SetDefaultRelationship( CLASS_ALIEN_PREDATOR, CLASS_PLAYER_BIOWEAPON, D_NU, 0 ); + CBaseCombatCharacter::SetDefaultRelationship( CLASS_ALIEN_PREDATOR, CLASS_INSECT, D_NU, 0 ); + + // ------------------------------------------------------------ + // > CLASS_HUMAN_MILITARY + // ------------------------------------------------------------ + CBaseCombatCharacter::SetDefaultRelationship( CLASS_HUMAN_MILITARY, CLASS_NONE, D_NU, 0 ); + CBaseCombatCharacter::SetDefaultRelationship( CLASS_HUMAN_MILITARY, CLASS_PLAYER, D_HT, 0 ); + CBaseCombatCharacter::SetDefaultRelationship( CLASS_HUMAN_MILITARY, CLASS_PLAYER_ALLY, D_HT, 0 ); + CBaseCombatCharacter::SetDefaultRelationship( CLASS_HUMAN_MILITARY, CLASS_HUMAN_PASSIVE, D_HT, 0 ); + CBaseCombatCharacter::SetDefaultRelationship( CLASS_HUMAN_MILITARY, CLASS_ALIEN_PREY, D_HT, 0 ); + CBaseCombatCharacter::SetDefaultRelationship( CLASS_HUMAN_MILITARY, CLASS_ALIEN_MILITARY, D_HT, 0 ); + CBaseCombatCharacter::SetDefaultRelationship( CLASS_HUMAN_MILITARY, CLASS_ALIEN_MONSTER, D_HT, 0 ); + CBaseCombatCharacter::SetDefaultRelationship( CLASS_HUMAN_MILITARY, CLASS_ALIEN_PREDATOR, D_HT, 0 ); + CBaseCombatCharacter::SetDefaultRelationship( CLASS_HUMAN_MILITARY, CLASS_HUMAN_MILITARY, D_NU, 0 ); + CBaseCombatCharacter::SetDefaultRelationship( CLASS_HUMAN_MILITARY, CLASS_MACHINE, D_NU, 0 ); + CBaseCombatCharacter::SetDefaultRelationship( CLASS_HUMAN_MILITARY, CLASS_ALIEN_BIOWEAPON, D_NU, 0 ); + CBaseCombatCharacter::SetDefaultRelationship( CLASS_HUMAN_MILITARY, CLASS_PLAYER_BIOWEAPON, D_NU, 0 ); + CBaseCombatCharacter::SetDefaultRelationship( CLASS_HUMAN_MILITARY, CLASS_INSECT, D_NU, 0 ); + + // ------------------------------------------------------------ + // > CLASS_MACHINE + // ------------------------------------------------------------ + CBaseCombatCharacter::SetDefaultRelationship( CLASS_MACHINE, CLASS_NONE, D_NU, 0 ); + CBaseCombatCharacter::SetDefaultRelationship( CLASS_MACHINE, CLASS_MACHINE, D_NU, 0 ); + CBaseCombatCharacter::SetDefaultRelationship( CLASS_MACHINE, CLASS_PLAYER, D_HT, 0 ); + CBaseCombatCharacter::SetDefaultRelationship( CLASS_MACHINE, CLASS_HUMAN_PASSIVE, D_HT, 0 ); + CBaseCombatCharacter::SetDefaultRelationship( CLASS_MACHINE, CLASS_HUMAN_MILITARY, D_NU, 0 ); + CBaseCombatCharacter::SetDefaultRelationship( CLASS_MACHINE, CLASS_ALIEN_MILITARY, D_HT, 0 ); + CBaseCombatCharacter::SetDefaultRelationship( CLASS_MACHINE, CLASS_ALIEN_MONSTER, D_HT, 0 ); + CBaseCombatCharacter::SetDefaultRelationship( CLASS_MACHINE, CLASS_ALIEN_PREY, D_HT, 0 ); + CBaseCombatCharacter::SetDefaultRelationship( CLASS_MACHINE, CLASS_ALIEN_PREDATOR, D_HT, 0 ); + CBaseCombatCharacter::SetDefaultRelationship( CLASS_MACHINE, CLASS_PLAYER_ALLY, D_HT, 0 ); + CBaseCombatCharacter::SetDefaultRelationship( CLASS_MACHINE, CLASS_ALIEN_BIOWEAPON, D_HT, 0 ); + CBaseCombatCharacter::SetDefaultRelationship( CLASS_MACHINE, CLASS_PLAYER_BIOWEAPON, D_HT, 0 ); + CBaseCombatCharacter::SetDefaultRelationship( CLASS_MACHINE, CLASS_INSECT, D_NU, 0 ); + + // ------------------------------------------------------------ + // > CLASS_ALIEN_BIOWEAPON + // ------------------------------------------------------------ + CBaseCombatCharacter::SetDefaultRelationship( CLASS_ALIEN_BIOWEAPON, CLASS_NONE, D_NU, 0 ); + CBaseCombatCharacter::SetDefaultRelationship( CLASS_ALIEN_BIOWEAPON, CLASS_MACHINE, D_NU, 0 ); + CBaseCombatCharacter::SetDefaultRelationship( CLASS_ALIEN_BIOWEAPON, CLASS_PLAYER, D_HT, 0 ); + CBaseCombatCharacter::SetDefaultRelationship( CLASS_ALIEN_BIOWEAPON, CLASS_HUMAN_PASSIVE, D_HT, 0 ); + CBaseCombatCharacter::SetDefaultRelationship( CLASS_ALIEN_BIOWEAPON, CLASS_HUMAN_MILITARY, D_HT, 0 ); + CBaseCombatCharacter::SetDefaultRelationship( CLASS_ALIEN_BIOWEAPON, CLASS_ALIEN_MILITARY, D_LI, 0 ); + CBaseCombatCharacter::SetDefaultRelationship( CLASS_ALIEN_BIOWEAPON, CLASS_ALIEN_MONSTER, D_HT, 0 ); + CBaseCombatCharacter::SetDefaultRelationship( CLASS_ALIEN_BIOWEAPON, CLASS_ALIEN_PREY, D_HT, 0 ); + CBaseCombatCharacter::SetDefaultRelationship( CLASS_ALIEN_BIOWEAPON, CLASS_ALIEN_PREDATOR, D_NU, 0 ); + CBaseCombatCharacter::SetDefaultRelationship( CLASS_ALIEN_BIOWEAPON, CLASS_PLAYER_ALLY, D_HT, 0 ); + CBaseCombatCharacter::SetDefaultRelationship( CLASS_ALIEN_BIOWEAPON, CLASS_ALIEN_BIOWEAPON, D_NU, 0 ); + CBaseCombatCharacter::SetDefaultRelationship( CLASS_ALIEN_BIOWEAPON, CLASS_PLAYER_BIOWEAPON, D_HT, 0 ); + CBaseCombatCharacter::SetDefaultRelationship( CLASS_ALIEN_BIOWEAPON, CLASS_INSECT, D_NU, 0 ); + + // ------------------------------------------------------------ + // > CLASS_PLAYER_BIOWEAPON + // ------------------------------------------------------------ + CBaseCombatCharacter::SetDefaultRelationship( CLASS_PLAYER_BIOWEAPON, CLASS_NONE, D_NU, 0 ); + CBaseCombatCharacter::SetDefaultRelationship( CLASS_PLAYER_BIOWEAPON, CLASS_MACHINE, D_NU, 0 ); + CBaseCombatCharacter::SetDefaultRelationship( CLASS_PLAYER_BIOWEAPON, CLASS_PLAYER, D_HT, 0 ); + CBaseCombatCharacter::SetDefaultRelationship( CLASS_PLAYER_BIOWEAPON, CLASS_HUMAN_PASSIVE, D_HT, 0 ); + CBaseCombatCharacter::SetDefaultRelationship( CLASS_PLAYER_BIOWEAPON, CLASS_HUMAN_MILITARY, D_HT, 0 ); + CBaseCombatCharacter::SetDefaultRelationship( CLASS_PLAYER_BIOWEAPON, CLASS_ALIEN_MILITARY, D_HT, 0 ); + CBaseCombatCharacter::SetDefaultRelationship( CLASS_PLAYER_BIOWEAPON, CLASS_ALIEN_MONSTER, D_HT, 0 ); + CBaseCombatCharacter::SetDefaultRelationship( CLASS_PLAYER_BIOWEAPON, CLASS_ALIEN_PREY, D_HT, 0 ); + CBaseCombatCharacter::SetDefaultRelationship( CLASS_PLAYER_BIOWEAPON, CLASS_ALIEN_PREDATOR, D_HT, 0 ); + CBaseCombatCharacter::SetDefaultRelationship( CLASS_PLAYER_BIOWEAPON, CLASS_PLAYER_ALLY, D_HT, 0 ); + CBaseCombatCharacter::SetDefaultRelationship( CLASS_PLAYER_BIOWEAPON, CLASS_ALIEN_BIOWEAPON, D_HT, 0 ); + CBaseCombatCharacter::SetDefaultRelationship( CLASS_PLAYER_BIOWEAPON, CLASS_PLAYER_BIOWEAPON, D_NU, 0 ); + CBaseCombatCharacter::SetDefaultRelationship( CLASS_PLAYER_BIOWEAPON, CLASS_INSECT, D_NU, 0 ); + + + // ------------------------------------------------------------ + // > CLASS_INSECT + // ------------------------------------------------------------ + CBaseCombatCharacter::SetDefaultRelationship( CLASS_INSECT, CLASS_NONE, D_FR, 0 ); + CBaseCombatCharacter::SetDefaultRelationship( CLASS_INSECT, CLASS_MACHINE, D_FR, 0 ); + CBaseCombatCharacter::SetDefaultRelationship( CLASS_INSECT, CLASS_PLAYER, D_FR, 0 ); + CBaseCombatCharacter::SetDefaultRelationship( CLASS_INSECT, CLASS_HUMAN_PASSIVE, D_FR, 0 ); + CBaseCombatCharacter::SetDefaultRelationship( CLASS_INSECT, CLASS_HUMAN_MILITARY, D_FR, 0 ); + CBaseCombatCharacter::SetDefaultRelationship( CLASS_INSECT, CLASS_ALIEN_MILITARY, D_NU, 0 ); + CBaseCombatCharacter::SetDefaultRelationship( CLASS_INSECT, CLASS_ALIEN_MONSTER, D_FR, 0 ); + CBaseCombatCharacter::SetDefaultRelationship( CLASS_INSECT, CLASS_ALIEN_PREY, D_FR, 0 ); + CBaseCombatCharacter::SetDefaultRelationship( CLASS_INSECT, CLASS_ALIEN_PREDATOR, D_FR, 0 ); + CBaseCombatCharacter::SetDefaultRelationship( CLASS_INSECT, CLASS_PLAYER_ALLY, D_FR, 0 ); + CBaseCombatCharacter::SetDefaultRelationship( CLASS_INSECT, CLASS_ALIEN_BIOWEAPON, D_NU, 0 ); + CBaseCombatCharacter::SetDefaultRelationship( CLASS_INSECT, CLASS_PLAYER_BIOWEAPON, D_NU, 0 ); + CBaseCombatCharacter::SetDefaultRelationship( CLASS_INSECT, CLASS_INSECT, D_NU, 0 ); +} + + +#endif diff --git a/game/shared/hl1/hl1mp_gamerules.h b/game/shared/hl1/hl1mp_gamerules.h new file mode 100644 index 0000000..c68743a --- /dev/null +++ b/game/shared/hl1/hl1mp_gamerules.h @@ -0,0 +1,91 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +#ifndef HL1MP_GAMERULES_H +#define HL1MP_GAMERULES_H +#pragma once + + +#include "gamerules.h" +#include "teamplay_gamerules.h" + +extern ConVar sk_mp_dmg_multiplier ; + +#ifdef CLIENT_DLL + #define CHL1MPRules C_HL1MPRules + #define CHL1MPGameRulesProxy C_HL1MPGameRulesProxy +#endif + + +class CHL1MPGameRulesProxy : public CGameRulesProxy +{ +public: + DECLARE_CLASS( CHL1MPGameRulesProxy, CGameRulesProxy ); + DECLARE_NETWORKCLASS(); +}; + + +class CHL1MPRules : public CTeamplayRules +{ +public: + DECLARE_CLASS( CHL1MPRules, CTeamplayRules ); + +#ifdef CLIENT_DLL + DECLARE_CLIENTCLASS_NOBASE(); +#else + DECLARE_SERVERCLASS_NOBASE(); +#endif + + CHL1MPRules(); + virtual ~CHL1MPRules(); + + virtual void CreateStandardEntities( void ); + + virtual bool IsTeamplay( void ) + { + return m_bTeamPlayEnabled; + } + + virtual float GetAmmoDamage( CBaseEntity *pAttacker, CBaseEntity *pVictim, int nAmmoType ); + virtual float GetDamageMultiplier( void ); + + virtual bool IsConnectedUserInfoChangeAllowed( CBasePlayer *pPlayer ) + { + return true; + } + bool ClientCommand( CBaseEntity *pEdict, const CCommand &args ); + +#ifdef CLIENT_DLL +#else + virtual const char *GetGameDescription( void ) { return "Half-Life Deathmatch: Source"; } // this is the game name that gets seen in the server browser + + virtual void Think ( void ); + + virtual void GoToIntermission( void ); + + virtual void InitDefaultAIRelationships( void ); + + virtual float FlWeaponRespawnTime( CBaseCombatWeapon *pWeapon ); + virtual float FlItemRespawnTime( CItem *pItem ); + + virtual const char *SetDefaultPlayerTeam( CBasePlayer *pPlayer ); + virtual void InitHUD( CBasePlayer *pPlayer ); + virtual void ChangePlayerTeam( CBasePlayer *pPlayer, const char *pTeamName, bool bKill, bool bGib ); + virtual void ClientSettingsChanged( CBasePlayer *pPlayer ); + + virtual int GetTeamIndex( const char * pName ); +#endif + +private: + + const char *TeamWithFewestPlayers( void ); + + CNetworkVar( bool, m_bTeamPlayEnabled ); +}; + + +inline CHL1MPRules* HL1MPRules() +{ + return dynamic_cast<CHL1MPRules*>(g_pGameRules); +} + + +#endif diff --git a/game/shared/hl1/hl1mp_weapon_357.cpp b/game/shared/hl1/hl1mp_weapon_357.cpp new file mode 100644 index 0000000..33d6757 --- /dev/null +++ b/game/shared/hl1/hl1mp_weapon_357.cpp @@ -0,0 +1,289 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: 357 - hand gun +// +// $NoKeywords: $ +//=============================================================================// + +#include "cbase.h" +#include "npcevent.h" +#include "hl1mp_basecombatweapon_shared.h" +#ifdef CLIENT_DLL +#include "c_baseplayer.h" +#else +#include "player.h" +#endif +#include "gamerules.h" +#include "in_buttons.h" +#ifndef CLIENT_DLL +#include "soundent.h" +#include "game.h" +#endif +#include "vstdlib/random.h" +#include "engine/IEngineSound.h" + +#ifdef CLIENT_DLL +#define CWeapon357 C_Weapon357 +#endif + +//----------------------------------------------------------------------------- +// CWeapon357 +//----------------------------------------------------------------------------- + +class CWeapon357 : public CBaseHL1MPCombatWeapon +{ + DECLARE_CLASS( CWeapon357, CBaseHL1CombatWeapon ); +public: + DECLARE_NETWORKCLASS(); + DECLARE_PREDICTABLE(); + + CWeapon357( void ); + + void Precache( void ); + bool Deploy( void ); + void PrimaryAttack( void ); + void SecondaryAttack( void ); + bool Reload( void ); + void WeaponIdle( void ); + bool Holster( CBaseCombatWeapon *pSwitchingTo = NULL ); + +// DECLARE_SERVERCLASS(); +// DECLARE_DATADESC(); + +private: + void ToggleZoom( void ); + +private: + CNetworkVar( float, m_fInZoom ); +}; + +IMPLEMENT_NETWORKCLASS_ALIASED( Weapon357, DT_Weapon357 ); + +BEGIN_NETWORK_TABLE( CWeapon357, DT_Weapon357 ) +#ifdef CLIENT_DLL + RecvPropFloat( RECVINFO( m_fInZoom ) ), +#else + SendPropFloat( SENDINFO( m_fInZoom ) ), +#endif +END_NETWORK_TABLE() + +BEGIN_PREDICTION_DATA( CWeapon357 ) +#ifdef CLIENT_DLL + DEFINE_PRED_FIELD( m_fInZoom, FIELD_FLOAT, FTYPEDESC_INSENDTABLE ), +#endif +END_PREDICTION_DATA() + +LINK_ENTITY_TO_CLASS( weapon_357, CWeapon357 ); + +PRECACHE_WEAPON_REGISTER( weapon_357 ); + +//IMPLEMENT_SERVERCLASS_ST( CWeapon357, DT_Weapon357 ) +//END_SEND_TABLE() + +//BEGIN_DATADESC( CWeapon357 ) +//END_DATADESC() + +//----------------------------------------------------------------------------- +// Purpose: Constructor +//----------------------------------------------------------------------------- +CWeapon357::CWeapon357( void ) +{ + m_bReloadsSingly = false; + m_bFiresUnderwater = false; + m_fInZoom = false; +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CWeapon357::Precache( void ) +{ + BaseClass::Precache(); + +#ifndef CLIENT_DLL + UTIL_PrecacheOther( "ammo_357" ); +#endif +} + +bool CWeapon357::Deploy( void ) +{ +// Bodygroup stuff not currently working correctly +// if ( g_pGameRules->IsMultiplayer() ) +// { + // enable laser sight geometry. +// SetBodygroup( 4, 1 ); +// } +// else +// { +// SetBodygroup( 4, 0 ); +// } + + return BaseClass::Deploy(); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CWeapon357::PrimaryAttack( void ) +{ + // Only the player fires this way so we can cast + CBasePlayer *pPlayer = ToBasePlayer( GetOwner() ); + + if ( !pPlayer ) + { + return; + } + + if ( m_iClip1 <= 0 ) + { + if ( !m_bFireOnEmpty ) + { + Reload(); + } + else + { + WeaponSound( EMPTY ); + m_flNextPrimaryAttack = 0.15; + } + + return; + } + + WeaponSound( SINGLE ); + pPlayer->DoMuzzleFlash(); + + SendWeaponAnim( ACT_VM_PRIMARYATTACK ); + pPlayer->SetAnimation( PLAYER_ATTACK1 ); + + m_flNextPrimaryAttack = gpGlobals->curtime + 0.75; + m_flNextSecondaryAttack = gpGlobals->curtime + 0.75; + + m_iClip1--; + + Vector vecSrc = pPlayer->Weapon_ShootPosition(); + Vector vecAiming = pPlayer->GetAutoaimVector( AUTOAIM_5DEGREES ); + +// pPlayer->FireBullets( 1, vecSrc, vecAiming, VECTOR_CONE_1DEGREES, MAX_TRACE_LENGTH, m_iPrimaryAmmoType, 0 ); + + FireBulletsInfo_t info( 1, vecSrc, vecAiming, VECTOR_CONE_1DEGREES, MAX_TRACE_LENGTH, m_iPrimaryAmmoType ); + info.m_pAttacker = pPlayer; + + pPlayer->FireBullets( info ); + +#ifndef CLIENT_DLL + pPlayer->SetMuzzleFlashTime( gpGlobals->curtime + 0.5 ); +#endif + + pPlayer->ViewPunch( QAngle( -10, 0, 0 ) ); + +#ifndef CLIENT_DLL + CSoundEnt::InsertSound( SOUND_COMBAT, GetAbsOrigin(), 600, 0.2 ); +#endif + + if ( !m_iClip1 && pPlayer->GetAmmoCount( m_iPrimaryAmmoType ) <= 0 ) + { + // HEV suit - indicate out of ammo condition + pPlayer->SetSuitUpdate( "!HEV_AMO0", FALSE, 0 ); + } +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CWeapon357::SecondaryAttack( void ) +{ + // only in multiplayer + if ( !g_pGameRules->IsMultiplayer() ) + { +#ifndef CLIENT_DLL + // unless we have cheats on + if ( !sv_cheats->GetBool() ) + { + return; + } +#endif + } + + ToggleZoom(); + + m_flNextSecondaryAttack = gpGlobals->curtime + 0.5; +} + + +bool CWeapon357::Reload( void ) +{ + bool fRet; + + fRet = DefaultReload( GetMaxClip1(), GetMaxClip2(), ACT_VM_RELOAD ); + if ( fRet ) + { + if ( m_fInZoom ) + { + ToggleZoom(); + } + } + + return fRet; +} + + +void CWeapon357::WeaponIdle( void ) +{ + CBasePlayer *pPlayer = ToBasePlayer( GetOwner() ); + if ( pPlayer ) + { + pPlayer->GetAutoaimVector( AUTOAIM_10DEGREES ); + } + + if ( !HasWeaponIdleTimeElapsed() ) + return; + + if ( random->RandomFloat( 0, 1 ) <= 0.9 ) + { + SendWeaponAnim( ACT_VM_IDLE ); + } + else + { + SendWeaponAnim( ACT_VM_FIDGET ); + } +} + + +bool CWeapon357::Holster( CBaseCombatWeapon *pSwitchingTo ) +{ + if ( m_fInZoom ) + { + ToggleZoom(); + } + + return BaseClass::Holster( pSwitchingTo ); +} + + +void CWeapon357::ToggleZoom( void ) +{ + CBasePlayer *pPlayer = ToBasePlayer( GetOwner() ); + if ( !pPlayer ) + { + return; + } + +#ifndef CLIENT_DLL + if ( m_fInZoom ) + { + if ( pPlayer->SetFOV( this, 0 ) ) + { + m_fInZoom = false; + pPlayer->ShowViewModel( true ); + } + } + else + { + if ( pPlayer->SetFOV( this, 40 ) ) + { + m_fInZoom = true; + pPlayer->ShowViewModel( false ); + } + } +#endif +} diff --git a/game/shared/hl1/hl1mp_weapon_crossbow.cpp b/game/shared/hl1/hl1mp_weapon_crossbow.cpp new file mode 100644 index 0000000..7118ac1 --- /dev/null +++ b/game/shared/hl1/hl1mp_weapon_crossbow.cpp @@ -0,0 +1,648 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: Crossbow +// +// $NoKeywords: $ +//=============================================================================// + +#include "cbase.h" +#include "npcevent.h" +#include "hl1mp_basecombatweapon_shared.h" +//#include "basecombatcharacter.h" +//#include "AI_BaseNPC.h" +#ifdef CLIENT_DLL +#include "c_baseplayer.h" +#else +#include "player.h" +#endif +//#include "player.h" +#include "gamerules.h" +#include "in_buttons.h" +#ifdef CLIENT_DLL +#else +#include "soundent.h" +#include "entitylist.h" +#include "game.h" +#endif +#include "vstdlib/random.h" +#include "engine/IEngineSound.h" +#include "IEffects.h" +#ifdef CLIENT_DLL +#include "c_te_effect_dispatch.h" +#else +#include "te_effect_dispatch.h" +#endif + +#define BOLT_MODEL "models/crossbow_bolt.mdl" + +#define BOLT_AIR_VELOCITY 2000 +#define BOLT_WATER_VELOCITY 1000 + +extern ConVar sk_plr_dmg_xbow_bolt_plr; +extern ConVar sk_plr_dmg_xbow_bolt_npc; + +extern short g_sModelIndexFireball; // (in combatweapon.cpp) holds the index for the fireball + +#if !defined(CLIENT_DLL) + +//----------------------------------------------------------------------------- +// Crossbow Bolt +//----------------------------------------------------------------------------- +class CCrossbowBolt : public CBaseCombatCharacter +{ + DECLARE_CLASS( CCrossbowBolt, CBaseCombatCharacter ); + +public: + CCrossbowBolt() + { + m_bExplode = true; + } + + Class_T Classify( void ) { return CLASS_NONE; } + +public: + void Spawn( void ); + void Precache( void ); + void BubbleThink( void ); + void BoltTouch( CBaseEntity *pOther ); + void ExplodeThink( void ); + void SetExplode( bool bVal ) { m_bExplode = bVal; } + bool CreateVPhysics( void ); + unsigned int PhysicsSolidMaskForEntity() const; + + static CCrossbowBolt *BoltCreate( const Vector &vecOrigin, const QAngle &angAngles, CBasePlayer *pentOwner = NULL ); + + DECLARE_DATADESC(); + +private: + bool m_bExplode; +}; +LINK_ENTITY_TO_CLASS( crossbow_bolt, CCrossbowBolt ); + +BEGIN_DATADESC( CCrossbowBolt ) + // Function Pointers + DEFINE_FUNCTION( BubbleThink ), + DEFINE_FUNCTION( BoltTouch ), + DEFINE_FUNCTION( ExplodeThink ), +END_DATADESC() + +CCrossbowBolt *CCrossbowBolt::BoltCreate( const Vector &vecOrigin, const QAngle &angAngles, CBasePlayer *pentOwner ) +{ + // Create a new entity with CCrossbowBolt private data + CCrossbowBolt *pBolt = (CCrossbowBolt *)CreateEntityByName( "crossbow_bolt" ); + UTIL_SetOrigin( pBolt, vecOrigin ); + pBolt->SetAbsAngles( angAngles ); + pBolt->Spawn(); + pBolt->SetOwnerEntity( pentOwner ); + + return pBolt; +} + +void CCrossbowBolt::Spawn( ) +{ + Precache( ); + + SetModel( BOLT_MODEL ); + UTIL_SetSize( this, -Vector(1, 1, 1), Vector(1, 1, 1) ); + + SetSolid( SOLID_BBOX ); + SetMoveType( MOVETYPE_FLYGRAVITY, MOVECOLLIDE_FLY_BOUNCE ); + SetGravity( UTIL_ScaleForGravity( 40 ) ); // use a really low gravity (40 in/s^2) + + SetTouch( &CCrossbowBolt::BoltTouch ); + + SetThink( &CCrossbowBolt::BubbleThink ); + SetNextThink( gpGlobals->curtime + 0.2 ); + + m_bExplode = true; +} + + +void CCrossbowBolt::Precache( ) +{ + PrecacheModel( BOLT_MODEL ); + PrecacheScriptSound( "BaseGrenade.Explode" ); +} + +void CCrossbowBolt::BoltTouch( CBaseEntity *pOther ) +{ + if ( !pOther->IsSolid() || pOther->IsSolidFlagSet(FSOLID_VOLUME_CONTENTS) ) + return; + + SetTouch( NULL ); + SetThink( NULL ); + + if ( pOther->m_takedamage != DAMAGE_NO ) + { + trace_t tr, tr2; + tr = BaseClass::GetTouchTrace( ); + Vector vecNormalizedVel = GetAbsVelocity(); + + ClearMultiDamage( ); + VectorNormalize( vecNormalizedVel ); + + if ( pOther->IsPlayer() ) + { + float m_fDamage = sk_plr_dmg_xbow_bolt_plr.GetFloat() * g_pGameRules->GetDamageMultiplier(); + + // If multiplayer sniper bolt, multiply damage by 4 + if ( g_pGameRules->IsMultiplayer() && !m_bExplode ) + m_fDamage *= 4; + + CTakeDamageInfo dmgInfo( this, GetOwnerEntity(), m_fDamage,DMG_NEVERGIB ); + CalculateMeleeDamageForce( &dmgInfo, vecNormalizedVel, tr.endpos ); + pOther->DispatchTraceAttack( dmgInfo, vecNormalizedVel, &tr ); + } + else + { + CTakeDamageInfo dmgInfo( this, GetOwnerEntity(), sk_plr_dmg_xbow_bolt_npc.GetFloat() * g_pGameRules->GetDamageMultiplier(), DMG_BULLET | DMG_NEVERGIB ); + CalculateMeleeDamageForce( &dmgInfo, vecNormalizedVel, tr.endpos ); + pOther->DispatchTraceAttack( dmgInfo, vecNormalizedVel, &tr ); + } + + ApplyMultiDamage(); + + SetAbsVelocity( Vector( 0, 0, 0 ) ); + + // play body "thwack" sound + EmitSound( "Weapon_Crossbow.BoltHitBody" ); + + Vector vForward; + + AngleVectors( GetAbsAngles(), &vForward ); + VectorNormalize ( vForward ); + + UTIL_TraceLine( GetAbsOrigin(), GetAbsOrigin() + vForward * 128, MASK_OPAQUE, pOther, COLLISION_GROUP_NONE, &tr2 ); + + if ( tr2.fraction != 1.0f ) + { +// NDebugOverlay::Box( tr2.endpos, Vector( -16, -16, -16 ), Vector( 16, 16, 16 ), 0, 255, 0, 0, 10 ); +// NDebugOverlay::Box( GetAbsOrigin(), Vector( -16, -16, -16 ), Vector( 16, 16, 16 ), 0, 0, 255, 0, 10 ); + + CEffectData data; + + data.m_vOrigin = tr2.endpos; + data.m_vNormal = vForward; + data.m_nEntIndex = tr2.fraction != 1.0f; + + DispatchEffect( "BoltImpact", data ); + } + + if ( !g_pGameRules->IsMultiplayer() || !m_bExplode ) + { + UTIL_Remove( this ); + } + } + else + { + EmitSound( "Weapon_Crossbow.BoltHitWorld" ); + + SetThink( &CCrossbowBolt::SUB_Remove ); + SetNextThink( gpGlobals->curtime );// this will get changed below if the bolt is allowed to stick in what it hit. + + if ( m_bExplode == false ) + { + Vector vForward; + AngleVectors( GetAbsAngles(), &vForward ); + VectorNormalize ( vForward ); + + CEffectData data; + + data.m_vOrigin = GetAbsOrigin(); + data.m_vNormal = vForward; + data.m_nEntIndex = 0; + + DispatchEffect( "BoltImpact", data ); + } + + if ( UTIL_PointContents( GetAbsOrigin() ) != CONTENTS_WATER) + { + g_pEffects->Sparks( GetAbsOrigin() ); + } + } + + // Set up an explosion in one tenth of a second + if ( g_pGameRules->IsMultiplayer() && m_bExplode ) + { + SetThink( &CCrossbowBolt::ExplodeThink ); + SetNextThink( gpGlobals->curtime + 0.1f ); + } +} + +void CCrossbowBolt::ExplodeThink( void ) +{ + // int iContents = UTIL_PointContents( pev->origin ); + CTakeDamageInfo dmgInfo( this, GetOwnerEntity(), sk_plr_dmg_xbow_bolt_npc.GetFloat() * g_pGameRules->GetDamageMultiplier(), DMG_BLAST ); + + ::RadiusDamage( dmgInfo, GetAbsOrigin(), 128, CLASS_NONE, NULL ); + +#if !defined( CLIENT_DLL ) + CPASFilter filter( GetAbsOrigin() ); + + te->Explosion( filter, /* filter */ + 0.0, /* delay */ + &GetAbsOrigin(), /* pos */ + g_sModelIndexFireball, /* modelindex */ + 0.2, /* scale */ + 25, /* framerate */ + TE_EXPLFLAG_NONE, /* flags */ + 128, /* radius */ + 64, /* magnitude */ + NULL, /* normal */ + 'C' ); /* materialType */ + + //CSoundEnt::InsertSound ( SOUND_COMBAT, GetAbsOrigin(), BASEGRENADE_EXPLOSION_VOLUME, 3.0 ); + EmitSound( "BaseGrenade.Explode" ); +#endif + + + SetThink( &CCrossbowBolt::SUB_Remove ); + SetNextThink( gpGlobals->curtime ); + + AddEffects( EF_NODRAW ); +} + +void CCrossbowBolt::BubbleThink( void ) +{ + QAngle angNewAngles; + + VectorAngles( GetAbsVelocity(), angNewAngles ); + SetAbsAngles( angNewAngles ); + + SetNextThink( gpGlobals->curtime + 0.1f ); + + if ( GetWaterLevel() == 0 ) + return; + + UTIL_BubbleTrail( GetAbsOrigin() - GetAbsVelocity() * 0.1, GetAbsOrigin(), 1 ); +} + + +//----------------------------------------------------------------------------- +// Purpose: +// Output : Returns true on success, false on failure. +//----------------------------------------------------------------------------- +bool CCrossbowBolt::CreateVPhysics( void ) +{ + // Create the object in the physics system + VPhysicsInitNormal( SOLID_BBOX, FSOLID_NOT_STANDABLE, false ); + + return true; +} + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +unsigned int CCrossbowBolt::PhysicsSolidMaskForEntity() const +{ + return ( BaseClass::PhysicsSolidMaskForEntity() | CONTENTS_HITBOX ) & ~CONTENTS_GRATE; +} + + +#endif // crossbowbolt + +//----------------------------------------------------------------------------- +// CWeaponCrossbow +//----------------------------------------------------------------------------- + +#ifdef CLIENT_DLL +#define CWeaponCrossbow C_WeaponCrossbow +#endif + +class CWeaponCrossbow : public CBaseHL1MPCombatWeapon +{ + DECLARE_CLASS( CWeaponCrossbow, CBaseHL1MPCombatWeapon ); +public: + + DECLARE_NETWORKCLASS(); + DECLARE_PREDICTABLE(); + + CWeaponCrossbow( void ); + + void Precache( void ); + void PrimaryAttack( void ); + void SecondaryAttack( void ); + bool Reload( void ); + void WeaponIdle( void ); + bool Deploy( void ); + bool Holster( CBaseCombatWeapon *pSwitchingTo = NULL ); + +// DECLARE_SERVERCLASS(); + DECLARE_DATADESC(); + +#ifndef CLIENT_DLL +// DECLARE_ACTTABLE(); +#endif + +private: + void FireBolt( void ); + void ToggleZoom( void ); + +private: +// bool m_fInZoom; + CNetworkVar( bool, m_fInZoom ); +}; + +IMPLEMENT_NETWORKCLASS_ALIASED( WeaponCrossbow, DT_WeaponCrossbow ); + +BEGIN_NETWORK_TABLE( CWeaponCrossbow, DT_WeaponCrossbow ) +#ifdef CLIENT_DLL + RecvPropBool( RECVINFO( m_fInZoom ) ), +#else + SendPropBool( SENDINFO( m_fInZoom ) ), +#endif +END_NETWORK_TABLE() + +BEGIN_PREDICTION_DATA( CWeaponCrossbow ) +#ifdef CLIENT_DLL + DEFINE_PRED_FIELD( m_fInZoom, FIELD_BOOLEAN, FTYPEDESC_INSENDTABLE ), +#endif +END_PREDICTION_DATA() + +LINK_ENTITY_TO_CLASS( weapon_crossbow, CWeaponCrossbow ); + +PRECACHE_WEAPON_REGISTER( weapon_crossbow ); + +//IMPLEMENT_SERVERCLASS_ST( CWeaponCrossbow, DT_WeaponCrossbow ) +//END_SEND_TABLE() + +BEGIN_DATADESC( CWeaponCrossbow ) +END_DATADESC() + +#if 0 +#ifndef CLIENT_DLL + +acttable_t CWeaponCrossbow::m_acttable[] = +{ + { ACT_HL2MP_IDLE, ACT_HL2MP_IDLE_CROSSBOW, false }, +// { ACT_HL2MP_RUN, ACT_HL2MP_RUN_CROSSBOW, false }, +// { ACT_HL2MP_IDLE_CROUCH, ACT_HL2MP_IDLE_CROUCH_CROSSBOW, false }, +// { ACT_HL2MP_WALK_CROUCH, ACT_HL2MP_WALK_CROUCH_CROSSBOW, false }, +// { ACT_HL2MP_GESTURE_RANGE_ATTACK, ACT_HL2MP_GESTURE_RANGE_ATTACK_CROSSBOW, false }, +// { ACT_HL2MP_GESTURE_RELOAD, ACT_HL2MP_GESTURE_RELOAD_CROSSBOW, false }, +// { ACT_HL2MP_JUMP, ACT_HL2MP_JUMP_CROSSBOW, false }, +}; + +IMPLEMENT_ACTTABLE(CWeaponCrossbow); + +#endif +#endif + +//----------------------------------------------------------------------------- +// Purpose: Constructor +//----------------------------------------------------------------------------- +CWeaponCrossbow::CWeaponCrossbow( void ) +{ + m_bReloadsSingly = false; + m_bFiresUnderwater = true; + m_fInZoom = false; +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CWeaponCrossbow::Precache( void ) +{ +#ifndef CLIENT_DLL + UTIL_PrecacheOther( "crossbow_bolt" ); +#endif + + PrecacheScriptSound( "Weapon_Crossbow.BoltHitBody" ); + PrecacheScriptSound( "Weapon_Crossbow.BoltHitWorld" ); + + BaseClass::Precache(); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CWeaponCrossbow::PrimaryAttack( void ) +{ + if ( m_fInZoom && g_pGameRules->IsMultiplayer() ) + { +// FireSniperBolt(); + FireBolt(); + } + else + { + FireBolt(); + } +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CWeaponCrossbow::SecondaryAttack( void ) +{ + ToggleZoom(); + m_flNextSecondaryAttack = gpGlobals->curtime + 1.0; +} + + +void CWeaponCrossbow::FireBolt( void ) +{ + if ( m_iClip1 <= 0 ) + { + if ( !m_bFireOnEmpty ) + { + Reload(); + } + else + { + WeaponSound( EMPTY ); + m_flNextPrimaryAttack = 0.15; + } + + return; + } + + CBasePlayer *pOwner = ToBasePlayer( GetOwner() ); + + if ( pOwner == NULL ) + return; + + Vector vecAiming = pOwner->GetAutoaimVector( AUTOAIM_2DEGREES ); + Vector vecSrc = pOwner->Weapon_ShootPosition(); + + QAngle angAiming; + VectorAngles( vecAiming, angAiming ); + +#ifndef CLIENT_DLL + CCrossbowBolt *pBolt = CCrossbowBolt::BoltCreate( vecSrc, angAiming, pOwner ); + + // In multiplayer, secondary fire is instantaneous. + if ( g_pGameRules->IsMultiplayer() && m_fInZoom ) + { + Vector vecEnd = vecSrc + ( vecAiming * MAX_TRACE_LENGTH ); + + trace_t trace; + UTIL_TraceLine( vecSrc, vecEnd, MASK_SHOT, GetOwner(), COLLISION_GROUP_NONE, &trace ); + pBolt->SetAbsOrigin( trace.endpos ); + + // We hit someone + if ( trace.m_pEnt && trace.m_pEnt->m_takedamage ) + { + pBolt->SetExplode( false ); + pBolt->BoltTouch( trace.m_pEnt ); + return; + } + } + else + { + if ( pOwner->GetWaterLevel() == 3 ) + { + pBolt->SetAbsVelocity( vecAiming * BOLT_WATER_VELOCITY ); + } + else + { + pBolt->SetAbsVelocity( vecAiming * BOLT_AIR_VELOCITY ); + } + } + + pBolt->SetLocalAngularVelocity( QAngle( 0, 0, 10 ) ); + + if ( m_fInZoom || !g_pGameRules->IsMultiplayer() ) + { + pBolt->SetExplode( false ); + + } +#endif + + m_iClip1--; + + pOwner->ViewPunch( QAngle( -2, 0, 0 ) ); + + WeaponSound( SINGLE ); + WeaponSound( RELOAD ); + +#ifdef CLIENT_DLL +#else + CSoundEnt::InsertSound( SOUND_COMBAT, GetAbsOrigin(), 200, 0.2 ); +#endif + + if ( m_iClip1 > 0 ) + { + SendWeaponAnim( ACT_VM_PRIMARYATTACK ); + } + else if ( pOwner->GetAmmoCount(m_iPrimaryAmmoType) > 0 ) + { + SendWeaponAnim( ACT_VM_SECONDARYATTACK ); + } + + if ( !m_iClip1 && pOwner->GetAmmoCount( m_iPrimaryAmmoType ) <= 0 ) + { + // HEV suit - indicate out of ammo condition + pOwner->SetSuitUpdate("!HEV_AMO0", FALSE, 0); + } + + m_flNextPrimaryAttack = gpGlobals->curtime + 0.75; + m_flNextSecondaryAttack = gpGlobals->curtime + 0.75; + + if ( m_iClip1 > 0 ) + { + SetWeaponIdleTime( gpGlobals->curtime + 5.0 ); + } + else + { + SetWeaponIdleTime( gpGlobals->curtime + 0.75 ); + } +} + + +bool CWeaponCrossbow::Reload( void ) +{ + bool fRet; + + fRet = DefaultReload( GetMaxClip1(), GetMaxClip2(), ACT_VM_RELOAD ); + if ( fRet ) + { + if ( m_fInZoom ) + { + ToggleZoom(); + } + + WeaponSound( RELOAD ); + } + + return fRet; +} + + +void CWeaponCrossbow::WeaponIdle( void ) +{ + CBasePlayer *pPlayer = ToBasePlayer( GetOwner() ); + if ( pPlayer ) + { + pPlayer->GetAutoaimVector( AUTOAIM_2DEGREES ); + } + + if ( !HasWeaponIdleTimeElapsed() ) + return; + + int iAnim; + float flRand = random->RandomFloat( 0, 1 ); + if ( flRand <= 0.75 ) + { + if ( m_iClip1 <= 0 ) + iAnim = ACT_CROSSBOW_IDLE_UNLOADED; + else + iAnim = ACT_VM_IDLE; + } + else + { + if ( m_iClip1 <= 0 ) + iAnim = ACT_CROSSBOW_FIDGET_UNLOADED; + else + iAnim = ACT_VM_FIDGET; + } + + SendWeaponAnim( iAnim ); +} + + +bool CWeaponCrossbow::Deploy( void ) +{ + if ( m_iClip1 <= 0 ) + { + return DefaultDeploy( (char*)GetViewModel(), (char*)GetWorldModel(), ACT_CROSSBOW_DRAW_UNLOADED, (char*)GetAnimPrefix() ); + } + + return DefaultDeploy( (char*)GetViewModel(), (char*)GetWorldModel(), ACT_VM_DRAW, (char*)GetAnimPrefix() ); +} + + +bool CWeaponCrossbow::Holster( CBaseCombatWeapon *pSwitchingTo ) +{ + if ( m_fInZoom ) + { + ToggleZoom(); + } + + return BaseClass::Holster( pSwitchingTo ); +} + + +void CWeaponCrossbow::ToggleZoom( void ) +{ + CBasePlayer *pPlayer = ToBasePlayer( GetOwner() ); + if ( !pPlayer ) + { + return; + } + +#if !defined(CLIENT_DLL) + if ( m_fInZoom ) + { + if ( pPlayer->SetFOV( this, 0 ) ) + { + m_fInZoom = false; + } + } + else + { + if ( pPlayer->SetFOV( this, 20 ) ) + { + m_fInZoom = true; + } + } +#endif +} diff --git a/game/shared/hl1/hl1mp_weapon_egon.cpp b/game/shared/hl1/hl1mp_weapon_egon.cpp new file mode 100644 index 0000000..335f687 --- /dev/null +++ b/game/shared/hl1/hl1mp_weapon_egon.cpp @@ -0,0 +1,529 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: Egon +// +// $NoKeywords: $ +//=============================================================================// + +#include "cbase.h" +#include "npcevent.h" +#include "hl1mp_basecombatweapon_shared.h" +#include "Sprite.h" +#include "beam_shared.h" +#include "takedamageinfo.h" +//#include "basecombatcharacter.h" +//#include "AI_BaseNPC.h" + +#ifdef CLIENT_DLL +#include "c_baseplayer.h" +#include "hl1/hl1_c_player.h" +#else +#include "player.h" +#include "hl1_player.h" +#endif + +//#include "player.h" +#include "gamerules.h" +#include "in_buttons.h" + +#ifdef CLIENT_DLL +#else +#include "soundent.h" +#include "game.h" +#endif + + +#include "vstdlib/random.h" +#include "engine/IEngineSound.h" +#include "IEffects.h" +#ifdef CLIENT_DLL +#include "c_te_effect_dispatch.h" +#else +#include "te_effect_dispatch.h" +#endif + + +enum EGON_FIRESTATE { FIRE_OFF, FIRE_STARTUP, FIRE_CHARGE }; + +#define EGON_PULSE_INTERVAL 0.1 +#define EGON_DISCHARGE_INTERVAL 0.1 + +#define EGON_BEAM_SPRITE "sprites/xbeam1.vmt" +#define EGON_FLARE_SPRITE "sprites/XSpark1.vmt" + +extern ConVar sk_plr_dmg_egon_wide; + +//----------------------------------------------------------------------------- +// CWeaponEgon +//----------------------------------------------------------------------------- + +#ifdef CLIENT_DLL +#define CWeaponEgon C_WeaponEgon +#endif + +class CWeaponEgon : public CBaseHL1MPCombatWeapon +{ + DECLARE_CLASS( CWeaponEgon, CBaseHL1MPCombatWeapon ); +public: + + DECLARE_NETWORKCLASS(); + DECLARE_PREDICTABLE(); + + CWeaponEgon(void); + + virtual bool Deploy( void ); + void PrimaryAttack( void ); + virtual void Precache( void ); + + void SecondaryAttack( void ) + { + PrimaryAttack(); + } + + void WeaponIdle( void ); + bool Holster( CBaseCombatWeapon *pSwitchingTo = NULL ); + + // DECLARE_SERVERCLASS(); + // DECLARE_DATADESC(); + +private: + bool HasAmmo( void ); + void UseAmmo( int count ); + void Attack( void ); + void EndAttack( void ); + void Fire( const Vector &vecOrigSrc, const Vector &vecDir ); + void UpdateEffect( const Vector &startPoint, const Vector &endPoint ); + void CreateEffect( void ); + void DestroyEffect( void ); + + EGON_FIRESTATE m_fireState; + float m_flAmmoUseTime; // since we use < 1 point of ammo per update, we subtract ammo on a timer. + float m_flShakeTime; + float m_flStartFireTime; + float m_flDmgTime; + CHandle<CSprite> m_hSprite; + CHandle<CBeam> m_hBeam; + CHandle<CBeam> m_hNoise; +}; + +IMPLEMENT_NETWORKCLASS_ALIASED( WeaponEgon, DT_WeaponEgon ); + +BEGIN_NETWORK_TABLE( CWeaponEgon, DT_WeaponEgon ) +END_NETWORK_TABLE() + +BEGIN_PREDICTION_DATA( CWeaponEgon ) +END_PREDICTION_DATA() + +LINK_ENTITY_TO_CLASS( weapon_egon, CWeaponEgon ); +PRECACHE_WEAPON_REGISTER( weapon_egon ); + +/* +IMPLEMENT_SERVERCLASS_ST( CWeaponEgon, DT_WeaponEgon ) +END_SEND_TABLE() +*/ + + /* +BEGIN_DATADESC( CWeaponEgon ) + DEFINE_FIELD( m_fireState, FIELD_INTEGER ), + DEFINE_FIELD( m_flAmmoUseTime, FIELD_TIME ), + DEFINE_FIELD( m_flShakeTime, FIELD_TIME ), + DEFINE_FIELD( m_flStartFireTime, FIELD_TIME ), + DEFINE_FIELD( m_flDmgTime, FIELD_TIME ), + DEFINE_FIELD( m_hSprite, FIELD_EHANDLE ), + DEFINE_FIELD( m_hBeam, FIELD_EHANDLE ), + DEFINE_FIELD( m_hNoise, FIELD_EHANDLE ), +END_DATADESC() + */ + +//----------------------------------------------------------------------------- +// Purpose: Constructor +//----------------------------------------------------------------------------- +CWeaponEgon::CWeaponEgon( void ) +{ + m_bReloadsSingly = false; + m_bFiresUnderwater = true; +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CWeaponEgon::Precache( void ) +{ + PrecacheScriptSound( "Weapon_Gluon.Start" ); + PrecacheScriptSound( "Weapon_Gluon.Run" ); + PrecacheScriptSound( "Weapon_Gluon.Off" ); + + PrecacheModel( EGON_BEAM_SPRITE ); + PrecacheModel( EGON_FLARE_SPRITE ); + + BaseClass::Precache(); +} + +bool CWeaponEgon::Deploy( void ) +{ + m_fireState = FIRE_OFF; + + return BaseClass::Deploy(); +} + +bool CWeaponEgon::HasAmmo( void ) +{ + CHL1_Player *pPlayer = ToHL1Player( GetOwner() ); + if ( !pPlayer ) + { + return false; + } + + if ( pPlayer->GetAmmoCount( m_iPrimaryAmmoType ) <= 0 ) + return false; + + return true; +} + +void CWeaponEgon::UseAmmo( int count ) +{ + CHL1_Player *pPlayer = ToHL1Player( GetOwner() ); + if ( !pPlayer ) + { + return; + } + + if ( pPlayer->GetAmmoCount( m_iPrimaryAmmoType ) >= count ) + pPlayer->RemoveAmmo( count, m_iPrimaryAmmoType ); + else + pPlayer->RemoveAmmo( pPlayer->GetAmmoCount( m_iPrimaryAmmoType ), m_iPrimaryAmmoType ); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CWeaponEgon::PrimaryAttack( void ) +{ + CHL1_Player *pPlayer = ToHL1Player( GetOwner() ); + if ( !pPlayer ) + { + return; + } + + // don't fire underwater + if ( pPlayer->GetWaterLevel() == 3 ) + { + if ( m_fireState != FIRE_OFF || m_hBeam ) + { + EndAttack(); + } + else + { + WeaponSound( EMPTY ); + } + + m_flNextPrimaryAttack = gpGlobals->curtime + 0.5; + m_flNextSecondaryAttack = gpGlobals->curtime + 0.5; + return; + } + + Vector vecAiming = pPlayer->GetAutoaimVector( 0 ); + Vector vecSrc = pPlayer->Weapon_ShootPosition( ); + + switch( m_fireState ) + { + case FIRE_OFF: + { + if ( !HasAmmo() ) + { + m_flNextPrimaryAttack = gpGlobals->curtime + 0.25; + m_flNextSecondaryAttack = gpGlobals->curtime + 0.25; + WeaponSound( EMPTY ); + return; + } + + m_flAmmoUseTime = gpGlobals->curtime;// start using ammo ASAP. + + EmitSound( "Weapon_Gluon.Start" ); + + SendWeaponAnim( ACT_VM_PRIMARYATTACK ); + + m_flShakeTime = 0; + m_flStartFireTime = gpGlobals->curtime; + + SetWeaponIdleTime( gpGlobals->curtime + 0.1 ); + + m_flDmgTime = gpGlobals->curtime + EGON_PULSE_INTERVAL; + m_fireState = FIRE_STARTUP; + } + break; + + case FIRE_STARTUP: + { + Fire( vecSrc, vecAiming ); + + if ( gpGlobals->curtime >= ( m_flStartFireTime + 2.0 ) ) + { + EmitSound( "Weapon_Gluon.Run" ); + + m_fireState = FIRE_CHARGE; + } + + if ( !HasAmmo() ) + { + EndAttack(); + m_flNextPrimaryAttack = gpGlobals->curtime + 1.0; + m_flNextSecondaryAttack = gpGlobals->curtime + 1.0; + } + } + case FIRE_CHARGE: + { + Fire( vecSrc, vecAiming ); + + if ( !HasAmmo() ) + { + EndAttack(); + m_flNextPrimaryAttack = gpGlobals->curtime + 1.0; + m_flNextSecondaryAttack = gpGlobals->curtime + 1.0; + } + } + break; + } +} + +void CWeaponEgon::Fire( const Vector &vecOrigSrc, const Vector &vecDir ) +{ + CHL1_Player *pPlayer = ToHL1Player( GetOwner() ); + if ( !pPlayer ) + { + return; + } + + //CSoundEnt::InsertSound( SOUND_COMBAT, GetAbsOrigin(), 450, 0.1 ); + WeaponSound( SINGLE ); + + Vector vecDest = vecOrigSrc + (vecDir * MAX_TRACE_LENGTH); + + trace_t tr; + UTIL_TraceLine( vecOrigSrc, vecDest, MASK_SHOT, pPlayer, COLLISION_GROUP_NONE, &tr ); + + if ( tr.allsolid ) + return; + + CBaseEntity *pEntity = tr.m_pEnt; + if ( pEntity == NULL ) + return; + + if ( g_pGameRules->IsMultiplayer() ) + { + if ( m_hSprite ) + { + if ( pEntity->m_takedamage != DAMAGE_NO ) + { + m_hSprite->TurnOn(); + } + else + { + m_hSprite->TurnOff(); + } + } + } + + if ( m_flDmgTime < gpGlobals->curtime ) + { + // wide mode does damage to the ent, and radius damage + if ( pEntity->m_takedamage != DAMAGE_NO ) + { + ClearMultiDamage(); + CTakeDamageInfo info( this, pPlayer, sk_plr_dmg_egon_wide.GetFloat() * g_pGameRules->GetDamageMultiplier(), DMG_ENERGYBEAM | DMG_ALWAYSGIB ); + CalculateMeleeDamageForce( &info, vecDir, tr.endpos ); + pEntity->DispatchTraceAttack( info, vecDir, &tr ); + ApplyMultiDamage(); + } + + if ( g_pGameRules->IsMultiplayer() ) + { + // radius damage a little more potent in multiplayer. +#ifndef CLIENT_DLL + RadiusDamage( CTakeDamageInfo( this, pPlayer, sk_plr_dmg_egon_wide.GetFloat() * g_pGameRules->GetDamageMultiplier() / 4, DMG_ENERGYBEAM | DMG_BLAST | DMG_ALWAYSGIB ), tr.endpos, 128, CLASS_NONE, NULL ); +#endif + } + + if ( !pPlayer->IsAlive() ) + return; + + if ( g_pGameRules->IsMultiplayer() ) + { + //multiplayer uses 5 ammo/second + if ( gpGlobals->curtime >= m_flAmmoUseTime ) + { + UseAmmo( 1 ); + m_flAmmoUseTime = gpGlobals->curtime + 0.2; + } + } + else + { + // Wide mode uses 10 charges per second in single player + if ( gpGlobals->curtime >= m_flAmmoUseTime ) + { + UseAmmo( 1 ); + m_flAmmoUseTime = gpGlobals->curtime + 0.1; + } + } + + m_flDmgTime = gpGlobals->curtime + EGON_DISCHARGE_INTERVAL; + if ( m_flShakeTime < gpGlobals->curtime ) + { +#ifndef CLIENT_DLL + UTIL_ScreenShake( tr.endpos, 5.0, 150.0, 0.75, 250.0, SHAKE_START ); +#endif + m_flShakeTime = gpGlobals->curtime + 1.5; + } + } + + Vector vecUp, vecRight; + QAngle angDir; + + VectorAngles( vecDir, angDir ); + AngleVectors( angDir, NULL, &vecRight, &vecUp ); + + Vector tmpSrc = vecOrigSrc + (vecUp * -8) + (vecRight * 3); + UpdateEffect( tmpSrc, tr.endpos ); +} + +void CWeaponEgon::UpdateEffect( const Vector &startPoint, const Vector &endPoint ) +{ + if ( !m_hBeam ) + { + CreateEffect(); + } + + if ( m_hBeam ) + { + m_hBeam->SetStartPos( endPoint ); + } + + if ( m_hSprite ) + { + m_hSprite->SetAbsOrigin( endPoint ); + + m_hSprite->m_flFrame += 8 * gpGlobals->frametime; + if ( m_hSprite->m_flFrame > m_hSprite->Frames() ) + m_hSprite->m_flFrame = 0; + } + + if ( m_hNoise ) + { + m_hNoise->SetStartPos( endPoint ); + } +} + +void CWeaponEgon::CreateEffect( void ) +{ +#ifndef CLIENT_DLL + CHL1_Player *pPlayer = ToHL1Player( GetOwner() ); + if ( !pPlayer ) + { + return; + } + + DestroyEffect(); + + m_hBeam = CBeam::BeamCreate( EGON_BEAM_SPRITE, 3.5 ); + m_hBeam->PointEntInit( GetAbsOrigin(), this ); + m_hBeam->SetBeamFlags( FBEAM_SINENOISE ); + m_hBeam->SetEndAttachment( 1 ); + m_hBeam->AddSpawnFlags( SF_BEAM_TEMPORARY ); // Flag these to be destroyed on save/restore or level transition + m_hBeam->SetOwnerEntity( pPlayer ); + m_hBeam->SetScrollRate( 10 ); + m_hBeam->SetBrightness( 200 ); + m_hBeam->SetColor( 50, 50, 255 ); + m_hBeam->SetNoise( 0.2 ); + + m_hNoise = CBeam::BeamCreate( EGON_BEAM_SPRITE, 5.0 ); + m_hNoise->PointEntInit( GetAbsOrigin(), this ); + m_hNoise->SetEndAttachment( 1 ); + m_hNoise->AddSpawnFlags( SF_BEAM_TEMPORARY ); + m_hNoise->SetOwnerEntity( pPlayer ); + m_hNoise->SetScrollRate( 25 ); + m_hNoise->SetBrightness( 200 ); + m_hNoise->SetColor( 50, 50, 255 ); + m_hNoise->SetNoise( 0.8 ); + + m_hSprite = CSprite::SpriteCreate( EGON_FLARE_SPRITE, GetAbsOrigin(), false ); + m_hSprite->SetScale( 1.0 ); + m_hSprite->SetTransparency( kRenderGlow, 255, 255, 255, 255, kRenderFxNoDissipation ); + m_hSprite->AddSpawnFlags( SF_SPRITE_TEMPORARY ); + m_hSprite->SetOwnerEntity( pPlayer ); +#endif +} + + +void CWeaponEgon::DestroyEffect( void ) +{ +#ifndef CLIENT_DLL + if ( m_hBeam ) + { + UTIL_Remove( m_hBeam ); + m_hBeam = NULL; + } + if ( m_hNoise ) + { + UTIL_Remove( m_hNoise ); + m_hNoise = NULL; + } + if ( m_hSprite ) + { + m_hSprite->Expand( 10, 500 ); + m_hSprite = NULL; + } +#endif +} + +void CWeaponEgon::EndAttack( void ) +{ + StopSound( "Weapon_Gluon.Run" ); + + if ( m_fireState != FIRE_OFF ) + { + EmitSound( "Weapon_Gluon.Off" ); + } + + SetWeaponIdleTime( gpGlobals->curtime + 2.0 ); + m_flNextPrimaryAttack = gpGlobals->curtime + 0.5; + m_flNextSecondaryAttack = gpGlobals->curtime + 0.5; + + m_fireState = FIRE_OFF; + + DestroyEffect(); +} + +bool CWeaponEgon::Holster( CBaseCombatWeapon *pSwitchingTo ) +{ + EndAttack(); + + return BaseClass::Holster( pSwitchingTo ); +} + +void CWeaponEgon::WeaponIdle( void ) +{ + if ( !HasWeaponIdleTimeElapsed() ) + return; + + if ( m_fireState != FIRE_OFF ) + EndAttack(); + + int iAnim; + + float flRand = random->RandomFloat( 0,1 ); + float flIdleTime; + if ( flRand <= 0.5 ) + { + iAnim = ACT_VM_IDLE; + flIdleTime = gpGlobals->curtime + random->RandomFloat( 10, 15 ); + } + else + { + iAnim = ACT_VM_FIDGET; + flIdleTime = gpGlobals->curtime + 3.0; + } + + SendWeaponAnim( iAnim ); + + SetWeaponIdleTime( flIdleTime ); +} diff --git a/game/shared/hl1/hl1mp_weapon_gauss.cpp b/game/shared/hl1/hl1mp_weapon_gauss.cpp new file mode 100644 index 0000000..e40f95d --- /dev/null +++ b/game/shared/hl1/hl1mp_weapon_gauss.cpp @@ -0,0 +1,719 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: Gauss +// +// $NoKeywords: $ +//=============================================================================// + +#include "cbase.h" +#include "npcevent.h" +#include "hl1mp_basecombatweapon_shared.h" +//#include "basecombatcharacter.h" +//#include "AI_BaseNPC.h" +#include "takedamageinfo.h" +#ifdef CLIENT_DLL +#include "hl1/hl1_c_player.h" +#else +#include "hl1_player.h" +#endif +#include "gamerules.h" +#include "in_buttons.h" +#ifdef CLIENT_DLL +#else +#include "soundent.h" +#include "game.h" +#endif +#include "vstdlib/random.h" +#include "engine/IEngineSound.h" +#include "soundenvelope.h" +//#include "hl1_player.h" +#include "shake.h" +#include "effect_dispatch_data.h" +#ifdef CLIENT_DLL +#include "c_te_effect_dispatch.h" +#else +#include "te_effect_dispatch.h" +#endif +#include "SoundEmitterSystem/isoundemittersystembase.h" + +#define GAUSS_GLOW_SPRITE "sprites/hotglow.vmt" +#define GAUSS_BEAM_SPRITE "sprites/smoke.vmt" + + +extern ConVar sk_plr_dmg_gauss; + +#ifdef CLIENT_DLL +#define CWeaponGauss C_WeaponGauss +#endif + +//----------------------------------------------------------------------------- +// CWeaponGauss +//----------------------------------------------------------------------------- + + +class CWeaponGauss : public CBaseHL1MPCombatWeapon +{ + DECLARE_CLASS( CWeaponGauss, CBaseHL1MPCombatWeapon ); +public: + + DECLARE_NETWORKCLASS(); + DECLARE_PREDICTABLE(); + + CWeaponGauss( void ); + + void Precache( void ); + void PrimaryAttack( void ); + void SecondaryAttack( void ); + void WeaponIdle( void ); + void AddViewKick( void ); + bool Deploy( void ); + bool Holster( CBaseCombatWeapon *pSwitchingTo = NULL ); + +// DECLARE_SERVERCLASS(); + DECLARE_DATADESC(); + +private: + void StopSpinSound( void ); + float GetFullChargeTime( void ); + void StartFire( void ); + void Fire( Vector vecOrigSrc, Vector vecDir, float flDamage ); + +private: +// int m_nAttackState; +// bool m_bPrimaryFire; + CNetworkVar( int, m_nAttackState); + CNetworkVar( bool, m_bPrimaryFire); + + CSoundPatch *m_sndCharge; +}; + +IMPLEMENT_NETWORKCLASS_ALIASED( WeaponGauss, DT_WeaponGauss ); + +BEGIN_NETWORK_TABLE( CWeaponGauss, DT_WeaponGauss ) +#ifdef CLIENT_DLL + RecvPropInt( RECVINFO( m_nAttackState ) ), + RecvPropBool( RECVINFO( m_bPrimaryFire ) ), +#else + SendPropInt( SENDINFO( m_nAttackState ) ), + SendPropBool( SENDINFO( m_bPrimaryFire ) ), +#endif +END_NETWORK_TABLE() + +BEGIN_PREDICTION_DATA( CWeaponGauss ) +#ifdef CLIENT_DLL + DEFINE_PRED_FIELD( m_nAttackState, FIELD_INTEGER, FTYPEDESC_INSENDTABLE ), + DEFINE_PRED_FIELD( m_bPrimaryFire, FIELD_BOOLEAN, FTYPEDESC_INSENDTABLE ), +#endif +END_PREDICTION_DATA() + +LINK_ENTITY_TO_CLASS( weapon_gauss, CWeaponGauss ); + +PRECACHE_WEAPON_REGISTER( weapon_gauss ); + +//IMPLEMENT_SERVERCLASS_ST( CWeaponGauss, DT_WeaponGauss ) +//END_SEND_TABLE() + +BEGIN_DATADESC( CWeaponGauss ) + DEFINE_FIELD( m_nAttackState, FIELD_INTEGER ), + DEFINE_FIELD( m_bPrimaryFire, FIELD_BOOLEAN ), + DEFINE_SOUNDPATCH( m_sndCharge ), +END_DATADESC() + +//----------------------------------------------------------------------------- +// Purpose: Constructor +//----------------------------------------------------------------------------- +CWeaponGauss::CWeaponGauss( void ) +{ + m_bReloadsSingly = false; + m_bFiresUnderwater = false; + + m_bPrimaryFire = false; + m_nAttackState = 0; + m_sndCharge = NULL; +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CWeaponGauss::Precache( void ) +{ + PrecacheModel( GAUSS_GLOW_SPRITE ); + PrecacheModel( GAUSS_BEAM_SPRITE ); + + PrecacheScriptSound( "Weapon_Gauss.Zap1" ); + PrecacheScriptSound( "Weapon_Gauss.Zap2" ); + PrecacheScriptSound( "Weapon_Gauss.Fire" ); + PrecacheScriptSound( "Weapon_Gauss.StaticDischarge" ); + PrecacheScriptSound( "Weapon_Gauss.Spin" ); + + BaseClass::Precache(); +} + +float CWeaponGauss::GetFullChargeTime( void ) +{ + if ( g_pGameRules->IsMultiplayer() ) + { + return 1.5; + } + else + { + return 4; + } +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CWeaponGauss::PrimaryAttack( void ) +{ + CBasePlayer *pPlayer = ToBasePlayer( GetOwner() ); + if ( !pPlayer ) + { + return; + } + + if ( pPlayer->GetAmmoCount( m_iPrimaryAmmoType ) < 2 ) + { + WeaponSound( EMPTY ); + pPlayer->SetNextAttack( gpGlobals->curtime + 0.5 ); + return; + } + +//FIXME pPlayer->m_iWeaponVolume = GAUSS_PRIMARY_FIRE_VOLUME; + m_bPrimaryFire = true; + + pPlayer->RemoveAmmo( 2, m_iPrimaryAmmoType ); + + StartFire(); + m_nAttackState = 0; + SetWeaponIdleTime( gpGlobals->curtime + 1.0 ); + pPlayer->SetNextAttack( gpGlobals->curtime + 0.2 ); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CWeaponGauss::SecondaryAttack( void ) +{ + CHL1_Player *pPlayer = ToHL1Player( GetOwner() ); + if ( !pPlayer ) + { + return; + } + + // don't fire underwater + if ( pPlayer->GetWaterLevel() == 3 ) + { + if ( m_nAttackState != 0 ) + { + EmitSound( "Weapon_Gauss.Zap1" ); + SendWeaponAnim( ACT_VM_IDLE ); + m_nAttackState = 0; + } + else + { + WeaponSound( EMPTY ); + } + + m_flNextSecondaryAttack = m_flNextPrimaryAttack = gpGlobals->curtime + 0.5; + return; + } + + if ( m_nAttackState == 0 ) + { + if ( pPlayer->GetAmmoCount( m_iPrimaryAmmoType ) <= 0 ) + { + WeaponSound( EMPTY ); + pPlayer->SetNextAttack( gpGlobals->curtime + 0.5 ); + return; + } + + m_bPrimaryFire = false; + + pPlayer->RemoveAmmo( 1, m_iPrimaryAmmoType ); // take one ammo just to start the spin + pPlayer->m_flNextAmmoBurn = gpGlobals->curtime; + + // spin up +//FIXME pPlayer->m_iWeaponVolume = GAUSS_PRIMARY_CHARGE_VOLUME; + + SendWeaponAnim( ACT_GAUSS_SPINUP ); + m_nAttackState = 1; + SetWeaponIdleTime( gpGlobals->curtime + 0.5 ); + pPlayer->m_flStartCharge = gpGlobals->curtime; + pPlayer->m_flAmmoStartCharge = gpGlobals->curtime + GetFullChargeTime(); + + //Start looping sound + if ( m_sndCharge == NULL ) + { + CPASAttenuationFilter filter( this ); + m_sndCharge = (CSoundEnvelopeController::GetController()).SoundCreate( filter, entindex(), CHAN_WEAPON, "Weapon_Gauss.Spin", ATTN_NORM ); + } + + if ( m_sndCharge != NULL ) + { + (CSoundEnvelopeController::GetController()).Play( m_sndCharge, 1.0f, 110 ); + } + } + else if (m_nAttackState == 1) + { + if ( HasWeaponIdleTimeElapsed() ) + { + SendWeaponAnim( ACT_GAUSS_SPINCYCLE ); + m_nAttackState = 2; + } + } + else + { + // during the charging process, eat one bit of ammo every once in a while + if ( gpGlobals->curtime >= pPlayer->m_flNextAmmoBurn && pPlayer->m_flNextAmmoBurn != 1000 ) + { + pPlayer->RemoveAmmo( 1, m_iPrimaryAmmoType ); + + if ( g_pGameRules->IsMultiplayer() ) + { + pPlayer->m_flNextAmmoBurn = gpGlobals->curtime + 0.1; + } + else + { + pPlayer->m_flNextAmmoBurn = gpGlobals->curtime + 0.3; + } + } + + if ( pPlayer->GetAmmoCount( m_iPrimaryAmmoType ) <= 0 ) + { + // out of ammo! force the gun to fire + StartFire(); + m_nAttackState = 0; + SetWeaponIdleTime( gpGlobals->curtime + 1.0 ); + pPlayer->SetNextAttack( gpGlobals->curtime + 1 ); + return; + } + + if ( gpGlobals->curtime >= pPlayer->m_flAmmoStartCharge ) + { + // don't eat any more ammo after gun is fully charged. + pPlayer->m_flNextAmmoBurn = 1000; + } + + int pitch = ( gpGlobals->curtime - pPlayer->m_flStartCharge ) * ( 150 / GetFullChargeTime() ) + 100; + if ( pitch > 250 ) + pitch = 250; + + // ALERT( at_console, "%d %d %d\n", m_nAttackState, m_iSoundState, pitch ); + +// if ( m_iSoundState == 0 ) +// ALERT( at_console, "sound state %d\n", m_iSoundState ); + + if ( m_sndCharge != NULL ) + { + (CSoundEnvelopeController::GetController()).SoundChangePitch( m_sndCharge, pitch, 0 ); + } + +//FIXME m_pPlayer->m_iWeaponVolume = GAUSS_PRIMARY_CHARGE_VOLUME; + + // m_flTimeWeaponIdle = gpGlobals->curtime + 0.1; + if ( pPlayer->m_flStartCharge < gpGlobals->curtime - 10 ) + { + // Player charged up too long. Zap him. + EmitSound( "Weapon_Gauss.Zap1" ); + EmitSound( "Weapon_Gauss.Zap2" ); + + m_nAttackState = 0; + SetWeaponIdleTime( gpGlobals->curtime + 1.0 ); + pPlayer->SetNextAttack( gpGlobals->curtime + 1.0 ); + +#if !defined(CLIENT_DLL ) + // Add DMG_CRUSH because we don't want any physics force + pPlayer->TakeDamage( CTakeDamageInfo( this, this, 50, DMG_SHOCK | DMG_CRUSH ) ); + + color32 gaussDamage = {255,128,0,128}; + UTIL_ScreenFade( pPlayer, gaussDamage, 2, 0.5, FFADE_IN ); +#endif + + SendWeaponAnim( ACT_VM_IDLE ); + + StopSpinSound(); + // Player may have been killed and this weapon dropped, don't execute any more code after this! + return; + } + } +} + +//========================================================= +// StartFire- since all of this code has to run and then +// call Fire(), it was easier at this point to rip it out +// of weaponidle() and make its own function then to try to +// merge this into Fire(), which has some identical variable names +//========================================================= +void CWeaponGauss::StartFire( void ) +{ + float flDamage; + + CHL1_Player *pPlayer = ToHL1Player( GetOwner() ); + if ( !pPlayer ) + { + return; + } + + Vector vecAiming = pPlayer->GetAutoaimVector( 0 ); + Vector vecSrc = pPlayer->Weapon_ShootPosition( ); + + if ( gpGlobals->curtime - pPlayer->m_flStartCharge > GetFullChargeTime() ) + { + flDamage = 200; + } + else + { + flDamage = 200 * (( gpGlobals->curtime - pPlayer->m_flStartCharge) / GetFullChargeTime() ); + } + + if ( m_bPrimaryFire ) + { + flDamage = sk_plr_dmg_gauss.GetFloat() * g_pGameRules->GetDamageMultiplier(); + } + + //ALERT ( at_console, "Time:%f Damage:%f\n", gpGlobals->curtime - m_pPlayer->m_flStartCharge, flDamage ); + Vector vecNewVel = pPlayer->GetAbsVelocity(); + float flZVel = vecNewVel.z; + + if ( !m_bPrimaryFire ) + { + vecNewVel = vecNewVel - vecAiming * flDamage * 5; + pPlayer->SetAbsVelocity( vecNewVel ); + } + + if ( !g_pGameRules->IsMultiplayer() ) + { + // in deathmatch, gauss can pop you up into the air. Not in single play. + vecNewVel.z = flZVel; + pPlayer->SetAbsVelocity( vecNewVel ); + } + + // player "shoot" animation + pPlayer->SetAnimation( PLAYER_ATTACK1 ); + + // time until aftershock 'static discharge' sound + pPlayer->m_flPlayAftershock = gpGlobals->curtime + random->RandomFloat( 0.3, 0.8 ); + + Fire( vecSrc, vecAiming, flDamage ); +} + +void CWeaponGauss::Fire( Vector vecOrigSrc, Vector vecDir, float flDamage ) +{ + CBaseEntity *pIgnore; + Vector vecSrc = vecOrigSrc; + Vector vecDest = vecSrc + vecDir * MAX_TRACE_LENGTH; + bool fFirstBeam = true; + bool fHasPunched = false; + float flMaxFrac = 1.0; + int nMaxHits = 10; + + CBasePlayer *pPlayer = ToBasePlayer( GetOwner() ); + if ( !pPlayer ) + { + return; + } + +//FIXME pPlayer->m_iWeaponVolume = GAUSS_PRIMARY_FIRE_VOLUME; + + StopSpinSound(); + + pIgnore = pPlayer; + +// ALERT( at_console, "%f %f\n", tr.flFraction, flMaxFrac ); + + while ( flDamage > 10 && nMaxHits > 0 ) + { + trace_t tr; + + nMaxHits--; + + // ALERT( at_console, "." ); + UTIL_TraceLine( vecSrc, vecDest, MASK_SHOT, pIgnore, COLLISION_GROUP_NONE, &tr ); + + if ( tr.allsolid ) + break; + + CBaseEntity *pEntity = tr.m_pEnt; + if (pEntity == NULL) + break; + + CBroadcastRecipientFilter filter; + CEffectData data6; + if ( fFirstBeam ) + { + pPlayer->DoMuzzleFlash(); + fFirstBeam = false; + + data6.m_vOrigin = tr.endpos; +// data6.m_nEntIndex = pPlayer->GetViewModel()->entindex(); +#ifdef CLIENT_DLL + data6.m_hEntity = pPlayer; +#else + data6.m_nEntIndex = pPlayer->entindex(); +#endif + data6.m_fFlags = m_bPrimaryFire; + te->DispatchEffect( filter, 0.0, data6.m_vOrigin, "HL1GaussBeam", data6 ); + } + else + { + data6.m_vOrigin = tr.endpos; + data6.m_vStart = vecSrc; + data6.m_fFlags = m_bPrimaryFire; + te->DispatchEffect( filter, 0.0, data6.m_vOrigin, "HL1GaussBeamReflect", data6 ); + } + + bool fShouldDamageEntity = ( pEntity->m_takedamage != DAMAGE_NO ); + + if ( fShouldDamageEntity ) + { + ClearMultiDamage(); + CTakeDamageInfo info( this, pPlayer, flDamage, DMG_ENERGYBEAM ); + CalculateMeleeDamageForce( &info, vecDir, tr.endpos ); + pEntity->DispatchTraceAttack( info, vecDir, &tr ); + ApplyMultiDamage(); + } + + if ( pEntity->IsBSPModel() && !fShouldDamageEntity ) + { + float n; + + pIgnore = NULL; + + n = -DotProduct( tr.plane.normal, vecDir ); + + if ( n < 0.5 ) // 60 degrees + { + // ALERT( at_console, "reflect %f\n", n ); + // reflect + Vector vecReflect; + + vecReflect = 2.0 * tr.plane.normal * n + vecDir; + flMaxFrac = flMaxFrac - tr.fraction; + vecDir = vecReflect; + vecSrc = tr.endpos;// + vecDir * 8; + vecDest = vecSrc + vecDir * MAX_TRACE_LENGTH; + +#if !defined(CLIENT_DLL) + // explode a bit + RadiusDamage( CTakeDamageInfo( this, pPlayer, flDamage * n, DMG_BLAST ), tr.endpos, flDamage * n * 2.5, CLASS_NONE, NULL ); +#endif + + CEffectData data1; + data1.m_vOrigin = tr.endpos; + data1.m_vNormal = tr.plane.normal; + data1.m_flMagnitude = flDamage * n; + DispatchEffect( "HL1GaussReflect", data1 ); + + // lose energy + if (n == 0) + n = 0.1; + + flDamage = flDamage * (1 - n); + } + else + { + // tunnel + UTIL_ImpactTrace( &tr, DMG_ENERGYBEAM ); + + CEffectData data4; + data4.m_vOrigin = tr.endpos; + data4.m_flMagnitude = flDamage; + DispatchEffect( "HL1GaussWallImpact1", data4 ); + + // limit it to one hole punch + if ( fHasPunched ) + break; + + fHasPunched = true; + + // try punching through wall if secondary attack (primary is incapable of breaking through) + if ( !m_bPrimaryFire ) + { + trace_t punch_tr; + + UTIL_TraceLine( tr.endpos + vecDir * 8, vecDest, MASK_SHOT, pIgnore, COLLISION_GROUP_NONE, &punch_tr); + if ( !punch_tr.allsolid ) + { + trace_t exit_tr; + // trace backwards to find exit point + UTIL_TraceLine( punch_tr.endpos, tr.endpos, MASK_SHOT, pIgnore, COLLISION_GROUP_NONE, &exit_tr); + + float n = (exit_tr.endpos - tr.endpos).Length( ); + + if ( n < flDamage ) + { + if (n == 0) + n = 1; + + flDamage -= n; + + CEffectData data2; + data2.m_vOrigin = tr.endpos; + data2.m_vNormal = vecDir; + DispatchEffect( "HL1GaussWallPunchEnter", data2 ); + + UTIL_ImpactTrace( &exit_tr, DMG_ENERGYBEAM ); + + CEffectData data3; + data3.m_vOrigin = exit_tr.endpos; + data3.m_vNormal = vecDir; + data3.m_flMagnitude = flDamage; + DispatchEffect( "HL1GaussWallPunchExit", data3 ); + + // ALERT( at_console, "punch %f\n", n ); + + // exit blast damage + float flDamageRadius; + + if ( g_pGameRules->IsMultiplayer() ) + { + flDamageRadius = flDamage * 1.75; // Old code == 2.5 + } + else + { + flDamageRadius = flDamage * 2.5; + } + +#if !defined( CLIENT_DLL) + RadiusDamage( CTakeDamageInfo( this, pPlayer, flDamage, DMG_BLAST ), exit_tr.endpos + vecDir * 8, flDamageRadius, CLASS_NONE, NULL ); + + CSoundEnt::InsertSound( SOUND_COMBAT, GetAbsOrigin(), 1024, 3.0 ); +#endif + + vecSrc = exit_tr.endpos + vecDir; + } + } + else + { + //ALERT( at_console, "blocked %f\n", n ); + flDamage = 0; + } + } + else + { + //ALERT( at_console, "blocked solid\n" ); + if ( m_bPrimaryFire ) + { + // slug doesn't punch through ever with primary + // fire, so leave a little glowy bit and make some balls + CEffectData data5; + data5.m_vOrigin = tr.endpos; + data5.m_vNormal = tr.plane.normal; + DispatchEffect( "HL1GaussWallImpact2", data5 ); +#if !defined( CLIENT_DLL) + CSoundEnt::InsertSound( SOUND_COMBAT, GetAbsOrigin(), 600, 0.5 ); +#endif + } + + flDamage = 0; + } + + } + } + else + { + vecSrc = tr.endpos + vecDir; + pIgnore = pEntity; + } + } + + pPlayer->ViewPunch( QAngle( -2, 0, 0 ) ); + SendWeaponAnim( ACT_VM_PRIMARYATTACK ); + + CPASAttenuationFilter filter( this ); + + CSoundParameters params; + if ( GetParametersForSound( "Weapon_Gauss.Fire", params, NULL ) ) + { + EmitSound_t ep( params ); + ep.m_flVolume = 0.5 + flDamage * (1.0 / 400.0); + EmitSound( filter, entindex(), ep ); + } +} + +void CWeaponGauss::WeaponIdle( void ) +{ + CHL1_Player *pPlayer = ToHL1Player( GetOwner() ); + if ( !pPlayer ) + { + return; + } + + // play aftershock static discharge + if ( pPlayer->m_flPlayAftershock && pPlayer->m_flPlayAftershock < gpGlobals->curtime ) + { + EmitSound( "Weapon_Gauss.StaticDischarge" ); + pPlayer->m_flPlayAftershock = 0.0; + } + + if ( !HasWeaponIdleTimeElapsed() ) + return; + + if ( m_nAttackState != 0 ) + { + StartFire(); + m_nAttackState = 0; + SetWeaponIdleTime( gpGlobals->curtime + 2.0 ); + } + else + { + float flRand = random->RandomFloat( 0, 1 ); + if ( flRand <= 0.75 ) + { + SendWeaponAnim( ACT_VM_IDLE ); + SetWeaponIdleTime( gpGlobals->curtime + random->RandomFloat( 10, 15 ) ); + } + else + { + SendWeaponAnim( ACT_VM_FIDGET ); + SetWeaponIdleTime( gpGlobals->curtime + 3 ); + } + } +} + +/* +================================================== +AddViewKick +================================================== +*/ + +void CWeaponGauss::AddViewKick( void ) +{ +} + +bool CWeaponGauss::Deploy( void ) +{ + if ( DefaultDeploy( (char*)GetViewModel(), (char*)GetWorldModel(), ACT_VM_DRAW, (char*)GetAnimPrefix() ) ) + { + CHL1_Player *pPlayer = ToHL1Player( GetOwner() ); + if ( pPlayer ) + { + pPlayer->m_flPlayAftershock = 0.0; + } + + return true; + } + else + { + return false; + } +} + +bool CWeaponGauss::Holster( CBaseCombatWeapon *pSwitchingTo ) +{ + + StopSpinSound(); + m_nAttackState = 0; + + return BaseClass::Holster(pSwitchingTo); +} + +void CWeaponGauss::StopSpinSound( void ) +{ + if ( m_sndCharge != NULL ) + { + (CSoundEnvelopeController::GetController()).SoundDestroy( m_sndCharge ); + m_sndCharge = NULL; + } +} diff --git a/game/shared/hl1/hl1mp_weapon_glock.cpp b/game/shared/hl1/hl1mp_weapon_glock.cpp new file mode 100644 index 0000000..a80b069 --- /dev/null +++ b/game/shared/hl1/hl1mp_weapon_glock.cpp @@ -0,0 +1,205 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: Glock - hand gun +// +// $NoKeywords: $ +//=============================================================================// + +#include "cbase.h" +#include "npcevent.h" +#include "hl1mp_basecombatweapon_shared.h" +//#include "basecombatcharacter.h" +//#include "AI_BaseNPC.h" +#ifdef CLIENT_DLL +#include "c_baseplayer.h" +#else +#include "player.h" +#endif +#include "gamerules.h" +#include "in_buttons.h" +#ifdef CLIENT_DLL +#else +#include "soundent.h" +#include "game.h" +#endif +#include "vstdlib/random.h" +#include "engine/IEngineSound.h" + +#ifdef CLIENT_DLL +#define CWeaponGlock C_WeaponGlock +#endif + +class CWeaponGlock : public CBaseHL1MPCombatWeapon +{ + DECLARE_CLASS( CWeaponGlock, CBaseHL1MPCombatWeapon ); + + DECLARE_NETWORKCLASS(); + DECLARE_PREDICTABLE(); + +public: + + CWeaponGlock(void); + + void Precache( void ); + void PrimaryAttack( void ); + void SecondaryAttack( void ); + bool Reload( void ); + void WeaponIdle( void ); + void DryFire( void ); + +private: + void GlockFire( float flSpread , float flCycleTime, bool fUseAutoAim ); +}; + +IMPLEMENT_NETWORKCLASS_ALIASED( WeaponGlock, DT_WeaponGlock ); + +BEGIN_NETWORK_TABLE( CWeaponGlock, DT_WeaponGlock ) +END_NETWORK_TABLE() + +LINK_ENTITY_TO_CLASS( weapon_glock, CWeaponGlock ); + +BEGIN_PREDICTION_DATA( CWeaponGlock ) +END_PREDICTION_DATA() + +PRECACHE_WEAPON_REGISTER( weapon_glock ); + + +CWeaponGlock::CWeaponGlock( void ) +{ + m_bReloadsSingly = false; + m_bFiresUnderwater = true; +} + + +void CWeaponGlock::Precache( void ) +{ + + BaseClass::Precache(); +} + + +void CWeaponGlock::DryFire( void ) +{ + WeaponSound( EMPTY ); + SendWeaponAnim( ACT_VM_DRYFIRE ); + + m_flNextPrimaryAttack = gpGlobals->curtime + 0.2; +} + + +void CWeaponGlock::PrimaryAttack( void ) +{ + GlockFire( 0.01, 0.3, TRUE ); +} + + +void CWeaponGlock::SecondaryAttack( void ) +{ + GlockFire( 0.1, 0.2, FALSE ); +} + + +void CWeaponGlock::GlockFire( float flSpread , float flCycleTime, bool fUseAutoAim ) +{ + // Only the player fires this way so we can cast + CBasePlayer *pPlayer = ToBasePlayer( GetOwner() ); + + if ( !pPlayer ) + { + return; + } + + if ( m_iClip1 <= 0 ) + { + if ( !m_bFireOnEmpty ) + { + Reload(); + } + else + { + DryFire(); + } + + return; + } + + WeaponSound( SINGLE ); + + pPlayer->DoMuzzleFlash(); + + m_iClip1--; + + if ( m_iClip1 == 0 ) + SendWeaponAnim( ACT_GLOCK_SHOOTEMPTY ); + else + SendWeaponAnim( ACT_VM_PRIMARYATTACK ); + + pPlayer->SetAnimation( PLAYER_ATTACK1 ); + + m_flNextPrimaryAttack = gpGlobals->curtime + flCycleTime; + m_flNextSecondaryAttack = gpGlobals->curtime + flCycleTime; + + Vector vecSrc = pPlayer->Weapon_ShootPosition(); + Vector vecAiming; + + if ( fUseAutoAim ) + { + vecAiming = pPlayer->GetAutoaimVector( AUTOAIM_10DEGREES ); + } + else + { + vecAiming = pPlayer->GetAutoaimVector( 0 ); + } + +// pPlayer->FireBullets( 1, vecSrc, vecAiming, Vector( flSpread, flSpread, flSpread ), MAX_TRACE_LENGTH, m_iPrimaryAmmoType, 0 ); + FireBulletsInfo_t info( 1, vecSrc, vecAiming, Vector( flSpread, flSpread, flSpread ), MAX_TRACE_LENGTH, m_iPrimaryAmmoType ); + info.m_pAttacker = pPlayer; + pPlayer->FireBullets( info ); + + EjectShell( pPlayer, 0 ); + + pPlayer->ViewPunch( QAngle( -2, 0, 0 ) ); +#if !defined(CLIENT_DLL) + pPlayer->SetMuzzleFlashTime( gpGlobals->curtime + 0.5 ); + + CSoundEnt::InsertSound( SOUND_COMBAT, GetAbsOrigin(), 400, 0.2 ); +#endif + + if ( !m_iClip1 && pPlayer->GetAmmoCount( m_iPrimaryAmmoType ) <= 0 ) + { + // HEV suit - indicate out of ammo condition + pPlayer->SetSuitUpdate("!HEV_AMO0", FALSE, 0); + } + + SetWeaponIdleTime( gpGlobals->curtime + random->RandomFloat( 10, 15 ) ); +} + + +bool CWeaponGlock::Reload( void ) +{ + bool iResult; + + if ( m_iClip1 == 0 ) + iResult = DefaultReload( GetMaxClip1(), GetMaxClip2(), ACT_GLOCK_SHOOT_RELOAD ); + else + iResult = DefaultReload( GetMaxClip1(), GetMaxClip2(), ACT_VM_RELOAD ); + + return iResult; +} + + + +void CWeaponGlock::WeaponIdle( void ) +{ + CBasePlayer *pPlayer = ToBasePlayer( GetOwner() ); + if ( pPlayer ) + { + pPlayer->GetAutoaimVector( AUTOAIM_10DEGREES ); + } + + // only idle if the slid isn't back + if ( m_iClip1 != 0 ) + { + BaseClass::WeaponIdle(); + } +} diff --git a/game/shared/hl1/hl1mp_weapon_handgrenade.cpp b/game/shared/hl1/hl1mp_weapon_handgrenade.cpp new file mode 100644 index 0000000..5676138 --- /dev/null +++ b/game/shared/hl1/hl1mp_weapon_handgrenade.cpp @@ -0,0 +1,456 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: Hand grenade +// +// $NoKeywords: $ +//=============================================================================// + +#include "cbase.h" +#include "npcevent.h" +#include "hl1mp_basecombatweapon_shared.h" +//#include "basecombatcharacter.h" +//#include "AI_BaseNPC.h" +#ifdef CLIENT_DLL +#include "hl1/hl1_c_player.h" +#else +#include "hl1_player.h" +#endif +#include "gamerules.h" +#include "in_buttons.h" +#ifdef CLIENT_DLL +#else +#include "soundent.h" +#include "game.h" +#endif +#include "vstdlib/random.h" +#include "engine/IEngineSound.h" +#ifdef CLIENT_DLL +#else +#include "hl1_basegrenade.h" +#endif + + +#define HANDGRENADE_MODEL "models/w_grenade.mdl" + + +#ifndef CLIENT_DLL + +extern ConVar sk_plr_dmg_grenade; + +//----------------------------------------------------------------------------- +// CHandGrenade +//----------------------------------------------------------------------------- +LINK_ENTITY_TO_CLASS( grenade_hand, CHandGrenade ); + +BEGIN_DATADESC( CHandGrenade ) + DEFINE_ENTITYFUNC( BounceTouch ), +END_DATADESC() + + +void CHandGrenade::Spawn( void ) +{ + SetMoveType( MOVETYPE_FLYGRAVITY, MOVECOLLIDE_FLY_BOUNCE ); + SetSolid( SOLID_BBOX ); + AddSolidFlags( FSOLID_NOT_STANDABLE ); + + SetModel( HANDGRENADE_MODEL ); + + UTIL_SetSize( this, Vector( 0, 0, 0 ), Vector( 0, 0, 0 ) ); + + m_bHasWarnedAI = false; +} + + +void CHandGrenade::Precache( void ) +{ + BaseClass::Precache( ); + + PrecacheScriptSound( "Weapon_HandGrenade.GrenadeBounce" ); + + PrecacheModel( HANDGRENADE_MODEL ); +} + + +void CHandGrenade::ShootTimed( CBaseCombatCharacter *pOwner, Vector vecVelocity, float flTime ) +{ + SetAbsVelocity( vecVelocity ); + + SetThrower( pOwner ); + SetOwnerEntity( pOwner ); + + SetTouch( &CHandGrenade::BounceTouch ); // Bounce if touched + + m_flDetonateTime = gpGlobals->curtime + flTime; + SetThink( &CBaseGrenade::TumbleThink ); + SetNextThink( gpGlobals->curtime + 0.1 ); + if ( flTime < 0.1 ) + { + SetNextThink( gpGlobals->curtime ); + SetAbsVelocity( vec3_origin ); + } + +// SetSequence( SelectWeightedSequence( ACT_GRENADE_TOSS ) ); + SetSequence( 0 ); + m_flPlaybackRate = 1.0; + + SetAbsAngles( QAngle( 0,0,60) ); + + AngularImpulse angImpulse; + angImpulse[0] = random->RandomInt( -200, 200 ); + angImpulse[1] = random->RandomInt( 400, 500 ); + angImpulse[2] = random->RandomInt( -100, 100 ); + ApplyLocalAngularVelocityImpulse( angImpulse ); + + SetGravity( UTIL_ScaleForGravity( 400 ) ); // use a lower gravity for grenades to make them easier to see + SetFriction( 0.8 ); + + SetDamage( sk_plr_dmg_grenade.GetFloat() ); + SetDamageRadius( GetDamage() * 2.5 ); +} + + +void CHandGrenade ::BounceSound( void ) +{ + EmitSound( "Weapon_HandGrenade.GrenadeBounce" ); +} + + +void CHandGrenade::BounceTouch( CBaseEntity *pOther ) +{ + if ( pOther->IsSolidFlagSet(FSOLID_TRIGGER | FSOLID_VOLUME_CONTENTS) ) + return; + + // don't hit the guy that launched this grenade + if ( pOther == GetThrower() ) + return; + + // Do a special test for players + if ( pOther->IsPlayer() ) + { + // Never hit a player again (we'll explode and fixup anyway) + SetCollisionGroup( COLLISION_GROUP_DEBRIS ); + } + // only do damage if we're moving fairly fast + if ( (pOther->m_takedamage != DAMAGE_NO) && (m_flNextAttack < gpGlobals->curtime && GetAbsVelocity().Length() > 100)) + { + if ( GetThrower() ) + { + trace_t tr; + tr = CBaseEntity::GetTouchTrace( ); + ClearMultiDamage( ); + Vector forward; + AngleVectors( GetAbsAngles(), &forward ); + + CTakeDamageInfo info( this, GetThrower(), 1, DMG_CLUB ); + CalculateMeleeDamageForce( &info, forward, tr.endpos ); + pOther->DispatchTraceAttack( info, forward, &tr ); + ApplyMultiDamage(); + } + m_flNextAttack = gpGlobals->curtime + 1.0; // debounce + } + + Vector vecTestVelocity; + // m_vecAngVelocity = Vector (300, 300, 300); + + // this is my heuristic for modulating the grenade velocity because grenades dropped purely vertical + // or thrown very far tend to slow down too quickly for me to always catch just by testing velocity. + // trimming the Z velocity a bit seems to help quite a bit. + vecTestVelocity = GetAbsVelocity(); + vecTestVelocity.z *= 0.45; + + if ( !m_bHasWarnedAI && vecTestVelocity.Length() <= 60 ) + { + // grenade is moving really slow. It's probably very close to where it will ultimately stop moving. + // emit the danger sound. + + // register a radius louder than the explosion, so we make sure everyone gets out of the way + CSoundEnt::InsertSound ( SOUND_DANGER, GetAbsOrigin(), m_flDamage / 0.4, 0.3 ); + m_bHasWarnedAI = TRUE; + } + + // HACKHACK - On ground isn't always set, so look for ground underneath + trace_t tr; + UTIL_TraceLine( GetAbsOrigin(), GetAbsOrigin() - Vector(0,0,10), MASK_SOLID_BRUSHONLY, this, COLLISION_GROUP_NONE, &tr ); + + if ( tr.fraction < 1.0 ) + { + // add a bit of static friction +// SetAbsVelocity( GetAbsVelocity() * 0.8 ); + SetSequence( SelectWeightedSequence( ACT_IDLE ) ); + SetAbsAngles( vec3_angle ); + } + + // play bounce sound + BounceSound(); + + m_flPlaybackRate = GetAbsVelocity().Length() / 200.0; + if (m_flPlaybackRate > 1.0) + m_flPlaybackRate = 1; + else if (m_flPlaybackRate < 0.5) + m_flPlaybackRate = 0; +} + +#endif + +#ifdef CLIENT_DLL +#define CWeaponHandGrenade C_WeaponHandGrenade +#endif + +//----------------------------------------------------------------------------- +// CWeaponHandGrenade +//----------------------------------------------------------------------------- + +class CWeaponHandGrenade : public CBaseHL1MPCombatWeapon +{ + DECLARE_CLASS( CWeaponHandGrenade, CBaseHL1MPCombatWeapon ); +public: + + DECLARE_NETWORKCLASS(); + DECLARE_PREDICTABLE(); + + CWeaponHandGrenade( void ); + + void Precache( void ); + void PrimaryAttack( void ); + void WeaponIdle( void ); + bool Deploy( void ); + bool Holster( CBaseCombatWeapon *pSwitchingTo = NULL ); + +// DECLARE_SERVERCLASS(); + DECLARE_DATADESC(); + +private: +// float m_flStartThrow; +// float m_flReleaseThrow; + CNetworkVar( float, m_flStartThrow ); + CNetworkVar( float, m_flReleaseThrow ); +}; + +IMPLEMENT_NETWORKCLASS_ALIASED( WeaponHandGrenade, DT_WeaponHandGrenade ); + +BEGIN_NETWORK_TABLE( CWeaponHandGrenade, DT_WeaponHandGrenade ) +#ifdef CLIENT_DLL + RecvPropFloat( RECVINFO( m_flStartThrow ) ), + RecvPropFloat( RECVINFO( m_flReleaseThrow ) ), +#else + SendPropFloat( SENDINFO( m_flStartThrow ) ), + SendPropFloat( SENDINFO( m_flReleaseThrow ) ), +#endif +END_NETWORK_TABLE() + +BEGIN_PREDICTION_DATA( CWeaponHandGrenade ) +#ifdef CLIENT_DLL + DEFINE_PRED_FIELD( m_flStartThrow, FIELD_INTEGER, FTYPEDESC_INSENDTABLE ), + DEFINE_PRED_FIELD( m_flReleaseThrow, FIELD_BOOLEAN, FTYPEDESC_INSENDTABLE ), +#endif +END_PREDICTION_DATA() + +LINK_ENTITY_TO_CLASS( weapon_handgrenade, CWeaponHandGrenade ); + +PRECACHE_WEAPON_REGISTER( weapon_handgrenade ); + +//IMPLEMENT_SERVERCLASS_ST( CWeaponHandGrenade, DT_WeaponHandGrenade ) +//END_SEND_TABLE() + +BEGIN_DATADESC( CWeaponHandGrenade ) +END_DATADESC() + +//----------------------------------------------------------------------------- +// Purpose: Constructor +//----------------------------------------------------------------------------- +CWeaponHandGrenade::CWeaponHandGrenade( void ) +{ + m_bReloadsSingly = false; + m_bFiresUnderwater = true; +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CWeaponHandGrenade::Precache( void ) +{ +#ifndef CLIENT_DLL + UTIL_PrecacheOther( "grenade_hand" ); +#endif + + BaseClass::Precache(); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CWeaponHandGrenade::PrimaryAttack( void ) +{ + CBasePlayer *pPlayer = ToBasePlayer( GetOwner() ); + if ( !pPlayer ) + { + return; + } + + if ( ( m_flStartThrow <= 0 ) && pPlayer->GetAmmoCount( m_iPrimaryAmmoType ) > 0 ) + { + m_flStartThrow = gpGlobals->curtime; + m_flReleaseThrow = 0; + + SendWeaponAnim( ACT_VM_PRIMARYATTACK ); + SetWeaponIdleTime( gpGlobals->curtime + 0.5 ); + } +} + + +void CWeaponHandGrenade::WeaponIdle( void ) +{ + if ( m_flReleaseThrow == 0 && m_flStartThrow ) + m_flReleaseThrow = gpGlobals->curtime; + + if ( !HasWeaponIdleTimeElapsed() ) + return; + + CBasePlayer *pPlayer = ToBasePlayer( GetOwner() ); + if ( !pPlayer ) + { + return; + } + + if ( m_flStartThrow ) + { + Vector vecAiming = pPlayer->GetAutoaimVector( 0 ); + + QAngle angThrow; + VectorAngles( vecAiming, angThrow ); + + Vector vecUp; + Vector vecRight; + AngleVectors( angThrow, NULL, &vecRight, &vecUp ); + + if ( angThrow.x > 180 ) // player is pitching up + angThrow.x = -15 - ( 360 - angThrow.x ) * ( ( 90 - 10 ) / 90.0 ); + else // player is pitching down + angThrow.x = -15 + angThrow.x * ( ( 90 + 10 ) / 90.0 ); + + float flVel = ( 90 - angThrow.x ) * 4; + if ( flVel > 500 ) + flVel = 500; + + Vector vecFwd; + AngleVectors( angThrow, &vecFwd ); + + Vector vecSrc = pPlayer->EyePosition() + vecFwd * 16; + Vector vecThrow = vecFwd * flVel + pPlayer->GetAbsVelocity(); + + QAngle angles; + VectorAngles( vecThrow, angles ); +#ifndef CLIENT_DLL + CHandGrenade *pGrenade = (CHandGrenade*)Create( "grenade_hand", vecSrc, angles ); + if ( pGrenade ) + { + // always explode 3 seconds after the pin was pulled + float flTime = m_flStartThrow - gpGlobals->curtime + 3.0; + if ( flTime < 0 ) + { + flTime = 0; + } + + pGrenade->ShootTimed( pPlayer, vecThrow, flTime ); + } +#endif + + if ( flVel < 500 ) + { + SendWeaponAnim( ACT_HANDGRENADE_THROW1 ); + } + else if ( flVel < 1000 ) + { + SendWeaponAnim( ACT_HANDGRENADE_THROW2 ); + } + else + { + SendWeaponAnim( ACT_HANDGRENADE_THROW3 ); + } + + // player "shoot" animation + pPlayer->SetAnimation( PLAYER_ATTACK1 ); + + m_flReleaseThrow = 0; + m_flStartThrow = 0; + + SetWeaponIdleTime( gpGlobals->curtime + 0.5 ); + m_flNextPrimaryAttack = gpGlobals->curtime + 0.5; + m_flNextSecondaryAttack = gpGlobals->curtime + 0.5; + + pPlayer->RemoveAmmo( 1, m_iPrimaryAmmoType ); + + return; + } + else if ( m_flReleaseThrow > 0 ) + { + // we've finished the throw, restart. + m_flStartThrow = 0; + + if ( pPlayer->GetAmmoCount( m_iPrimaryAmmoType ) > 0 ) + { + SendWeaponAnim( ACT_VM_DRAW ); + } + else + { +// RetireWeapon(); + return; + } + + SetWeaponIdleTime( gpGlobals->curtime + random->RandomFloat( 10, 15 ) ); + m_flReleaseThrow = -1; + return; + } + + if ( pPlayer->GetAmmoCount( m_iPrimaryAmmoType ) > 0 ) + { + float flRand = random->RandomFloat( 0, 1 ); + if ( flRand <= 0.75 ) + { + SendWeaponAnim( ACT_VM_IDLE ); + SetWeaponIdleTime( gpGlobals->curtime + random->RandomFloat( 10, 15 ) );// how long till we do this again. + } + else + { + SendWeaponAnim( ACT_VM_FIDGET ); + } + } +} + +bool CWeaponHandGrenade::Deploy( void ) +{ + m_flReleaseThrow = -1; + + return DefaultDeploy( (char*)GetViewModel(), (char*)GetWorldModel(), ACT_VM_DRAW, (char*)GetAnimPrefix() ); +} + +bool CWeaponHandGrenade::Holster( CBaseCombatWeapon *pSwitchingTo ) +{ + CBasePlayer *pPlayer = ToBasePlayer( GetOwner() ); + if ( !pPlayer ) + { + return false; + } + + if ( m_flStartThrow > 0 ) + { + return false; + } + + if ( !BaseClass::Holster( pSwitchingTo ) ) + { + return false; + } + + if ( pPlayer->GetAmmoCount( m_iPrimaryAmmoType ) <= 0 ) + { +#ifndef CLIENT_DLL + SetThink( &CWeaponHandGrenade::DestroyItem ); + SetNextThink( gpGlobals->curtime + 0.1 ); +#endif + } + + pPlayer->SetNextAttack( gpGlobals->curtime + 0.5 ); + + return true; +} diff --git a/game/shared/hl1/hl1mp_weapon_hornetgun.cpp b/game/shared/hl1/hl1mp_weapon_hornetgun.cpp new file mode 100644 index 0000000..e35c3dc --- /dev/null +++ b/game/shared/hl1/hl1mp_weapon_hornetgun.cpp @@ -0,0 +1,339 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: Hornetgun +// +// $NoKeywords: $ +//=============================================================================// + +#include "cbase.h" +#include "npcevent.h" +#include "hl1mp_basecombatweapon_shared.h" +//#include "basecombatcharacter.h" +//#include "AI_BaseNPC.h" +#include "gamerules.h" +#include "in_buttons.h" +#ifdef CLIENT_DLL +#include "hl1/c_hl1mp_player.h" +#else +#include "hl1mp_player.h" +#include "soundent.h" +#include "game.h" +#endif +#include "vstdlib/random.h" +#include "engine/IEngineSound.h" +#if !defined(CLIENT_DLL) +#include "hl1_npc_hornet.h" +#endif + + +//----------------------------------------------------------------------------- +// CWeaponHgun +//----------------------------------------------------------------------------- + +#ifdef CLIENT_DLL +#define CWeaponHgun C_WeaponHgun +#endif + +class CWeaponHgun : public CBaseHL1MPCombatWeapon +{ + DECLARE_CLASS( CWeaponHgun, CBaseHL1MPCombatWeapon ); +public: + + DECLARE_NETWORKCLASS(); + DECLARE_PREDICTABLE(); + + CWeaponHgun( void ); + + void Precache( void ); + void PrimaryAttack( void ); + void SecondaryAttack( void ); + void WeaponIdle( void ); + bool Holster( CBaseCombatWeapon *pSwitchingTo = NULL ); + bool Reload( void ); + + virtual void ItemPostFrame( void ); + +// DECLARE_SERVERCLASS(); + DECLARE_DATADESC(); + +private: + +// float m_flRechargeTime; +// int m_iFirePhase; + + CNetworkVar( float, m_flRechargeTime ); + CNetworkVar( int, m_iFirePhase ); +}; + +IMPLEMENT_NETWORKCLASS_ALIASED( WeaponHgun, DT_WeaponHgun ); + +BEGIN_NETWORK_TABLE( CWeaponHgun, DT_WeaponHgun ) +#ifdef CLIENT_DLL + RecvPropFloat( RECVINFO( m_flRechargeTime ) ), + RecvPropInt( RECVINFO( m_iFirePhase ) ), +#else + SendPropFloat( SENDINFO( m_flRechargeTime ) ), + SendPropInt( SENDINFO( m_iFirePhase ) ), +#endif +END_NETWORK_TABLE() + +BEGIN_PREDICTION_DATA( CWeaponHgun ) +#ifdef CLIENT_DLL + DEFINE_PRED_FIELD( m_flRechargeTime, FIELD_FLOAT, FTYPEDESC_INSENDTABLE ), + DEFINE_PRED_FIELD( m_iFirePhase, FIELD_INTEGER, FTYPEDESC_INSENDTABLE ), +#endif +END_PREDICTION_DATA() + +LINK_ENTITY_TO_CLASS( weapon_hornetgun, CWeaponHgun ); + +PRECACHE_WEAPON_REGISTER( weapon_hornetgun ); + +//IMPLEMENT_SERVERCLASS_ST( CWeaponHgun, DT_WeaponHgun ) +//END_SEND_TABLE() + +BEGIN_DATADESC( CWeaponHgun ) + DEFINE_FIELD( m_flRechargeTime, FIELD_TIME ), + DEFINE_FIELD( m_iFirePhase, FIELD_INTEGER ), +END_DATADESC() + +//----------------------------------------------------------------------------- +// Purpose: Constructor +//----------------------------------------------------------------------------- +CWeaponHgun::CWeaponHgun( void ) +{ + m_bReloadsSingly = false; + m_bFiresUnderwater = true; + + m_flRechargeTime = 0.0; + m_iFirePhase = 0; +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CWeaponHgun::Precache( void ) +{ +#ifndef CLIENT_DLL + UTIL_PrecacheOther( "hornet" ); +#endif + + BaseClass::Precache(); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CWeaponHgun::PrimaryAttack( void ) +{ + CHL1_Player *pPlayer = ToHL1Player( GetOwner() ); + if ( !pPlayer ) + { + return; + } + + if ( pPlayer->GetAmmoCount( m_iPrimaryAmmoType ) <= 0 ) + { + return; + } + + WeaponSound( SINGLE ); +#if !defined(CLIENT_DLL) + CSoundEnt::InsertSound( SOUND_COMBAT, GetAbsOrigin(), 200, 0.2 ); +#endif + pPlayer->DoMuzzleFlash(); + + SendWeaponAnim( ACT_VM_PRIMARYATTACK ); + pPlayer->SetAnimation( PLAYER_ATTACK1 ); + + Vector vForward, vRight, vUp; + QAngle vecAngles; + + pPlayer->EyeVectors( &vForward, &vRight, &vUp ); + VectorAngles( vForward, vecAngles ); + +#if !defined(CLIENT_DLL) + CBaseEntity *pHornet = CBaseEntity::Create( "hornet", pPlayer->Weapon_ShootPosition() + vForward * 16 + vRight * 8 + vUp * -12, vecAngles, pPlayer ); + pHornet->SetAbsVelocity( vForward * 300 ); +#endif + + m_flRechargeTime = gpGlobals->curtime + 0.5; + + pPlayer->RemoveAmmo( 1, m_iPrimaryAmmoType ); + + pPlayer->ViewPunch( QAngle( -2, 0, 0 ) ); + + m_flNextPrimaryAttack = m_flNextPrimaryAttack + 0.25; + + if (m_flNextPrimaryAttack < gpGlobals->curtime ) + { + m_flNextPrimaryAttack = gpGlobals->curtime + 0.25; + } + + SetWeaponIdleTime( random->RandomFloat( 10, 15 ) ); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CWeaponHgun::SecondaryAttack( void ) +{ + CHL1_Player *pPlayer = ToHL1Player( GetOwner() ); + if ( !pPlayer ) + { + return; + } + + if ( pPlayer->GetAmmoCount( m_iPrimaryAmmoType ) <= 0 ) + { + return; + } + + WeaponSound( SINGLE ); +#if !defined(CLIENT_DLL) + CSoundEnt::InsertSound( SOUND_COMBAT, GetAbsOrigin(), 200, 0.2 ); +#endif + pPlayer->DoMuzzleFlash(); + + SendWeaponAnim( ACT_VM_PRIMARYATTACK ); + pPlayer->SetAnimation( PLAYER_ATTACK1 ); + + CBaseEntity *pHornet; + Vector vecSrc; + + Vector vForward, vRight, vUp; + QAngle vecAngles; + + pPlayer->EyeVectors( &vForward, &vRight, &vUp ); + VectorAngles( vForward, vecAngles ); + + vecSrc = pPlayer->Weapon_ShootPosition() + vForward * 16 + vRight * 8 + vUp * -12; + + m_iFirePhase++; + switch ( m_iFirePhase ) + { + case 1: + vecSrc = vecSrc + vUp * 8; + break; + case 2: + vecSrc = vecSrc + vUp * 8; + vecSrc = vecSrc + vRight * 8; + break; + case 3: + vecSrc = vecSrc + vRight * 8; + break; + case 4: + vecSrc = vecSrc + vUp * -8; + vecSrc = vecSrc + vRight * 8; + break; + case 5: + vecSrc = vecSrc + vUp * -8; + break; + case 6: + vecSrc = vecSrc + vUp * -8; + vecSrc = vecSrc + vRight * -8; + break; + case 7: + vecSrc = vecSrc + vRight * -8; + break; + case 8: + vecSrc = vecSrc + vUp * 8; + vecSrc = vecSrc + vRight * -8; + m_iFirePhase = 0; + break; + } + +#ifdef CLIENT_DLL + pHornet = NULL; +#else + pHornet = CBaseEntity::Create( "hornet", vecSrc, vecAngles, pPlayer ); + pHornet->SetAbsVelocity( vForward * 1200 ); + pHornet->SetThink( &CNPC_Hornet::StartDart ); +#endif + + m_flRechargeTime = gpGlobals->curtime + 0.5; + + pPlayer->ViewPunch( QAngle( -2, 0, 0 ) ); + pPlayer->RemoveAmmo( 1, m_iPrimaryAmmoType ); + + m_flNextPrimaryAttack = m_flNextSecondaryAttack = gpGlobals->curtime + 0.1; + SetWeaponIdleTime( random->RandomFloat( 10, 15 ) ); +} + +void CWeaponHgun::WeaponIdle( void ) +{ + if ( !HasWeaponIdleTimeElapsed() ) + return; + + int iAnim; + float flRand = random->RandomFloat( 0, 1 ); + if ( flRand <= 0.75 ) + { + iAnim = ACT_VM_IDLE; + } + else + { + iAnim = ACT_VM_FIDGET; + } + + SendWeaponAnim( iAnim ); +} + +bool CWeaponHgun::Holster( CBaseCombatWeapon *pSwitchingTo ) +{ + bool bRet; + + bRet = BaseClass::Holster( pSwitchingTo ); + + if ( bRet ) + { + CHL1_Player *pPlayer = ToHL1Player( GetOwner() ); + if ( pPlayer ) + { +#if !defined(CLIENT_DLL) + //!!!HACKHACK - can't select hornetgun if it's empty! no way to get ammo for it, either. + int iCount = pPlayer->GetAmmoCount( m_iPrimaryAmmoType ); + if ( iCount <= 0 ) + { + pPlayer->GiveAmmo( iCount+1, m_iPrimaryAmmoType, true ); + } +#endif + } + } + + return bRet; +} + +bool CWeaponHgun::Reload( void ) +{ + if ( m_flRechargeTime >= gpGlobals->curtime ) + { + return true; + } + + CHL1_Player *pPlayer = ToHL1Player( GetOwner() ); + if ( !pPlayer ) + { + return true; + } + +#ifdef CLIENT_DLL +#else + if ( !g_pGameRules->CanHaveAmmo( pPlayer, m_iPrimaryAmmoType ) ) + return true; + + while ( ( m_flRechargeTime < gpGlobals->curtime ) && g_pGameRules->CanHaveAmmo( pPlayer, m_iPrimaryAmmoType ) ) + { + pPlayer->GiveAmmo( 1, m_iPrimaryAmmoType, true ); + m_flRechargeTime += 0.5; + } +#endif + + return true; +} + +void CWeaponHgun::ItemPostFrame( void ) +{ + Reload(); + + BaseClass::ItemPostFrame(); +} diff --git a/game/shared/hl1/hl1mp_weapon_mp5.cpp b/game/shared/hl1/hl1mp_weapon_mp5.cpp new file mode 100644 index 0000000..46b7fb9 --- /dev/null +++ b/game/shared/hl1/hl1mp_weapon_mp5.cpp @@ -0,0 +1,237 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#include "cbase.h" +//#include "basecombatweapon.h" +#include "hl1mp_basecombatweapon_shared.h" +#include "npcevent.h" +//#include "basecombatcharacter.h" +//#include "AI_BaseNPC.h" +#ifdef CLIENT_DLL +#include "hl1/hl1_c_player.h" +#else +#include "player.h" +#endif +#include "hl1mp_weapon_mp5.h" +//#include "hl1_weapon_mp5.h" +#ifdef CLIENT_DLL +#else +#include "hl1_grenade_mp5.h" +#endif +#include "gamerules.h" +#ifdef CLIENT_DLL +#else +#include "soundent.h" +#include "game.h" +#endif +#include "in_buttons.h" +#include "engine/IEngineSound.h" + +extern ConVar sk_plr_dmg_mp5_grenade; +extern ConVar sk_max_mp5_grenade; +extern ConVar sk_mp5_grenade_radius; + +//========================================================= +//========================================================= + +IMPLEMENT_NETWORKCLASS_ALIASED( WeaponMP5, DT_WeaponMP5 ); + +BEGIN_NETWORK_TABLE( CWeaponMP5, DT_WeaponMP5 ) +END_NETWORK_TABLE() + +BEGIN_PREDICTION_DATA( CWeaponMP5 ) +END_PREDICTION_DATA() + +LINK_ENTITY_TO_CLASS( weapon_mp5, CWeaponMP5 ); + +PRECACHE_WEAPON_REGISTER(weapon_mp5); + +//IMPLEMENT_SERVERCLASS_ST( CWeaponMP5, DT_WeaponMP5 ) +//END_SEND_TABLE() + +BEGIN_DATADESC( CWeaponMP5 ) +END_DATADESC() + +CWeaponMP5::CWeaponMP5( ) +{ + m_bReloadsSingly = false; + m_bFiresUnderwater = false; +} + +void CWeaponMP5::Precache( void ) +{ + BaseClass::Precache(); + +#ifndef CLIENT_DLL + UTIL_PrecacheOther( "grenade_mp5" ); +#endif +} + + +void CWeaponMP5::PrimaryAttack( void ) +{ + // Only the player fires this way so we can cast + CBasePlayer *pPlayer = ToBasePlayer( GetOwner() ); + + if ( !pPlayer ) + { + return; + } + + if ( m_iClip1 <= 0 ) + { + DryFire(); + return; + } + + WeaponSound( SINGLE ); + + pPlayer->DoMuzzleFlash(); + + m_iClip1--; + + SendWeaponAnim( ACT_VM_PRIMARYATTACK ); + pPlayer->SetAnimation( PLAYER_ATTACK1 ); + + m_flNextPrimaryAttack = gpGlobals->curtime + 0.1; + + Vector vecSrc = pPlayer->Weapon_ShootPosition(); + Vector vecAiming = pPlayer->GetAutoaimVector( AUTOAIM_5DEGREES ); + + if ( !g_pGameRules->IsMultiplayer() ) + { + // optimized multiplayer. Widened to make it easier to hit a moving player +// pPlayer->FireBullets( 1, vecSrc, vecAiming, VECTOR_CONE_6DEGREES, MAX_TRACE_LENGTH, m_iPrimaryAmmoType, 2 ); + FireBulletsInfo_t info( 1, vecSrc, vecAiming, VECTOR_CONE_6DEGREES, MAX_TRACE_LENGTH, m_iPrimaryAmmoType ); + info.m_pAttacker = pPlayer; + info.m_iTracerFreq = 2; + + pPlayer->FireBullets( info ); + } + else + { + // single player spread +// pPlayer->FireBullets( 1, vecSrc, vecAiming, VECTOR_CONE_3DEGREES, MAX_TRACE_LENGTH, m_iPrimaryAmmoType, 2 ); + FireBulletsInfo_t info( 1, vecSrc, vecAiming, VECTOR_CONE_3DEGREES, MAX_TRACE_LENGTH, m_iPrimaryAmmoType ); + info.m_pAttacker = pPlayer; + info.m_iTracerFreq = 2; + + pPlayer->FireBullets( info ); + } + + EjectShell( pPlayer, 0 ); + + pPlayer->ViewPunch( QAngle( random->RandomFloat( -2, 2 ), 0, 0 ) ); +#ifdef CLIENT_DLL + pPlayer->DoMuzzleFlash(); +#else + pPlayer->SetMuzzleFlashTime( gpGlobals->curtime + 0.5 ); +#endif + +#ifdef CLIENT_DLL +#else + CSoundEnt::InsertSound( SOUND_COMBAT, GetAbsOrigin(), 600, 0.2 ); +#endif + + if ( !m_iClip1 && pPlayer->GetAmmoCount( m_iPrimaryAmmoType ) <= 0 ) + { + // HEV suit - indicate out of ammo condition + pPlayer->SetSuitUpdate("!HEV_AMO0", FALSE, 0); + } + + SetWeaponIdleTime( gpGlobals->curtime + random->RandomFloat( 10, 15 ) ); +} + + +void CWeaponMP5::SecondaryAttack( void ) +{ + // Only the player fires this way so we can cast + CBasePlayer *pPlayer = ToBasePlayer( GetOwner() ); + + if (!pPlayer) + { + return; + } + + if ( pPlayer->GetAmmoCount( m_iSecondaryAmmoType ) <= 0 ) + { + DryFire( ); + return; + } + + WeaponSound(WPN_DOUBLE); + + pPlayer->DoMuzzleFlash(); + + Vector vecSrc = pPlayer->Weapon_ShootPosition(); + Vector vecThrow = pPlayer->GetAutoaimVector( 0 ) * 800; + QAngle angGrenAngle; + + VectorAngles( vecThrow, angGrenAngle ); + +#ifdef CLIENT_DLL +#else + CGrenadeMP5 * m_pMyGrenade = (CGrenadeMP5*)Create( "grenade_mp5", vecSrc, angGrenAngle, GetOwner() ); + m_pMyGrenade->SetAbsVelocity( vecThrow ); + m_pMyGrenade->SetLocalAngularVelocity( QAngle( random->RandomFloat( -100, -500 ), 0, 0 ) ); + m_pMyGrenade->SetMoveType( MOVETYPE_FLYGRAVITY ); + m_pMyGrenade->SetThrower( GetOwner() ); + m_pMyGrenade->SetDamage( sk_plr_dmg_mp5_grenade.GetFloat() * g_pGameRules->GetDamageMultiplier() ); +#endif + + SendWeaponAnim( ACT_VM_SECONDARYATTACK ); + pPlayer->SetAnimation( PLAYER_ATTACK1 ); + + pPlayer->ViewPunch( QAngle( -10, 0, 0 ) ); + + // Register a muzzleflash for the AI. +#if !defined(CLIENT_DLL) + pPlayer->SetMuzzleFlashTime( gpGlobals->curtime + 0.5 ); +#endif + +#ifdef CLIENT_DLL +#else + CSoundEnt::InsertSound( SOUND_COMBAT, GetAbsOrigin(), 600, 0.2 ); +#endif + + // Decrease ammo + pPlayer->RemoveAmmo( 1, m_iSecondaryAmmoType ); + if ( pPlayer->GetAmmoCount( m_iSecondaryAmmoType ) <= 0 ) + { + // HEV suit - indicate out of ammo condition + pPlayer->SetSuitUpdate("!HEV_AMO0", FALSE, 0); + } + + m_flNextPrimaryAttack = gpGlobals->curtime + 1.0; + m_flNextSecondaryAttack = gpGlobals->curtime + 1.0; + SetWeaponIdleTime( gpGlobals->curtime + 5.0 ); +} + + +void CWeaponMP5::DryFire( void ) +{ + WeaponSound( EMPTY ); + m_flNextPrimaryAttack = gpGlobals->curtime + 0.15; + m_flNextSecondaryAttack = gpGlobals->curtime + 0.15; +} + + +void CWeaponMP5::WeaponIdle( void ) +{ + CBasePlayer *pPlayer = ToBasePlayer( GetOwner() ); + if ( pPlayer ) + { + pPlayer->GetAutoaimVector( AUTOAIM_5DEGREES ); + } + + bool bElapsed = HasWeaponIdleTimeElapsed(); + + BaseClass::WeaponIdle(); + + if( bElapsed ) + SetWeaponIdleTime( gpGlobals->curtime + random->RandomInt( 3, 5 ) ); +} diff --git a/game/shared/hl1/hl1mp_weapon_mp5.h b/game/shared/hl1/hl1mp_weapon_mp5.h new file mode 100644 index 0000000..427c630 --- /dev/null +++ b/game/shared/hl1/hl1mp_weapon_mp5.h @@ -0,0 +1,53 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: Projectile shot from the MP5 +// +// $Workfile: $ +// $Date: $ +// +//----------------------------------------------------------------------------- +// $Log: $ +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef WEAPONMP5_H +#define WEAPONMP5_H + +#ifdef CLIENT_DLL +#else +#include "hl1_basegrenade.h" +#endif +#include "hl1mp_basecombatweapon_shared.h" + +#ifdef CLIENT_DLL +class CGrenadeMP5; +#else +#endif + +#ifdef CLIENT_DLL +#define CWeaponMP5 C_WeaponMP5 +#endif + +class CWeaponMP5 : public CBaseHL1MPCombatWeapon +{ + DECLARE_CLASS( CWeaponMP5, CBaseHL1MPCombatWeapon ); +public: + + DECLARE_NETWORKCLASS(); + DECLARE_PREDICTABLE(); + + CWeaponMP5(); + + void Precache( void ); + void PrimaryAttack( void ); + void SecondaryAttack( void ); + void DryFire( void ); + void WeaponIdle( void ); + +// DECLARE_SERVERCLASS(); + DECLARE_DATADESC(); +}; + + +#endif //WEAPONMP5_H diff --git a/game/shared/hl1/hl1mp_weapon_rpg.cpp b/game/shared/hl1/hl1mp_weapon_rpg.cpp new file mode 100644 index 0000000..98cf2fa --- /dev/null +++ b/game/shared/hl1/hl1mp_weapon_rpg.cpp @@ -0,0 +1,1080 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: RPG +// +// $NoKeywords: $ +//=============================================================================// + +#include "cbase.h" +#include "npcevent.h" +#include "in_buttons.h" +#include "hl1mp_basecombatweapon_shared.h" +#include "hl1mp_weapon_rpg.h" + +#ifdef CLIENT_DLL +#include "hl1/c_hl1mp_player.h" +#include "model_types.h" +#include "beamdraw.h" +#include "fx_line.h" +#include "view.h" +#else +#include "basecombatcharacter.h" +#include "movie_explosion.h" +#include "hl1mp_player.h" +#include "rope.h" +#include "soundent.h" +#include "vstdlib/random.h" +#include "engine/IEngineSound.h" +#include "explode.h" +#include "util.h" +#include "te_effect_dispatch.h" +#include "shake.h" +#endif + +// memdbgon must be the last include file in a .cpp file!!! +#include "tier0/memdbgon.h" + +extern ConVar sk_plr_dmg_rpg; + + +void TE_BeamFollow( IRecipientFilter& filter, float delay, + int iEntIndex, int modelIndex, int haloIndex, float life, float width, float endWidth, + float fadeLength,float r, float g, float b, float a ); + +#define RPG_LASER_SPRITE "sprites/redglow_mp1" + +class CLaserDot : public CBaseEntity +{ + DECLARE_CLASS( CLaserDot, CBaseEntity ); +public: + + CLaserDot( void ); + ~CLaserDot( void ); + + static CLaserDot *Create( const Vector &origin, CBaseEntity *pOwner = NULL, bool bVisibleDot = true ); + + void SetTargetEntity( CBaseEntity *pTarget ) { m_hTargetEnt = pTarget; } + CBaseEntity *GetTargetEntity( void ) { return m_hTargetEnt; } + + void SetLaserPosition( const Vector &origin, const Vector &normal ); + Vector GetChasePosition(); + void TurnOn( void ); + void TurnOff( void ); + bool IsOn() const { return m_bIsOn; } + + void Toggle( void ); + + int ObjectCaps() { return (BaseClass::ObjectCaps() & ~FCAP_ACROSS_TRANSITION) | FCAP_DONT_SAVE; } + + void MakeInvisible( void ); + +#ifdef CLIENT_DLL + + virtual bool IsTransparent( void ) { return true; } + virtual RenderGroup_t GetRenderGroup( void ) { return RENDER_GROUP_TRANSLUCENT_ENTITY; } + virtual int DrawModel( int flags ); + virtual void OnDataChanged( DataUpdateType_t updateType ); + virtual bool ShouldDraw( void ) { return (IsEffectActive(EF_NODRAW)==false); } + + CMaterialReference m_hSpriteMaterial; +#endif + +protected: + Vector m_vecSurfaceNormal; + EHANDLE m_hTargetEnt; + bool m_bVisibleLaserDot; +// bool m_bIsOn; + CNetworkVar( bool, m_bIsOn ); + + DECLARE_NETWORKCLASS(); + DECLARE_DATADESC(); +public: + CLaserDot *m_pNext; +}; + + +#ifndef CLIENT_DLL + +//============================================================================= +// RPG Rocket +//============================================================================= + + +BEGIN_DATADESC( CRpgRocket ) + DEFINE_FIELD( m_hOwner, FIELD_EHANDLE ), + DEFINE_FIELD( m_vecAbsVelocity, FIELD_VECTOR ), + DEFINE_FIELD( m_flIgniteTime, FIELD_TIME ), + //DEFINE_FIELD( m_iTrail, FIELD_INTEGER ), + + // Function Pointers + DEFINE_ENTITYFUNC( RocketTouch ), + DEFINE_THINKFUNC( IgniteThink ), + DEFINE_THINKFUNC( SeekThink ), +END_DATADESC() + +LINK_ENTITY_TO_CLASS( rpg_rocket, CRpgRocket ); + +IMPLEMENT_SERVERCLASS_ST(CRpgRocket, DT_RpgRocket) +END_SEND_TABLE() + +CRpgRocket::CRpgRocket() +{ +} + + +//----------------------------------------------------------------------------- +// Purpose: +// +// +//----------------------------------------------------------------------------- +void CRpgRocket::Precache( void ) +{ + PrecacheModel( "models/rpgrocket.mdl" ); + PrecacheModel( "sprites/animglow01.vmt" ); + + PrecacheScriptSound( "Weapon_RPG.RocketIgnite" ); + + m_iTrail = PrecacheModel("sprites/smoke.vmt"); +} + +//----------------------------------------------------------------------------- +// Purpose: +// +// +//----------------------------------------------------------------------------- +void CRpgRocket::Spawn( void ) +{ + Precache(); + + SetSolid( SOLID_BBOX ); + SetModel("models/rpgrocket.mdl"); + UTIL_SetSize( this, -Vector(0,0,0), Vector(0,0,0) ); + + SetTouch( &CRpgRocket::RocketTouch ); + + SetMoveType( MOVETYPE_FLYGRAVITY, MOVECOLLIDE_FLY_BOUNCE ); + SetThink( &CRpgRocket::IgniteThink ); + + SetNextThink( gpGlobals->curtime + 0.4f ); + + QAngle angAngs; + Vector vecFwd; + + angAngs = GetAbsAngles(); + angAngs.x -= 30; + AngleVectors( angAngs, &vecFwd ); + SetAbsVelocity( vecFwd * 250 ); + + SetGravity( UTIL_ScaleForGravity( 400 ) ); // use a lower gravity for rockets + + m_flDamage = sk_plr_dmg_rpg.GetFloat(); + m_DmgRadius = m_flDamage * 2.5; +} + + +//----------------------------------------------------------------------------- +// Purpose: +// Input : *pOther - +//----------------------------------------------------------------------------- +void CRpgRocket::RocketTouch( CBaseEntity *pOther ) +{ + if ( !pOther->IsSolid() || pOther->IsSolidFlagSet(FSOLID_VOLUME_CONTENTS) ) + return; + + if ( m_hOwner != NULL ) + { + m_hOwner->NotifyRocketDied(); + } + + StopSound( "Weapon_RPG.RocketIgnite" ); + ExplodeTouch( pOther ); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CRpgRocket::IgniteThink( void ) +{ + SetMoveType( MOVETYPE_FLY ); + + AddEffects( EF_DIMLIGHT ); + + EmitSound( "Weapon_RPG.RocketIgnite" ); + + SetThink( &CRpgRocket::SeekThink ); + SetNextThink( gpGlobals->curtime + 0.1f ); + + CBroadcastRecipientFilter filter; + TE_BeamFollow( filter, 0.0, + entindex(), + m_iTrail, + 0, + 4, + 5, + 5, + 0, + 224, + 224, + 255, + 255 ); + + m_flIgniteTime = gpGlobals->curtime; +} + +#define RPG_HOMING_SPEED 0.125f + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CRpgRocket::SeekThink( void ) +{ + CBaseEntity *pOther = NULL; + Vector vecTarget; + Vector vecFwd; + Vector vecDir; + float flDist, flMax, flDot; + trace_t tr; + + AngleVectors( GetAbsAngles(), &vecFwd ); + + vecTarget = vecFwd; + flMax = 4096; + + // Examine all entities within a reasonable radius + while ( (pOther = gEntList.FindEntityByClassname( pOther, "laser_spot" ) ) != NULL) + { + CLaserDot *pDot = dynamic_cast<CLaserDot*>(pOther); + +// if ( pDot->IsActive() ) + if ( pDot->IsOn() ) + { + UTIL_TraceLine( GetAbsOrigin(), pDot->GetAbsOrigin(), MASK_SHOT, this, COLLISION_GROUP_NONE, &tr ); + if ( tr.fraction >= 0.90 ) + { + vecDir = pDot->GetAbsOrigin() - GetAbsOrigin(); + flDist = VectorLength( vecDir ); + VectorNormalize( vecDir ); + flDot = DotProduct( vecFwd, vecDir ); + if ( (flDot > 0) && (flDist * (1 - flDot) < flMax) ) + { + flMax = flDist * (1 - flDot); + vecTarget = vecDir; + } + } + } + } + + QAngle vecAng; + VectorAngles( vecTarget, vecAng ); + SetAbsAngles( vecAng ); + + // this acceleration and turning math is totally wrong, but it seems to respond well so don't change it. + float flSpeed = GetAbsVelocity().Length(); + if ( gpGlobals->curtime - m_flIgniteTime < 1.0 ) + { + SetAbsVelocity( GetAbsVelocity() * 0.2 + vecTarget * (flSpeed * 0.8 + 400) ); + if ( GetWaterLevel() == 3 ) + { + // go slow underwater + if ( GetAbsVelocity().Length() > 300 ) + { + Vector vecVel = GetAbsVelocity(); + VectorNormalize( vecVel ); + SetAbsVelocity( vecVel * 300 ); + } + + UTIL_BubbleTrail( GetAbsOrigin() - GetAbsVelocity() * 0.1, GetAbsOrigin(), 4 ); + } + else + { + if ( GetAbsVelocity().Length() > 2000 ) + { + Vector vecVel = GetAbsVelocity(); + VectorNormalize( vecVel ); + SetAbsVelocity( vecVel * 2000 ); + } + } + } + else + { + if ( IsEffectActive( EF_DIMLIGHT ) ) + { + ClearEffects(); + } + + SetAbsVelocity( GetAbsVelocity() * 0.2 + vecTarget * flSpeed * 0.798 ); + + if ( GetWaterLevel() == 0 && GetAbsVelocity().Length() < 1500 ) + { + Detonate(); + } + } + + SetNextThink( gpGlobals->curtime + 0.1f ); +} + +void CRpgRocket::Detonate( void ) +{ + StopSound( "Weapon_RPG.RocketIgnite" ); + BaseClass::Detonate(); +} + +//----------------------------------------------------------------------------- +// Purpose: +// +// Input : &vecOrigin - +// &vecAngles - +// NULL - +// +// Output : CRpgRocket +//----------------------------------------------------------------------------- +CRpgRocket *CRpgRocket::Create( const Vector &vecOrigin, const QAngle &angAngles, CBasePlayer *pentOwner ) +{ + CRpgRocket *pRocket = (CRpgRocket *)CreateEntityByName( "rpg_rocket" ); + UTIL_SetOrigin( pRocket, vecOrigin ); + pRocket->SetAbsAngles( angAngles ); + pRocket->Spawn(); + pRocket->SetOwnerEntity( pentOwner ); + + return pRocket; +} + +#endif // endif #ifndef CLIENT_DLL + + +//============================================================================= +// Laser Dot +//============================================================================= + +IMPLEMENT_NETWORKCLASS_ALIASED( LaserDot, DT_LaserDot ) + +BEGIN_NETWORK_TABLE( CLaserDot, DT_LaserDot ) +#ifdef CLIENT_DLL + RecvPropBool( RECVINFO( m_bIsOn ) ), +#else + SendPropBool( SENDINFO( m_bIsOn ) ), +#endif +END_NETWORK_TABLE() + +#ifndef CLIENT_DLL +// a list of laser dots to search quickly +CEntityClassList<CLaserDot> g_LaserDotList; +template <> CLaserDot *CEntityClassList<CLaserDot>::m_pClassList = NULL; +CLaserDot *GetLaserDotList() +{ + return g_LaserDotList.m_pClassList; +} + +#endif + +LINK_ENTITY_TO_CLASS( laser_spot, CLaserDot ); + +BEGIN_DATADESC( CLaserDot ) + DEFINE_FIELD( m_vecSurfaceNormal, FIELD_VECTOR ), + DEFINE_FIELD( m_hTargetEnt, FIELD_EHANDLE ), + DEFINE_FIELD( m_bVisibleLaserDot, FIELD_BOOLEAN ), + DEFINE_FIELD( m_bIsOn, FIELD_BOOLEAN ), + + //DEFINE_FIELD( m_pNext, FIELD_CLASSPTR ), // don't save - regenerated by constructor +END_DATADESC() + + +//----------------------------------------------------------------------------- +// Finds missiles in cone +//----------------------------------------------------------------------------- +CBaseEntity *CreateLaserDot( const Vector &origin, CBaseEntity *pOwner, bool bVisibleDot ) +{ + return CLaserDot::Create( origin, pOwner, bVisibleDot ); +} + +void SetLaserDotTarget( CBaseEntity *pLaserDot, CBaseEntity *pTarget ) +{ + CLaserDot *pDot = assert_cast< CLaserDot* >(pLaserDot ); + pDot->SetTargetEntity( pTarget ); +} + +void EnableLaserDot( CBaseEntity *pLaserDot, bool bEnable ) +{ + CLaserDot *pDot = assert_cast< CLaserDot* >(pLaserDot ); + if ( bEnable ) + { + pDot->TurnOn(); + } + else + { + pDot->TurnOff(); + } +} + +CLaserDot::CLaserDot( void ) +{ + m_hTargetEnt = NULL; + m_bIsOn = true; +#ifndef CLIENT_DLL + g_LaserDotList.Insert( this ); +#endif +} + +CLaserDot::~CLaserDot( void ) +{ +#ifndef CLIENT_DLL + g_LaserDotList.Remove( this ); +#endif +} + + +//----------------------------------------------------------------------------- +// Purpose: +// Input : &origin - +// Output : CLaserDot +//----------------------------------------------------------------------------- +CLaserDot *CLaserDot::Create( const Vector &origin, CBaseEntity *pOwner, bool bVisibleDot ) +{ +#ifndef CLIENT_DLL + CLaserDot *pLaserDot = (CLaserDot *) CBaseEntity::Create( "laser_spot", origin, QAngle(0,0,0) ); + + if ( pLaserDot == NULL ) + return NULL; + + pLaserDot->m_bVisibleLaserDot = bVisibleDot; + pLaserDot->SetMoveType( MOVETYPE_NONE ); + pLaserDot->AddSolidFlags( FSOLID_NOT_SOLID ); + pLaserDot->AddEffects( EF_NOSHADOW ); + UTIL_SetSize( pLaserDot, -Vector(6,6,6), Vector(6,6,6) ); + + pLaserDot->SetOwnerEntity( pOwner ); + + pLaserDot->AddEFlags( EFL_FORCE_CHECK_TRANSMIT ); + + if ( !bVisibleDot ) + { + pLaserDot->MakeInvisible(); + } + + return pLaserDot; +#else + return NULL; +#endif +} + +void CLaserDot::SetLaserPosition( const Vector &origin, const Vector &normal ) +{ + SetAbsOrigin( origin ); + m_vecSurfaceNormal = normal; +} + +Vector CLaserDot::GetChasePosition() +{ + return GetAbsOrigin() - m_vecSurfaceNormal * 10; +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CLaserDot::TurnOn( void ) +{ + m_bIsOn = true; + RemoveEffects(EF_NODRAW); + + if ( m_bVisibleLaserDot ) + { + //BaseClass::TurnOn(); + } +} + + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CLaserDot::TurnOff( void ) +{ + m_bIsOn = false; + AddEffects(EF_NODRAW); + if ( m_bVisibleLaserDot ) + { + //BaseClass::TurnOff(); + } +} + + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CLaserDot::MakeInvisible( void ) +{ +} + +#ifdef CLIENT_DLL + +//----------------------------------------------------------------------------- +// Purpose: Draw our sprite +//----------------------------------------------------------------------------- +int CLaserDot::DrawModel( int flags ) +{ + color32 color={255,255,255,255}; + Vector vecAttachment, vecDir; + QAngle angles; + + float scale; + Vector endPos; + + C_HL1MP_Player *pOwner = ToHL1MPPlayer( GetOwnerEntity() ); + + if ( pOwner != NULL && pOwner->IsDormant() == false ) + { + // Always draw the dot in front of our faces when in first-person + if ( pOwner->IsLocalPlayer() ) + { + // Take our view position and orientation + vecAttachment = CurrentViewOrigin(); + vecDir = CurrentViewForward(); + } + else + { + // Take the eye position and direction + vecAttachment = pOwner->EyePosition(); + + QAngle angles = pOwner->EyeAngles(); + AngleVectors( angles, &vecDir ); + } + + trace_t tr; + UTIL_TraceLine( vecAttachment, vecAttachment + ( vecDir * MAX_TRACE_LENGTH ), MASK_SHOT, pOwner, COLLISION_GROUP_NONE, &tr ); + + // Backup off the hit plane + endPos = tr.endpos + ( tr.plane.normal * 4.0f ); + } + else + { + // Just use our position if we can't predict it otherwise + endPos = GetAbsOrigin(); + } + + // Randomly flutter + scale = 16.0f + random->RandomFloat( -4.0f, 4.0f ); + + // Draw our laser dot in space + CMatRenderContextPtr pRenderContext( materials ); + pRenderContext->Bind( m_hSpriteMaterial, this ); + DrawSprite( endPos, scale, scale, color ); + + return 1; +} + +//----------------------------------------------------------------------------- +// Purpose: Setup our sprite reference +//----------------------------------------------------------------------------- +void CLaserDot::OnDataChanged( DataUpdateType_t updateType ) +{ + if ( updateType == DATA_UPDATE_CREATED ) + { + m_hSpriteMaterial.Init( RPG_LASER_SPRITE, TEXTURE_GROUP_CLIENT_EFFECTS ); + } +} + +#endif //CLIENT_DLL + +//============================================================================= +// RPG Weapon +//============================================================================= + +LINK_ENTITY_TO_CLASS( weapon_rpg, CWeaponRPG ); + +PRECACHE_WEAPON_REGISTER( weapon_rpg ); + +//IMPLEMENT_SERVERCLASS_ST( CWeaponRPG, DT_WeaponRPG ) +//END_SEND_TABLE() + +IMPLEMENT_NETWORKCLASS_ALIASED( WeaponRPG, DT_WeaponRPG ) + +BEGIN_DATADESC( CWeaponRPG ) +DEFINE_FIELD( m_bIntialStateUpdate, FIELD_BOOLEAN ), + DEFINE_FIELD( m_bGuiding, FIELD_BOOLEAN ), +#ifndef CLIENT_DLL + DEFINE_FIELD( m_hLaserDot, FIELD_EHANDLE ), +#endif + DEFINE_FIELD( m_hMissile, FIELD_EHANDLE ), + DEFINE_FIELD( m_bLaserDotSuspended, FIELD_BOOLEAN ), + DEFINE_FIELD( m_flLaserDotReviveTime, FIELD_TIME ), +END_DATADESC() + + +BEGIN_NETWORK_TABLE( CWeaponRPG, DT_WeaponRPG ) +#ifdef CLIENT_DLL + RecvPropBool( RECVINFO( m_bIntialStateUpdate ) ), + RecvPropBool( RECVINFO( m_bGuiding ) ), + RecvPropBool( RECVINFO( m_bLaserDotSuspended ) ), +// RecvPropEHandle( RECVINFO( m_hMissile ), RecvProxy_MissileDied ), +// RecvPropVector( RECVINFO( m_vecLaserDot ) ), +#else + SendPropBool( SENDINFO( m_bIntialStateUpdate ) ), + SendPropBool( SENDINFO( m_bGuiding ) ), + SendPropBool( SENDINFO( m_bLaserDotSuspended ) ), +// SendPropEHandle( SENDINFO( m_hMissile ) ), +// SendPropVector( SENDINFO( m_vecLaserDot ) ), +#endif +END_NETWORK_TABLE() + + +BEGIN_PREDICTION_DATA( CWeaponRPG ) +#ifdef CLIENT_DLL + DEFINE_PRED_FIELD( m_bIntialStateUpdate, FIELD_BOOLEAN, FTYPEDESC_INSENDTABLE ), + DEFINE_PRED_FIELD( m_bGuiding, FIELD_BOOLEAN, FTYPEDESC_INSENDTABLE ), + DEFINE_PRED_FIELD( m_bLaserDotSuspended, FIELD_BOOLEAN, FTYPEDESC_INSENDTABLE ), + DEFINE_PRED_FIELD( m_flLaserDotReviveTime, FIELD_FLOAT, FTYPEDESC_INSENDTABLE ), +#endif +END_PREDICTION_DATA() + + +//----------------------------------------------------------------------------- +// Purpose: Constructor +//----------------------------------------------------------------------------- +CWeaponRPG::CWeaponRPG( void ) +{ + m_bReloadsSingly = false; + m_bFiresUnderwater = true; + m_bGuiding = true; + m_bIntialStateUpdate = false; + m_bLaserDotSuspended = false; +} + + +CWeaponRPG::~CWeaponRPG() +{ +#ifndef CLIENT_DLL + if ( m_hLaserDot != NULL ) + { + UTIL_Remove( m_hLaserDot ); + m_hLaserDot = NULL; + } +#endif +} + + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CWeaponRPG::ItemPostFrame( void ) +{ + BaseClass::ItemPostFrame(); + + CBasePlayer *pPlayer = ToBasePlayer( GetOwner() ); + + if ( pPlayer == NULL ) + return; + + //If we're pulling the weapon out for the first time, wait to draw the laser + if ( m_bIntialStateUpdate ) + { + if ( GetActivity() != ACT_VM_DRAW ) + { + if ( IsGuiding() && !m_bLaserDotSuspended ) + { +#ifndef CLIENT_DLL + if ( m_hLaserDot != NULL ) + { + m_hLaserDot->TurnOn(); + } +#endif + } + + m_bIntialStateUpdate = false; + } + else + { + return; + } + } + + //Player has toggled guidance state + if ( pPlayer->m_afButtonPressed & IN_ATTACK2 ) + { + if ( IsGuiding() ) + { + StopGuiding(); + } + else + { + StartGuiding(); + } + } + + //Move the laser + UpdateSpot(); +} + + +void CWeaponRPG::Drop( const Vector &vecVelocity ) +{ + StopGuiding(); + +#ifndef CLIENT_DLL + if ( m_hLaserDot != NULL ) + { + UTIL_Remove( m_hLaserDot ); + m_hLaserDot = NULL; + } +#endif + + BaseClass::Drop( vecVelocity ); +} + + +int CWeaponRPG::GetDefaultClip1( void ) const +{ + if ( g_pGameRules->IsMultiplayer() ) + { + // more default ammo in multiplay. + return BaseClass::GetDefaultClip1() * 2; + } + else + { + return BaseClass::GetDefaultClip1(); + } +} + + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CWeaponRPG::Precache( void ) +{ +#ifndef CLIENT_DLL + UTIL_PrecacheOther( "laser_spot" ); + UTIL_PrecacheOther( "rpg_rocket" ); +#endif + +// PrecacheModel( RPG_LASER_SPRITE ); + PrecacheModel( "sprites/redglow_mp1.vmt" ); + + BaseClass::Precache(); +} + + +bool CWeaponRPG::Deploy( void ) +{ + m_bIntialStateUpdate = true; + m_bLaserDotSuspended = false; + CreateLaserPointer(); +#ifndef CLIENT_DLL + if ( m_hLaserDot != NULL ) + { + m_hLaserDot->TurnOff(); + } +#endif + + if ( m_iClip1 <= 0 ) + { + return DefaultDeploy( (char*)GetViewModel(), (char*)GetWorldModel(), ACT_RPG_DRAW_UNLOADED, (char*)GetAnimPrefix() ); + } + + return DefaultDeploy( (char*)GetViewModel(), (char*)GetWorldModel(), ACT_VM_DRAW, (char*)GetAnimPrefix() ); +} + + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CWeaponRPG::PrimaryAttack( void ) +{ + // Can't have an active missile out + if ( m_hMissile != NULL ) + return; + + // Can't be reloading + if ( GetActivity() == ACT_VM_RELOAD ) + return; + + if ( m_iClip1 <= 0 ) + { + if ( !m_bFireOnEmpty ) + { + Reload(); + } + else + { + WeaponSound( EMPTY ); + m_flNextPrimaryAttack = gpGlobals->curtime + 0.2; + } + } + + Vector vecOrigin; + Vector vecForward; + + CBasePlayer *pOwner = ToBasePlayer( GetOwner() ); + + if ( pOwner == NULL ) + return; + + SendWeaponAnim( ACT_VM_PRIMARYATTACK ); + WeaponSound( SINGLE ); +#ifndef CLIENT_DLL + CSoundEnt::InsertSound( SOUND_COMBAT, GetAbsOrigin(), 400, 0.2 ); +#endif + pOwner->DoMuzzleFlash(); + +#ifndef CLIENT_DLL + // Register a muzzleflash for the AI + pOwner->SetMuzzleFlashTime( gpGlobals->curtime + 0.5 ); +#endif + + Vector vForward, vRight, vUp; + + pOwner->EyeVectors( &vForward, &vRight, &vUp ); + + Vector muzzlePoint = pOwner->Weapon_ShootPosition() + vForward * 16.0f + vRight * 8.0f + vUp * -8.0f; + +#ifndef CLIENT_DLL + QAngle vecAngles; + VectorAngles( vForward, vecAngles ); + + CRpgRocket * pMissile = CRpgRocket::Create( muzzlePoint, vecAngles, pOwner ); + pMissile->m_hOwner = this; + pMissile->SetAbsVelocity( pMissile->GetAbsVelocity() + vForward * DotProduct( pOwner->GetAbsVelocity(), vForward ) ); + + m_hMissile = pMissile; +#endif + + pOwner->ViewPunch( QAngle( -5, 0, 0 ) ); + + m_iClip1--; + + m_flNextPrimaryAttack = gpGlobals->curtime + 1.5; + SetWeaponIdleTime( 1.5 ); + + UpdateSpot(); +} + + +void CWeaponRPG::WeaponIdle( void ) +{ + CBaseCombatCharacter *pOwner = GetOwner(); + + if ( pOwner == NULL ) + return; + + if ( !HasWeaponIdleTimeElapsed() ) + return; + + int iAnim; + float flRand = random->RandomFloat( 0, 1 ); + if ( flRand <= 0.75 || IsGuiding() ) + { + if ( m_iClip1 <= 0 ) + iAnim = ACT_RPG_IDLE_UNLOADED; + else + iAnim = ACT_VM_IDLE; + } + else + { + if ( m_iClip1 <= 0 ) + iAnim = ACT_RPG_FIDGET_UNLOADED; + else + iAnim = ACT_VM_FIDGET; + } + + SendWeaponAnim( iAnim ); +} + + +void CWeaponRPG::NotifyRocketDied( void ) +{ + m_hMissile = NULL; + + // Can't be reloading + if ( GetActivity() == ACT_VM_RELOAD ) + return; + +// Reload(); +} + + +bool CWeaponRPG::Reload( void ) +{ + CBaseCombatCharacter *pOwner = GetOwner(); + +#if 0 + if ( pOwner == NULL ) + return false; + + if ( pOwner->GetAmmoCount(m_iPrimaryAmmoType) <= 0 ) + return false; + + WeaponSound( RELOAD ); + + SendWeaponAnim( ACT_VM_RELOAD ); + +#ifndef CLIENT_DLL + if ( m_hLaserDot != NULL ) + { + m_hLaserDot->TurnOff(); + } +#endif + + m_bLaserDotSuspended = true; + m_flLaserDotReviveTime = gpGlobals->curtime + 2.1; + m_flNextPrimaryAttack = gpGlobals->curtime + 2.1; + m_flNextSecondaryAttack = gpGlobals->curtime + 2.1; + + return true; +#endif + + // Can't be reloading + if ( GetActivity() == ACT_VM_RELOAD ) + return false; + + if ( pOwner == NULL ) + return false; + + if ( m_iClip1 > 0 ) + return false; + + if ( pOwner->GetAmmoCount(m_iPrimaryAmmoType) <= 0 ) + return false; + + // because the RPG waits to autoreload when no missiles are active while the LTD is on, the + // weapons code is constantly calling into this function, but is often denied because + // a) missiles are in flight, but the LTD is on + // or + // b) player is totally out of ammo and has nothing to switch to, and should be allowed to + // shine the designator around + // + // Set the next attack time into the future so that WeaponIdle will get called more often + // than reload, allowing the RPG LTD to be updated + + if ( ( m_hMissile != NULL ) && IsGuiding() ) + { + // no reloading when there are active missiles tracking the designator. + // ward off future autoreload attempts by setting next attack time into the future for a bit. + return false; + } + +#ifndef CLIENT_DLL + if ( m_hLaserDot != NULL ) + { + m_hLaserDot->TurnOff(); + } +#endif + + m_bLaserDotSuspended = true; + m_flLaserDotReviveTime = gpGlobals->curtime + 2.1; + m_flNextSecondaryAttack = gpGlobals->curtime + 2.1; + + return DefaultReload( GetMaxClip1(), GetMaxClip2(), ACT_VM_RELOAD ); +} + + +bool CWeaponRPG::Holster( CBaseCombatWeapon *pSwitchingTo ) +{ + // can't put away while guiding a missile. + if ( IsGuiding() && ( m_hMissile != NULL ) ) + return false; + +// StopGuiding(); + +#ifndef CLIENT_DLL + if ( m_hLaserDot != NULL ) + { + m_hLaserDot->TurnOff(); + UTIL_Remove( m_hLaserDot ); + m_hLaserDot = NULL; + } +#endif + + m_bLaserDotSuspended = false; + + return BaseClass::Holster( pSwitchingTo ); +} + + +void CWeaponRPG::UpdateSpot( void ) +{ + CBasePlayer *pPlayer = ToBasePlayer( GetOwner() ); + + if ( pPlayer == NULL ) + return; + + CreateLaserPointer(); + +#ifndef CLIENT_DLL + if ( m_hLaserDot == NULL ) + return; +#endif + + if ( IsGuiding() && m_bLaserDotSuspended && ( m_flLaserDotReviveTime <= gpGlobals->curtime ) ) + { +#ifndef CLIENT_DLL + m_hLaserDot->TurnOn(); +#endif + m_bLaserDotSuspended = false; + } + + //Move the laser dot, if active + trace_t tr; + Vector muzzlePos = pPlayer->Weapon_ShootPosition(); + + Vector forward; + AngleVectors( pPlayer->EyeAngles() + pPlayer->m_Local.m_vecPunchAngle, &forward ); + + Vector endPos = muzzlePos + ( forward * MAX_TRACE_LENGTH ); + + // Trace out for the endpoint + UTIL_TraceLine( muzzlePos, endPos, MASK_SHOT, this, COLLISION_GROUP_NONE, &tr ); + + // Move the laser sprite + Vector laserPos = tr.endpos + ( tr.plane.normal * 2.0f ); +#ifndef CLIENT_DLL + m_hLaserDot->SetLaserPosition( laserPos, tr.plane.normal ); +#endif +} + + +void CWeaponRPG::CreateLaserPointer( void ) +{ +#ifndef CLIENT_DLL + if ( m_hLaserDot != NULL ) + return; + + m_hLaserDot = CLaserDot::Create( GetAbsOrigin(), GetOwner() ); + if ( !IsGuiding() ) + { + if ( m_hLaserDot ) + { + m_hLaserDot->TurnOff(); + } + } +#endif +} + + +bool CWeaponRPG::IsGuiding( void ) +{ + return m_bGuiding; +} + + +void CWeaponRPG::StartGuiding( void ) +{ + m_bGuiding = true; + +#ifndef CLIENT_DLL + if ( m_hLaserDot != NULL ) + { + m_hLaserDot->TurnOn(); + } +#endif + + UpdateSpot(); +} + +void CWeaponRPG::StopGuiding( void ) +{ + m_bGuiding = false; + +#ifndef CLIENT_DLL + if ( m_hLaserDot != NULL ) + { + m_hLaserDot->TurnOff(); + } +#endif +} diff --git a/game/shared/hl1/hl1mp_weapon_rpg.h b/game/shared/hl1/hl1mp_weapon_rpg.h new file mode 100644 index 0000000..8e57e03 --- /dev/null +++ b/game/shared/hl1/hl1mp_weapon_rpg.h @@ -0,0 +1,135 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: RPG +// +//=============================================================================// + + +#ifndef WEAPON_RPG_H +#define WEAPON_RPG_H +#ifdef _WIN32 +#pragma once +#endif + + +#include "hl1mp_basecombatweapon_shared.h" + +#ifdef CLIENT_DLL +#include "iviewrender_beams.h" +#include "c_smoke_trail.h" +#endif + +#ifndef CLIENT_DLL +#include "smoke_trail.h" +#include "Sprite.h" +#include "npcevent.h" +#include "beam_shared.h" +#include "hl1_basegrenade.h" + +class CWeaponRPG; + +//########################################################################### +// CRpgRocket +//########################################################################### +class CRpgRocket : public CHL1BaseGrenade +{ + DECLARE_CLASS( CRpgRocket, CHL1BaseGrenade ); + DECLARE_SERVERCLASS(); + +public: + CRpgRocket(); + + Class_T Classify( void ) { return CLASS_NONE; } + + void Spawn( void ); + void Precache( void ); + void RocketTouch( CBaseEntity *pOther ); + void IgniteThink( void ); + void SeekThink( void ); + + virtual void Detonate( void ); + + static CRpgRocket *Create( const Vector &vecOrigin, const QAngle &angAngles, CBasePlayer *pentOwner = NULL ); + + CHandle<CWeaponRPG> m_hOwner; + float m_flIgniteTime; + int m_iTrail; + + DECLARE_DATADESC(); +}; + + +#endif + +#ifdef CLIENT_DLL +#define CLaserDot C_LaserDot +#endif + +class CLaserDot; + +#ifdef CLIENT_DLL +#define CWeaponRPG C_WeaponRPG +#endif + +//----------------------------------------------------------------------------- +// CWeaponRPG +//----------------------------------------------------------------------------- +class CWeaponRPG : public CBaseHL1MPCombatWeapon +{ + DECLARE_CLASS( CWeaponRPG, CBaseHL1MPCombatWeapon ); +public: + + CWeaponRPG( void ); + ~CWeaponRPG(); + + void ItemPostFrame( void ); + void Precache( void ); + bool Deploy( void ); + void PrimaryAttack( void ); + void WeaponIdle( void ); + bool Holster( CBaseCombatWeapon *pSwitchingTo = NULL ); + void NotifyRocketDied( void ); + bool Reload( void ); + + void Drop( const Vector &vecVelocity ); + + virtual int GetDefaultClip1( void ) const; + +// DECLARE_SERVERCLASS(); + DECLARE_DATADESC(); + DECLARE_NETWORKCLASS(); + DECLARE_PREDICTABLE(); + +private: + void CreateLaserPointer( void ); + void UpdateSpot( void ); + bool IsGuiding( void ); + void StartGuiding( void ); + void StopGuiding( void ); + +#ifndef CLIENT_DLL +// DECLARE_ACTTABLE(); +#endif + +private: +// bool m_bGuiding; +// CHandle<CLaserDot> m_hLaserDot; +// CHandle<CRpgRocket> m_hMissile; +// bool m_bIntialStateUpdate; +// bool m_bLaserDotSuspended; +// float m_flLaserDotReviveTime; + + CNetworkVar( bool, m_bGuiding ); + CNetworkVar( bool, m_bIntialStateUpdate ); + CNetworkVar( bool, m_bLaserDotSuspended ); + CNetworkVar( float, m_flLaserDotReviveTime ); + + CNetworkHandle( CBaseEntity, m_hMissile ); + +#ifndef CLIENT_DLL + CHandle<CLaserDot> m_hLaserDot; +#endif +}; + + +#endif // WEAPON_RPG_H diff --git a/game/shared/hl1/hl1mp_weapon_sachel.cpp b/game/shared/hl1/hl1mp_weapon_sachel.cpp new file mode 100644 index 0000000..cc26019 --- /dev/null +++ b/game/shared/hl1/hl1mp_weapon_sachel.cpp @@ -0,0 +1,600 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: Satchel charge +// +// $NoKeywords: $ +//=============================================================================// + +#include "cbase.h" +#include "npcevent.h" +#include "hl1_basecombatweapon_shared.h" +//#include "basecombatweapon.h" +//#include "basecombatcharacter.h" +#ifdef CLIENT_DLL +#include "c_baseplayer.h" +#else +#include "player.h" +#endif +//#include "AI_BaseNPC.h" +//#include "player.h" +#include "gamerules.h" +#include "in_buttons.h" +#ifndef CLIENT_DLL +#include "soundent.h" +#include "game.h" +#endif +#include "vstdlib/random.h" +#include "engine/IEngineSound.h" +#include "hl1mp_weapon_satchel.h" + + +//----------------------------------------------------------------------------- +// CWeaponSatchel +//----------------------------------------------------------------------------- + + +#define SATCHEL_VIEW_MODEL "models/v_satchel.mdl" +#define SATCHEL_WORLD_MODEL "models/w_satchel.mdl" +#define SATCHELRADIO_VIEW_MODEL "models/v_satchel_radio.mdl" +#define SATCHELRADIO_WORLD_MODEL "models/w_satchel.mdl" // this needs fixing if we do multiplayer + +IMPLEMENT_NETWORKCLASS_ALIASED( WeaponSatchel, DT_WeaponSatchel ); + +BEGIN_NETWORK_TABLE( CWeaponSatchel, DT_WeaponSatchel ) +#ifdef CLIENT_DLL + RecvPropInt( RECVINFO( m_iRadioViewIndex ) ), + RecvPropInt( RECVINFO( m_iRadioWorldIndex ) ), + RecvPropInt( RECVINFO( m_iSatchelViewIndex ) ), + RecvPropInt( RECVINFO( m_iSatchelWorldIndex ) ), + RecvPropInt( RECVINFO( m_iChargeReady ) ), +#else + SendPropInt( SENDINFO( m_iRadioViewIndex ) ), + SendPropInt( SENDINFO( m_iRadioWorldIndex ) ), + SendPropInt( SENDINFO( m_iSatchelViewIndex ) ), + SendPropInt( SENDINFO( m_iSatchelWorldIndex ) ), + SendPropInt( SENDINFO( m_iChargeReady ) ), +#endif +END_NETWORK_TABLE() + +LINK_ENTITY_TO_CLASS( weapon_satchel, CWeaponSatchel ); + +PRECACHE_WEAPON_REGISTER( weapon_satchel ); + +//IMPLEMENT_SERVERCLASS_ST( CWeaponSatchel, DT_WeaponSatchel ) +//END_SEND_TABLE() + + +BEGIN_PREDICTION_DATA( CWeaponSatchel ) +#ifdef CLIENT_DLL + DEFINE_PRED_FIELD( m_iRadioViewIndex, FIELD_INTEGER, FTYPEDESC_INSENDTABLE | FTYPEDESC_MODELINDEX ), + DEFINE_PRED_FIELD( m_iRadioWorldIndex, FIELD_INTEGER, FTYPEDESC_INSENDTABLE | FTYPEDESC_MODELINDEX ), + DEFINE_PRED_FIELD( m_iSatchelViewIndex, FIELD_INTEGER, FTYPEDESC_INSENDTABLE | FTYPEDESC_MODELINDEX ), + DEFINE_PRED_FIELD( m_iSatchelWorldIndex, FIELD_INTEGER, FTYPEDESC_INSENDTABLE | FTYPEDESC_MODELINDEX ), + DEFINE_PRED_FIELD( m_iChargeReady, FIELD_INTEGER, FTYPEDESC_INSENDTABLE ), +#endif +END_PREDICTION_DATA() + + +BEGIN_DATADESC( CWeaponSatchel ) + DEFINE_FIELD( m_iChargeReady, FIELD_INTEGER ), + +// DEFINE_FIELD( m_iRadioViewIndex, FIELD_INTEGER ), +// DEFINE_FIELD( m_iRadioWorldIndex, FIELD_INTEGER ), +// DEFINE_FIELD( m_iSatchelViewIndex, FIELD_INTEGER ), +// DEFINE_FIELD( m_iSatchelWorldIndex, FIELD_INTEGER ), +END_DATADESC() + +//----------------------------------------------------------------------------- +// Purpose: Constructor +//----------------------------------------------------------------------------- +CWeaponSatchel::CWeaponSatchel( void ) +{ + m_bReloadsSingly = false; + m_bFiresUnderwater = true; +} + +void CWeaponSatchel::Equip( CBaseCombatCharacter *pOwner ) +{ + BaseClass::Equip( pOwner ); + + m_iChargeReady = 0; // this satchel charge weapon now forgets that any satchels are deployed by it. +} + +bool CWeaponSatchel::HasAnyAmmo( void ) +{ + CBasePlayer *pPlayer = ToBasePlayer( GetOwner() ); + if ( !pPlayer ) + { + return false; + } + + if ( pPlayer->GetAmmoCount( m_iPrimaryAmmoType ) > 0 ) + { + // player is carrying some satchels + return true; + } + + if ( HasChargeDeployed() ) + { + // player isn't carrying any satchels, but has some out + return true; + } + + return BaseClass::HasAnyAmmo(); +} + +bool CWeaponSatchel::CanDeploy( void ) +{ + if ( HasAnyAmmo() ) + { + return true; + } + else + { + return false; + } +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CWeaponSatchel::Precache( void ) +{ + m_iSatchelViewIndex = PrecacheModel( SATCHEL_VIEW_MODEL ); + m_iSatchelWorldIndex = PrecacheModel( SATCHEL_WORLD_MODEL ); + m_iRadioViewIndex = PrecacheModel( SATCHELRADIO_VIEW_MODEL ); + m_iRadioWorldIndex = PrecacheModel( SATCHELRADIO_WORLD_MODEL ); + +#ifndef CLIENT_DLL + UTIL_PrecacheOther( "monster_satchel" ); +#endif + + BaseClass::Precache(); +} + +void CWeaponSatchel::ItemPostFrame( void ) +{ + CBasePlayer *pOwner = ToBasePlayer( GetOwner() ); + if (!pOwner) + { + return; + } + + if ( (pOwner->m_nButtons & IN_ATTACK) && (m_flNextPrimaryAttack <= gpGlobals->curtime) ) + { + // If the firing button was just pressed, reset the firing time + if ( pOwner->m_afButtonPressed & IN_ATTACK ) + { + m_flNextPrimaryAttack = gpGlobals->curtime; + } + + PrimaryAttack(); + } + + BaseClass::ItemPostFrame(); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CWeaponSatchel::PrimaryAttack( void ) +{ + switch ( m_iChargeReady ) + { + case 0: + { + Throw(); + } + break; + case 1: + { + CBasePlayer *pPlayer = ToBasePlayer( GetOwner() ); + if ( !pPlayer ) + { + return; + } + + SendWeaponAnim( ACT_VM_PRIMARYATTACK ); + +#ifndef CLIENT_DLL + CBaseEntity *pSatchel = NULL; + + while ( (pSatchel = gEntList.FindEntityByClassname( pSatchel, "monster_satchel" ) ) != NULL) + { + if ( pSatchel->GetOwnerEntity() == pPlayer ) + { + pSatchel->Use( pPlayer, pPlayer, USE_ON, 0 ); + } + } +#endif + + m_iChargeReady = 2; + m_flNextPrimaryAttack = gpGlobals->curtime + 0.5; + m_flNextSecondaryAttack = gpGlobals->curtime + 0.5; + SetWeaponIdleTime( gpGlobals->curtime + 0.5 ); + break; + } + + case 2: + // we're reloading, don't allow fire + break; + } +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CWeaponSatchel::SecondaryAttack( void ) +{ + if ( m_iChargeReady != 2 ) + { + Throw(); + } +} + +void CWeaponSatchel::Throw( void ) +{ + CBasePlayer *pPlayer = ToBasePlayer( GetOwner() ); + if ( !pPlayer ) + { + return; + } + + if ( pPlayer->GetAmmoCount( m_iPrimaryAmmoType ) > 0 ) + { + Vector vecForward; + pPlayer->EyeVectors( &vecForward ); + + Vector vecSrc = pPlayer->WorldSpaceCenter(); + Vector vecThrow = vecForward * 274 + pPlayer->GetAbsVelocity(); + +#ifndef CLIENT_DLL + CBaseEntity *pSatchel = Create( "monster_satchel", vecSrc, QAngle( 0, 0, 90 ), pPlayer ); + if ( pSatchel ) + { + pSatchel->SetAbsVelocity( vecThrow ); + QAngle angVel = pSatchel->GetLocalAngularVelocity(); + angVel.y = 400; + pSatchel->SetLocalAngularVelocity( angVel ); + + ActivateRadioModel(); + + SendWeaponAnim( ACT_VM_DRAW ); + + // player "shoot" animation + pPlayer->SetAnimation( PLAYER_ATTACK1 ); + + m_iChargeReady = 1; + + pPlayer->RemoveAmmo( 1, m_iPrimaryAmmoType ); + + } +#endif + + m_flNextPrimaryAttack = gpGlobals->curtime + 1.0; + m_flNextSecondaryAttack = gpGlobals->curtime + 0.5; + } +} + +void CWeaponSatchel::WeaponIdle( void ) +{ + if ( !HasWeaponIdleTimeElapsed() ) + return; + + switch( m_iChargeReady ) + { + case 0: + case 1: + SendWeaponAnim( ACT_VM_FIDGET ); + break; + case 2: + { + CBasePlayer *pPlayer = ToBasePlayer( GetOwner() ); + + if ( pPlayer && (pPlayer->GetAmmoCount( m_iPrimaryAmmoType ) <= 0) ) + { + m_iChargeReady = 0; + if ( !pPlayer->SwitchToNextBestWeapon( pPlayer->GetActiveWeapon() ) ) + { + Holster(); + } + + return; + } + + ActivateSatchelModel(); + + SendWeaponAnim( ACT_VM_DRAW ); + + m_flNextPrimaryAttack = gpGlobals->curtime + 0.5; + m_flNextSecondaryAttack = gpGlobals->curtime + 0.5; + m_iChargeReady = 0; + break; + } + } + + SetWeaponIdleTime( gpGlobals->curtime + random->RandomFloat( 10, 15 ) );// how long till we do this again. +} + +bool CWeaponSatchel::Deploy( void ) +{ + SetWeaponIdleTime( gpGlobals->curtime + random->RandomFloat( 10, 15 ) ); + + if ( HasChargeDeployed() ) + { + ActivateRadioModel(); + } + else + { + ActivateSatchelModel(); + } + + bool bRet = BaseClass::Deploy(); + if ( bRet ) + { + // + CBasePlayer *pPlayer = ToBasePlayer( GetOwner() ); + if ( pPlayer ) + { + pPlayer->SetNextAttack( gpGlobals->curtime + 1.0 ); + } + } + + return bRet; + +} + +bool CWeaponSatchel::Holster( CBaseCombatWeapon *pSwitchingTo ) +{ + if ( !BaseClass::Holster( pSwitchingTo ) ) + { + return false; + } + + CBasePlayer *pPlayer = ToBasePlayer( GetOwner() ); + if ( pPlayer ) + { + pPlayer->SetNextAttack( gpGlobals->curtime + 0.5 ); + + if ( (pPlayer->GetAmmoCount( m_iPrimaryAmmoType ) <= 0) && !HasChargeDeployed() ) + { +#ifndef CLIENT_DLL + SetThink( &CWeaponSatchel::DestroyItem ); + SetNextThink( gpGlobals->curtime + 0.1 ); +#endif + } + } + + return true; +} + +void CWeaponSatchel::ActivateSatchelModel( void ) +{ + m_iViewModelIndex = m_iSatchelViewIndex; + m_iWorldModelIndex = m_iSatchelWorldIndex; + SetModel( GetViewModel() ); +} + +void CWeaponSatchel::ActivateRadioModel( void ) +{ + m_iViewModelIndex = m_iRadioViewIndex; + m_iWorldModelIndex = m_iRadioWorldIndex; + SetModel( GetViewModel() ); +} + +const char *CWeaponSatchel::GetViewModel( int ) const +{ + if ( m_iViewModelIndex == m_iSatchelViewIndex ) + { + return SATCHEL_VIEW_MODEL; + } + else + { + return SATCHELRADIO_VIEW_MODEL; + } +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +const char *CWeaponSatchel::GetWorldModel( void ) const +{ + if ( m_iViewModelIndex == m_iSatchelViewIndex ) + { + return SATCHEL_WORLD_MODEL; + } + else + { + return SATCHELRADIO_WORLD_MODEL; + } +} + +void CWeaponSatchel::OnRestore( void ) +{ + BaseClass::OnRestore(); + if ( HasChargeDeployed() ) + { + ActivateRadioModel(); + } + else + { + ActivateSatchelModel(); + } +} + +#ifndef CLIENT_DLL +//----------------------------------------------------------------------------- +// CSatchelCharge +//----------------------------------------------------------------------------- + +#define SATCHEL_CHARGE_MODEL "models/w_satchel.mdl" + + +extern ConVar sk_plr_dmg_satchel; + + +BEGIN_DATADESC( CSatchelCharge ) + DEFINE_FIELD( m_flNextBounceSoundTime, FIELD_TIME ), + DEFINE_FIELD( m_bInAir, FIELD_BOOLEAN ), + DEFINE_FIELD( m_vLastPosition, FIELD_POSITION_VECTOR ), + + // Function Pointers + DEFINE_ENTITYFUNC( SatchelTouch ), + DEFINE_THINKFUNC( SatchelThink ), + DEFINE_USEFUNC( SatchelUse ), +END_DATADESC() + +LINK_ENTITY_TO_CLASS( monster_satchel, CSatchelCharge ); + +//========================================================= +// Deactivate - do whatever it is we do to an orphaned +// satchel when we don't want it in the world anymore. +//========================================================= +void CSatchelCharge::Deactivate( void ) +{ + AddSolidFlags( FSOLID_NOT_SOLID ); + UTIL_Remove( this ); +} + + +void CSatchelCharge::Spawn( void ) +{ + Precache( ); + // motor + SetMoveType( MOVETYPE_FLYGRAVITY, MOVECOLLIDE_FLY_SLIDE ); + SetSolid( SOLID_BBOX ); + + SetModel( SATCHEL_CHARGE_MODEL ); + + UTIL_SetSize( this, Vector( -4, -4, 0), Vector(4, 4, 8) ); + + SetTouch( &CSatchelCharge::SatchelTouch ); + SetUse( &CSatchelCharge::SatchelUse ); + SetThink( &CSatchelCharge::SatchelThink ); + SetNextThink( gpGlobals->curtime + 0.1f ); + + m_flDamage = sk_plr_dmg_satchel.GetFloat(); + m_DmgRadius = m_flDamage * 2.5; + m_takedamage = DAMAGE_NO; + m_iHealth = 1; + + SetGravity( UTIL_ScaleForGravity( 560 ) ); // slightly lower gravity + SetFriction( 0.97 ); //used in SatchelTouch to slow us when sliding + SetSequence( LookupSequence( "onback" ) ); + + m_bInAir = false; + m_flNextBounceSoundTime = 0; + + m_vLastPosition = vec3_origin; +} + +//----------------------------------------------------------------------------- +// Purpose: +// Input : +// Output : +//----------------------------------------------------------------------------- +void CSatchelCharge::SatchelUse( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) +{ + SetThink( &CBaseGrenade::Detonate ); + SetNextThink( gpGlobals->curtime ); +} + +//----------------------------------------------------------------------------- +// Purpose: +// Input : +// Output : +//----------------------------------------------------------------------------- +void CSatchelCharge::SatchelTouch( CBaseEntity *pOther ) +{ + Assert( pOther ); + if ( pOther->IsSolidFlagSet(FSOLID_TRIGGER | FSOLID_VOLUME_CONTENTS) || GetWaterLevel() > 0 ) + return; + + StudioFrameAdvance( ); + + UpdateSlideSound(); + + if ( m_bInAir ) + { + BounceSound(); + m_bInAir = false; + } + + // add a bit of static friction + SetAbsVelocity( GetAbsVelocity() * GetFriction() ); + SetLocalAngularVelocity( GetLocalAngularVelocity() * GetFriction() ); +} + +void CSatchelCharge::UpdateSlideSound( void ) +{ + // HACKHACK - On ground isn't always set, so look for ground underneath + trace_t tr; + UTIL_TraceLine( GetAbsOrigin(), GetAbsOrigin() - Vector(0,0,10), MASK_SOLID_BRUSHONLY, this, COLLISION_GROUP_NONE, &tr ); + + if ( !(tr.fraction < 1.0) ) + { + m_bInAir = true; + } +} + +void CSatchelCharge::SatchelThink( void ) +{ + UpdateSlideSound(); + + StudioFrameAdvance( ); + SetNextThink( gpGlobals->curtime + 0.1f ); + + if (!IsInWorld()) + { + UTIL_Remove( this ); + return; + } + + Vector vecNewVel = GetAbsVelocity(); + + if ( GetWaterLevel() > 0 ) + { + SetMoveType( MOVETYPE_FLYGRAVITY, MOVECOLLIDE_FLY_BOUNCE ); + vecNewVel *= 0.8; + SetLocalAngularVelocity( GetLocalAngularVelocity() * 0.9 ); + + vecNewVel.z = 0; + SetGravity( -0.2 ); + } + else if ( GetWaterLevel() == 0 ) + { + SetMoveType( MOVETYPE_FLYGRAVITY, MOVECOLLIDE_FLY_SLIDE ); + + SetGravity( 1.0 ); + } + + SetAbsVelocity( vecNewVel ); +} + +void CSatchelCharge::Precache( void ) +{ + PrecacheModel( SATCHEL_CHARGE_MODEL ); + PrecacheScriptSound( "SatchelCharge.Bounce" ); +} + +void CSatchelCharge::BounceSound( void ) +{ + if ( gpGlobals->curtime > m_flNextBounceSoundTime ) + { + EmitSound( "SatchelCharge.Bounce" ); + + m_flNextBounceSoundTime = gpGlobals->curtime + 0.1; + } +} + +//----------------------------------------------------------------------------- +// Purpose: Constructor +// Input : +// Output : +//----------------------------------------------------------------------------- +CSatchelCharge::CSatchelCharge(void) +{ + m_vLastPosition.Init(); +} + +#endif diff --git a/game/shared/hl1/hl1mp_weapon_satchel.h b/game/shared/hl1/hl1mp_weapon_satchel.h new file mode 100644 index 0000000..c7ed022 --- /dev/null +++ b/game/shared/hl1/hl1mp_weapon_satchel.h @@ -0,0 +1,107 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=============================================================================// + +#ifndef HL1_WEAPON_SATCHEL_H +#define HL1_WEAPON_SATCHEL_H +#ifdef _WIN32 +#pragma once +#endif + + +#ifndef CLIENT_DLL +#include "hl1_basegrenade.h" +#include "hl1_basecombatweapon_shared.h" +#endif + + +#ifdef CLIENT_DLL +#define CWeaponSatchel C_WeaponSatchel +#endif + + +//----------------------------------------------------------------------------- +// CWeaponSatchel +//----------------------------------------------------------------------------- + +class CWeaponSatchel : public CBaseHL1CombatWeapon +{ + DECLARE_CLASS( CWeaponSatchel, CBaseHL1CombatWeapon ); + + DECLARE_NETWORKCLASS(); + DECLARE_PREDICTABLE(); +public: + + CWeaponSatchel( void ); + + void Equip( CBaseCombatCharacter *pOwner ); + bool HasAnyAmmo( void ); + bool CanDeploy( void ); + void Precache( void ); + void PrimaryAttack( void ); + void SecondaryAttack( void ); + void WeaponIdle( void ); + bool Deploy( void ); + bool Holster( CBaseCombatWeapon *pSwitchingTo = NULL ); + + void ItemPostFrame( void ); + const char *GetViewModel( int viewmodelindex = 0 ) const; + const char *GetWorldModel( void ) const; + + bool HasChargeDeployed() { return ( m_iChargeReady != 0 ); } + + void OnRestore( void ); + +// DECLARE_SERVERCLASS(); + DECLARE_DATADESC(); + +private: + void Throw( void ); + void ActivateSatchelModel( void ); + void ActivateRadioModel( void ); + +private: + CNetworkVar( int, m_iRadioViewIndex ); + CNetworkVar( int, m_iRadioWorldIndex ); + CNetworkVar( int, m_iSatchelViewIndex ); + CNetworkVar( int, m_iSatchelWorldIndex ); + CNetworkVar( int, m_iChargeReady ); +}; + + +#ifndef CLIENT_DLL +//----------------------------------------------------------------------------- +// CSatchelCharge +//----------------------------------------------------------------------------- + +class CSatchelCharge : public CHL1BaseGrenade +{ +public: + DECLARE_CLASS( CSatchelCharge, CHL1BaseGrenade ); + + CSatchelCharge(); + + void Spawn( void ); + void Precache( void ); + void SatchelTouch( CBaseEntity *pOther ); + void SatchelThink( void ); + void SatchelUse( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); + + DECLARE_DATADESC(); + +private: + Vector m_vLastPosition; + float m_flNextBounceSoundTime; + bool m_bInAir; + +private: + void BounceSound( void ); + void UpdateSlideSound( void ); + void Deactivate( void ); +}; +#endif + + +#endif // HL1_WEAPON_SATCHEL_H diff --git a/game/shared/hl1/hl1mp_weapon_shotgun.cpp b/game/shared/hl1/hl1mp_weapon_shotgun.cpp new file mode 100644 index 0000000..ce730f7 --- /dev/null +++ b/game/shared/hl1/hl1mp_weapon_shotgun.cpp @@ -0,0 +1,417 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: This is the Shotgun weapon +// +// $Workfile: $ +// $Date: $ +// $NoKeywords: $ +//=============================================================================// + +#include "cbase.h" +#include "npcevent.h" +#include "hl1mp_basecombatweapon_shared.h" +//#include "basecombatcharacter.h" +//#include "AI_BaseNPC.h" +#ifdef CLIENT_DLL +#include "c_baseplayer.h" +#else +#include "player.h" +#endif +#include "gamerules.h" // For g_pGameRules +#include "in_buttons.h" +//#include "soundent.h" +#include "vstdlib/random.h" + + +#ifdef CLIENT_DLL +#define CWeaponShotgun C_WeaponShotgun +#endif + +// special deathmatch shotgun spreads +#define VECTOR_CONE_DM_SHOTGUN Vector( 0.08716, 0.04362, 0.00 )// 10 degrees by 5 degrees +#define VECTOR_CONE_DM_DOUBLESHOTGUN Vector( 0.17365, 0.04362, 0.00 ) // 20 degrees by 5 degrees + + +class CWeaponShotgun : public CBaseHL1MPCombatWeapon +{ + DECLARE_CLASS( CWeaponShotgun, CBaseHL1MPCombatWeapon ); + + DECLARE_NETWORKCLASS(); + DECLARE_PREDICTABLE(); + +private: +// float m_flPumpTime; +// int m_fInSpecialReload; + + CNetworkVar( float, m_flPumpTime); + CNetworkVar( int, m_fInSpecialReload ); + +public: + void Precache( void ); + + bool Reload( void ); + void FillClip( void ); + void WeaponIdle( void ); + void PrimaryAttack( void ); + void SecondaryAttack( void ); + void DryFire( void ); + +// DECLARE_SERVERCLASS(); +// DECLARE_DATADESC(); + + CWeaponShotgun(void); + +//#ifndef CLIENT_DLL +// DECLARE_ACTTABLE(); +//#endif +}; + + +IMPLEMENT_NETWORKCLASS_ALIASED( WeaponShotgun, DT_WeaponShotgun ); + +BEGIN_NETWORK_TABLE( CWeaponShotgun, DT_WeaponShotgun ) +#ifdef CLIENT_DLL + RecvPropFloat( RECVINFO( m_flPumpTime ) ), + RecvPropInt( RECVINFO( m_fInSpecialReload ) ), +#else + SendPropFloat( SENDINFO( m_flPumpTime ) ), + SendPropInt( SENDINFO( m_fInSpecialReload ) ), +#endif +END_NETWORK_TABLE() + +BEGIN_PREDICTION_DATA( CWeaponShotgun ) +#ifdef CLIENT_DLL + DEFINE_PRED_FIELD( m_flPumpTime, FIELD_FLOAT, FTYPEDESC_INSENDTABLE ), + DEFINE_PRED_FIELD( m_fInSpecialReload, FIELD_INTEGER, FTYPEDESC_INSENDTABLE ), +#endif +END_PREDICTION_DATA() + +LINK_ENTITY_TO_CLASS( weapon_shotgun, CWeaponShotgun ); +PRECACHE_WEAPON_REGISTER(weapon_shotgun); + +//IMPLEMENT_SERVERCLASS_ST( CWeaponShotgun, DT_WeaponShotgun ) +//END_SEND_TABLE() + +//BEGIN_DATADESC( CWeaponShotgun ) +//END_DATADESC() + +//----------------------------------------------------------------------------- +// Purpose: Constructor +//----------------------------------------------------------------------------- +CWeaponShotgun::CWeaponShotgun( void ) +{ + m_bReloadsSingly = true; + m_bFiresUnderwater = false; + m_flPumpTime = 0.0; + m_fInSpecialReload = 0; +} + + +void CWeaponShotgun::Precache( void ) +{ + BaseClass::Precache(); +} + +void CWeaponShotgun::PrimaryAttack( void ) +{ + // Only the player fires this way so we can cast + CBasePlayer *pPlayer = ToBasePlayer( GetOwner() ); + + if (!pPlayer) + { + return; + } + + if ( m_iClip1 <= 0 ) + { + Reload(); + if ( m_iClip1 <= 0 ) + DryFire( ); + + return; + } + + // MUST call sound before removing a round from the clip of a CMachineGun + WeaponSound( SINGLE ); + + pPlayer->DoMuzzleFlash(); + + SendWeaponAnim( ACT_VM_PRIMARYATTACK ); + pPlayer->SetAnimation( PLAYER_ATTACK1 ); + + // Don't fire again until fire animation has completed + m_flNextPrimaryAttack = gpGlobals->curtime + 0.75; + m_flNextSecondaryAttack = gpGlobals->curtime + 0.75; + m_iClip1 -= 1; + + Vector vecSrc = pPlayer->Weapon_ShootPosition(); + Vector vecAiming = pPlayer->GetAutoaimVector( AUTOAIM_5DEGREES ); + + if ( g_pGameRules->IsMultiplayer() ) + { + FireBulletsInfo_t info( 4, vecSrc, vecAiming, VECTOR_CONE_DM_SHOTGUN, MAX_TRACE_LENGTH, m_iPrimaryAmmoType ); + info.m_pAttacker = pPlayer; + + pPlayer->FireBullets( info ); + } + else + { + FireBulletsInfo_t info( 6, vecSrc, vecAiming, VECTOR_CONE_10DEGREES, MAX_TRACE_LENGTH, m_iPrimaryAmmoType ); + info.m_pAttacker = pPlayer; + + pPlayer->FireBullets( info ); + +// pPlayer->FireBullets( 6, vecSrc, vecAiming, VECTOR_CONE_10DEGREES, MAX_TRACE_LENGTH, m_iPrimaryAmmoType, 0 ); + } + + EjectShell( pPlayer, 1 ); + +#if !defined(CLIENT_DLL) + pPlayer->SetMuzzleFlashTime( gpGlobals->curtime + 1.0 ); +#endif + + pPlayer->ViewPunch( QAngle( -5, 0, 0 ) ); + +// CSoundEnt::InsertSound( SOUND_COMBAT, GetAbsOrigin(), 600, 0.2 ); + WeaponSound( SINGLE ); + + if ( !m_iClip1 && pPlayer->GetAmmoCount( m_iPrimaryAmmoType ) <= 0 ) + { + // HEV suit - indicate out of ammo condition + pPlayer->SetSuitUpdate("!HEV_AMO0", FALSE, 0); + } + + if ( m_iClip1 > 0 ) + { + m_flPumpTime = gpGlobals->curtime + 0.5; + } + + m_fInSpecialReload = 0; +} + + +void CWeaponShotgun::SecondaryAttack( void ) +{ + // Only the player fires this way so we can cast + CBasePlayer *pPlayer = ToBasePlayer( GetOwner() ); + + if (!pPlayer) + { + return; + } + + if ( m_iClip1 <= 1 ) + { + Reload(); + if ( m_iClip1 <= 0 ) + DryFire( ); + + return; + } + + if ( pPlayer->GetWaterLevel() == 3 ) + { + // This weapon doesn't fire underwater + WeaponSound(EMPTY); + m_flNextPrimaryAttack = gpGlobals->curtime + 0.2; + m_flNextSecondaryAttack = gpGlobals->curtime + 0.2; + return; + } + + // MUST call sound before removing a round from the clip of a CMachineGun + WeaponSound( WPN_DOUBLE ); + + pPlayer->DoMuzzleFlash(); + + SendWeaponAnim( ACT_VM_SECONDARYATTACK ); + pPlayer->SetAnimation( PLAYER_ATTACK1 ); + + // Don't fire again until fire animation has completed + m_flNextPrimaryAttack = gpGlobals->curtime + 1.5; + m_flNextSecondaryAttack = gpGlobals->curtime + 1.5; + + m_iClip1 -= 2; // Shotgun uses same clip for primary and secondary attacks + + Vector vecSrc = pPlayer->Weapon_ShootPosition(); + Vector vecAiming = pPlayer->GetAutoaimVector( AUTOAIM_5DEGREES ); + + // Fire the bullets + if ( g_pGameRules->IsMultiplayer() ) + { + FireBulletsInfo_t info( 8, vecSrc, vecAiming, VECTOR_CONE_DM_DOUBLESHOTGUN, MAX_TRACE_LENGTH, m_iPrimaryAmmoType ); + info.m_pAttacker = pPlayer; + + pPlayer->FireBullets( info ); + +// pPlayer->FireBullets( 8, vecSrc, vecAiming, VECTOR_CONE_DM_DOUBLESHOTGUN, MAX_TRACE_LENGTH, m_iPrimaryAmmoType, 0 ); + } + else + { + FireBulletsInfo_t info( 12, vecSrc, vecAiming, VECTOR_CONE_10DEGREES, MAX_TRACE_LENGTH, m_iPrimaryAmmoType ); + + pPlayer->FireBullets( info ); +// pPlayer->FireBullets( 12, vecSrc, vecAiming, VECTOR_CONE_10DEGREES, MAX_TRACE_LENGTH, m_iPrimaryAmmoType, 0 ); + } + + EjectShell( pPlayer, 1 ); + EjectShell( pPlayer, 1 ); + + pPlayer->ViewPunch( QAngle( -10, 0, 0 ) ); +#if !defined(CLIENT_DLL) + pPlayer->SetMuzzleFlashTime( gpGlobals->curtime + 1.0 ); +#endif + +// CSoundEnt::InsertSound( SOUND_COMBAT, GetAbsOrigin(), 800, 0.2 ); + WeaponSound( SINGLE ); + + if ( !m_iClip1 && pPlayer->GetAmmoCount( m_iPrimaryAmmoType ) <= 0 ) + { + // HEV suit - indicate out of ammo condition + pPlayer->SetSuitUpdate("!HEV_AMO0", FALSE, 0); + } + + if ( m_iClip1 > 0 ) + { + m_flPumpTime = gpGlobals->curtime + 0.5; + } + + m_fInSpecialReload = 0; +} + + +bool CWeaponShotgun::Reload( void ) +{ + CBaseCombatCharacter *pOwner = GetOwner(); + + if ( pOwner == NULL ) + return false; + + if ( pOwner->GetAmmoCount( m_iPrimaryAmmoType ) <= 0 ) + return false; + + if ( m_iClip1 >= GetMaxClip1() ) + return false; + + // don't reload until recoil is done + if ( m_flNextPrimaryAttack > gpGlobals->curtime ) + return false; + + // check to see if we're ready to reload + if ( m_fInSpecialReload == 0 ) + { + SendWeaponAnim( ACT_SHOTGUN_RELOAD_START ); + m_fInSpecialReload = 1; + + pOwner->m_flNextAttack = gpGlobals->curtime + 0.6; + SetWeaponIdleTime( gpGlobals->curtime + 0.6 ); + m_flNextPrimaryAttack = gpGlobals->curtime + 1.0; + m_flNextSecondaryAttack = gpGlobals->curtime + 1.0; + + return true; + } + else if ( m_fInSpecialReload == 1 ) + { + if ( !HasWeaponIdleTimeElapsed() ) + return false; + + // was waiting for gun to move to side + m_fInSpecialReload = 2; + + // Play reload on different channel as otherwise steals channel away from fire sound + WeaponSound( RELOAD ); + SendWeaponAnim( ACT_VM_RELOAD ); + + SetWeaponIdleTime( gpGlobals->curtime + 0.5 ); + } + else + { + FillClip(); + m_fInSpecialReload = 1; + } + + return true; +} + + +void CWeaponShotgun::FillClip( void ) +{ + CBaseCombatCharacter *pOwner = GetOwner(); + + if ( pOwner == NULL ) + return; + + // Add them to the clip + m_iClip1++; + pOwner->RemoveAmmo( 1, m_iPrimaryAmmoType ); +} + + +void CWeaponShotgun::DryFire( void ) +{ + WeaponSound( EMPTY ); + m_flNextPrimaryAttack = gpGlobals->curtime + 0.75; + m_flNextSecondaryAttack = gpGlobals->curtime + 0.75; +} + + +void CWeaponShotgun::WeaponIdle( void ) +{ + CBasePlayer *pPlayer = ToBasePlayer( GetOwner() ); + + if ( pPlayer == NULL ) + return; + + pPlayer->GetAutoaimVector( AUTOAIM_10DEGREES ); + + if ( m_flPumpTime && m_flPumpTime < gpGlobals->curtime ) + { + // play pumping sound + WeaponSound( SPECIAL1 ); + m_flPumpTime = 0; + } + + if ( HasWeaponIdleTimeElapsed() ) + { + if ( m_iClip1 == 0 && m_fInSpecialReload == 0 && pPlayer->GetAmmoCount( m_iPrimaryAmmoType ) > 0 ) + { + Reload(); + } + else if ( m_fInSpecialReload != 0 ) + { + if ( m_iClip1 != 8 && pPlayer->GetAmmoCount( m_iPrimaryAmmoType ) > 0 ) + { + Reload( ); + } + else + { + // reload debounce has timed out + SendWeaponAnim( ACT_SHOTGUN_PUMP ); + + // play cocking sound + WeaponSound( SPECIAL1 ); + m_fInSpecialReload = 0; + SetWeaponIdleTime( gpGlobals->curtime + 1.5 ); + } + } + else + { + int iAnim; + float flRand = random->RandomFloat( 0, 1 ); + + if ( flRand <= 0.8 ) + { + iAnim = ACT_SHOTGUN_IDLE_DEEP; + } + else if ( flRand <= 0.95 ) + { + iAnim = ACT_VM_IDLE; + } + else + { + iAnim = ACT_SHOTGUN_IDLE4; + } + + SendWeaponAnim( iAnim ); + } + } +} |