//========= Copyright Valve Corporation, All rights reserved. ============// // // Purpose: Player for HL2. // //=============================================================================// #include "cbase.h" #include "hl2_player.h" #include "globalstate.h" #include "game.h" #include "gamerules.h" #include "trains.h" #include "basehlcombatweapon_shared.h" #include "vcollide_parse.h" #include "in_buttons.h" #include "ai_interactions.h" #include "ai_squad.h" #include "igamemovement.h" #include "ai_hull.h" #include "hl2_shareddefs.h" #include "info_camera_link.h" #include "point_camera.h" #include "engine/IEngineSound.h" #include "ndebugoverlay.h" #include "iservervehicle.h" #include "IVehicle.h" #include "globals.h" #include "collisionutils.h" #include "coordsize.h" #include "effect_color_tables.h" #include "vphysics/player_controller.h" #include "player_pickup.h" #include "weapon_physcannon.h" #include "script_intro.h" #include "effect_dispatch_data.h" #include "te_effect_dispatch.h" #include "ai_basenpc.h" #include "AI_Criteria.h" #include "npc_barnacle.h" #include "entitylist.h" #include "env_zoom.h" #include "hl2_gamerules.h" #include "prop_combine_ball.h" #include "datacache/imdlcache.h" #include "eventqueue.h" #include "gamestats.h" #include "filters.h" #include "tier0/icommandline.h" #include "grenade_frag.h" // BriJee OVR: Grenade types for fast throw #include "overcharged/grenade_flash.h" #include "overcharged/grenade_smoke.h" #include "BasePropDoor.h" #ifdef HL2_EPISODIC #include "npc_alyx_episodic.h" #endif #ifdef PORTAL #include "portal_player.h" #endif // PORTAL // memdbgon must be the last include file in a .cpp file!!! #include "tier0/memdbgon.h" extern ConVar weapon_showproficiency; extern ConVar autoaim_max_dist; ConVar oc_player_allow_kick("oc_player_allow_kick", "0", FCVAR_ARCHIVE, "Player allow kick"); ConVar oc_player_allow_kick_doors("oc_player_allow_kick_doors", "0", FCVAR_ARCHIVE, "Player allow kick doors"); ConVar oc_player_allow_swing("oc_player_allow_swing", "0", FCVAR_ARCHIVE, "Player allow swing"); ConVar oc_player_swing_range("oc_player_swing_range", "85", FCVAR_ARCHIVE); // Do not touch with without seeing me, please! (sjb) // For consistency's sake, enemy gunfire is traced against a scaled down // version of the player's hull, not the hitboxes for the player's model // because the player isn't aware of his model, and can't do anything about // preventing headshots and other such things. Also, game difficulty will // not change if the model changes. This is the value by which to scale // the X/Y of the player's hull to get the volume to trace bullets against. #define PLAYER_HULL_REDUCTION 0.70 // This switches between the single primary weapon, and multiple weapons with buckets approach (jdw) //#define HL2_SINGLE_PRIMARY_WEAPON_MODE 0 #define TIME_IGNORE_FALL_DAMAGE 10.0 extern int gEvilImpulse101; ConVar sv_autojump( "sv_autojump", "0" ); ConVar hl2_walkspeed( "hl2_walkspeed", "150" ); ConVar hl2_normspeed( "hl2_normspeed", "190" ); ConVar hl2_sprintspeed( "hl2_sprintspeed", "320" ); ConVar hl2_darkness_flashlight_factor ( "hl2_darkness_flashlight_factor", "1" ); #ifdef HL2MP #define HL2_WALK_SPEED 150 #define HL2_NORM_SPEED 190 #define HL2_SPRINT_SPEED 320 #else #define HL2_WALK_SPEED hl2_walkspeed.GetFloat() #define HL2_NORM_SPEED hl2_normspeed.GetFloat() #define HL2_SPRINT_SPEED hl2_sprintspeed.GetFloat() #endif ConVar player_showpredictedposition( "player_showpredictedposition", "0" ); ConVar player_showpredictedposition_timestep( "player_showpredictedposition_timestep", "1.0" ); ConVar player_squad_transient_commands( "player_squad_transient_commands", "1", FCVAR_REPLICATED ); ConVar player_squad_double_tap_time( "player_squad_double_tap_time", "0.25" ); ConVar sv_infinite_aux_power( "sv_infinite_aux_power", "0", FCVAR_CHEAT ); ConVar autoaim_unlock_target( "autoaim_unlock_target", "0.8666" ); ConVar sv_stickysprint("sv_stickysprint", "0", FCVAR_ARCHIVE | FCVAR_ARCHIVE_XBOX); #define FLASH_DRAIN_TIME 1.1111 // 100 units / 90 secs #define FLASH_CHARGE_TIME 50.0f // 100 units / 2 secs //============================================================================================== // CAPPED PLAYER PHYSICS DAMAGE TABLE //============================================================================================== static impactentry_t cappedPlayerLinearTable[] = { { 150*150, 5 }, { 250*250, 10 }, { 450*450, 20 }, { 550*550, 30 }, //{ 700*700, 100 }, //{ 1000*1000, 500 }, }; static impactentry_t cappedPlayerAngularTable[] = { { 100*100, 10 }, { 150*150, 20 }, { 200*200, 30 }, //{ 300*300, 500 }, }; static impactdamagetable_t gCappedPlayerImpactDamageTable = { cappedPlayerLinearTable, cappedPlayerAngularTable, ARRAYSIZE(cappedPlayerLinearTable), ARRAYSIZE(cappedPlayerAngularTable), 24*24.0f, // minimum linear speed 360*360.0f, // minimum angular speed 2.0f, // can't take damage from anything under 2kg 5.0f, // anything less than 5kg is "small" 5.0f, // never take more than 5 pts of damage from anything under 5kg 36*36.0f, // <5kg objects must go faster than 36 in/s to do damage 0.0f, // large mass in kg (no large mass effects) 1.0f, // large mass scale 2.0f, // large mass falling scale 320.0f, // min velocity for player speed to cause damage }; // Flashlight utility bool g_bCacheLegacyFlashlightStatus = true; bool g_bUseLegacyFlashlight; bool Flashlight_UseLegacyVersion( void ) { // If this is the first run through, cache off what the answer should be (cannot change during a session) if ( g_bCacheLegacyFlashlightStatus ) { char modDir[MAX_PATH]; if ( UTIL_GetModDir( modDir, sizeof(modDir) ) == false ) return false; g_bUseLegacyFlashlight = ( !Q_strcmp( modDir, "hl2" ) || !Q_strcmp( modDir, "episodic" ) || !Q_strcmp( modDir, "lostcoast" ) || !Q_strcmp( modDir, "hl1" )); g_bCacheLegacyFlashlightStatus = false; } // Return the results return g_bUseLegacyFlashlight; } //----------------------------------------------------------------------------- // Purpose: Used to relay outputs/inputs from the player to the world and viceversa //----------------------------------------------------------------------------- class CLogicPlayerProxy : public CLogicalEntity { DECLARE_CLASS( CLogicPlayerProxy, CLogicalEntity ); private: DECLARE_DATADESC(); public: COutputEvent m_OnFlashlightOn; COutputEvent m_OnFlashlightOff; COutputEvent m_PlayerHasAmmo; COutputEvent m_PlayerHasNoAmmo; COutputEvent m_PlayerDied; COutputEvent m_PlayerMissedAR2AltFire; // Player fired a combine ball which did not dissolve any enemies. COutputInt m_RequestedPlayerHealth; void InputRequestPlayerHealth( inputdata_t &inputdata ); void InputSetFlashlightSlowDrain( inputdata_t &inputdata ); void InputSetFlashlightNormalDrain( inputdata_t &inputdata ); void InputSetPlayerHealth( inputdata_t &inputdata ); void InputRequestAmmoState( inputdata_t &inputdata ); void InputLowerWeapon( inputdata_t &inputdata ); void InputEnableCappedPhysicsDamage( inputdata_t &inputdata ); void InputDisableCappedPhysicsDamage( inputdata_t &inputdata ); void InputSetLocatorTargetEntity( inputdata_t &inputdata ); #ifdef PORTAL void InputSuppressCrosshair( inputdata_t &inputdata ); #endif // PORTAL2 void Activate ( void ); bool PassesDamageFilter( const CTakeDamageInfo &info ); EHANDLE m_hPlayer; }; //------------------------------------------------------------------------------ //------------------------------------------------------------------------------ void CC_ToggleZoom( void ) { CBasePlayer* pPlayer = UTIL_GetCommandClient(); if( pPlayer ) { CHL2_Player *pHL2Player = dynamic_cast(pPlayer); if( pHL2Player && pHL2Player->IsSuitEquipped() ) { pHL2Player->ToggleZoom(); } } } static ConCommand toggle_zoom("toggle_zoom", CC_ToggleZoom, "Toggles zoom display" ); // ConVar cl_forwardspeed( "cl_forwardspeed", "400", FCVAR_CHEAT ); // Links us to the client's version ConVar xc_crouch_range( "xc_crouch_range", "0.85", FCVAR_ARCHIVE, "Percentarge [1..0] of joystick range to allow ducking within" ); // Only 1/2 of the range is used ConVar xc_use_crouch_limiter( "xc_use_crouch_limiter", "0", FCVAR_ARCHIVE, "Use the crouch limiting logic on the controller" ); //------------------------------------------------------------------------------ //------------------------------------------------------------------------------ void CC_ToggleDuck( void ) { CBasePlayer* pPlayer = UTIL_GetCommandClient(); if ( pPlayer == NULL ) return; // Cannot be frozen if ( pPlayer->GetFlags() & FL_FROZEN ) return; static bool bChecked = false; static ConVar *pCVcl_forwardspeed = NULL; if ( !bChecked ) { bChecked = true; pCVcl_forwardspeed = ( ConVar * )cvar->FindVar( "cl_forwardspeed" ); } // If we're not ducked, do extra checking if ( xc_use_crouch_limiter.GetBool() ) { if ( pPlayer->GetToggledDuckState() == false ) { float flForwardSpeed = 400.0f; if ( pCVcl_forwardspeed ) { flForwardSpeed = pCVcl_forwardspeed->GetFloat(); } flForwardSpeed = MAX( 1.0f, flForwardSpeed ); // Make sure we're not in the blindspot on the crouch detection float flStickDistPerc = ( pPlayer->GetStickDist() / flForwardSpeed ); // Speed is the magnitude if ( flStickDistPerc > xc_crouch_range.GetFloat() ) return; } } // Toggle the duck pPlayer->ToggleDuck(); } static ConCommand toggle_duck("toggle_duck", CC_ToggleDuck, "Toggles duck" ); #ifndef HL2MP #ifndef PORTAL LINK_ENTITY_TO_CLASS( player, CHL2_Player ); #endif #endif PRECACHE_REGISTER(player); CBaseEntity *FindEntityForward( CBasePlayer *pMe, bool fHull ); BEGIN_SIMPLE_DATADESC( LadderMove_t ) DEFINE_FIELD( m_bForceLadderMove, FIELD_BOOLEAN ), DEFINE_FIELD( m_bForceMount, FIELD_BOOLEAN ), DEFINE_FIELD( m_flStartTime, FIELD_TIME ), DEFINE_FIELD( m_flArrivalTime, FIELD_TIME ), DEFINE_FIELD( m_vecGoalPosition, FIELD_POSITION_VECTOR ), DEFINE_FIELD( m_vecStartPosition, FIELD_POSITION_VECTOR ), DEFINE_FIELD( m_hForceLadder, FIELD_EHANDLE ), DEFINE_FIELD( m_hReservedSpot, FIELD_EHANDLE ), END_DATADESC() // Global Savedata for HL2 player BEGIN_DATADESC( CHL2_Player ) DEFINE_FIELD(heavyWeight, FIELD_BOOLEAN), DEFINE_FIELD( m_nControlClass, FIELD_INTEGER ), DEFINE_EMBEDDED( m_HL2Local ), DEFINE_FIELD(bg_rh, FIELD_INTEGER), DEFINE_FIELD(bg_lh, FIELD_INTEGER), DEFINE_FIELD(bg_rl, FIELD_INTEGER), DEFINE_FIELD(bg_rh_val, FIELD_INTEGER), DEFINE_FIELD(bg_lh_val, FIELD_INTEGER), DEFINE_FIELD(bg_rl_val, FIELD_INTEGER), DEFINE_FIELD( m_bSprintEnabled, FIELD_BOOLEAN ), DEFINE_FIELD( m_flTimeAllSuitDevicesOff, FIELD_TIME ), DEFINE_FIELD( m_fIsSprinting, FIELD_BOOLEAN ), DEFINE_FIELD( m_fIsWalking, FIELD_BOOLEAN ), DEFINE_FIELD( m_flPlayerTimeNextAnim, FIELD_TIME ), /* // These are initialized every time the player calls Activate() DEFINE_FIELD( m_bIsAutoSprinting, FIELD_BOOLEAN ), DEFINE_FIELD( m_fAutoSprintMinTime, FIELD_TIME ), */ // Field is used within a single tick, no need to save restore // DEFINE_FIELD( m_bPlayUseDenySound, FIELD_BOOLEAN ), // m_pPlayerAISquad reacquired on load DEFINE_AUTO_ARRAY( m_vecMissPositions, FIELD_POSITION_VECTOR ), DEFINE_FIELD( m_nNumMissPositions, FIELD_INTEGER ), // m_pPlayerAISquad DEFINE_EMBEDDED( m_CommanderUpdateTimer ), // m_RealTimeLastSquadCommand DEFINE_FIELD( m_QueuedCommand, FIELD_INTEGER ), DEFINE_FIELD( m_flTimeIgnoreFallDamage, FIELD_TIME ), DEFINE_FIELD( m_bIgnoreFallDamageResetAfterImpact, FIELD_BOOLEAN ), // Suit power fields DEFINE_FIELD( m_flSuitPowerLoad, FIELD_FLOAT ), DEFINE_FIELD( m_flIdleTime, FIELD_TIME ), DEFINE_FIELD( m_flMoveTime, FIELD_TIME ), DEFINE_FIELD( m_flLastDamageTime, FIELD_TIME ), DEFINE_FIELD( m_flTargetFindTime, FIELD_TIME ), DEFINE_FIELD( m_flAdmireGlovesAnimTime, FIELD_TIME ), DEFINE_FIELD( KickAnim, FIELD_INTEGER ), DEFINE_FIELD( Kicking, FIELD_BOOLEAN ), DEFINE_FIELD( Kicked, FIELD_BOOLEAN ), DEFINE_FIELD( Swinged, FIELD_BOOLEAN ), DEFINE_FIELD( Swing, FIELD_BOOLEAN ), DEFINE_FIELD( m_flKickEventAnimTime, FIELD_TIME ), DEFINE_FIELD( m_flNextFlashlightCheckTime, FIELD_TIME ), DEFINE_FIELD( m_flFlashlightPowerDrainScale, FIELD_FLOAT ), DEFINE_FIELD( m_bFlashlightDisabled, FIELD_BOOLEAN ), DEFINE_FIELD( m_bUseCappedPhysicsDamageTable, FIELD_BOOLEAN ), DEFINE_FIELD( m_hLockedAutoAimEntity, FIELD_EHANDLE ), DEFINE_EMBEDDED( m_LowerWeaponTimer ), DEFINE_EMBEDDED( m_AutoaimTimer ), DEFINE_INPUTFUNC( FIELD_FLOAT, "IgnoreFallDamage", InputIgnoreFallDamage ), DEFINE_INPUTFUNC( FIELD_FLOAT, "IgnoreFallDamageWithoutReset", InputIgnoreFallDamageWithoutReset ), DEFINE_INPUTFUNC( FIELD_VOID, "OnSquadMemberKilled", OnSquadMemberKilled ), DEFINE_INPUTFUNC( FIELD_VOID, "DisableFlashlight", InputDisableFlashlight ), DEFINE_INPUTFUNC( FIELD_VOID, "EnableFlashlight", InputEnableFlashlight ), DEFINE_INPUTFUNC( FIELD_VOID, "ForceDropPhysObjects", InputForceDropPhysObjects ), DEFINE_SOUNDPATCH( m_sndLeeches ), DEFINE_SOUNDPATCH( m_sndWaterSplashes ), DEFINE_FIELD( m_flArmorReductionTime, FIELD_TIME ), DEFINE_FIELD( m_iArmorReductionFrom, FIELD_INTEGER ), DEFINE_FIELD( m_flTimeUseSuspended, FIELD_TIME ), DEFINE_FIELD( m_hLocatorTargetEntity, FIELD_EHANDLE ), DEFINE_FIELD( m_flTimeNextLadderHint, FIELD_TIME ), //DEFINE_FIELD( m_hPlayerProxy, FIELD_EHANDLE ), //Shut up class check! END_DATADESC() CHL2_Player::CHL2_Player() { // Overcharged: Player anims m_pPlayerAnimState = CreatePlayerAnimationState(this); m_angEyeAngles.Init(); m_nNumMissPositions = 0; m_pPlayerAISquad = 0; m_bSprintEnabled = true; heavyWeight = false; m_flPlayerTimeNextAnim = gpGlobals->curtime; m_flArmorReductionTime = 0.0f; m_iArmorReductionFrom = 0; } // // SUIT POWER DEVICES // #define SUITPOWER_CHARGE_RATE 12.5 // 100 units in 8 seconds #ifdef HL2MP CSuitPowerDevice SuitDeviceSprint( bits_SUIT_DEVICE_SPRINT, 25.0f ); // 100 units in 4 seconds #else CSuitPowerDevice SuitDeviceSprint( bits_SUIT_DEVICE_SPRINT, 12.5f ); // 100 units in 8 seconds #endif //#ifdef HL2_EPISODIC CSuitPowerDevice SuitDeviceFlashlight( bits_SUIT_DEVICE_FLASHLIGHT, 1.111 ); // 100 units in 90 second //#else // CSuitPowerDevice SuitDeviceFlashlight( bits_SUIT_DEVICE_FLASHLIGHT, 2.222 ); // 100 units in 45 second //#endif CSuitPowerDevice SuitDeviceBreather( bits_SUIT_DEVICE_BREATHER, 6.7f ); // 100 units in 15 seconds (plus three padded seconds) IMPLEMENT_SERVERCLASS_ST(CHL2_Player, DT_HL2_Player) SendPropDataTable(SENDINFO_DT(m_HL2Local), &REFERENCE_SEND_TABLE(DT_HL2Local), SendProxy_SendLocalDataTable), SendPropBool( SENDINFO(m_fIsSprinting) ), END_SEND_TABLE() void CHL2_Player::Precache( void ) { BaseClass::Precache(); PrecacheModel(cvar->FindVar("oc_playermodel_suit")->GetString());//("models/player.mdl"); //old model PrecacheModel(cvar->FindVar("oc_playermodel_nosuit")->GetString()); PrecacheScriptSound( "HL2Player.SprintNoPower" ); PrecacheScriptSound( "HL2Player.SprintStart" ); PrecacheScriptSound( "HL2Player.UseDeny" ); PrecacheScriptSound( "HL2Player.FlashLightOn" ); PrecacheScriptSound( "HL2Player.FlashLightOff" ); PrecacheScriptSound( "HL2Player.PickupWeapon" ); PrecacheScriptSound( "HL2Player.TrainUse" ); PrecacheScriptSound( "HL2Player.Use" ); PrecacheScriptSound( "HL2Player.BurnPain" ); //BriJee OVR: Precache custom things PrecacheScriptSound("HL2Player.NightvisionOn"); PrecacheScriptSound("HL2Player.NightvisionOff"); PrecacheScriptSound("HL2Player.DeployWeapon"); //PrecacheScriptSound("HL2Player.HolsterWeapon"); PrecacheScriptSound("HL2Player.IronsightOn"); PrecacheScriptSound("HL2Player.IronsightOff"); PrecacheScriptSound("WeaponSwing.HitWorld"); // BriJee OVR: Weapon swing sounds PrecacheScriptSound("WeaponSwing.Miss"); PrecacheScriptSound("WeaponSwing.HitAlly"); PrecacheScriptSound("WeaponSwing.HitEnemy"); PrecacheModel("models/player/v_kick.mdl"); PrecacheModel("models/player/v_kick_nosuit.mdl"); PrecacheScriptSound("Player.KickAir"); PrecacheScriptSound("Player.KickSolid"); PrecacheScriptSound("Player.KickBody"); PrecacheScriptSound(cvar->FindVar("oc_player_death_sound_name")->GetString()); // BriJee OVR: Player death music name } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void CHL2_Player::CheckSuitZoom( void ) { if (IsSuitEquipped() && !m_HL2Local.m_bIsIronsighted) { if ( m_afButtonReleased & IN_ZOOM ) { StopZooming(); } else if ( m_afButtonPressed & IN_ZOOM ) { StartZooming(); } } } void CHL2_Player::EquipSuit( bool bPlayEffects ) { MDLCACHE_CRITICAL_SECTION(); SetBodyRenderingState(true); BaseClass::EquipSuit(); m_HL2Local.m_bDisplayReticle = true; if ( bPlayEffects == true ) { StartAdmireGlovesAnimation(); } } void CHL2_Player::RemoveSuit( void ) { SetBodyRenderingState(false); BaseClass::RemoveSuit(); m_HL2Local.m_bDisplayReticle = false; } void CHL2_Player::HandleSpeedChanges( void ) { int buttonsChanged = m_afButtonPressed | m_afButtonReleased; bool bCanSprint = CanSprint(); bool bIsSprinting = IsSprinting(); bool bWantSprint = ( bCanSprint && IsSuitEquipped() && (m_nButtons & IN_SPEED) ); if ( bIsSprinting != bWantSprint && (buttonsChanged & IN_SPEED) ) { // If someone wants to sprint, make sure they've pressed the button to do so. We want to prevent the // case where a player can hold down the sprint key and burn tiny bursts of sprint as the suit recharges // We want a full debounce of the key to resume sprinting after the suit is completely drained if ( bWantSprint ) { if ( sv_stickysprint.GetBool() ) { StartAutoSprint(); } else { StartSprinting(); } } else { if ( !sv_stickysprint.GetBool() ) { StopSprinting(); } // Reset key, so it will be activated post whatever is suppressing it. m_nButtons &= ~IN_SPEED; } } bool bIsWalking = IsWalking(); // have suit, pressing button, not sprinting or ducking bool bWantWalking; if( IsSuitEquipped() ) { bWantWalking = (m_nButtons & IN_WALK) && !IsSprinting() && !(m_nButtons & IN_DUCK); } else { bWantWalking = true; } if( bIsWalking != bWantWalking ) { if ( bWantWalking ) { StartWalking(); } else { StopWalking(); } } } //----------------------------------------------------------------------------- // This happens when we powerdown from the mega physcannon to the regular one //----------------------------------------------------------------------------- void CHL2_Player::HandleArmorReduction( void ) { if ( m_flArmorReductionTime < gpGlobals->curtime ) return; if ( ArmorValue() <= 0 ) return; float flPercent = 1.0f - (( m_flArmorReductionTime - gpGlobals->curtime ) / ARMOR_DECAY_TIME ); int iArmor = Lerp( flPercent, m_iArmorReductionFrom, 0 ); SetArmorValue( iArmor ); } void CHL2_Player::WeaponSwing(void) // BriJee OVR: Weapon Swing Addition { if (IsOnLadder())// || return; CBaseViewModel *vm = GetViewModel(); if (!vm) return; CBaseCombatWeapon *pWeapon = GetActiveWeapon(); if (!pWeapon) return; if (pWeapon->m_flNextSilencer > gpGlobals->curtime) return; if (pWeapon->isPlayingLoopingSound()) pWeapon->DestroyLoopSound(); if (cvar->FindVar("oc_state_InSecondFire")->GetInt() != 0 || pWeapon->m_bInReload || pWeapon->m_bReloadComplete || this->IsInAVehicle() || this->IsOnLadder() || !pWeapon->GetWpnData().SwingHitTime || pWeapon->GetWpnData().animData[pWeapon->m_bFireMode].SwingAnim == ACT_RESET) return; if (pWeapon->IsIronSighted()) pWeapon->OffIronSight(); if (pWeapon->IsScopeSighted()) pWeapon->OffScopeSight(); Activity swingAnim = pWeapon->GetWpnData().animData[pWeapon->m_bFireMode].SwingAnim != ACT_RESET ? pWeapon->GetWpnData().animData[pWeapon->m_bFireMode].SwingAnim : ACT_VM_MELEE; pWeapon->SendWeaponAnim(swingAnim); pWeapon->m_flTimeWeaponIdle = pWeapon->m_flNextInspectAnimation = pWeapon->m_flNextLaserSwitchTime = pWeapon->m_flNextSilencer = pWeapon->m_flNextShotgunReload = pWeapon->m_flNextSwitchTime = pWeapon->m_flNextSecondaryAttack = pWeapon->m_flNextPrimaryAttack = gpGlobals->curtime + pWeapon->SequenceDuration(); Swinged = true; Swing = true; float seqDuration = pWeapon->SequenceDuration(); float checkTime = seqDuration * pWeapon->GetWpnData().SwingHitTime; m_flSwingEventAnimTime = gpGlobals->curtime + checkTime;// pWeapon->SequenceDuration(); if (GetActiveWeapon()->GetWpnData().enableLaser) { GetActiveWeapon()->EnableLaserInterrupt = true; GetActiveWeapon()->StopLaserEffects(this); } } void CHL2_Player::WeaponSwingHandle(bool stop) { CBaseCombatWeapon *pWeapon = GetActiveWeapon(); CBaseViewModel *vm = GetViewModel(); if (stop || !vm || !pWeapon) { m_flSwingEventAnimTime = 0.f;// gpGlobals->curtime; Swinged = false; Swing = Swinged; } if (Swinged) { //float checkTime = pWeapon->GetWpnData().SwingHitTime; if ((m_flSwingEventAnimTime < gpGlobals->curtime/* + checkTime*/) && Swing) { WeaponSwingHit(); Swing = false; } if (m_flSwingEventAnimTime < gpGlobals->curtime) { Swinged = false; Swing = Swinged; m_flSwingEventAnimTime = 0.f; } } } void CHL2_Player::WeaponSwingHit(void) { CBasePlayer *pPlayer = (CBasePlayer *)this; if (!pPlayer) return; CBaseCombatWeapon *pWeapon = pPlayer->GetActiveWeapon(); if (!pWeapon || pPlayer->IsInAVehicle()) return; if (pWeapon->IsIronSighted()) pWeapon->OffIronSight(); if (pWeapon->IsScopeSighted()) pWeapon->OffScopeSight(); Vector vecDirection, vecStart, vecStop, vecDir, vecEnd; AngleVectors(GetAbsAngles(), &vecDirection); VectorMA(pPlayer->Weapon_ShootPosition(), 50, vecDirection, vecEnd); trace_t tr; AngleVectors(pPlayer->EyeAngles(), &vecDir); vecStart = pPlayer->EyePosition(); vecStop = vecStart + vecDir * oc_player_swing_range.GetInt(); UTIL_TraceHull(vecStart, vecStop, Vector(-3, -3, -3), Vector(3, 3, 3), MASK_SHOT, pPlayer, COLLISION_GROUP_NONE, &tr); Disposition_t RelShip = pPlayer->IRelationType(tr.m_pEnt); // Relationships check. if (!tr.m_pEnt || (tr.surface.flags & SURF_SKY)) // Check all surfaces... { EmitSound("WeaponSwing.Miss"); pPlayer->ViewPunch(QAngle(-2, 5, random->RandomFloat(-1, 2))); } else if (tr.m_pEnt->IsNPC()) // We see npc ? lets hit him. { //MikeD //WTF is this, BriJee? /*if (pWeapon->IsBehindTarget(tr.m_pEnt)) { CBaseEntity *pHurt = pPlayer->CheckTraceHullAttack(pPlayer->Weapon_ShootPosition(), vecEnd, Vector(-1, -1, -1), Vector(0, 0, 0), cvar->FindVar("oc_weapon_swing_backstab_dmg")->GetFloat(), DMG_CLUB, 0.75); if (pHurt) { EmitSound("WeaponSwing.HitEnemy"); UTIL_ScreenShake(tr.endpos, 1.0, 50.0, 0.45, 150.0, SHAKE_START); } else { if (RelShip == D_LI || D_NU) EmitSound("WeaponSwing.HitAlly"); else EmitSound("WeaponSwing.Miss"); } } else { if (pWeapon && FClassnameIs(pWeapon, "weapon_pistol") || FClassnameIs(pWeapon, "weapon_glock") || FClassnameIs(pWeapon, "weapon_beretta") || FClassnameIs(pWeapon, "weapon_pistol_silent") //fx || FClassnameIs(pWeapon, "weapon_dualpistol") || FClassnameIs(pWeapon, "weapon_laserpistol") || FClassnameIs(pWeapon, "weapon_alyxgun") || FClassnameIs(pWeapon, "weapon_357") || FClassnameIs(pWeapon, "weapon_flaregun") || FClassnameIs(pWeapon, "weapon_deagle")) { CBaseEntity *pHurt = pPlayer->CheckTraceHullAttack(pPlayer->Weapon_ShootPosition(), vecEnd, Vector(-1, -1, -1), Vector(12, 12, 12), cvar->FindVar("oc_weapon_swing_dmg_pistols")->GetFloat(), DMG_CLUB, 0.75); if (pHurt) { EmitSound("WeaponSwing.HitEnemy"); } else { if (RelShip == D_LI || D_NU) EmitSound("WeaponSwing.HitAlly"); else EmitSound("WeaponSwing.Miss"); } } else if (pWeapon && FClassnameIs(pWeapon, "weapon_smg1") || FClassnameIs(pWeapon, "weapon_mp5") || FClassnameIs(pWeapon, "weapon_ak47") || FClassnameIs(pWeapon, "weapon_m4") //fx || FClassnameIs(pWeapon, "weapon_sg552") || FClassnameIs(pWeapon, "weapon_oicw") || FClassnameIs(pWeapon, "weapon_ar2") || FClassnameIs(pWeapon, "weapon_machinegun")) //machinegun addition { CBaseEntity *pHurt = pPlayer->CheckTraceHullAttack(pPlayer->Weapon_ShootPosition(), vecEnd, Vector(-1, -1, -1), Vector(12, 12, 12), cvar->FindVar("oc_weapon_swing_dmg_machineguns")->GetFloat(), DMG_CLUB, 0.75); if (pHurt) { EmitSound("WeaponSwing.HitEnemy"); } else { if (RelShip == D_LI || D_NU) EmitSound("WeaponSwing.HitAlly"); else EmitSound("WeaponSwing.Miss"); } } else { CBaseEntity *pHurt = pPlayer->CheckTraceHullAttack(pPlayer->Weapon_ShootPosition(), vecEnd, Vector(-1, -1, -1), Vector(12, 12, 12), cvar->FindVar("oc_weapon_swing_dmg_other")->GetFloat(), DMG_CLUB, 0.75); if (pHurt) { EmitSound("WeaponSwing.HitEnemy"); } else { if (RelShip == D_LI || D_NU) EmitSound("WeaponSwing.HitAlly"); else EmitSound("WeaponSwing.Miss"); } } }*/ //MikeD //This is how it must works { //Get eye-orient forward vector Vector hitDirection; pPlayer->EyeVectors(&hitDirection, NULL, NULL); VectorNormalize(hitDirection); //Create our Takedmg obj CTakeDamageInfo info(pPlayer, pPlayer, pWeapon->GetWpnData().SwingDamage, DMG_CLUB); info.SetAttacker(pPlayer); //Play client-side effects CEffectData data; data.m_vStart = tr.startpos; data.m_vOrigin = tr.endpos; DispatchEffect("RagdollImpact", data); //Play camera smooth snap pPlayer->ViewPunch(QAngle(-8, random->RandomFloat(-2, 2), -3)); //Scale dmg relative to skill level info.AdjustPlayerDamageInflictedForSkillLevel(); //Calc dmg force CalculateMeleeDamageForce(&info, hitDirection, tr.endpos); //Dispatch dmg to entity tr.m_pEnt->DispatchTraceAttack(info, hitDirection, &tr); ApplyMultiDamage(); //Check glass triggers TraceAttackToTriggers(info, tr.startpos, tr.endpos, hitDirection); if (RelShip == D_LI || D_NU) EmitSound("WeaponSwing.HitAlly"); else EmitSound("WeaponSwing.HitEnemy"); } } else // Alright its non npc, but hit it anyway. { CBaseEntity *pHurt = pPlayer->CheckTraceHullAttack(pPlayer->Weapon_ShootPosition(), vecEnd, Vector(-1, -1, -1), Vector(0, 0, 0), 25, DMG_CLUB, 0.75); if (pHurt) { // All works right, nothing here } else { // Need new prop hit checker } // BriJee : Server Side Ragdolls & Objects? min 1 damage to get work right RadiusDamage(CTakeDamageInfo(this, this, pWeapon->GetWpnData().SwingDamage, DMG_CLUB), tr.endpos, 20.0f, CLASS_PLAYER, NULL); CEffectData data; data.m_vStart = tr.startpos; data.m_vOrigin = tr.endpos; DispatchEffect("RagdollImpact", data); if (tr.DidHitWorld()) { UTIL_DecalTrace(&tr, "ManhackCut"); } UTIL_ScreenShake(tr.endpos, 1.0, 50.0, 0.35, 150.0, SHAKE_START); pPlayer->ViewPunch(QAngle(-4, random->RandomFloat(-2, 2), 1)); EmitSound("WeaponSwing.HitWorld"); } } ConVar oc_test_weapon_weight("oc_test_weapon_weight", "0"); // void CHL2_Player::ThirdpersonShootPosition(void) // DEFINE LATER!!! //======================= BriJee OVR: END //----------------------------------------------------------------------------- // Purpose: Allow pre-frame adjustments on the player //----------------------------------------------------------------------------- void CHL2_Player::PreThink(void) { if (player_showpredictedposition.GetBool()) { Vector predPos; UTIL_PredictedPosition(this, player_showpredictedposition_timestep.GetFloat(), &predPos); NDebugOverlay::Box(predPos, NAI_Hull::Mins(GetHullType()), NAI_Hull::Maxs(GetHullType()), 0, 255, 0, 0, 0.01f); NDebugOverlay::Line(GetAbsOrigin(), predPos, 0, 255, 0, 0, 0.01f); } #ifdef HL2_EPISODIC if (m_hLocatorTargetEntity != NULL) { // Keep track of the entity here, the client will pick up the rest of the work m_HL2Local.m_vecLocatorOrigin = m_hLocatorTargetEntity->WorldSpaceCenter(); } else { m_HL2Local.m_vecLocatorOrigin = vec3_invalid; // This tells the client we have no locator target. } #endif//HL2_EPISODIC // Riding a vehicle? if (IsInAVehicle()) { VPROF("CHL2_Player::PreThink-Vehicle"); // make sure we update the client, check for timed damage and update suit even if we are in a vehicle UpdateClientData(); CheckTimeBasedDamage(); // Allow the suit to recharge when in the vehicle. SuitPower_Update(); CheckSuitUpdate(); CheckSuitZoom(); WaterMove(); return; } // This is an experiment of mine- autojumping! // only affects you if sv_autojump is nonzero. if ((GetFlags() & FL_ONGROUND) && sv_autojump.GetFloat() != 0) { VPROF("CHL2_Player::PreThink-Autojump"); // check autojump Vector vecCheckDir; vecCheckDir = GetAbsVelocity(); float flVelocity = VectorNormalize(vecCheckDir); if (flVelocity > 200) { // Going fast enough to autojump vecCheckDir = WorldSpaceCenter() + vecCheckDir * 34 - Vector(0, 0, 16); trace_t tr; UTIL_TraceHull(WorldSpaceCenter() - Vector(0, 0, 16), vecCheckDir, NAI_Hull::Mins(HULL_TINY_CENTERED), NAI_Hull::Maxs(HULL_TINY_CENTERED), MASK_PLAYERSOLID, this, COLLISION_GROUP_PLAYER, &tr); //NDebugOverlay::Line( tr.startpos, tr.endpos, 0,255,0, true, 10 ); if (tr.fraction == 1.0 && !tr.startsolid) { // Now trace down! UTIL_TraceLine(vecCheckDir, vecCheckDir - Vector(0, 0, 64), MASK_PLAYERSOLID, this, COLLISION_GROUP_NONE, &tr); //NDebugOverlay::Line( tr.startpos, tr.endpos, 0,255,0, true, 10 ); if (tr.fraction == 1.0 && !tr.startsolid) { // !!!HACKHACK // I KNOW, I KNOW, this is definitely not the right way to do this, // but I'm prototyping! (sjb) Vector vecNewVelocity = GetAbsVelocity(); vecNewVelocity.z += 250; SetAbsVelocity(vecNewVelocity); } } } } VPROF_SCOPE_BEGIN("CHL2_Player::PreThink-Speed"); HandleSpeedChanges(); #ifdef HL2_EPISODIC HandleArmorReduction(); #endif if( sv_stickysprint.GetBool() && m_bIsAutoSprinting ) { // If we're ducked and not in the air if( IsDucked() && GetGroundEntity() != NULL ) { StopSprinting(); } // Stop sprinting if the player lets off the stick for a moment. else if( GetStickDist() == 0.0f ) { if( gpGlobals->curtime > m_fAutoSprintMinTime ) { StopSprinting(); } } else { // Stop sprinting one half second after the player stops inputting with the move stick. m_fAutoSprintMinTime = gpGlobals->curtime + 0.5f; } } else if ( IsSprinting() ) { // Disable sprint while ducked unless we're in the air (jumping) if ( IsDucked() && ( GetGroundEntity() != NULL ) ) { StopSprinting(); } } VPROF_SCOPE_END(); if ( g_fGameOver || IsPlayerLockedInPlace() ) return; // finale VPROF_SCOPE_BEGIN( "CHL2_Player::PreThink-ItemPreFrame" ); ItemPreFrame( ); VPROF_SCOPE_END(); VPROF_SCOPE_BEGIN( "CHL2_Player::PreThink-WaterMove" ); WaterMove(); VPROF_SCOPE_END(); if ( g_pGameRules && g_pGameRules->FAllowFlashlight() ) m_Local.m_iHideHUD &= ~HIDEHUD_FLASHLIGHT; else m_Local.m_iHideHUD |= HIDEHUD_FLASHLIGHT; VPROF_SCOPE_BEGIN( "CHL2_Player::PreThink-CommanderUpdate" ); CommanderUpdate(); VPROF_SCOPE_END(); // Operate suit accessories and manage power consumption/charge VPROF_SCOPE_BEGIN( "CHL2_Player::PreThink-SuitPower_Update" ); SuitPower_Update(); VPROF_SCOPE_END(); // checks if new client data (for HUD and view control) needs to be sent to the client VPROF_SCOPE_BEGIN( "CHL2_Player::PreThink-UpdateClientData" ); UpdateClientData(); VPROF_SCOPE_END(); VPROF_SCOPE_BEGIN( "CHL2_Player::PreThink-CheckTimeBasedDamage" ); CheckTimeBasedDamage(); VPROF_SCOPE_END(); VPROF_SCOPE_BEGIN( "CHL2_Player::PreThink-CheckSuitUpdate" ); CheckSuitUpdate(); VPROF_SCOPE_END(); VPROF_SCOPE_BEGIN( "CHL2_Player::PreThink-CheckSuitZoom" ); CheckSuitZoom(); VPROF_SCOPE_END(); if (m_lifeState >= LIFE_DYING) { PlayerDeathThink(); return; } //#ifdef HL2_EPISODIC CheckFlashlight(); //#endif // HL2_EPISODIC // So the correct flags get sent to client asap. // if ( m_afPhysicsFlags & PFLAG_DIROVERRIDE ) AddFlag( FL_ONTRAIN ); else RemoveFlag( FL_ONTRAIN ); // Train speed control if ( m_afPhysicsFlags & PFLAG_DIROVERRIDE ) { CBaseEntity *pTrain = GetGroundEntity(); float vel; if ( pTrain ) { if ( !(pTrain->ObjectCaps() & FCAP_DIRECTIONAL_USE) ) pTrain = NULL; } if ( !pTrain ) { if ( GetActiveWeapon() && (GetActiveWeapon()->ObjectCaps() & FCAP_DIRECTIONAL_USE) ) { m_iTrain = TRAIN_ACTIVE | TRAIN_NEW; if ( m_nButtons & IN_FORWARD ) { m_iTrain |= TRAIN_FAST; } else if ( m_nButtons & IN_BACK ) { m_iTrain |= TRAIN_BACK; } else { m_iTrain |= TRAIN_NEUTRAL; } return; } else { trace_t trainTrace; // Maybe this is on the other side of a level transition UTIL_TraceLine( GetAbsOrigin(), GetAbsOrigin() + Vector(0,0,-38), MASK_PLAYERSOLID_BRUSHONLY, this, COLLISION_GROUP_NONE, &trainTrace ); if ( trainTrace.fraction != 1.0 && trainTrace.m_pEnt ) pTrain = trainTrace.m_pEnt; if ( !pTrain || !(pTrain->ObjectCaps() & FCAP_DIRECTIONAL_USE) || !pTrain->OnControls(this) ) { // Warning( "In train mode with no train!\n" ); m_afPhysicsFlags &= ~PFLAG_DIROVERRIDE; m_iTrain = TRAIN_NEW|TRAIN_OFF; return; } } } else if ( !( GetFlags() & FL_ONGROUND ) || pTrain->HasSpawnFlags( SF_TRACKTRAIN_NOCONTROL ) || (m_nButtons & (IN_MOVELEFT|IN_MOVERIGHT) ) ) { // Turn off the train if you jump, strafe, or the train controls go dead m_afPhysicsFlags &= ~PFLAG_DIROVERRIDE; m_iTrain = TRAIN_NEW|TRAIN_OFF; return; } SetAbsVelocity( vec3_origin ); vel = 0; if ( m_afButtonPressed & IN_FORWARD ) { vel = 1; pTrain->Use( this, this, USE_SET, (float)vel ); } else if ( m_afButtonPressed & IN_BACK ) { vel = -1; pTrain->Use( this, this, USE_SET, (float)vel ); } if (vel) { m_iTrain = TrainSpeed(pTrain->m_flSpeed, ((CFuncTrackTrain*)pTrain)->GetMaxSpeed()); m_iTrain |= TRAIN_ACTIVE|TRAIN_NEW; } } else if (m_iTrain & TRAIN_ACTIVE) { m_iTrain = TRAIN_NEW; // turn off train } // // If we're not on the ground, we're falling. Update our falling velocity. // if ( !( GetFlags() & FL_ONGROUND ) ) { m_Local.m_flFallVelocity = -GetAbsVelocity().z; } if ( m_afPhysicsFlags & PFLAG_ONBARNACLE ) { bool bOnBarnacle = false; CNPC_Barnacle *pBarnacle = NULL; do { // FIXME: Not a good or fast solution, but maybe it will catch the bug! pBarnacle = (CNPC_Barnacle*)gEntList.FindEntityByClassname( pBarnacle, "npc_barnacle" ); if ( pBarnacle ) { if ( pBarnacle->GetEnemy() == this ) { bOnBarnacle = true; } } } while ( pBarnacle ); if ( !bOnBarnacle ) { Warning( "Attached to barnacle?\n" ); Assert( 0 ); m_afPhysicsFlags &= ~PFLAG_ONBARNACLE; } else { SetAbsVelocity( vec3_origin ); } } // StudioFrameAdvance( );//!!!HACKHACK!!! Can't be hit by traceline when not animating? // Update weapon's ready status UpdateWeaponPosture(); // Disallow shooting while zooming if ( IsX360() ) { if ( IsZooming() ) { if( GetActiveWeapon() && !GetActiveWeapon()->IsWeaponZoomed() ) { // If not zoomed because of the weapon itself, do not attack. m_nButtons &= ~(IN_ATTACK|IN_ATTACK2); } } } else { if ( m_nButtons & IN_ZOOM ) { //FIXME: Held weapons like the grenade get sad when this happens #ifdef HL2_EPISODIC // Episodic allows players to zoom while using a func_tank CBaseCombatWeapon* pWep = GetActiveWeapon(); if ( !m_hUseEntity || ( pWep && pWep->IsWeaponVisible() ) ) #endif m_nButtons &= ~(IN_ATTACK|IN_ATTACK2); } } } void CHL2_Player::StartAdmireGlovesAnimation(void) { MDLCACHE_CRITICAL_SECTION(); CBaseViewModel *vm = GetViewModel(0); if (vm && !GetActiveWeapon()) { SetAdmireGlovesVisible(true); vm->SetWeaponModel("models/weapons/v_hands.mdl", NULL); ShowViewModel(true); int idealSequence = vm->SelectWeightedSequence(ACT_VM_IDLE); if (idealSequence >= 0) { vm->SendViewModelMatchingSequence(idealSequence); m_flAdmireGlovesAnimTime = gpGlobals->curtime + vm->SequenceDuration(idealSequence); } } } void CHL2_Player::HandleAdmireGlovesAnimation(void) { CBaseViewModel *pVM = GetViewModel(0); if (pVM && pVM->GetOwningWeapon() == NULL) { if (m_flAdmireGlovesAnimTime != 0.0) { if (m_flAdmireGlovesAnimTime > gpGlobals->curtime) { pVM->m_flPlaybackRate = 1.0f; pVM->StudioFrameAdvance(); SetAdmireGlovesVisible(true); } else if (m_flAdmireGlovesAnimTime < gpGlobals->curtime) { m_flAdmireGlovesAnimTime = 0.0f; pVM->SetWeaponModel(NULL, NULL); SetHandsVisible(false); } } } else { m_flAdmireGlovesAnimTime = 0.0f; } } void CHL2_Player::PostThink( void ) { BaseClass::PostThink(); if ( !g_fGameOver && !IsPlayerLockedInPlace() && IsAlive() ) { HandleAdmireGlovesAnimation(); } if (!GetActiveWeapon() && m_flAdmireGlovesAnimTime < gpGlobals->curtime) { CBaseAnimating *pAnimating = this->GetBaseAnimating(); if (pAnimating) { if (pAnimating->GetBodygroup(bg_rh) || pAnimating->GetBodygroup(bg_lh))//1 - invisible SetHandsVisible(true); } } if (!g_fGameOver && !IsPlayerLockedInPlace() && IsAlive()) { if (oc_player_allow_swing.GetBool()) { if ((m_afButtonPressed & IN_SWING) && !Swinged && m_flSwingEventAnimTime < gpGlobals->curtime) { WeaponSwing(); // Wpn swing } if (Swinged && !IsInAVehicle()) { WeaponSwingHandle(); } else if (Swinged && IsInAVehicle()) { WeaponSwingHandle(true); } } if (oc_player_allow_kick.GetBool()) { if (IsSuitEquipped() && /*GetActiveWeapon() && */!IsRunning() && !(GetFlags() & FL_DUCKING)) { if ((m_afButtonPressed & IN_KICK) && !IsInAVehicle()) { QAngle AnglesEyes = EyeAngles(); if (AnglesEyes.x <= 60.0f || AnglesEyes.x >= -75.0f) { CBaseViewModel *vm = GetViewModel(1); if (vm) { if (m_flKickEventAnimTime < gpGlobals->curtime + vm->SequenceDuration()*0.5f) KickEvent(); } else KickEvent(); } } if (Kicking && !IsInAVehicle()) { KickEventHandle(); } else if (Kicking && IsInAVehicle()) { CBaseViewModel *vm = GetViewModel(1); if (vm) { Kicking = false; Kicked = Kicking; m_flKickEventAnimTime = 0.0f; vm->SetWeaponModel(NULL, NULL); UTIL_RemoveImmediate(vm); } } } } } else { if (IsSuitEquipped()) { CBaseViewModel *vm = GetViewModel(1); if (vm) { Kicking = false; Kicked = Kicking; m_flKickEventAnimTime = 0.0f; vm->SetWeaponModel(NULL, NULL); UTIL_RemoveImmediate(vm); } } } m_pPlayerAnimState->Update(); } void CHL2_Player::KickEvent(void) { MDLCACHE_CRITICAL_SECTION(); CBaseViewModel *vm = GetViewModel(1); const char *suitModel = "models/player/v_kick.mdl"; const char *nonSuitModel = "models/player/v_kick_nosuit.mdl"; if (!vm) { CreateViewModel(1, true); vm = GetViewModel(1); vm->m_bIsLeg = true; } if (vm) { SetRightLegVisible(false); if (IsSuitEquipped()) { vm->SetWeaponModel(suitModel, NULL); } else { vm->SetWeaponModel(nonSuitModel, NULL); } KickAnim = (int)ACT_VM_PRIMARYATTACK;//random->RandomInt(0, 1) == 0 ? (int)ACT_VM_PRIMARYATTACK : (int)ACT_VM_SECONDARYATTACK; int idealSequence = vm->SelectWeightedSequence((Activity)KickAnim); //DevMsg("idealSequence: %i\n", idealSequence); Kicking = true; Kicked = !Kicking; if (!vm->IsActivityFinished()) { vm->StopAnimation(); m_flKickEventAnimTime = 0.0f; vm->ResetSequence(KickAnim); } ShowViewModel(Kicking); EmitSound("Player.KickAir"); if (idealSequence >= 0) { vm->SendViewModelMatchingSequence(idealSequence); m_flKickEventAnimTime = gpGlobals->curtime + vm->SequenceDuration(idealSequence); } /*Vector origin = vm->GetViewOffset(); origin.z -= 150; vm->SetViewOffset(origin);*/ //vm->SetRenderMode(); /*Vector origin = vm->GetAbsOrigin(); origin.z -= 150; vm->SetAbsOrigin(origin);*/ } } ConVar oc_player_kick_damage("oc_player_kick_damage", "40", FCVAR_ARCHIVE); ConVar oc_player_kick_range("oc_player_kick_range", "85", FCVAR_ARCHIVE); ConVar oc_player_kick_rate("oc_player_kick_rate", "0.85", FCVAR_ARCHIVE); void CHL2_Player::KickEventHandle(void) { CBaseViewModel *vm = GetViewModel(1); if (vm) { if (Kicking) { if (m_flKickEventAnimTime < gpGlobals->curtime + (vm->SequenceDuration()*oc_player_kick_rate.GetFloat()) && !Kicked) { Kicked = true; float vel = 80.f; Vector recoilForce = GetAbsVelocity() - BaseClass::GetAutoaimVector(0) * vel; SetAbsVelocity(recoilForce); EventHit(); } if (m_flKickEventAnimTime > gpGlobals->curtime) { vm->m_flPlaybackRate = 1.0f; vm->StudioFrameAdvance(); } else if (m_flKickEventAnimTime < gpGlobals->curtime) { Kicking = false; Kicked = Kicking; m_flKickEventAnimTime = 0.0f; vm->SetWeaponModel(NULL, NULL); UTIL_RemoveImmediate(vm); SetRightLegVisible(true); } } } } void CHL2_Player::EventHit(bool swing) { //ViewPunch(QAngle(-8, random->RandomFloat(-2, 2), -3)); CBasePlayer *pPlayer = ToBasePlayer(this); Vector vecAiming = pPlayer->GetAutoaimVector(AUTOAIM_SCALE_DEFAULT); trace_t tr; Vector vecStart = pPlayer->EyePosition(); Vector vecStop = vecStart + vecAiming * oc_player_kick_range.GetFloat(); UTIL_TraceHull(vecStart, vecStop, Vector(-3,-3,-3), Vector(3,3,3), MASK_SHOT, pPlayer, COLLISION_GROUP_NONE, &tr); UTIL_ScreenShake(tr.endpos, 1.0, 50.0, 0.35, 150.0, SHAKE_START); pPlayer->ViewPunch(QAngle(-4, 5, random->RandomFloat(-1, 2))); //pPlayer->ViewPunch(QAngle(-2, 5, random->RandomFloat(-1, 2))); CBaseEntity *pHitEntity = tr.m_pEnt; if (!tr.DidHit()) { //EmitSound("Player.KickAir"); } if (pHitEntity != NULL) { if (pHitEntity->IsNPC()) EmitSound("Player.KickBody"); else EmitSound("Player.KickSolid"); Vector hitDirection; pPlayer->EyeVectors(&hitDirection, NULL, NULL); VectorNormalize(hitDirection); CTakeDamageInfo info(pPlayer, pPlayer, oc_player_kick_damage.GetFloat(), DMG_CLUB); info.SetAttacker(pPlayer); if (pPlayer && pHitEntity->IsNPC()) { } if (oc_player_allow_kick_doors.GetBool()) { if (FClassnameIs(pHitEntity, "prop_door") || FClassnameIs(pHitEntity, "prop_door_rotating")) { CBasePropDoor *pDoor = (CBasePropDoor*)pHitEntity; if (pDoor) { if (oc_player_allow_kick_doors.GetInt() == 2) { pDoor->Kick(this, this, USE_TOGGLE, 0.f); } else { Vector normal = tr.plane.normal; info.SetDamagePosition(tr.endpos); CalculateMeleeDamageForce(&info, normal, tr.endpos); info.SetDamageForce(normal); pDoor->TakeKick(info); } } } } /*if (pHitEntity) { IPhysicsObject *pPhysics = pHitEntity->VPhysicsGetObject(); if (pPhysics != NULL) { Vector vel = vecStart + vecStop; AngularImpulse angImp(15, 15, 15); pPhysics->AddVelocity(&vel, &angImp); } }*/ CEffectData data; data.m_vStart = tr.startpos; data.m_vOrigin = tr.endpos; DispatchEffect("RagdollImpact", data); info.AdjustPlayerDamageInflictedForSkillLevel(); CalculateMeleeDamageForce(&info, hitDirection, tr.endpos); if (!pPlayer->IsInAVehicle()) { pHitEntity->DispatchTraceAttack(info, hitDirection, &tr); ApplyMultiDamage(); TraceAttackToTriggers(info, tr.startpos, tr.endpos, hitDirection); } } } void CHL2_Player::SetPlayerAnimation(PLAYER_ANIM playerAnim) { int animDesired; float speed; speed = GetAbsVelocity().Length2D(); bool hasWeapons = HasWeapons(); //if (m_hUseEntity != NULL) //hasWeapons = false; if (GetFlags() & (FL_FROZEN | FL_ATCONTROLS)) { speed = 0; playerAnim = PLAYER_IDLE; } if (this->m_hUseEntity) { playerAnim = PLAYER_IDLE; } Activity idealActivity = ACT_HL2MP_RUN; if (playerAnim == PLAYER_JUMP) { if (hasWeapons) idealActivity = ACT_HL2MP_JUMP; else idealActivity = ACT_JUMP; } else if (playerAnim == PLAYER_DIE) { if (m_lifeState == LIFE_ALIVE) { return; } } else if (playerAnim == PLAYER_ATTACK1) { if (GetActivity() == ACT_HOVER || GetActivity() == ACT_SWIM || GetActivity() == ACT_HOP || GetActivity() == ACT_LEAP || GetActivity() == ACT_DIESIMPLE) { idealActivity = GetActivity(); } else { idealActivity = ACT_HL2MP_GESTURE_RANGE_ATTACK; } } else if (playerAnim == PLAYER_RELOAD) { idealActivity = ACT_HL2MP_GESTURE_RELOAD; } else if (playerAnim == PLAYER_IDLE || playerAnim == PLAYER_WALK) { if (!(GetFlags() & FL_ONGROUND) && (GetActivity() == ACT_HL2MP_JUMP || GetActivity() == ACT_JUMP)) // Still jumping { idealActivity = GetActivity(); } /*else if (GetWaterLevel() > 1) { if (speed == 0) { if (HasWeapons()) idealActivity = ACT_HL2MP_IDLE; else idealActivity = ACT_IDLE; } else { if (HasWeapons()) idealActivity = ACT_HL2MP_RUN; else idealActivity = ACT_RUN; } }*/ else { //if (GetFlags() & FL_DUCKING) if ((m_nButtons & IN_DUCK) && idealActivity != ACT_HL2MP_WALK_CROUCH && idealActivity != ACT_WALK_CROUCH && idealActivity != ACT_HL2MP_IDLE_CROUCH && idealActivity != ACT_COVER_LOW) { if ((GetWaterLevel() > 1) ? speed > 15 : speed > 0) { if (hasWeapons) idealActivity = ACT_HL2MP_WALK_CROUCH; else idealActivity = ACT_WALK_CROUCH; } else { if (hasWeapons) idealActivity = ACT_HL2MP_IDLE_CROUCH; else idealActivity = ACT_COVER_LOW; } } else { if ((GetWaterLevel() > 1) ? speed > 15 : speed > 0) { { if (hasWeapons) idealActivity = ACT_HL2MP_RUN; else { if (speed > HL2_WALK_SPEED + 20.0f) idealActivity = ACT_RUN; else idealActivity = ACT_WALK; } } } else { if (hasWeapons) idealActivity = ACT_HL2MP_IDLE; else idealActivity = ACT_IDLE; } } } } if (IsInAVehicle()) { idealActivity = ACT_COVER_LOW; } if (idealActivity == ACT_HL2MP_GESTURE_RANGE_ATTACK) { SetActivity(idealActivity); RestartGesture(Weapon_TranslateActivity(idealActivity)); return; } else if (idealActivity == ACT_HL2MP_GESTURE_RELOAD) { SetActivity(idealActivity); RestartGesture(Weapon_TranslateActivity(idealActivity)); return; } else { SetActivity(idealActivity); animDesired = this->m_hUseEntity ? -1 : SelectWeightedSequence(Weapon_TranslateActivity(idealActivity)); if (animDesired == -1) { animDesired = SelectWeightedSequence(idealActivity); if (animDesired == -1) { animDesired = 0; } } // Already using the desired animation? if (GetSequence() == animDesired) return; m_flPlaybackRate = 1.0; ResetSequence(animDesired); SetCycle(0); return; } // Already using the desired animation? if (GetSequence() == animDesired) return; ResetSequence(animDesired); SetCycle(0); } void CHL2_Player::SetAnimation(PLAYER_ANIM playerAnim) { //BaseClass::SetAnimation(playerAnim); SetPlayerAnimation(playerAnim); } #define HL2PLAYER_RELOADGAME_ATTACK_DELAY 1.0f void CHL2_Player::Activate( void ) { BaseClass::Activate(); InitSprinting(); #ifdef HL2_EPISODIC // Delay attacks by 1 second after loading a game. if ( GetActiveWeapon() ) { float flRemaining = GetActiveWeapon()->m_flNextPrimaryAttack - gpGlobals->curtime; if ( flRemaining < HL2PLAYER_RELOADGAME_ATTACK_DELAY ) { GetActiveWeapon()->m_flNextPrimaryAttack = gpGlobals->curtime + HL2PLAYER_RELOADGAME_ATTACK_DELAY; } flRemaining = GetActiveWeapon()->m_flNextSecondaryAttack - gpGlobals->curtime; if ( flRemaining < HL2PLAYER_RELOADGAME_ATTACK_DELAY ) { GetActiveWeapon()->m_flNextSecondaryAttack = gpGlobals->curtime + HL2PLAYER_RELOADGAME_ATTACK_DELAY; } } #endif GetPlayerProxy(); } //------------------------------------------------------------------------------ // Purpose : // Input : // Output : //------------------------------------------------------------------------------ Class_T CHL2_Player::Classify ( void ) { // If player controlling another entity? If so, return this class if (m_nControlClass != CLASS_NONE) { return m_nControlClass; } else { if(IsInAVehicle()) { IServerVehicle *pVehicle = GetVehicle(); return pVehicle->ClassifyPassenger( this, CLASS_PLAYER ); } else { return CLASS_PLAYER; } } } //----------------------------------------------------------------------------- // Purpose: This is a generic function (to be implemented by sub-classes) to // handle specific interactions between different types of characters // (For example the barnacle grabbing an NPC) // Input : Constant for the type of interaction // Output : true - if sub-class has a response for the interaction // false - if sub-class has no response //----------------------------------------------------------------------------- bool CHL2_Player::HandleInteraction(int interactionType, void *data, CBaseCombatCharacter* sourceEnt) { if ( interactionType == g_interactionBarnacleVictimDangle ) return false; if (interactionType == g_interactionBarnacleVictimReleased) { m_afPhysicsFlags &= ~PFLAG_ONBARNACLE; SetMoveType( MOVETYPE_WALK ); return true; } else if (interactionType == g_interactionBarnacleVictimGrab) { #ifdef HL2_EPISODIC CNPC_Alyx *pAlyx = CNPC_Alyx::GetAlyx(); if ( pAlyx ) { // Make Alyx totally hate this barnacle so that she saves the player. int priority; priority = pAlyx->IRelationPriority(sourceEnt); pAlyx->AddEntityRelationship( sourceEnt, D_HT, priority + 5 ); } #endif//HL2_EPISODIC m_afPhysicsFlags |= PFLAG_ONBARNACLE; ClearUseEntity(); return true; } return false; } void CHL2_Player::PlayerRunCommand(CUserCmd *ucmd, IMoveHelper *moveHelper) { // Handle FL_FROZEN. if ( m_afPhysicsFlags & PFLAG_ONBARNACLE ) { ucmd->forwardmove = 0; ucmd->sidemove = 0; ucmd->upmove = 0; ucmd->buttons &= ~IN_USE; } // Can't use stuff while dead if ( IsDead() ) { ucmd->buttons &= ~IN_USE; } //Update our movement information if ( ( ucmd->forwardmove != 0 ) || ( ucmd->sidemove != 0 ) || ( ucmd->upmove != 0 ) ) { m_flIdleTime -= TICK_INTERVAL * 2.0f; if ( m_flIdleTime < 0.0f ) { m_flIdleTime = 0.0f; } m_flMoveTime += TICK_INTERVAL; if ( m_flMoveTime > 4.0f ) { m_flMoveTime = 4.0f; } } else { m_flIdleTime += TICK_INTERVAL; if ( m_flIdleTime > 4.0f ) { m_flIdleTime = 4.0f; } m_flMoveTime -= TICK_INTERVAL * 2.0f; if ( m_flMoveTime < 0.0f ) { m_flMoveTime = 0.0f; } } //Msg("Player time: [ACTIVE: %f]\t[IDLE: %f]\n", m_flMoveTime, m_flIdleTime ); BaseClass::PlayerRunCommand( ucmd, moveHelper ); } //#define PLAYER_MODEL "models/player/gordon_hev_body_legs.mdl" //----------------------------------------------------------------------------- // Purpose: Sets HL2 specific defaults. //----------------------------------------------------------------------------- void CHL2_Player::Spawn(void) { #ifndef HL2MP #ifndef PORTAL PrecacheModel(cvar->FindVar("oc_playermodel_suit")->GetString()); PrecacheModel(cvar->FindVar("oc_playermodel_nosuit")->GetString()); SetBodyRenderingState(IsSuitEquipped()); #endif #endif BaseClass::Spawn(); if ( !IsSuitEquipped() ) StartWalking(); SuitPower_SetCharge( 100 ); m_Local.m_iHideHUD |= HIDEHUD_CHAT; m_pPlayerAISquad = g_AI_SquadManager.FindCreateSquad(AllocPooledString(PLAYER_SQUADNAME)); InitSprinting(); // Setup our flashlight values //#ifdef HL2_EPISODIC m_HL2Local.m_flFlashBattery = 100.0f; //#endif GetPlayerProxy(); SetFlashlightPowerDrainScale(1.0f); //=============================== Overcharged Reset player state here cvar->FindVar("oc_state_InSecondFire_sniper")->SetValue(0); cvar->FindVar("oc_state_InSecondFire_crossbow")->SetValue(0); cvar->FindVar("oc_state_InSecondFire_357")->SetValue(0); cvar->FindVar("oc_state_InSecondFire_oicw")->SetValue(0); cvar->FindVar("oc_state_InSecondFire_sg552")->SetValue(0); //================================================================================== } //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- void CHL2_Player::UpdateLocatorPosition( const Vector &vecPosition ) { #ifdef HL2_EPISODIC m_HL2Local.m_vecLocatorOrigin = vecPosition; #endif//HL2_EPISODIC } //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- void CHL2_Player::InitSprinting( void ) { StopSprinting(); } //----------------------------------------------------------------------------- // Purpose: Returns whether or not we are allowed to sprint now. //----------------------------------------------------------------------------- bool CHL2_Player::CanSprint() { bool notInSilencering = GetActiveWeapon() ? GetActiveWeapon()->m_flNextSilencer < gpGlobals->curtime : true; bool notInSwitch = GetActiveWeapon() ? GetActiveWeapon()->m_flNextSwitchTime < gpGlobals->curtime : true; //bool notInInspect = GetActiveWeapon() ? GetActiveWeapon()->m_flNextInspectAnimation < gpGlobals->curtime : true; //bool notInReload = GetActiveWeapon() ? !GetActiveWeapon()->m_bInReload && !GetActiveWeapon()->m_bReloadComplete && !GetActiveWeapon()->m_iShotgunReloadState : true; return ( m_bSprintEnabled && // Only if sprint is enabled !IsWalking() && notInSilencering && notInSwitch && //!cvar->FindVar("oc_state_InSecondFire")->GetInt() && //!cvar->FindVar("oc_state_IRsight_on")->GetInt() && !( m_Local.m_bDucked && !m_Local.m_bDucking ) && // Nor if we're ducking (GetWaterLevel() != 3) && // Certainly not underwater (GlobalEntity_GetState("suit_no_sprint") != GLOBAL_ON) ); // Out of the question without the sprint module } //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- void CHL2_Player::StartAutoSprint() { if( IsSprinting() ) { StopSprinting(); } else { StartSprinting(); m_bIsAutoSprinting = true; m_fAutoSprintMinTime = gpGlobals->curtime + 1.5f; } } //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- void CHL2_Player::StartSprinting( void ) { if( m_HL2Local.m_flSuitPower < 10 ) { // Don't sprint unless there's a reasonable // amount of suit power. // debounce the button for sound playing if ( m_afButtonPressed & IN_SPEED ) { CPASAttenuationFilter filter( this ); filter.UsePredictionRules(); EmitSound( filter, entindex(), "HL2Player.SprintNoPower" ); } return; } if( !SuitPower_AddDevice( SuitDeviceSprint ) ) return; CPASAttenuationFilter filter( this ); filter.UsePredictionRules(); EmitSound( filter, entindex(), "HL2Player.SprintStart" ); /*if (GetActiveWeapon()) {*/ /*float massKoefficient = 0.f; if (GetActiveWeapon()->GetWpnData().weaponMassKoefficient && oc_test_weapon_weight.GetFloat() == 0) massKoefficient = GetActiveWeapon()->GetWpnData().weaponMassKoefficient; else if (!GetActiveWeapon()->GetWpnData().weaponMassKoefficient) massKoefficient = 1.f; else if (oc_test_weapon_weight.GetFloat() != 0.f) massKoefficient = oc_test_weapon_weight.GetFloat(); SetMaxSpeed(HL2_SPRINT_SPEED * massKoefficient);*/ /*if (GetActiveWeapon()->GetWpnData().PlayerDisableSprint) EnableSprint(!GetActiveWeapon()->GetWpnData().PlayerDisableSprint); else EnableSprint(!GetActiveWeapon()->GetWpnData().PlayerDisableSprint); if (GetActiveWeapon()->GetWpnData().PlayerSpeedRunKoefficient) SetMaxSpeed(HL2_SPRINT_SPEED * GetActiveWeapon()->GetWpnData().PlayerSpeedRunKoefficient); else SetMaxSpeed(HL2_SPRINT_SPEED); } else*/ SetMaxSpeed( HL2_SPRINT_SPEED ); m_fIsSprinting = true; } //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- void CHL2_Player::StopSprinting( void ) { if ( m_HL2Local.m_bitsActiveDevices & SuitDeviceSprint.GetDeviceID() ) { SuitPower_RemoveDevice( SuitDeviceSprint ); } if( IsSuitEquipped() ) { /*if (oc_test_weapon_weight.GetFloat() == 0) { if (GetActiveWeapon() && GetActiveWeapon()->GetWpnData().PlayerSpeedWalkKoefficient) SetMaxSpeed(HL2_NORM_SPEED * GetActiveWeapon()->GetWpnData().PlayerSpeedWalkKoefficient); else SetMaxSpeed(HL2_NORM_SPEED); } else { SetMaxSpeed(HL2_NORM_SPEED * oc_test_weapon_weight.GetFloat()); }*/ SetMaxSpeed(HL2_NORM_SPEED); } else { SetMaxSpeed( HL2_WALK_SPEED ); } m_fIsSprinting = false; if ( sv_stickysprint.GetBool() ) { m_bIsAutoSprinting = false; m_fAutoSprintMinTime = 0.0f; } } //----------------------------------------------------------------------------- // Purpose: Called to disable and enable sprint due to temporary circumstances: // - Carrying a heavy object with the physcannon //----------------------------------------------------------------------------- void CHL2_Player::EnableSprint( bool bEnable ) { if ( !bEnable && IsSprinting() ) { StopSprinting(); } m_bSprintEnabled = bEnable; } //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- void CHL2_Player::StartWalking( void ) { SetMaxSpeed( HL2_WALK_SPEED ); m_fIsWalking = true; } //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- void CHL2_Player::StopWalking( void ) { /*if (oc_test_weapon_weight.GetFloat() == 0) { if (GetActiveWeapon() && GetActiveWeapon()->GetWpnData().PlayerSpeedWalkKoefficient) SetMaxSpeed(HL2_NORM_SPEED * GetActiveWeapon()->GetWpnData().PlayerSpeedWalkKoefficient); else SetMaxSpeed(HL2_NORM_SPEED); } else { SetMaxSpeed(HL2_NORM_SPEED * oc_test_weapon_weight.GetFloat()); }*/ SetMaxSpeed(HL2_NORM_SPEED); m_fIsWalking = false; } //----------------------------------------------------------------------------- // Purpose: // Output : Returns true on success, false on failure. //----------------------------------------------------------------------------- bool CHL2_Player::CanZoom( CBaseEntity *pRequester ) { if ( IsZooming() ) return false; //Check our weapon return true; } //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- void CHL2_Player::ToggleZoom(void) { if( IsZooming() ) { StopZooming(); } else { StartZooming(); } } //----------------------------------------------------------------------------- // Purpose: +zoom suit zoom //----------------------------------------------------------------------------- void CHL2_Player::StartZooming(bool ironsighted, float fov) { if (SetFOV(this, fov, 0.4f)) { m_HL2Local.m_bZooming = true; m_HL2Local.m_bIsIronsighted = ironsighted; } } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void CHL2_Player::StopZooming(bool ironsighted) { int iFOV = GetZoomOwnerDesiredFOV( m_hZoomOwner ); if ( SetFOV( this, iFOV, 0.2f ) ) { m_HL2Local.m_bZooming = false; m_HL2Local.m_bIsIronsighted = false; } } //----------------------------------------------------------------------------- // Purpose: // Output : Returns true on success, false on failure. //----------------------------------------------------------------------------- bool CHL2_Player::IsZooming( void ) { if ( m_hZoomOwner != NULL ) return true; return false; } class CPhysicsPlayerCallback : public IPhysicsPlayerControllerEvent { public: int ShouldMoveTo( IPhysicsObject *pObject, const Vector &position ) { CHL2_Player *pPlayer = (CHL2_Player *)pObject->GetGameData(); if ( pPlayer ) { if ( pPlayer->TouchedPhysics() ) { return 0; } } return 1; } }; static CPhysicsPlayerCallback playerCallback; //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void CHL2_Player::InitVCollision( const Vector &vecAbsOrigin, const Vector &vecAbsVelocity ) { BaseClass::InitVCollision( vecAbsOrigin, vecAbsVelocity ); // Setup the HL2 specific callback. IPhysicsPlayerController *pPlayerController = GetPhysicsController(); if ( pPlayerController ) { pPlayerController->SetEventHandler( &playerCallback ); } } CHL2_Player::~CHL2_Player( void ) { // Clears the animation state. // Overcharged: Player anims if (m_pPlayerAnimState != NULL) { m_pPlayerAnimState->Release(); m_pPlayerAnimState = NULL; } } //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- bool CHL2_Player::CommanderFindGoal( commandgoal_t *pGoal ) { CAI_BaseNPC *pAllyNpc; trace_t tr; Vector vecTarget; Vector forward; EyeVectors( &forward ); //--------------------------------- // MASK_SHOT on purpose! So that you don't hit the invisible hulls of the NPCs. CTraceFilterSkipTwoEntities filter( this, PhysCannonGetHeldEntity( GetActiveWeapon() ), COLLISION_GROUP_INTERACTIVE_DEBRIS ); UTIL_TraceLine( EyePosition(), EyePosition() + forward * MAX_COORD_RANGE, MASK_SHOT, &filter, &tr ); if( !tr.DidHitWorld() ) { CUtlVector Allies; AISquadIter_t iter; for ( pAllyNpc = m_pPlayerAISquad->GetFirstMember(&iter); pAllyNpc; pAllyNpc = m_pPlayerAISquad->GetNextMember(&iter) ) { if ( pAllyNpc->IsCommandable() ) Allies.AddToTail( pAllyNpc ); } for( int i = 0 ; i < Allies.Count() ; i++ ) { if( Allies[ i ]->IsValidCommandTarget( tr.m_pEnt ) ) { pGoal->m_pGoalEntity = tr.m_pEnt; return true; } } } if( tr.fraction == 1.0 || (tr.surface.flags & SURF_SKY) ) { // Move commands invalid against skybox. pGoal->m_vecGoalLocation = tr.endpos; return false; } if ( tr.m_pEnt->IsNPC() && ((CAI_BaseNPC *)(tr.m_pEnt))->IsCommandable() ) { pGoal->m_vecGoalLocation = tr.m_pEnt->GetAbsOrigin(); } else { vecTarget = tr.endpos; Vector mins( -16, -16, 0 ); Vector maxs( 16, 16, 0 ); // Back up from whatever we hit so that there's enough space at the // target location for a bounding box. // Now trace down. //UTIL_TraceLine( vecTarget, vecTarget - Vector( 0, 0, 8192 ), MASK_SOLID, this, COLLISION_GROUP_NONE, &tr ); UTIL_TraceHull( vecTarget + tr.plane.normal * 24, vecTarget - Vector( 0, 0, 8192 ), mins, maxs, MASK_SOLID_BRUSHONLY, this, COLLISION_GROUP_NONE, &tr ); if ( !tr.startsolid ) pGoal->m_vecGoalLocation = tr.endpos; else pGoal->m_vecGoalLocation = vecTarget; } pAllyNpc = GetSquadCommandRepresentative(); if ( !pAllyNpc ) return false; vecTarget = pGoal->m_vecGoalLocation; if ( !pAllyNpc->FindNearestValidGoalPos( vecTarget, &pGoal->m_vecGoalLocation ) ) return false; return ( ( vecTarget - pGoal->m_vecGoalLocation ).LengthSqr() < Square( 15*12 ) ); } //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- CAI_BaseNPC *CHL2_Player::GetSquadCommandRepresentative() { if ( m_pPlayerAISquad != NULL ) { CAI_BaseNPC *pAllyNpc = m_pPlayerAISquad->GetFirstMember(); if ( pAllyNpc ) { return pAllyNpc->GetSquadCommandRepresentative(); } } return NULL; } //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- int CHL2_Player::GetNumSquadCommandables() { AISquadIter_t iter; int c = 0; for ( CAI_BaseNPC *pAllyNpc = m_pPlayerAISquad->GetFirstMember(&iter); pAllyNpc; pAllyNpc = m_pPlayerAISquad->GetNextMember(&iter) ) { if ( pAllyNpc->IsCommandable() ) c++; } return c; } //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- int CHL2_Player::GetNumSquadCommandableMedics() { AISquadIter_t iter; int c = 0; for ( CAI_BaseNPC *pAllyNpc = m_pPlayerAISquad->GetFirstMember(&iter); pAllyNpc; pAllyNpc = m_pPlayerAISquad->GetNextMember(&iter) ) { if ( pAllyNpc->IsCommandable() && pAllyNpc->IsMedic() ) c++; } return c; } //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- void CHL2_Player::CommanderUpdate() { CAI_BaseNPC *pCommandRepresentative = GetSquadCommandRepresentative(); bool bFollowMode = false; if ( pCommandRepresentative ) { bFollowMode = ( pCommandRepresentative->GetCommandGoal() == vec3_invalid ); // set the variables for network transmission (to show on the hud) m_HL2Local.m_iSquadMemberCount = GetNumSquadCommandables(); m_HL2Local.m_iSquadMedicCount = GetNumSquadCommandableMedics(); m_HL2Local.m_fSquadInFollowMode = bFollowMode; // debugging code for displaying extra squad indicators /* char *pszMoving = ""; AISquadIter_t iter; for ( CAI_BaseNPC *pAllyNpc = m_pPlayerAISquad->GetFirstMember(&iter); pAllyNpc; pAllyNpc = m_pPlayerAISquad->GetNextMember(&iter) ) { if ( pAllyNpc->IsCommandMoving() ) { pszMoving = "<-"; break; } } NDebugOverlay::ScreenText( 0.932, 0.919, CFmtStr( "%d|%c%s", GetNumSquadCommandables(), ( bFollowMode ) ? 'F' : 'S', pszMoving ), 255, 128, 0, 128, 0 ); */ } else { m_HL2Local.m_iSquadMemberCount = 0; m_HL2Local.m_iSquadMedicCount = 0; m_HL2Local.m_fSquadInFollowMode = true; } if ( m_QueuedCommand != CC_NONE && ( m_QueuedCommand == CC_FOLLOW || gpGlobals->realtime - m_RealTimeLastSquadCommand >= player_squad_double_tap_time.GetFloat() ) ) { CommanderExecute( m_QueuedCommand ); m_QueuedCommand = CC_NONE; } else if ( !bFollowMode && pCommandRepresentative && m_CommanderUpdateTimer.Expired() && player_squad_transient_commands.GetBool() ) { m_CommanderUpdateTimer.Set(2.5); if ( pCommandRepresentative->ShouldAutoSummon() ) CommanderExecute( CC_FOLLOW ); } } //----------------------------------------------------------------------------- // Purpose: // // bHandled - indicates whether to continue delivering this order to // all allies. Allows us to stop delivering certain types of orders once we find // a suitable candidate. (like picking up a single weapon. We don't wish for // all allies to respond and try to pick up one weapon). //----------------------------------------------------------------------------- bool CHL2_Player::CommanderExecuteOne( CAI_BaseNPC *pNpc, const commandgoal_t &goal, CAI_BaseNPC **Allies, int numAllies ) { if ( goal.m_pGoalEntity ) { return pNpc->TargetOrder( goal.m_pGoalEntity, Allies, numAllies ); } else if ( pNpc->IsInPlayerSquad() ) { pNpc->MoveOrder( goal.m_vecGoalLocation, Allies, numAllies ); } return true; } //--------------------------------------------------------- //--------------------------------------------------------- void CHL2_Player::CommanderExecute( CommanderCommand_t command ) { CAI_BaseNPC *pPlayerSquadLeader = GetSquadCommandRepresentative(); if ( !pPlayerSquadLeader ) { EmitSound( "HL2Player.UseDeny" ); return; } int i; CUtlVector Allies; commandgoal_t goal; if ( command == CC_TOGGLE ) { if ( pPlayerSquadLeader->GetCommandGoal() != vec3_invalid ) command = CC_FOLLOW; else command = CC_SEND; } else { if ( command == CC_FOLLOW && pPlayerSquadLeader->GetCommandGoal() == vec3_invalid ) return; } if ( command == CC_FOLLOW ) { goal.m_pGoalEntity = this; goal.m_vecGoalLocation = vec3_invalid; } else { goal.m_pGoalEntity = NULL; goal.m_vecGoalLocation = vec3_invalid; // Find a goal for ourselves. if( !CommanderFindGoal( &goal ) ) { EmitSound( "HL2Player.UseDeny" ); return; // just keep following } } #ifdef _DEBUG if( goal.m_pGoalEntity == NULL && goal.m_vecGoalLocation == vec3_invalid ) { DevMsg( 1, "**ERROR: Someone sent an invalid goal to CommanderExecute!\n" ); } #endif // _DEBUG AISquadIter_t iter; for ( CAI_BaseNPC *pAllyNpc = m_pPlayerAISquad->GetFirstMember(&iter); pAllyNpc; pAllyNpc = m_pPlayerAISquad->GetNextMember(&iter) ) { if ( pAllyNpc->IsCommandable() ) Allies.AddToTail( pAllyNpc ); } //--------------------------------- // If the trace hits an NPC, send all ally NPCs a "target" order. Always // goes to targeted one first #ifdef DBGFLAG_ASSERT int nAIs = g_AI_Manager.NumAIs(); #endif CAI_BaseNPC * pTargetNpc = (goal.m_pGoalEntity) ? goal.m_pGoalEntity->MyNPCPointer() : NULL; bool bHandled = false; if( pTargetNpc ) { bHandled = !CommanderExecuteOne( pTargetNpc, goal, Allies.Base(), Allies.Count() ); } for ( i = 0; !bHandled && i < Allies.Count(); i++ ) { if ( Allies[i] != pTargetNpc && Allies[i]->IsPlayerAlly() ) { bHandled = !CommanderExecuteOne( Allies[i], goal, Allies.Base(), Allies.Count() ); } Assert( nAIs == g_AI_Manager.NumAIs() ); // not coded to support mutating set of NPCs } } //----------------------------------------------------------------------------- // Enter/exit commander mode, manage ally selection. //----------------------------------------------------------------------------- void CHL2_Player::CommanderMode() { float commandInterval = gpGlobals->realtime - m_RealTimeLastSquadCommand; m_RealTimeLastSquadCommand = gpGlobals->realtime; if ( commandInterval < player_squad_double_tap_time.GetFloat() ) { m_QueuedCommand = CC_FOLLOW; } else { m_QueuedCommand = (player_squad_transient_commands.GetBool()) ? CC_SEND : CC_TOGGLE; } } //----------------------------------------------------------------------------- // Purpose: // Input : iImpulse - //----------------------------------------------------------------------------- void CHL2_Player::CheatImpulseCommands( int iImpulse ) { switch( iImpulse ) { case 50: { CommanderMode(); break; } case 51: { // Cheat to create a dynamic resupply item Vector vecForward; AngleVectors( EyeAngles(), &vecForward ); CBaseEntity *pItem = (CBaseEntity *)CreateEntityByName( "item_dynamic_resupply" ); if ( pItem ) { Vector vecOrigin = GetAbsOrigin() + vecForward * 256 + Vector(0,0,64); QAngle vecAngles( 0, GetAbsAngles().y - 90, 0 ); pItem->SetAbsOrigin( vecOrigin ); pItem->SetAbsAngles( vecAngles ); pItem->KeyValue( "targetname", "resupply" ); pItem->Spawn(); pItem->Activate(); } break; } case 52: { // Rangefinder trace_t tr; UTIL_TraceLine( EyePosition(), EyePosition() + EyeDirection3D() * MAX_COORD_RANGE, MASK_SHOT, this, COLLISION_GROUP_NONE, &tr ); if( tr.fraction != 1.0 ) { float flDist = (tr.startpos - tr.endpos).Length(); float flDist2D = (tr.startpos - tr.endpos).Length2D(); DevMsg( 1,"\nStartPos: %.4f %.4f %.4f --- EndPos: %.4f %.4f %.4f\n", tr.startpos.x,tr.startpos.y,tr.startpos.z,tr.endpos.x,tr.endpos.y,tr.endpos.z ); DevMsg( 1,"3D Distance: %.4f units (%.2f feet) --- 2D Distance: %.4f units (%.2f feet)\n", flDist, flDist / 12.0, flDist2D, flDist2D / 12.0 ); } break; } default: BaseClass::CheatImpulseCommands( iImpulse ); } } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void CHL2_Player::SetupVisibility( CBaseEntity *pViewEntity, unsigned char *pvs, int pvssize ) { BaseClass::SetupVisibility( pViewEntity, pvs, pvssize ); int area = pViewEntity ? pViewEntity->NetworkProp()->AreaNum() : NetworkProp()->AreaNum(); PointCameraSetupVisibility( this, area, pvs, pvssize ); // If the intro script is playing, we want to get it's visibility points if ( g_hIntroScript ) { Vector vecOrigin; CBaseEntity *pCamera; if ( g_hIntroScript->GetIncludedPVSOrigin( &vecOrigin, &pCamera ) ) { // If it's a point camera, turn it on CPointCamera *pPointCamera = dynamic_cast< CPointCamera* >(pCamera); if ( pPointCamera ) { pPointCamera->SetActive( true ); } engine->AddOriginToPVS( vecOrigin ); } } } //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- void CHL2_Player::SuitPower_Update( void ) { if( SuitPower_ShouldRecharge() ) { SuitPower_Charge( SUITPOWER_CHARGE_RATE * gpGlobals->frametime ); } else if( m_HL2Local.m_bitsActiveDevices ) { float flPowerLoad = m_flSuitPowerLoad; //Since stickysprint quickly shuts off sprint if it isn't being used, this isn't an issue. if ( !sv_stickysprint.GetBool() ) { if( SuitPower_IsDeviceActive(SuitDeviceSprint) ) { if( !fabs(GetAbsVelocity().x) && !fabs(GetAbsVelocity().y) ) { // If player's not moving, don't drain sprint juice. flPowerLoad -= SuitDeviceSprint.GetDeviceDrainRate(); } } } if( SuitPower_IsDeviceActive(SuitDeviceFlashlight) ) { float factor; factor = 1.0f / m_flFlashlightPowerDrainScale; flPowerLoad -= ( SuitDeviceFlashlight.GetDeviceDrainRate() * (1.0f - factor) ); } if( !SuitPower_Drain( flPowerLoad * gpGlobals->frametime ) ) { // TURN OFF ALL DEVICES!! if( IsSprinting() ) { StopSprinting(); } if ( Flashlight_UseLegacyVersion() ) { if( FlashlightIsOn() ) { #ifndef HL2MP FlashlightTurnOff(); #endif } } } if ( Flashlight_UseLegacyVersion() ) { // turn off flashlight a little bit after it hits below one aux power notch (5%) if( m_HL2Local.m_flSuitPower < 4.8f && FlashlightIsOn() ) { #ifndef HL2MP FlashlightTurnOff(); #endif } } } } //----------------------------------------------------------------------------- // Charge battery fully, turn off all devices. //----------------------------------------------------------------------------- void CHL2_Player::SuitPower_Initialize( void ) { m_HL2Local.m_bitsActiveDevices = 0x00000000; m_HL2Local.m_flSuitPower = 100.0; m_flSuitPowerLoad = 0.0; } //----------------------------------------------------------------------------- // Purpose: Interface to drain power from the suit's power supply. // Input: Amount of charge to remove (expressed as percentage of full charge) // Output: Returns TRUE if successful, FALSE if not enough power available. //----------------------------------------------------------------------------- bool CHL2_Player::SuitPower_Drain( float flPower ) { // Suitpower cheat on? if ( sv_infinite_aux_power.GetBool() ) return true; m_HL2Local.m_flSuitPower -= flPower; if( m_HL2Local.m_flSuitPower < 0.0 ) { // Power is depleted! // Clamp and fail m_HL2Local.m_flSuitPower = 0.0; return false; } return true; } //----------------------------------------------------------------------------- // Purpose: Interface to add power to the suit's power supply // Input: Amount of charge to add //----------------------------------------------------------------------------- void CHL2_Player::SuitPower_Charge( float flPower ) { m_HL2Local.m_flSuitPower += flPower; if( m_HL2Local.m_flSuitPower > 100.0 ) { // Full charge, clamp. m_HL2Local.m_flSuitPower = 100.0; } } //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- bool CHL2_Player::SuitPower_IsDeviceActive( const CSuitPowerDevice &device ) { return (m_HL2Local.m_bitsActiveDevices & device.GetDeviceID()) != 0; } //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- bool CHL2_Player::SuitPower_AddDevice( const CSuitPowerDevice &device ) { // Make sure this device is NOT active!! if( m_HL2Local.m_bitsActiveDevices & device.GetDeviceID() ) return false; if( !IsSuitEquipped() ) return false; m_HL2Local.m_bitsActiveDevices |= device.GetDeviceID(); m_flSuitPowerLoad += device.GetDeviceDrainRate(); return true; } //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- bool CHL2_Player::SuitPower_RemoveDevice( const CSuitPowerDevice &device ) { // Make sure this device is active!! if( ! (m_HL2Local.m_bitsActiveDevices & device.GetDeviceID()) ) return false; if( !IsSuitEquipped() ) return false; // Take a little bit of suit power when you disable a device. If the device is shutting off // because the battery is drained, no harm done, the battery charge cannot go below 0. // This code in combination with the delay before the suit can start recharging are a defense // against exploits where the player could rapidly tap sprint and never run out of power. SuitPower_Drain( device.GetDeviceDrainRate() * 0.1f ); m_HL2Local.m_bitsActiveDevices &= ~device.GetDeviceID(); m_flSuitPowerLoad -= device.GetDeviceDrainRate(); if( m_HL2Local.m_bitsActiveDevices == 0x00000000 ) { // With this device turned off, we can set this timer which tells us when the // suit power system entered a no-load state. m_flTimeAllSuitDevicesOff = gpGlobals->curtime; } return true; } //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- #define SUITPOWER_BEGIN_RECHARGE_DELAY 0.5f bool CHL2_Player::SuitPower_ShouldRecharge( void ) { // Make sure all devices are off. if( m_HL2Local.m_bitsActiveDevices != 0x00000000 ) return false; // Is the system fully charged? if( m_HL2Local.m_flSuitPower >= 100.0f ) return false; // Has the system been in a no-load state for long enough // to begin recharging? if( gpGlobals->curtime < m_flTimeAllSuitDevicesOff + SUITPOWER_BEGIN_RECHARGE_DELAY ) return false; return true; } //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- ConVar sk_battery( "sk_battery","0" ); bool CHL2_Player::ApplyBattery( float powerMultiplier ) { const float MAX_NORMAL_BATTERY = 100; if ((ArmorValue() < MAX_NORMAL_BATTERY) && IsSuitEquipped()) { int pct; char szcharge[64]; IncrementArmorValue( sk_battery.GetFloat() * powerMultiplier, MAX_NORMAL_BATTERY ); CPASAttenuationFilter filter( this, "ItemBattery.Touch" ); EmitSound( filter, entindex(), "ItemBattery.Touch" ); CSingleUserRecipientFilter user( this ); user.MakeReliable(); UserMessageBegin( user, "ItemPickup" ); WRITE_STRING( "item_battery" ); MessageEnd(); CanDropGarbage = true; garbage.AddToHead(MAKE_STRING("item_battery")); garbageIndex.AddToHead(gpGlobals->curtime + cvar->FindVar("oc_player_garbage_drop_delay")->GetFloat()); // Suit reports new power level // For some reason this wasn't working in release build -- round it. pct = (int)( (float)(ArmorValue() * 100.0) * (1.0/MAX_NORMAL_BATTERY) + 0.5); pct = (pct / 5); if (pct > 0) pct--; Q_snprintf( szcharge,sizeof(szcharge),"!HEV_%1dP", pct ); EntityMessageBegin(this); WRITE_BYTE(PLAYER_MSG_DO_BATTERY); MessageEnd(); //UTIL_EmitSoundSuit(edict(), szcharge); //SetSuitUpdate(szcharge, FALSE, SUIT_NEXT_IN_30SEC); return true; } return false; } //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- int CHL2_Player::FlashlightIsOn( void ) { return IsEffectActive( EF_DIMLIGHT ); } //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- void CHL2_Player::FlashlightTurnOn( void ) { if( m_bFlashlightDisabled ) return; if ( Flashlight_UseLegacyVersion() ) { if( !SuitPower_AddDevice( SuitDeviceFlashlight ) ) return; } #ifdef HL2_DLL if( !IsSuitEquipped() ) return; #endif AddEffects( EF_DIMLIGHT ); EmitSound( "HL2Player.FlashLightOn" ); variant_t flashlighton; flashlighton.SetFloat( m_HL2Local.m_flSuitPower / 100.0f ); FirePlayerProxyOutput( "OnFlashlightOn", flashlighton, this, this ); } //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- void CHL2_Player::FlashlightTurnOff( void ) { if ( Flashlight_UseLegacyVersion() ) { if( !SuitPower_RemoveDevice( SuitDeviceFlashlight ) ) return; } RemoveEffects( EF_DIMLIGHT ); EmitSound( "HL2Player.FlashLightOff" ); variant_t flashlightoff; flashlightoff.SetFloat( m_HL2Local.m_flSuitPower / 100.0f ); FirePlayerProxyOutput( "OnFlashlightOff", flashlightoff, this, this ); } //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- #define FLASHLIGHT_RANGE Square(600) bool CHL2_Player::IsIlluminatedByFlashlight( CBaseEntity *pEntity, float *flReturnDot ) { if( !FlashlightIsOn() ) return false; if( pEntity->Classify() == CLASS_BARNACLE && pEntity->GetEnemy() == this ) { // As long as my flashlight is on, the barnacle that's pulling me in is considered illuminated. // This is because players often shine their flashlights at Alyx when they are in a barnacle's // grasp, and wonder why Alyx isn't helping. Alyx isn't helping because the light isn't pointed // at the barnacle. This will allow Alyx to see the barnacle no matter which way the light is pointed. return true; } // Within 50 feet? float flDistSqr = GetAbsOrigin().DistToSqr(pEntity->GetAbsOrigin()); if( flDistSqr > FLASHLIGHT_RANGE ) return false; // Within 45 degrees? Vector vecSpot = pEntity->WorldSpaceCenter(); Vector los; // If the eyeposition is too close, move it back. Solves problems // caused by the player being too close the target. if ( flDistSqr < (128 * 128) ) { Vector vecForward; EyeVectors( &vecForward ); Vector vecMovedEyePos = EyePosition() - (vecForward * 128); los = ( vecSpot - vecMovedEyePos ); } else { los = ( vecSpot - EyePosition() ); } VectorNormalize( los ); Vector facingDir = EyeDirection3D( ); float flDot = DotProduct( los, facingDir ); if ( flReturnDot ) { *flReturnDot = flDot; } if ( flDot < 0.92387f ) return false; if( !FVisible(pEntity) ) return false; return true; } //----------------------------------------------------------------------------- // Purpose: Let NPCs know when the flashlight is trained on them //----------------------------------------------------------------------------- void CHL2_Player::CheckFlashlight( void ) { if ( !FlashlightIsOn() ) return; if ( m_flNextFlashlightCheckTime > gpGlobals->curtime ) return; m_flNextFlashlightCheckTime = gpGlobals->curtime + FLASHLIGHT_NPC_CHECK_INTERVAL; // Loop through NPCs looking for illuminated ones for ( int i = 0; i < g_AI_Manager.NumAIs(); i++ ) { CAI_BaseNPC *pNPC = g_AI_Manager.AccessAIs()[i]; float flDot; if ( IsIlluminatedByFlashlight( pNPC, &flDot ) ) { pNPC->PlayerHasIlluminatedNPC( this, flDot ); } } } //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- void CHL2_Player::SetPlayerUnderwater( bool state ) { if ( state ) { SuitPower_AddDevice( SuitDeviceBreather ); } else { SuitPower_RemoveDevice( SuitDeviceBreather ); } BaseClass::SetPlayerUnderwater( state ); } //----------------------------------------------------------------------------- bool CHL2_Player::PassesDamageFilter( const CTakeDamageInfo &info ) { CBaseEntity *pAttacker = info.GetAttacker(); if( pAttacker && pAttacker->MyNPCPointer() && pAttacker->MyNPCPointer()->IsPlayerAlly() ) { return false; } if( m_hPlayerProxy && !m_hPlayerProxy->PassesDamageFilter( info ) ) { return false; } return BaseClass::PassesDamageFilter( info ); } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void CHL2_Player::SetFlashlightEnabled( bool bState ) { m_bFlashlightDisabled = !bState; } //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- void CHL2_Player::InputDisableFlashlight( inputdata_t &inputdata ) { if( FlashlightIsOn() ) FlashlightTurnOff(); SetFlashlightEnabled( false ); } //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- void CHL2_Player::InputEnableFlashlight( inputdata_t &inputdata ) { SetFlashlightEnabled( true ); } //----------------------------------------------------------------------------- // Purpose: Prevent the player from taking fall damage for [n] seconds, but // reset back to taking fall damage after the first impact (so players will be // hurt if they bounce off what they hit). This is the original behavior. //----------------------------------------------------------------------------- void CHL2_Player::InputIgnoreFallDamage( inputdata_t &inputdata ) { float timeToIgnore = inputdata.value.Float(); if ( timeToIgnore <= 0.0 ) timeToIgnore = TIME_IGNORE_FALL_DAMAGE; m_flTimeIgnoreFallDamage = gpGlobals->curtime + timeToIgnore; m_bIgnoreFallDamageResetAfterImpact = true; } //----------------------------------------------------------------------------- // Purpose: Absolutely prevent the player from taking fall damage for [n] seconds. //----------------------------------------------------------------------------- void CHL2_Player::InputIgnoreFallDamageWithoutReset( inputdata_t &inputdata ) { float timeToIgnore = inputdata.value.Float(); if ( timeToIgnore <= 0.0 ) timeToIgnore = TIME_IGNORE_FALL_DAMAGE; m_flTimeIgnoreFallDamage = gpGlobals->curtime + timeToIgnore; m_bIgnoreFallDamageResetAfterImpact = false; } //----------------------------------------------------------------------------- // Purpose: Notification of a player's npc ally in the players squad being killed //----------------------------------------------------------------------------- void CHL2_Player::OnSquadMemberKilled( inputdata_t &data ) { // send a message to the client, to notify the hud of the loss CSingleUserRecipientFilter user( this ); user.MakeReliable(); UserMessageBegin( user, "SquadMemberDied" ); MessageEnd(); } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void CHL2_Player::NotifyFriendsOfDamage( CBaseEntity *pAttackerEntity ) { CAI_BaseNPC *pAttacker = pAttackerEntity->MyNPCPointer(); if ( pAttacker ) { const Vector &origin = GetAbsOrigin(); for ( int i = 0; i < g_AI_Manager.NumAIs(); i++ ) { const float NEAR_Z = 12*12; const float NEAR_XY_SQ = Square( 50*12 ); CAI_BaseNPC *pNpc = g_AI_Manager.AccessAIs()[i]; if ( pNpc->IsPlayerAlly() ) { const Vector &originNpc = pNpc->GetAbsOrigin(); if ( fabsf( originNpc.z - origin.z ) < NEAR_Z ) { if ( (originNpc.AsVector2D() - origin.AsVector2D()).LengthSqr() < NEAR_XY_SQ ) { pNpc->OnFriendDamaged( this, pAttacker ); } } } } } } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- ConVar test_massive_dmg("test_massive_dmg", "30" ); ConVar test_massive_dmg_clip("test_massive_dmg_clip", "0.5" ); int CHL2_Player::OnTakeDamage( const CTakeDamageInfo &info ) { if ( GlobalEntity_GetState( "gordon_invulnerable" ) == GLOBAL_ON ) return 0; // ignore fall damage if instructed to do so by input /*if ( ( info.GetDamageType() & DMG_FALL ) && m_flTimeIgnoreFallDamage > gpGlobals->curtime ) { // usually, we will reset the input flag after the first impact. However there is another input that // prevents this behavior. if ( m_bIgnoreFallDamageResetAfterImpact ) { m_flTimeIgnoreFallDamage = 0; } return 0; }*/ if (cvar->FindVar("oc_player_nofalldamage")->GetInt() == 1) // L1ght 15 : Let's do this Portal style ;D { if (info.GetDamageType() & DMG_FALL) { return 0; } } else { // ignore fall damage if instructed to do so by input if ((info.GetDamageType() & DMG_FALL) && m_flTimeIgnoreFallDamage > gpGlobals->curtime) { // usually, we will reset the input flag after the first impact. However there is another input that // prevents this behavior. if (m_bIgnoreFallDamageResetAfterImpact) { m_flTimeIgnoreFallDamage = 0; } return 0; } } if( info.GetDamageType() & DMG_BLAST_SURFACE ) { if( GetWaterLevel() > 2 ) { // Don't take blast damage from anything above the surface. if (info.GetInflictor() && info.GetInflictor()->GetWaterLevel() == 0) { return 0; } } } if ( info.GetDamage() > 0.0f ) { m_flLastDamageTime = gpGlobals->curtime; if ( info.GetAttacker() ) NotifyFriendsOfDamage( info.GetAttacker() ); } // Modify the amount of damage the player takes, based on skill. CTakeDamageInfo playerDamage = info; // Should we run this damage through the skill level adjustment? bool bAdjustForSkillLevel = true; if (info.GetDamageType() == DMG_GENERIC && info.GetAttacker() && info.GetInflictor() && info.GetAttacker() == this && info.GetInflictor() == this) { // Only do a skill level adjustment if the player isn't his own attacker AND inflictor. // This prevents damage from SetHealth() inputs from being adjusted for skill level. bAdjustForSkillLevel = false; } if ( GetVehicleEntity() != NULL && GlobalEntity_GetState("gordon_protect_driver") == GLOBAL_ON ) { if( playerDamage.GetDamage() > test_massive_dmg.GetFloat() && playerDamage.GetInflictor() == GetVehicleEntity() && (playerDamage.GetDamageType() & DMG_CRUSH) ) { playerDamage.ScaleDamage( test_massive_dmg_clip.GetFloat() / playerDamage.GetDamage() ); } } if( bAdjustForSkillLevel ) { playerDamage.AdjustPlayerDamageTakenForSkillLevel(); } gamestats->Event_PlayerDamage( this, info ); return BaseClass::OnTakeDamage( playerDamage ); } //----------------------------------------------------------------------------- // Purpose: // Input : &info - //----------------------------------------------------------------------------- int CHL2_Player::OnTakeDamage_Alive( const CTakeDamageInfo &info ) { // Drown if( info.GetDamageType() & DMG_DROWN ) { if( m_idrowndmg == m_idrownrestored ) { EmitSound( "Player.DrownStart" ); } else { EmitSound( "Player.DrownContinue" ); } } // Burnt if ( info.GetDamageType() & DMG_BURN ) { EmitSound( "HL2Player.BurnPain" ); } if( (info.GetDamageType() & DMG_SLASH) && hl2_episodic.GetBool() ) { if( m_afPhysicsFlags & PFLAG_USING ) { // Stop the player using a rotating button for a short time if hit by a creature's melee attack. // This is for the antlion burrow-corking training in EP1 (sjb). SuspendUse( 0.5f ); } } // Call the base class implementation return BaseClass::OnTakeDamage_Alive( info ); } //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- void CHL2_Player::OnDamagedByExplosion( const CTakeDamageInfo &info ) { if ( info.GetInflictor() && info.GetInflictor()->ClassMatches( "mortarshell" ) ) { // No ear ringing for mortar UTIL_ScreenShake( info.GetInflictor()->GetAbsOrigin(), 4.0, 1.0, 0.5, 1000, SHAKE_START, false ); return; } BaseClass::OnDamagedByExplosion( info ); } //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- bool CHL2_Player::ShouldShootMissTarget( CBaseCombatCharacter *pAttacker ) { if( gpGlobals->curtime > m_flTargetFindTime ) { // Put this off into the future again. m_flTargetFindTime = gpGlobals->curtime + random->RandomFloat( 3, 5 ); return true; } return false; } //----------------------------------------------------------------------------- // Purpose: Notifies Alyx that player has put a combine ball into a socket so she can comment on it. // Input : pCombineBall - ball the was socketed //----------------------------------------------------------------------------- void CHL2_Player::CombineBallSocketed( CPropCombineBall *pCombineBall ) { #ifdef HL2_EPISODIC CNPC_Alyx *pAlyx = CNPC_Alyx::GetAlyx(); if ( pAlyx ) { pAlyx->CombineBallSocketed( pCombineBall->NumBounces() ); } #endif } //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- void CHL2_Player::Event_KilledOther( CBaseEntity *pVictim, const CTakeDamageInfo &info ) { BaseClass::Event_KilledOther( pVictim, info ); #ifdef HL2_EPISODIC CAI_BaseNPC **ppAIs = g_AI_Manager.AccessAIs(); for ( int i = 0; i < g_AI_Manager.NumAIs(); i++ ) { if ( ppAIs[i] && ppAIs[i]->IRelationType(this) == D_LI ) { ppAIs[i]->OnPlayerKilledOther( pVictim, info ); } } #endif } //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- void CHL2_Player::Event_Killed( const CTakeDamageInfo &info ) { BaseClass::Event_Killed( info ); if (cvar->FindVar("oc_player_draw_body")->GetInt()) { SetHandsVisible(true); SetRightLegVisible(true); } if (cvar->FindVar("oc_player_death_sound")->GetInt() == 1) // BriJee OVR : Play death music { EmitSound(cvar->FindVar("oc_player_death_sound_name")->GetString()); } if (Kicking) { CBaseViewModel *vm = GetViewModel(1); if (vm) { Kicking = false; Kicked = Kicking; m_flKickEventAnimTime = 0.0f; vm->SetWeaponModel(NULL, NULL); UTIL_RemoveImmediate(vm); } } FirePlayerProxyOutput( "PlayerDied", variant_t(), this, this ); NotifyScriptsOfDeath(); } //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- void CHL2_Player::NotifyScriptsOfDeath( void ) { CBaseEntity *pEnt = gEntList.FindEntityByClassname( NULL, "scripted_sequence" ); while( pEnt ) { variant_t emptyVariant; pEnt->AcceptInput( "ScriptPlayerDeath", NULL, NULL, emptyVariant, 0 ); pEnt = gEntList.FindEntityByClassname( pEnt, "scripted_sequence" ); } pEnt = gEntList.FindEntityByClassname( NULL, "logic_choreographed_scene" ); while( pEnt ) { variant_t emptyVariant; pEnt->AcceptInput( "ScriptPlayerDeath", NULL, NULL, emptyVariant, 0 ); pEnt = gEntList.FindEntityByClassname( pEnt, "logic_choreographed_scene" ); } } //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- void CHL2_Player::GetAutoaimVector( autoaim_params_t ¶ms ) { BaseClass::GetAutoaimVector( params ); if ( IsX360() ) { if( IsInAVehicle() ) { if( m_hLockedAutoAimEntity && m_hLockedAutoAimEntity->IsAlive() && ShouldKeepLockedAutoaimTarget(m_hLockedAutoAimEntity) ) { if( params.m_hAutoAimEntity && params.m_hAutoAimEntity != m_hLockedAutoAimEntity ) { // Autoaim has picked a new target. Switch. m_hLockedAutoAimEntity = params.m_hAutoAimEntity; } // Ignore autoaim and just keep aiming at this target. params.m_hAutoAimEntity = m_hLockedAutoAimEntity; Vector vecTarget = m_hLockedAutoAimEntity->BodyTarget( EyePosition(), false ); Vector vecDir = vecTarget - EyePosition(); VectorNormalize( vecDir ); params.m_vecAutoAimDir = vecDir; params.m_vecAutoAimPoint = vecTarget; return; } else { m_hLockedAutoAimEntity = NULL; } } // If the player manually gets his crosshair onto a target, make that target sticky if( params.m_fScale != AUTOAIM_SCALE_DIRECT_ONLY ) { // Only affect this for 'real' queries //if( params.m_hAutoAimEntity && params.m_bOnTargetNatural ) if( params.m_hAutoAimEntity ) { // Turn on sticky. m_HL2Local.m_bStickyAutoAim = true; if( IsInAVehicle() ) { m_hLockedAutoAimEntity = params.m_hAutoAimEntity; } } else if( !params.m_hAutoAimEntity ) { // Turn off sticky only if there's no target at all. m_HL2Local.m_bStickyAutoAim = false; m_hLockedAutoAimEntity = NULL; } } } } //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- bool CHL2_Player::ShouldKeepLockedAutoaimTarget( EHANDLE hLockedTarget ) { Vector vecLooking; Vector vecToTarget; vecToTarget = hLockedTarget->WorldSpaceCenter() - EyePosition(); float flDist = vecToTarget.Length2D(); VectorNormalize( vecToTarget ); if( flDist > autoaim_max_dist.GetFloat() ) return false; float flDot; vecLooking = EyeDirection3D(); flDot = DotProduct( vecLooking, vecToTarget ); if( flDot < autoaim_unlock_target.GetFloat() ) return false; return true; } //----------------------------------------------------------------------------- // Purpose: // Input : iCount - // iAmmoIndex - // bSuppressSound - // Output : int //----------------------------------------------------------------------------- int CHL2_Player::GiveAmmo( int nCount, int nAmmoIndex, bool bSuppressSound) { // Don't try to give the player invalid ammo indices. if (nAmmoIndex < 0) return 0; bool bCheckAutoSwitch = false; if (!HasAnyAmmoOfType(nAmmoIndex)) { bCheckAutoSwitch = true; } int nAdd = BaseClass::GiveAmmo(nCount, nAmmoIndex, bSuppressSound); if ( nCount > 0 && nAdd == 0 ) { // we've been denied the pickup, display a hud icon to show that CSingleUserRecipientFilter user( this ); user.MakeReliable(); UserMessageBegin( user, "AmmoDenied" ); WRITE_SHORT( nAmmoIndex ); MessageEnd(); } // // If I was dry on ammo for my best weapon and justed picked up ammo for it, // autoswitch to my best weapon now. // if (bCheckAutoSwitch) { CBaseCombatWeapon *pWeapon = g_pGameRules->GetNextBestWeapon(this, GetActiveWeapon()); if ( pWeapon && pWeapon->GetPrimaryAmmoType() == nAmmoIndex ) { SwitchToNextBestWeapon(GetActiveWeapon()); } } return nAdd; } //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- bool CHL2_Player::Weapon_CanUse( CBaseCombatWeapon *pWeapon ) { if (cvar->FindVar("oc_allow_pick_stunbaton")->GetInt() == 0 || HasNamedPlayerItem("weapon_stunbaton")) // BriJee OVR: Allow to pick stunstick, next turn into battery {// обратная логика функции #ifndef HL2MP if ( pWeapon->ClassMatches( "weapon_stunstick" ) ) { if ( ApplyBattery( 0.5 ) ) UTIL_Remove( pWeapon ); return false; } #endif } else if (cvar->FindVar("oc_allow_pick_stunbaton")->GetInt() == 1 && !HasNamedPlayerItem("weapon_stunbaton")) { if (pWeapon->ClassMatches("weapon_stunstick")) { GiveNamedItem("weapon_stunbaton"); UTIL_Remove(pWeapon); return false; } } else if (cvar->FindVar("oc_allow_pick_stunbaton")->GetInt() == 1 && HasNamedPlayerItem("weapon_stunbaton")) { if (pWeapon->ClassMatches("weapon_stunstick")) { ApplyBattery(0.5); UTIL_Remove(pWeapon); return false; } } if (cvar->FindVar("oc_allow_pick_dual_pistols")->GetInt() == 1) // BriJee OVR: Allow to pick double pistols //MideD: Very bad thing... { if (pWeapon->ClassMatches("weapon_pistol") && HasNamedPlayerItem("weapon_pistol") && !HasNamedPlayerItem("weapon_dual_pistols") ) //&& (pWeapon->GetDefaultClip1() - pWeapon->GetMaxClip1() >= pWeapon->GetPrimaryAmmoCount())) { int clip1 = pWeapon->Clip1(); int clip2 = pWeapon->Clip2(); int PrimaryAmmoCount = pWeapon->GetPrimaryAmmoCount(); int SecondaryAmmoCount = pWeapon->GetSecondaryAmmoCount(); UTIL_Remove(pWeapon); GiveNamedItem("weapon_dual_pistols"); CBaseCombatWeapon *pDPistols = GetWeapon("weapon_dual_pistols"); if (pDPistols) { CBaseCombatWeapon *pPistol = GetWeapon("weapon_pistol"); if (pPistol) { pDPistols->m_iClip1 = Clamp(clip1 /*+ clip1-1*/, 0, pDPistols->GetDefaultClip1()); pDPistols->m_iClip2 = Clamp(pPistol->Clip2() + clip2, 0, pDPistols->GetDefaultClip2()); pDPistols->SetPrimaryAmmoCount(PrimaryAmmoCount); pDPistols->SetSecondaryAmmoCount(SecondaryAmmoCount); } } } /*else if (pWeapon->ClassMatches("weapon_pistol") && (HasNamedPlayerItem("weapon_pistol") || HasNamedPlayerItem("weapon_dual_pistols")) && (pWeapon->GetDefaultClip1() - pWeapon->GetMaxClip1() >= pWeapon->GetPrimaryAmmoCount())) { UTIL_Remove(pWeapon); GiveNamedItem("weapon_dual_pistols"); }*/ } return BaseClass::Weapon_CanUse( pWeapon ); } //----------------------------------------------------------------------------- // Purpose: // Input : *pWeapon - //----------------------------------------------------------------------------- void CHL2_Player::Weapon_Equip( CBaseCombatWeapon *pWeapon ) { #if HL2_SINGLE_PRIMARY_WEAPON_MODE //if (cvar->FindVar("oc_single_primary_weapon_mode")->GetInt() == 1) { if (pWeapon->GetSlot() == WEAPON_PRIMARY_SLOT) { Weapon_DropSlot(WEAPON_PRIMARY_SLOT); } } #endif if( GetActiveWeapon() == NULL ) { m_HL2Local.m_bWeaponLowered = false; } BaseClass::Weapon_Equip( pWeapon ); /*if (pWeapon->IsGrenade()) SetHandsVisible(true);*/ } //----------------------------------------------------------------------------- // Purpose: Player reacts to bumping a weapon. // Input : pWeapon - the weapon that the player bumped into. // Output : Returns true if player picked up the weapon //----------------------------------------------------------------------------- bool CHL2_Player::BumpWeapon(CBaseCombatWeapon *pWeapon) { #if HL2_SINGLE_PRIMARY_WEAPON_MODE // if (cvar->FindVar("oc_single_primary_weapon_mode")->GetInt() == 1) { CBaseCombatCharacter *pOwner = pWeapon->GetOwner(); if (pWeapon && !pWeapon->Pickable) return false; // Can I have this weapon type? if (pOwner || !Weapon_CanUse(pWeapon) || !g_pGameRules->CanHavePlayerItem(this, pWeapon)) { if (gEvilImpulse101) { UTIL_Remove(pWeapon); } return false; } // ---------------------------------------- // If I already have it just take the ammo // ---------------------------------------- if (Weapon_OwnsThisType(pWeapon->GetClassname(), pWeapon->GetSubType())) { //Only remove the weapon if we attained ammo from it if (Weapon_EquipAmmoOnly(pWeapon) == false) return false; // Only remove me if I have no ammo left // Can't just check HasAnyAmmo because if I don't use clips, I want to be removed, if (pWeapon->UsesClipsForAmmo1() && pWeapon->HasPrimaryAmmo()) return false; UTIL_Remove(pWeapon); return false; } // ------------------------- // Otherwise take the weapon // ------------------------- else { //Make sure we're not trying to take a new weapon type we already have if (Weapon_SlotOccupied(pWeapon)) { CBaseCombatWeapon *pActiveWeapon = Weapon_GetSlot(WEAPON_PRIMARY_SLOT); if (pActiveWeapon != NULL && pActiveWeapon->HasAnyAmmo() == false && Weapon_CanSwitchTo(pWeapon)) { Weapon_Equip(pWeapon); return true; } //Attempt to take ammo if this is the gun we're holding already if (Weapon_OwnsThisType(pWeapon->GetClassname(), pWeapon->GetSubType())) { Weapon_EquipAmmoOnly(pWeapon); } return false; } pWeapon->CheckRespawn(); pWeapon->AddSolidFlags(FSOLID_NOT_SOLID); pWeapon->AddEffects(EF_NODRAW); Weapon_Equip(pWeapon); EmitSound("HL2Player.PickupWeapon"); return true; } } //else { #else //BaseClass::AddGrenadeToSlot(pWeapon); if (cvar->FindVar("oc_player_allow_fast_gren_throw")->GetInt()) UpdateGrenadeInfo(); /*for (int i = 0; i < m_hMyWeapons.Count(); i++) { if (m_hMyWeapons[i].Get()->GetWpnData().iSlot == pWeapon->GetWpnData().iSlot) { if (m_hMyWeapons[i].Get()->GetWpnData().iPosition == pWeapon->GetWpnData().iPosition) { if (m_hMyWeapons[i].Get()->GetWpnData().m_bReservedSlot) return false; } } }*/ return BaseClass::BumpWeapon(pWeapon); //} #endif } //----------------------------------------------------------------------------- // Purpose: // Input : *cmd - // Output : Returns true on success, false on failure. //----------------------------------------------------------------------------- bool CHL2_Player::ClientCommand( const CCommand &args ) { #if HL2_SINGLE_PRIMARY_WEAPON_MODE //if (cvar->FindVar("oc_single_primary_weapon_mode")->GetInt() == 1) { //Drop primary weapon if (!Q_stricmp(args[0], "DropPrimary")) { Weapon_DropSlot(WEAPON_PRIMARY_SLOT); return true; } } #endif if ( !Q_stricmp( args[0], "emit" ) ) { CSingleUserRecipientFilter filter( this ); if ( args.ArgC() > 1 ) { EmitSound( filter, entindex(), args[ 1 ] ); } else { EmitSound( filter, entindex(), "Test.Sound" ); } return true; } return BaseClass::ClientCommand( args ); } //----------------------------------------------------------------------------- // Purpose: // Output : void CBasePlayer::PlayerUse //----------------------------------------------------------------------------- void CHL2_Player::PlayerUse ( void ) { // Was use pressed or released? if ( ! ((m_nButtons | m_afButtonPressed | m_afButtonReleased) & IN_USE) ) return; if ( m_afButtonPressed & IN_USE ) { // Currently using a latched entity? if ( ClearUseEntity() ) { return; } else { if ( m_afPhysicsFlags & PFLAG_DIROVERRIDE ) { m_afPhysicsFlags &= ~PFLAG_DIROVERRIDE; m_iTrain = TRAIN_NEW|TRAIN_OFF; return; } else { // Start controlling the train! CBaseEntity *pTrain = GetGroundEntity(); if ( pTrain && !(m_nButtons & IN_JUMP) && (GetFlags() & FL_ONGROUND) && (pTrain->ObjectCaps() & FCAP_DIRECTIONAL_USE) && pTrain->OnControls(this) ) { m_afPhysicsFlags |= PFLAG_DIROVERRIDE; m_iTrain = TrainSpeed(pTrain->m_flSpeed, ((CFuncTrackTrain*)pTrain)->GetMaxSpeed()); m_iTrain |= TRAIN_NEW; EmitSound( "HL2Player.TrainUse" ); return; } } } // Tracker 3926: We can't +USE something if we're climbing a ladder if ( GetMoveType() == MOVETYPE_LADDER ) { return; } } if( m_flTimeUseSuspended > gpGlobals->curtime ) { // Something has temporarily stopped us being able to USE things. // Obviously, this should be used very carefully.(sjb) return; } CBaseEntity *pUseEntity = FindUseEntity(); bool usedSomething = false; // Found an object if ( pUseEntity ) { //!!!UNDONE: traceline here to prevent +USEing buttons through walls int caps = pUseEntity->ObjectCaps(); variant_t emptyVariant; if ( m_afButtonPressed & IN_USE ) { // Robin: Don't play sounds for NPCs, because NPCs will allow respond with speech. if ( !pUseEntity->MyNPCPointer() ) { EmitSound( "HL2Player.Use" ); } } if ( ( (m_nButtons & IN_USE) && (caps & FCAP_CONTINUOUS_USE) ) || ( (m_afButtonPressed & IN_USE) && (caps & (FCAP_IMPULSE_USE|FCAP_ONOFF_USE)) ) ) { if ( caps & FCAP_CONTINUOUS_USE ) m_afPhysicsFlags |= PFLAG_USING; pUseEntity->AcceptInput( "Use", this, this, emptyVariant, USE_TOGGLE ); usedSomething = true; } // UNDONE: Send different USE codes for ON/OFF. Cache last ONOFF_USE object to send 'off' if you turn away else if ( (m_afButtonReleased & IN_USE) && (pUseEntity->ObjectCaps() & FCAP_ONOFF_USE) ) // BUGBUG This is an "off" use { pUseEntity->AcceptInput( "Use", this, this, emptyVariant, USE_TOGGLE ); usedSomething = true; } //#if HL2_SINGLE_PRIMARY_WEAPON_MODE #if HL2_SINGLE_PRIMARY_WEAPON_MODE //if (cvar->FindVar("oc_single_primary_weapon_mode")->GetInt() == 1) { //Check for weapon pick-up if (m_afButtonPressed & IN_USE) { CBaseCombatWeapon *pWeapon = dynamic_cast(pUseEntity); if ((pWeapon != NULL) && (Weapon_CanSwitchTo(pWeapon))) { //Try to take ammo or swap the weapon if (Weapon_OwnsThisType(pWeapon->GetClassname(), pWeapon->GetSubType())) { Weapon_EquipAmmoOnly(pWeapon); } else { Weapon_DropSlot(pWeapon->GetSlot()); Weapon_Equip(pWeapon); } pWeapon->Deploy(); // BriJee OVR: Added. This will prevent 'empty hands' on few guns with long animations. usedSomething = true; } } } #endif } else if ( m_afButtonPressed & IN_USE ) { // Signal that we want to play the deny sound, unless the user is +USEing on a ladder! // The sound is emitted in ItemPostFrame, since that occurs after GameMovement::ProcessMove which // lets the ladder code unset this flag. m_bPlayUseDenySound = true; } // Debounce the use key if ( usedSomething && pUseEntity ) { m_Local.m_nOldButtons |= IN_USE; m_afButtonPressed &= ~IN_USE; } } ConVar sv_show_crosshair_target( "sv_show_crosshair_target", "0" ); //----------------------------------------------------------------------------- // Purpose: Updates the posture of the weapon from lowered to ready //----------------------------------------------------------------------------- void CHL2_Player::UpdateWeaponPosture( void ) { CBaseCombatWeapon *pWeapon = dynamic_cast(GetActiveWeapon()); if ( pWeapon && m_LowerWeaponTimer.Expired() && pWeapon->CanLower() ) { m_LowerWeaponTimer.Set( .3 ); VPROF( "CHL2_Player::UpdateWeaponPosture-CheckLower" ); // BriJee OVR: Simple weapon lower on sprint /*if (cvar->FindVar("oc_weapons_allow_sprint_lower")->GetInt() == 1) { if (m_fIsSprinting) { Weapon_Lower(); return; } }*///===end Vector vecAim = BaseClass::GetAutoaimVector( AUTOAIM_SCALE_DIRECT_ONLY ); const float CHECK_FRIENDLY_RANGE = 50 * 12; trace_t tr; UTIL_TraceLine( EyePosition(), EyePosition() + vecAim * CHECK_FRIENDLY_RANGE, MASK_SHOT, this, COLLISION_GROUP_NONE, &tr ); CBaseEntity *aimTarget = tr.m_pEnt; //If we're over something if ( aimTarget && !tr.DidHitWorld() ) { if ( !aimTarget->IsNPC() || aimTarget->MyNPCPointer()->GetState() != NPC_STATE_COMBAT ) { Disposition_t dis = IRelationType( aimTarget ); //Debug info for seeing what an object "cons" as if ( sv_show_crosshair_target.GetBool() ) { int text_offset = BaseClass::DrawDebugTextOverlays(); char tempstr[255]; switch ( dis ) { case D_LI: Q_snprintf( tempstr, sizeof(tempstr), "Disposition: Like" ); break; case D_HT: Q_snprintf( tempstr, sizeof(tempstr), "Disposition: Hate" ); break; case D_FR: Q_snprintf( tempstr, sizeof(tempstr), "Disposition: Fear" ); break; case D_NU: Q_snprintf( tempstr, sizeof(tempstr), "Disposition: Neutral" ); break; default: case D_ER: Q_snprintf( tempstr, sizeof(tempstr), "Disposition: !!!ERROR!!!" ); break; } //Draw the text NDebugOverlay::EntityText( aimTarget->entindex(), text_offset, tempstr, 0 ); } //See if we hates it if ( dis == D_LI ) { //We're over a friendly, drop our weapon if ( Weapon_Lower() == false ) { //FIXME: We couldn't lower our weapon! } return; } } } if ( Weapon_Ready() == false ) { //FIXME: We couldn't raise our weapon! } } if( g_pGameRules->GetAutoAimMode() != AUTOAIM_NONE ) { if( !pWeapon ) { // This tells the client to draw no crosshair m_HL2Local.m_bWeaponLowered = true; return; } else { if( !pWeapon->CanLower() && m_HL2Local.m_bWeaponLowered ) m_HL2Local.m_bWeaponLowered = false; } if( !m_AutoaimTimer.Expired() ) return; m_AutoaimTimer.Set( .1 ); VPROF( "hl2_x360_aiming" ); // Call the autoaim code to update the local player data, which allows the client to update. autoaim_params_t params; params.m_vecAutoAimPoint.Init(); params.m_vecAutoAimDir.Init(); params.m_fScale = AUTOAIM_SCALE_DEFAULT; params.m_fMaxDist = autoaim_max_dist.GetFloat(); GetAutoaimVector( params ); m_HL2Local.m_hAutoAimTarget.Set( params.m_hAutoAimEntity ); m_HL2Local.m_vecAutoAimPoint.Set( params.m_vecAutoAimPoint ); m_HL2Local.m_bAutoAimTarget = ( params.m_bAutoAimAssisting || params.m_bOnTargetNatural ); return; } else { // Make sure there's no residual autoaim target if the user changes the xbox_aiming convar on the fly. m_HL2Local.m_hAutoAimTarget.Set(NULL); } } //----------------------------------------------------------------------------- // Purpose: Lowers the weapon posture (for hovering over friendlies) // Output : Returns true on success, false on failure. //----------------------------------------------------------------------------- bool CHL2_Player::Weapon_Lower( void ) { CBaseCombatWeapon *pWeapon = dynamic_cast(GetActiveWeapon()); if (pWeapon == NULL) return false; if (pWeapon->IsNearWall() || pWeapon->IsScopeSighted() || pWeapon->IsIronSighted()) return false; //cvar->FindVar("oc_weapon_is_lowered")->SetValue(1); VPROF( "CHL2_Player::Weapon_Lower" ); // Already lowered? if ( m_HL2Local.m_bWeaponLowered ) return true; m_HL2Local.m_bWeaponLowered = true; return pWeapon->Lower(); } //----------------------------------------------------------------------------- // Purpose: Returns the weapon posture to normal // Output : Returns true on success, false on failure. //----------------------------------------------------------------------------- bool CHL2_Player::Weapon_Ready( void ) { VPROF( "CHL2_Player::Weapon_Ready" ); // Already ready? if ( m_HL2Local.m_bWeaponLowered == false ) return true; m_HL2Local.m_bWeaponLowered = false; CBaseCombatWeapon *pWeapon = dynamic_cast(GetActiveWeapon()); if ( pWeapon == NULL ) return false; return pWeapon->Ready(); } //----------------------------------------------------------------------------- // Purpose: Returns whether or not we can switch to the given weapon. // Input : pWeapon - //----------------------------------------------------------------------------- bool CHL2_Player::Weapon_CanSwitchTo( CBaseCombatWeapon *pWeapon ) { CBasePlayer *pPlayer = (CBasePlayer *)this; #if !defined( CLIENT_DLL ) IServerVehicle *pVehicle = pPlayer->GetVehicle(); #else IClientVehicle *pVehicle = pPlayer->GetVehicle(); #endif if (pVehicle && !pPlayer->UsingStandardWeaponsInVehicle()) return false; #if !defined( CLIENT_DLL ) if (cvar->FindVar("oc_player_allow_fast_gren_throw")->GetInt()) { if (pPlayer && pWeapon && pPlayer->grenadeState <= 0 && pWeapon->thisType == TYPE_GRENADE) return false; } #endif /*if (cvar->FindVar("oc_weapon_disable_autoswitch")->GetInt() == 1) { // BriJee OVR: Nothing } else*/ { if (!pWeapon->HasAnyAmmo() && !GetAmmoCount(pWeapon->m_iPrimaryAmmoType)) return false; } if ( !pWeapon->CanDeploy() ) return false; if ( GetActiveWeapon() ) { if ( PhysCannonGetHeldEntity( GetActiveWeapon() ) == pWeapon && Weapon_OwnsThisType( pWeapon->GetClassname(), pWeapon->GetSubType()) ) { return true; } if ( !GetActiveWeapon()->CanHolster() ) return false; } return true; } void CHL2_Player::PickupObject( CBaseEntity *pObject, bool bLimitMassAndSize ) { // can't pick up what you're standing on if ( GetGroundEntity() == pObject ) return; if ( bLimitMassAndSize == true ) { if ( CBasePlayer::CanPickupObject( pObject, 35, 128 ) == false ) return; } // Can't be picked up if NPCs are on me if ( pObject->HasNPCsOnIt() ) return; PlayerPickupObject( this, pObject ); } //----------------------------------------------------------------------------- // Purpose: // Output : CBaseEntity //----------------------------------------------------------------------------- bool CHL2_Player::IsHoldingEntity( CBaseEntity *pEnt ) { return PlayerPickupControllerIsHoldingEntity( m_hUseEntity, pEnt ); } float CHL2_Player::GetHeldObjectMass( IPhysicsObject *pHeldObject ) { float mass = PlayerPickupGetHeldObjectMass( m_hUseEntity, pHeldObject ); if ( mass == 0.0f ) { mass = PhysCannonGetHeldObjectMass( GetActiveWeapon(), pHeldObject ); } return mass; } //----------------------------------------------------------------------------- // Purpose: Force the player to drop any physics objects he's carrying //----------------------------------------------------------------------------- void CHL2_Player::ForceDropOfCarriedPhysObjects( CBaseEntity *pOnlyIfHoldingThis ) { if ( PhysIsInCallback() ) { variant_t value; g_EventQueue.AddEvent( this, "ForceDropPhysObjects", value, 0.01f, pOnlyIfHoldingThis, this ); return; } #ifdef HL2_EPISODIC if ( hl2_episodic.GetBool() ) { CBaseEntity *pHeldEntity = PhysCannonGetHeldEntity( GetActiveWeapon() ); if( pHeldEntity && pHeldEntity->ClassMatches( "grenade_helicopter" ) ) { return; } } #endif // Drop any objects being handheld. ClearUseEntity(); // Then force the physcannon to drop anything it's holding, if it's our active weapon PhysCannonForceDrop( GetActiveWeapon(), NULL ); } void CHL2_Player::InputForceDropPhysObjects( inputdata_t &data ) { ForceDropOfCarriedPhysObjects( data.pActivator ); } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void CHL2_Player::UpdateClientData( void ) { if (m_DmgTake || m_DmgSave || m_bitsHUDDamage != m_bitsDamageType) { // Comes from inside me if not set Vector damageOrigin = GetLocalOrigin(); // send "damage" message // causes screen to flash, and pain compass to show direction of damage damageOrigin = m_DmgOrigin; // only send down damage type that have hud art int iShowHudDamage = g_pGameRules->Damage_GetShowOnHud(); int visibleDamageBits = m_bitsDamageType & iShowHudDamage; m_DmgTake = clamp( m_DmgTake, 0, 255 ); m_DmgSave = clamp( m_DmgSave, 0, 255 ); // If we're poisoned, but it wasn't this frame, don't send the indicator // Without this check, any damage that occured to the player while they were // recovering from a poison bite would register as poisonous as well and flash // the whole screen! -- jdw if ( visibleDamageBits & DMG_POISON ) { float flLastPoisonedDelta = gpGlobals->curtime - m_tbdPrev; if ( flLastPoisonedDelta > 0.1f ) { visibleDamageBits &= ~DMG_POISON; } } CSingleUserRecipientFilter user( this ); user.MakeReliable(); UserMessageBegin( user, "Damage" ); WRITE_BYTE( m_DmgSave ); WRITE_BYTE( m_DmgTake ); WRITE_LONG( visibleDamageBits ); WRITE_FLOAT( damageOrigin.x ); //BUG: Should be fixed point (to hud) not floats WRITE_FLOAT( damageOrigin.y ); //BUG: However, the HUD does _not_ implement bitfield messages (yet) WRITE_FLOAT( damageOrigin.z ); //BUG: We use WRITE_VEC3COORD for everything else MessageEnd(); m_DmgTake = 0; m_DmgSave = 0; m_bitsHUDDamage = m_bitsDamageType; // Clear off non-time-based damage indicators int iTimeBasedDamage = g_pGameRules->Damage_GetTimeBased(); m_bitsDamageType &= iTimeBasedDamage; } // Update Flashlight //#ifdef HL2_EPISODIC if ( Flashlight_UseLegacyVersion() == false ) { if ( FlashlightIsOn() && sv_infinite_aux_power.GetBool() == false ) { m_HL2Local.m_flFlashBattery -= FLASH_DRAIN_TIME * gpGlobals->frametime; if ( m_HL2Local.m_flFlashBattery < 0.0f ) { FlashlightTurnOff(); m_HL2Local.m_flFlashBattery = 0.0f; } } else { m_HL2Local.m_flFlashBattery += FLASH_CHARGE_TIME * gpGlobals->frametime; if ( m_HL2Local.m_flFlashBattery > 100.0f ) { m_HL2Local.m_flFlashBattery = 100.0f; } } } else { m_HL2Local.m_flFlashBattery = -1.0f; } //#endif // HL2_EPISODIC BaseClass::UpdateClientData(); } //--------------------------------------------------------- //--------------------------------------------------------- void CHL2_Player::OnRestore() { BaseClass::OnRestore(); m_pPlayerAISquad = g_AI_SquadManager.FindCreateSquad(AllocPooledString(PLAYER_SQUADNAME)); } //--------------------------------------------------------- //--------------------------------------------------------- Vector CHL2_Player::EyeDirection2D( void ) { Vector vecReturn = EyeDirection3D(); vecReturn.z = 0; vecReturn.AsVector2D().NormalizeInPlace(); return vecReturn; } //--------------------------------------------------------- //--------------------------------------------------------- Vector CHL2_Player::EyeDirection3D( void ) { Vector vecForward; // Return the vehicle angles if we request them if ( GetVehicle() != NULL ) { CacheVehicleView(); EyeVectors( &vecForward ); return vecForward; } AngleVectors( EyeAngles(), &vecForward ); return vecForward; } //--------------------------------------------------------- //--------------------------------------------------------- bool CHL2_Player::Weapon_Switch( CBaseCombatWeapon *pWeapon, int viewmodelindex ) { MDLCACHE_CRITICAL_SECTION(); // Recalculate proficiency! SetCurrentWeaponProficiency( CalcWeaponProficiency( pWeapon ) ); // Come out of suit zoom mode if ( IsZooming() ) { StopZooming(); } return BaseClass::Weapon_Switch( pWeapon, viewmodelindex ); } //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- WeaponProficiency_t CHL2_Player::CalcWeaponProficiency( CBaseCombatWeapon *pWeapon ) { WeaponProficiency_t proficiency; proficiency = WEAPON_PROFICIENCY_PERFECT; if( weapon_showproficiency.GetBool() != 0 ) { Msg("Player switched to %s, proficiency is %s\n", pWeapon->GetClassname(), GetWeaponProficiencyName( proficiency ) ); } return proficiency; } //----------------------------------------------------------------------------- // Purpose: override how single player rays hit the player //----------------------------------------------------------------------------- bool LineCircleIntersection( const Vector2D ¢er, const float radius, const Vector2D &vLinePt, const Vector2D &vLineDir, float *fIntersection1, float *fIntersection2) { // Line = P + Vt // Sphere = r (assume we've translated to origin) // (P + Vt)^2 = r^2 // VVt^2 + 2PVt + (PP - r^2) // Solve as quadratic: (-b +/- sqrt(b^2 - 4ac)) / 2a // If (b^2 - 4ac) is < 0 there is no solution. // If (b^2 - 4ac) is = 0 there is one solution (a case this function doesn't support). // If (b^2 - 4ac) is > 0 there are two solutions. Vector2D P; float a, b, c, sqr, insideSqr; // Translate circle to origin. P[0] = vLinePt[0] - center[0]; P[1] = vLinePt[1] - center[1]; a = vLineDir.Dot(vLineDir); b = 2.0f * P.Dot(vLineDir); c = P.Dot(P) - (radius * radius); insideSqr = b*b - 4*a*c; if(insideSqr <= 0.000001f) return false; // Ok, two solutions. sqr = (float)FastSqrt(insideSqr); float denom = 1.0 / (2.0f * a); *fIntersection1 = (-b - sqr) * denom; *fIntersection2 = (-b + sqr) * denom; return true; } static void Collision_ClearTrace( const Vector &vecRayStart, const Vector &vecRayDelta, CBaseTrace *pTrace ) { pTrace->startpos = vecRayStart; pTrace->endpos = vecRayStart; pTrace->endpos += vecRayDelta; pTrace->startsolid = false; pTrace->allsolid = false; pTrace->fraction = 1.0f; pTrace->contents = 0; } bool IntersectRayWithAACylinder( const Ray_t &ray, const Vector ¢er, float radius, float height, CBaseTrace *pTrace ) { Assert( ray.m_IsRay ); Collision_ClearTrace( ray.m_Start, ray.m_Delta, pTrace ); // First intersect the ray with the top + bottom planes float halfHeight = height * 0.5; // Handle parallel case Vector vStart = ray.m_Start - center; Vector vEnd = vStart + ray.m_Delta; float flEnterFrac, flLeaveFrac; if (FloatMakePositive(ray.m_Delta.z) < 1e-8) { if ( (vStart.z < -halfHeight) || (vStart.z > halfHeight) ) { return false; // no hit } flEnterFrac = 0.0f; flLeaveFrac = 1.0f; } else { // Clip the ray to the top and bottom of box flEnterFrac = IntersectRayWithAAPlane( vStart, vEnd, 2, 1, halfHeight); flLeaveFrac = IntersectRayWithAAPlane( vStart, vEnd, 2, 1, -halfHeight); if ( flLeaveFrac < flEnterFrac ) { float temp = flLeaveFrac; flLeaveFrac = flEnterFrac; flEnterFrac = temp; } if ( flLeaveFrac < 0 || flEnterFrac > 1) { return false; } } // Intersect with circle float flCircleEnterFrac, flCircleLeaveFrac; if ( !LineCircleIntersection( vec3_origin.AsVector2D(), radius, vStart.AsVector2D(), ray.m_Delta.AsVector2D(), &flCircleEnterFrac, &flCircleLeaveFrac ) ) { return false; // no hit } Assert( flCircleEnterFrac <= flCircleLeaveFrac ); if ( flCircleLeaveFrac < 0 || flCircleEnterFrac > 1) { return false; } if ( flEnterFrac < flCircleEnterFrac ) flEnterFrac = flCircleEnterFrac; if ( flLeaveFrac > flCircleLeaveFrac ) flLeaveFrac = flCircleLeaveFrac; if ( flLeaveFrac < flEnterFrac ) return false; VectorMA( ray.m_Start, flEnterFrac , ray.m_Delta, pTrace->endpos ); pTrace->fraction = flEnterFrac; pTrace->contents = CONTENTS_SOLID; // Calculate the point on our center line where we're nearest the intersection point Vector collisionCenter; CalcClosestPointOnLineSegment( pTrace->endpos, center + Vector( 0, 0, halfHeight ), center - Vector( 0, 0, halfHeight ), collisionCenter ); // Our normal is the direction from that center point to the intersection point pTrace->plane.normal = pTrace->endpos - collisionCenter; VectorNormalize( pTrace->plane.normal ); return true; } bool CHL2_Player::TestHitboxes( const Ray_t &ray, unsigned int fContentsMask, trace_t& tr ) { if( g_pGameRules->IsMultiplayer() ) { return BaseClass::TestHitboxes( ray, fContentsMask, tr ); } else { Assert( ray.m_IsRay ); Vector mins, maxs; mins = WorldAlignMins(); maxs = WorldAlignMaxs(); if ( IntersectRayWithAACylinder( ray, WorldSpaceCenter(), maxs.x * PLAYER_HULL_REDUCTION, maxs.z - mins.z, &tr ) ) { tr.hitbox = 0; CStudioHdr *pStudioHdr = GetModelPtr( ); if (!pStudioHdr) return false; mstudiohitboxset_t *set = pStudioHdr->pHitboxSet( m_nHitboxSet ); if ( !set || !set->numhitboxes ) return false; mstudiobbox_t *pbox = set->pHitbox( tr.hitbox ); mstudiobone_t *pBone = pStudioHdr->pBone(pbox->bone); tr.surface.name = "**studio**"; tr.surface.flags = SURF_HITBOX; tr.surface.surfaceProps = physprops->GetSurfaceIndex( pBone->pszSurfaceProp() ); } return true; } } //--------------------------------------------------------- // Show the player's scaled down bbox that we use for // bullet impacts. //--------------------------------------------------------- void CHL2_Player::DrawDebugGeometryOverlays(void) { BaseClass::DrawDebugGeometryOverlays(); if (m_debugOverlays & OVERLAY_BBOX_BIT) { Vector mins, maxs; mins = WorldAlignMins(); maxs = WorldAlignMaxs(); mins.x *= PLAYER_HULL_REDUCTION; mins.y *= PLAYER_HULL_REDUCTION; maxs.x *= PLAYER_HULL_REDUCTION; maxs.y *= PLAYER_HULL_REDUCTION; NDebugOverlay::Box( GetAbsOrigin(), mins, maxs, 255, 0, 0, 100, 0 ); } } //----------------------------------------------------------------------------- // Purpose: Helper to remove from ladder //----------------------------------------------------------------------------- void CHL2_Player::ExitLadder() { if ( MOVETYPE_LADDER != GetMoveType() ) return; SetMoveType( MOVETYPE_WALK ); SetMoveCollide( MOVECOLLIDE_DEFAULT ); // Remove from ladder m_HL2Local.m_hLadder.Set( NULL ); } surfacedata_t *CHL2_Player::GetLadderSurface( const Vector &origin ) { extern const char *FuncLadder_GetSurfaceprops(CBaseEntity *pLadderEntity); CBaseEntity *pLadder = m_HL2Local.m_hLadder.Get(); if ( pLadder ) { const char *pSurfaceprops = FuncLadder_GetSurfaceprops(pLadder); // get ladder material from func_ladder return physprops->GetSurfaceData( physprops->GetSurfaceIndex( pSurfaceprops ) ); } return BaseClass::GetLadderSurface(origin); } //----------------------------------------------------------------------------- // Purpose: Queues up a use deny sound, played in ItemPostFrame. //----------------------------------------------------------------------------- void CHL2_Player::PlayUseDenySound() { m_bPlayUseDenySound = true; } void CHL2_Player::ItemPostFrame() { BaseClass::ItemPostFrame(); if ( m_bPlayUseDenySound ) { m_bPlayUseDenySound = false; EmitSound( "HL2Player.UseDeny" ); } //if (GetActiveWeapon() /*&& !GetActiveWeapon()->IsHolstered()*/)// ? GetActiveWeapon()->thisType != TYPE_GRENADE : true) /*{ CBaseAnimating *pAnimating = this->GetBaseAnimating(); if (pAnimating) { /*if (m_hUseEntity) DevMsg("In using\n");*/ //bool weapVisible = GetActiveWeapon() != NULL ? !(GetActiveWeapon()->IsWeaponVisible()) : false; /*bool weapVisible = GetActiveWeapon() == NULL ? true : false; if (IsSuitEquipped()) { if (m_hUseEntity != NULL) { if (!pAnimating->GetBodygroup(bg_rh) || !pAnimating->GetBodygroup(bg_lh))//0 - visible SetHandsVisible(false); } else { if (pAnimating->GetBodygroup(bg_rh) || pAnimating->GetBodygroup(bg_lh))//1 - invisible SetHandsVisible(weapVisible); } } else { if (m_hUseEntity != NULL) { if (!pAnimating->GetBodygroup(bg_rh) || !pAnimating->GetBodygroup(bg_lh))//0 - visible SetHandsVisible(false); } else { if (pAnimating->GetBodygroup(bg_rh) || pAnimating->GetBodygroup(bg_lh))//1 - invisible SetHandsVisible(weapVisible); } } } }*/ /*else { CBaseAnimating *pAnimating = this->GetBaseAnimating(); if (pAnimating && gpGlobals->curtime > m_flAdmireGlovesAnimTime) { if (IsSuitEquipped()) { if (pAnimating->GetBodygroup(bg_rh) || pAnimating->GetBodygroup(bg_lh))//0 - visible SetHandsVisible(true); } else { if (pAnimating->GetBodygroup(bg_rh) || pAnimating->GetBodygroup(bg_lh))//0 - visible SetHandsVisible(true); } } }*/ CheckLean(); // BriJee : Checking lean state } void CHL2_Player::SetBodyRenderingState(bool HEVSuit) { CBaseAnimating *pAnimating = this->GetBaseAnimating(); if (pAnimating) { if (HEVSuit) { PrecacheModel(cvar->FindVar("oc_playermodel_suit")->GetString()); SetModel(cvar->FindVar("oc_playermodel_suit")->GetString()); } else { PrecacheModel(cvar->FindVar("oc_playermodel_nosuit")->GetString()); SetModel(cvar->FindVar("oc_playermodel_nosuit")->GetString()); } } if (!cvar->FindVar("oc_player_draw_body")->GetInt()) return; if (!IsAlive()) { SetHandsVisible(true); SetRightLegVisible(true); return; } bool weapVisible = GetActiveWeapon() != NULL ? GetActiveWeapon()->IsWeaponVisible() : false; if (weapVisible) SetHandsVisible(false); else SetHandsVisible(true); SetRightLegVisible(true); } void CHL2_Player::SetRightLegVisible(bool visible) { if (!cvar->FindVar("oc_player_draw_body")->GetInt()) return; CBaseAnimating *pAnimating = this->GetBaseAnimating(); if (pAnimating) { if (visible) { bg_rl = pAnimating->FindBodygroupByName("right_leg"); bg_rl_val = 0;//Visible pAnimating->SetBodygroup(bg_rl, bg_rl_val); } else { bg_rl = pAnimating->FindBodygroupByName("right_leg"); bg_rl_val = 1;//InVisible pAnimating->SetBodygroup(bg_rl, bg_rl_val); } } } void CHL2_Player::SetHandsVisible(bool visible) { if (!cvar->FindVar("oc_player_draw_body")->GetInt()) return; CBaseAnimating *pAnimating = this->GetBaseAnimating(); if (pAnimating)// 0 - visible; 1 - InVisible { if (visible) { bg_rh = pAnimating->FindBodygroupByName("right_hand"); bg_lh = pAnimating->FindBodygroupByName("left_hand"); bg_rh_val = 0;//Visible bg_lh_val = 0;//Visible pAnimating->SetBodygroup(bg_rh, bg_rh_val);//Visible pAnimating->SetBodygroup(bg_lh, bg_lh_val);//Visible } else { bg_rh = pAnimating->FindBodygroupByName("right_hand"); bg_lh = pAnimating->FindBodygroupByName("left_hand"); bg_rh_val = 1;//InVisible bg_lh_val = 1;//InVisible pAnimating->SetBodygroup(bg_rh, bg_rh_val);//InVisible pAnimating->SetBodygroup(bg_lh, bg_lh_val);//InVisible } } } void CHL2_Player::SetAdmireGlovesVisible(bool visible) { SetHandsVisible(!visible); } void CHL2_Player::StartWaterDeathSounds( void ) { CPASAttenuationFilter filter( this ); if ( m_sndLeeches == NULL ) { m_sndLeeches = (CSoundEnvelopeController::GetController()).SoundCreate( filter, entindex(), CHAN_STATIC, "coast.leech_bites_loop" , ATTN_NORM ); } if ( m_sndLeeches ) { (CSoundEnvelopeController::GetController()).Play( m_sndLeeches, 1.0f, 100 ); } if ( m_sndWaterSplashes == NULL ) { m_sndWaterSplashes = (CSoundEnvelopeController::GetController()).SoundCreate( filter, entindex(), CHAN_STATIC, "coast.leech_water_churn_loop" , ATTN_NORM ); } if ( m_sndWaterSplashes ) { (CSoundEnvelopeController::GetController()).Play( m_sndWaterSplashes, 1.0f, 100 ); } } void CHL2_Player::StopWaterDeathSounds( void ) { if ( m_sndLeeches ) { (CSoundEnvelopeController::GetController()).SoundFadeOut( m_sndLeeches, 0.5f, true ); m_sndLeeches = NULL; } if ( m_sndWaterSplashes ) { (CSoundEnvelopeController::GetController()).SoundFadeOut( m_sndWaterSplashes, 0.5f, true ); m_sndWaterSplashes = NULL; } } //----------------------------------------------------------------------------- // //----------------------------------------------------------------------------- void CHL2_Player::MissedAR2AltFire() { if( GetPlayerProxy() != NULL ) { GetPlayerProxy()->m_PlayerMissedAR2AltFire.FireOutput( this, this ); } } //----------------------------------------------------------------------------- // //----------------------------------------------------------------------------- void CHL2_Player::DisplayLadderHudHint() { #if !defined( CLIENT_DLL ) if( gpGlobals->curtime > m_flTimeNextLadderHint ) { m_flTimeNextLadderHint = gpGlobals->curtime + 60.0f; CFmtStr hint; hint.sprintf( "#Valve_Hint_Ladder" ); UTIL_HudHintText( this, hint.Access() ); } #endif//CLIENT_DLL } //----------------------------------------------------------------------------- // Shuts down sounds //----------------------------------------------------------------------------- void CHL2_Player::StopLoopingSounds( void ) { if ( m_sndLeeches != NULL ) { (CSoundEnvelopeController::GetController()).SoundDestroy( m_sndLeeches ); m_sndLeeches = NULL; } if ( m_sndWaterSplashes != NULL ) { (CSoundEnvelopeController::GetController()).SoundDestroy( m_sndWaterSplashes ); m_sndWaterSplashes = NULL; } BaseClass::StopLoopingSounds(); } //----------------------------------------------------------------------------- void CHL2_Player::ModifyOrAppendPlayerCriteria( AI_CriteriaSet& set ) { BaseClass::ModifyOrAppendPlayerCriteria( set ); if ( GlobalEntity_GetIndex( "gordon_precriminal" ) == -1 ) { set.AppendCriteria( "gordon_precriminal", "0" ); } } //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- const impactdamagetable_t &CHL2_Player::GetPhysicsImpactDamageTable() { if ( m_bUseCappedPhysicsDamageTable ) return gCappedPlayerImpactDamageTable; return BaseClass::GetPhysicsImpactDamageTable(); } //----------------------------------------------------------------------------- // Purpose: Makes a splash when the player transitions between water states //----------------------------------------------------------------------------- void CHL2_Player::Splash( void ) { CEffectData data; data.m_fFlags = 0; data.m_vOrigin = GetAbsOrigin(); data.m_vNormal = Vector(0,0,1); data.m_vAngles = QAngle( 0, 0, 0 ); if ( GetWaterType() & CONTENTS_SLIME ) { data.m_fFlags |= FX_WATER_IN_SLIME; } float flSpeed = GetAbsVelocity().Length(); if ( flSpeed < 300 ) { data.m_flScale = random->RandomFloat( 10, 12 ); DispatchEffect( "waterripple", data ); DispatchEffect("watersplash", data); } else { data.m_flScale = random->RandomFloat( 6, 8 ); DispatchEffect( "watersplash", data ); } } CLogicPlayerProxy *CHL2_Player::GetPlayerProxy( void ) { CLogicPlayerProxy *pProxy = dynamic_cast< CLogicPlayerProxy* > ( m_hPlayerProxy.Get() ); if ( pProxy == NULL ) { pProxy = (CLogicPlayerProxy*)gEntList.FindEntityByClassname(NULL, "logic_playerproxy" ); if ( pProxy == NULL ) return NULL; pProxy->m_hPlayer = this; m_hPlayerProxy = pProxy; } return pProxy; } void CHL2_Player::FirePlayerProxyOutput( const char *pszOutputName, variant_t variant, CBaseEntity *pActivator, CBaseEntity *pCaller ) { if ( GetPlayerProxy() == NULL ) return; GetPlayerProxy()->FireNamedOutput( pszOutputName, variant, pActivator, pCaller ); } LINK_ENTITY_TO_CLASS( logic_playerproxy, CLogicPlayerProxy); BEGIN_DATADESC( CLogicPlayerProxy ) DEFINE_OUTPUT( m_OnFlashlightOn, "OnFlashlightOn" ), DEFINE_OUTPUT( m_OnFlashlightOff, "OnFlashlightOff" ), DEFINE_OUTPUT( m_RequestedPlayerHealth, "PlayerHealth" ), DEFINE_OUTPUT( m_PlayerHasAmmo, "PlayerHasAmmo" ), DEFINE_OUTPUT( m_PlayerHasNoAmmo, "PlayerHasNoAmmo" ), DEFINE_OUTPUT( m_PlayerDied, "PlayerDied" ), DEFINE_OUTPUT( m_PlayerMissedAR2AltFire, "PlayerMissedAR2AltFire" ), DEFINE_INPUTFUNC( FIELD_VOID, "RequestPlayerHealth", InputRequestPlayerHealth ), DEFINE_INPUTFUNC( FIELD_VOID, "SetFlashlightSlowDrain", InputSetFlashlightSlowDrain ), DEFINE_INPUTFUNC( FIELD_VOID, "SetFlashlightNormalDrain", InputSetFlashlightNormalDrain ), DEFINE_INPUTFUNC( FIELD_INTEGER, "SetPlayerHealth", InputSetPlayerHealth ), DEFINE_INPUTFUNC( FIELD_VOID, "RequestAmmoState", InputRequestAmmoState ), DEFINE_INPUTFUNC( FIELD_VOID, "LowerWeapon", InputLowerWeapon ), DEFINE_INPUTFUNC( FIELD_VOID, "EnableCappedPhysicsDamage", InputEnableCappedPhysicsDamage ), DEFINE_INPUTFUNC( FIELD_VOID, "DisableCappedPhysicsDamage", InputDisableCappedPhysicsDamage ), DEFINE_INPUTFUNC( FIELD_STRING, "SetLocatorTargetEntity", InputSetLocatorTargetEntity ), #ifdef PORTAL DEFINE_INPUTFUNC( FIELD_VOID, "SuppressCrosshair", InputSuppressCrosshair ), #endif // PORTAL DEFINE_FIELD( m_hPlayer, FIELD_EHANDLE ), END_DATADESC() //==============================BriJee OVR: Server side leaning void CHL2_Player::CheckLean() { if ((m_nButtons & IN_FORWARD) || (m_nButtons & IN_BACK) // BriJee : First check walking off || (m_nButtons & IN_MOVELEFT) || (m_nButtons & IN_MOVERIGHT)) { } else { //if(IsSuitEquipped()) //{ if (/*m_afButtonPressed*/ m_nButtons & IN_LEANLEFT) StartLeaning(); else if (m_nButtons & IN_LEANRIGHT) StartLeaning(); else if (m_afButtonReleased & IN_LEANLEFT) StopLeaning(); else if (m_afButtonReleased & IN_LEANRIGHT) StopLeaning(); } //} //else //return; } int iDynLeanValue1; int iDynLeanValue2; void CHL2_Player::StartLeaning() { if (IsSprinting()) StopSprinting(); //if (IsZooming()) //StopZooming(); //if (IsWalking()) // BriJee : No leaning on walk //return; //Create new vectors Vector forward, lean, currentoffset, newoffset; currentoffset = GetViewOffset(); AngleVectors(EyeAngles(), &forward, &lean, NULL); newoffset = currentoffset; iDynLeanValue1 = iDynLeanValue1 + 1; // BriJee : Dynamic algorithm if (iDynLeanValue1 > 8) iDynLeanValue1 = 8; iDynLeanValue2 = iDynLeanValue2 - 1; if (iDynLeanValue2 < -8) iDynLeanValue2 = -8; if (m_nButtons & IN_LEANLEFT) { lean *= -25; newoffset.x = clamp(lean.x, iDynLeanValue2, iDynLeanValue1); newoffset.y = clamp(lean.y, iDynLeanValue2, iDynLeanValue1); SetViewOffset(newoffset); } else if (m_nButtons & IN_LEANRIGHT) { lean *= 25; newoffset.x = clamp(lean.x, iDynLeanValue2, iDynLeanValue1); newoffset.y = clamp(lean.y, iDynLeanValue2, iDynLeanValue1); SetViewOffset(newoffset); } m_bIsLeaning = true; } void CHL2_Player::StopLeaning() { if (IsDucking()) SetViewOffset(VEC_DUCK_VIEW); else SetViewOffset(VEC_VIEW); m_bIsLeaning = false; iDynLeanValue1 = 0; // addition iDynLeanValue2 = 0; } //==============================BriJee OVR: Server side leaning // Set the activity based on an event or current state //================================= Overcharged Player Anims definition /*void CHL2_Player::SetAnimation(PLAYER_ANIM playerAnim) { int animDesired; float speed; speed = GetAbsVelocity().Length2D(); if (GetFlags() & (FL_FROZEN | FL_ATCONTROLS)) { speed = 0; playerAnim = PLAYER_IDLE; } Activity idealActivity = ACT_HL2MP_RUN; if (playerAnim == PLAYER_JUMP) { if (HasWeapons()) idealActivity = ACT_HL2MP_JUMP; else idealActivity = ACT_JUMP; } else if (playerAnim == PLAYER_DIE) { if (m_lifeState == LIFE_ALIVE) { return; } } else if (playerAnim == PLAYER_ATTACK1) { if (GetActivity() == ACT_HOVER || GetActivity() == ACT_SWIM || GetActivity() == ACT_HOP || GetActivity() == ACT_LEAP || GetActivity() == ACT_DIESIMPLE) { idealActivity = GetActivity(); } else { idealActivity = ACT_HL2MP_GESTURE_RANGE_ATTACK; } } else if (playerAnim == PLAYER_RELOAD) { idealActivity = ACT_HL2MP_GESTURE_RELOAD; } else if (playerAnim == PLAYER_IDLE || playerAnim == PLAYER_WALK) { if (!(GetFlags() & FL_ONGROUND) && (GetActivity() == ACT_HL2MP_JUMP || GetActivity() == ACT_JUMP)) // Still jumping { idealActivity = GetActivity(); } else if (GetWaterLevel() > 1) { if (speed == 0) { if (HasWeapons()) idealActivity = ACT_HL2MP_IDLE; else idealActivity = ACT_IDLE; } else { if (HasWeapons()) idealActivity = ACT_HL2MP_RUN; else idealActivity = ACT_RUN; } } else { if (GetFlags() & FL_DUCKING) { if (speed > 0) { if (HasWeapons()) idealActivity = ACT_HL2MP_WALK_CROUCH; else idealActivity = ACT_WALK_CROUCH; } else { if (HasWeapons()) idealActivity = ACT_HL2MP_IDLE_CROUCH; else idealActivity = ACT_COVER_LOW; } } else { if (speed > 0) { { if (HasWeapons()) idealActivity = ACT_HL2MP_RUN; else { if (speed > HL2_WALK_SPEED + 20.0f) idealActivity = ACT_RUN; else idealActivity = ACT_WALK; } } } else { if (HasWeapons()) idealActivity = ACT_HL2MP_IDLE; else idealActivity = ACT_IDLE; } } } //idealActivity = TranslateTeamActivity( idealActivity ); } if (IsInAVehicle()) { idealActivity = ACT_COVER_LOW; } if (idealActivity == ACT_HL2MP_GESTURE_RANGE_ATTACK) { RestartGesture(Weapon_TranslateActivity(idealActivity)); // FIXME: this seems a bit wacked Weapon_SetActivity(Weapon_TranslateActivity(ACT_RANGE_ATTACK1), 0); return; } else if (idealActivity == ACT_HL2MP_GESTURE_RELOAD) { RestartGesture(Weapon_TranslateActivity(idealActivity)); return; } else { SetActivity(idealActivity); animDesired = SelectWeightedSequence(Weapon_TranslateActivity(idealActivity)); if (animDesired == -1) { animDesired = SelectWeightedSequence(idealActivity); if (animDesired == -1) { animDesired = 0; } } // Already using the desired animation? if (GetSequence() == animDesired) return; m_flPlaybackRate = 1.0; ResetSequence(animDesired); SetCycle(0); return; } // Already using the desired animation? if (GetSequence() == animDesired) return; //Msg( "Set animation to %d\n", animDesired ); // Reset to first frame of desired animation ResetSequence(animDesired); SetCycle(0); }*/ //================================= Overcharged Player Anims definition void CLogicPlayerProxy::Activate( void ) { BaseClass::Activate(); if ( m_hPlayer == NULL ) { m_hPlayer = AI_GetSinglePlayer(); } } bool CLogicPlayerProxy::PassesDamageFilter( const CTakeDamageInfo &info ) { if (m_hDamageFilter) { CBaseFilter *pFilter = (CBaseFilter *)(m_hDamageFilter.Get()); return pFilter->PassesDamageFilter(info); } return true; } void CLogicPlayerProxy::InputSetPlayerHealth( inputdata_t &inputdata ) { if ( m_hPlayer == NULL ) return; m_hPlayer->SetHealth( inputdata.value.Int() ); } void CLogicPlayerProxy::InputRequestPlayerHealth( inputdata_t &inputdata ) { if ( m_hPlayer == NULL ) return; m_RequestedPlayerHealth.Set( m_hPlayer->GetHealth(), inputdata.pActivator, inputdata.pCaller ); } void CLogicPlayerProxy::InputSetFlashlightSlowDrain( inputdata_t &inputdata ) { if( m_hPlayer == NULL ) return; CHL2_Player *pPlayer = dynamic_cast(m_hPlayer.Get()); if( pPlayer ) pPlayer->SetFlashlightPowerDrainScale( hl2_darkness_flashlight_factor.GetFloat() ); } void CLogicPlayerProxy::InputSetFlashlightNormalDrain( inputdata_t &inputdata ) { if( m_hPlayer == NULL ) return; CHL2_Player *pPlayer = dynamic_cast(m_hPlayer.Get()); if( pPlayer ) pPlayer->SetFlashlightPowerDrainScale( 1.0f ); } void CLogicPlayerProxy::InputRequestAmmoState( inputdata_t &inputdata ) { if( m_hPlayer == NULL ) return; CHL2_Player *pPlayer = dynamic_cast(m_hPlayer.Get()); for ( int i = 0 ; i < pPlayer->WeaponCount(); ++i ) { CBaseCombatWeapon* pCheck = pPlayer->GetWeapon( i ); if ( pCheck ) { if ( pCheck->HasAnyAmmo() && (pCheck->UsesPrimaryAmmo() || pCheck->UsesSecondaryAmmo())) { m_PlayerHasAmmo.FireOutput( this, this, 0 ); return; } } } m_PlayerHasNoAmmo.FireOutput( this, this, 0 ); } void CLogicPlayerProxy::InputLowerWeapon( inputdata_t &inputdata ) { if( m_hPlayer == NULL ) return; CHL2_Player *pPlayer = dynamic_cast(m_hPlayer.Get()); pPlayer->Weapon_Lower(); } void CLogicPlayerProxy::InputEnableCappedPhysicsDamage( inputdata_t &inputdata ) { if( m_hPlayer == NULL ) return; CHL2_Player *pPlayer = dynamic_cast(m_hPlayer.Get()); pPlayer->EnableCappedPhysicsDamage(); } void CLogicPlayerProxy::InputDisableCappedPhysicsDamage( inputdata_t &inputdata ) { if( m_hPlayer == NULL ) return; CHL2_Player *pPlayer = dynamic_cast(m_hPlayer.Get()); pPlayer->DisableCappedPhysicsDamage(); } void CLogicPlayerProxy::InputSetLocatorTargetEntity( inputdata_t &inputdata ) { if( m_hPlayer == NULL ) return; CBaseEntity *pTarget = NULL; // assume no target string_t iszTarget = MAKE_STRING( inputdata.value.String() ); if( iszTarget != NULL_STRING ) { pTarget = gEntList.FindEntityByName( NULL, iszTarget ); } CHL2_Player *pPlayer = dynamic_cast(m_hPlayer.Get()); pPlayer->SetLocatorTargetEntity(pTarget); } #ifdef PORTAL void CLogicPlayerProxy::InputSuppressCrosshair( inputdata_t &inputdata ) { if( m_hPlayer == NULL ) return; CPortal_Player *pPlayer = ToPortalPlayer(m_hPlayer.Get()); pPlayer->SuppressCrosshair( true ); } #endif // PORTAL