diff --git a/sp/src/game/server/basebludgeonweapon.cpp b/sp/src/game/server/basebludgeonweapon.cpp index 93903616..c755e2ef 100644 --- a/sp/src/game/server/basebludgeonweapon.cpp +++ b/sp/src/game/server/basebludgeonweapon.cpp @@ -28,6 +28,15 @@ IMPLEMENT_SERVERCLASS_ST( CBaseHLBludgeonWeapon, DT_BaseHLBludgeonWeapon ) END_SEND_TABLE() +#ifdef MAPBASE +BEGIN_DATADESC(CBaseHLBludgeonWeapon) + +DEFINE_FIELD(m_flDelayedFire, FIELD_TIME), +DEFINE_FIELD(m_bShotDelayed, FIELD_BOOLEAN), + +END_DATADESC() +#endif // MAPBASE + #define BLUDGEON_HULL_DIM 16 static const Vector g_bludgeonMins(-BLUDGEON_HULL_DIM,-BLUDGEON_HULL_DIM,-BLUDGEON_HULL_DIM); @@ -39,6 +48,9 @@ static const Vector g_bludgeonMaxs(BLUDGEON_HULL_DIM,BLUDGEON_HULL_DIM,BLUDGEON_ CBaseHLBludgeonWeapon::CBaseHLBludgeonWeapon() { m_bFiresUnderwater = true; +#ifdef MAPBASE + m_bShotDelayed = false; +#endif // MAPBASE } //----------------------------------------------------------------------------- @@ -96,11 +108,19 @@ void CBaseHLBludgeonWeapon::ItemPostFrame( void ) #ifdef MAPBASE if (pOwner->HasSpawnFlags( SF_PLAYER_SUPPRESS_FIRING )) { + m_bShotDelayed = false; WeaponIdle(); return; } -#endif + // See if we need to fire off our secondary round + if (m_bShotDelayed) + { + if (gpGlobals->curtime > m_flDelayedFire) + DelayedAttack(); + } + else +#endif if ( (pOwner->m_nButtons & IN_ATTACK) && (m_flNextPrimaryAttack <= gpGlobals->curtime) ) { PrimaryAttack(); @@ -239,7 +259,7 @@ Activity CBaseHLBludgeonWeapon::ChooseIntersectionPointAndActivity( trace_t &hit } - return ACT_VM_HITCENTER; + return GetPrimaryAttackActivity(); } //----------------------------------------------------------------------------- @@ -297,7 +317,6 @@ void CBaseHLBludgeonWeapon::ImpactEffect( trace_t &traceHit ) UTIL_ImpactTrace( &traceHit, DMG_CLUB ); } - //------------------------------------------------------------------------------ // Purpose : Starts the swing of the weapon and determines the animation // Input : bIsSecondary - is this a secondary attack? @@ -320,10 +339,14 @@ void CBaseHLBludgeonWeapon::Swing( int bIsSecondary ) Vector swingEnd = swingStart + forward * GetRange(); UTIL_TraceLine( swingStart, swingEnd, MASK_SHOT_HULL, pOwner, COLLISION_GROUP_NONE, &traceHit ); - Activity nHitActivity = ACT_VM_HITCENTER; + Activity nHitActivity = GetPrimaryAttackActivity(); // Like bullets, bludgeon traces have to trace against triggers. - CTakeDamageInfo triggerInfo( GetOwner(), GetOwner(), GetDamageForActivity( nHitActivity ), DMG_CLUB ); +#ifdef MAPBASE + CTakeDamageInfo triggerInfo(GetOwner(), GetOwner(), GetDamageForActivity(nHitActivity), GetDamageType()); +#else + CTakeDamageInfo triggerInfo(GetOwner(), GetOwner(), GetDamageForActivity(nHitActivity), DMG_CLUB); +#endif // MAPBASE triggerInfo.SetDamagePosition( traceHit.startpos ); triggerInfo.SetDamageForce( forward ); TraceAttackToTriggers( triggerInfo, traceHit.startpos, traceHit.endpos, forward ); @@ -374,31 +397,20 @@ void CBaseHLBludgeonWeapon::Swing( int bIsSecondary ) { nHitActivity = bIsSecondary ? ACT_VM_MISSCENTER2 : ACT_VM_MISSCENTER; +#ifndef MAPBASE // We want to test the first swing again Vector testEnd = swingStart + forward * GetRange(); -#ifdef MAPBASE - // Sound has been moved here since we're using the other melee sounds now - WeaponSound( SINGLE ); -#endif - // See if we happened to hit water - ImpactWater( swingStart, testEnd ); + ImpactWater(swingStart, testEnd); +#endif // !MAPBASE } +#ifndef MAPBASE else { -#ifdef MAPBASE - // Other melee sounds - if (traceHit.m_pEnt && traceHit.m_pEnt->IsWorld()) - WeaponSound(MELEE_HIT_WORLD); - else if (traceHit.m_pEnt && !traceHit.m_pEnt->PassesDamageFilter(triggerInfo)) - WeaponSound(MELEE_MISS); - else - WeaponSound(MELEE_HIT); -#endif - Hit( traceHit, nHitActivity, bIsSecondary ? true : false ); } +#endif // Send the anim SendWeaponAnim( nHitActivity ); @@ -414,5 +426,125 @@ void CBaseHLBludgeonWeapon::Swing( int bIsSecondary ) #ifdef MAPBASE pOwner->SetAnimation( PLAYER_ATTACK1 ); + + if (GetHitDelay() > 0.f) + { + //Play swing sound + WeaponSound(SINGLE); + + m_flDelayedFire = gpGlobals->curtime + GetHitDelay(); + m_bShotDelayed = true; + } + else + { + if (traceHit.fraction == 1.0f) + { + // We want to test the first swing again + Vector testEnd = swingStart + forward * GetRange(); + + //Play swing sound + WeaponSound(SINGLE); + + // See if we happened to hit water + ImpactWater(swingStart, testEnd); + } + else + { + // Other melee sounds + if (traceHit.m_pEnt && traceHit.m_pEnt->IsWorld()) + WeaponSound(MELEE_HIT_WORLD); + else if (traceHit.m_pEnt && !traceHit.m_pEnt->PassesDamageFilter(triggerInfo)) + WeaponSound(MELEE_MISS); + else + WeaponSound(MELEE_HIT); + + Hit(traceHit, nHitActivity, bIsSecondary ? true : false); + } + } #endif } + +#ifdef MAPBASE +void CBaseHLBludgeonWeapon::DelayedAttack(void) +{ + m_bShotDelayed = false; + + trace_t traceHit; + + // Try a ray + CBasePlayer* pOwner = ToBasePlayer(GetOwner()); + if (!pOwner) + return; + + pOwner->RumbleEffect(RUMBLE_CROWBAR_SWING, 0, RUMBLE_FLAG_RESTART); + + Vector swingStart = pOwner->Weapon_ShootPosition(); + Vector forward; + + forward = pOwner->GetAutoaimVector(AUTOAIM_SCALE_DEFAULT, GetRange()); + + Vector swingEnd = swingStart + forward * GetRange(); + UTIL_TraceLine(swingStart, swingEnd, MASK_SHOT_HULL, pOwner, COLLISION_GROUP_NONE, &traceHit); + + if (traceHit.fraction == 1.0) + { + float bludgeonHullRadius = 1.732f * BLUDGEON_HULL_DIM; // hull is +/- 16, so use cuberoot of 2 to determine how big the hull is from center to the corner point + + // Back off by hull "radius" + swingEnd -= forward * bludgeonHullRadius; + + UTIL_TraceHull(swingStart, swingEnd, g_bludgeonMins, g_bludgeonMaxs, MASK_SHOT_HULL, pOwner, COLLISION_GROUP_NONE, &traceHit); + if (traceHit.fraction < 1.0 && traceHit.m_pEnt) + { + Vector vecToTarget = traceHit.m_pEnt->GetAbsOrigin() - swingStart; + VectorNormalize(vecToTarget); + + float dot = vecToTarget.Dot(forward); + + // YWB: Make sure they are sort of facing the guy at least... + if (dot < 0.70721f) + { + // Force amiss + traceHit.fraction = 1.0f; + } + else + { + ChooseIntersectionPointAndActivity(traceHit, g_bludgeonMins, g_bludgeonMaxs, pOwner); + } + } + } + + if (traceHit.fraction == 1.0f) + { + // We want to test the first swing again + Vector testEnd = swingStart + forward * GetRange(); + + // See if we happened to hit water + ImpactWater(swingStart, testEnd); + } + else + { + CTakeDamageInfo triggerInfo(GetOwner(), GetOwner(), GetDamageForActivity(GetActivity()), GetDamageType()); + triggerInfo.SetDamagePosition(traceHit.startpos); + triggerInfo.SetDamageForce(forward); + + // Other melee sounds + if (traceHit.m_pEnt && traceHit.m_pEnt->IsWorld()) + WeaponSound(MELEE_HIT_WORLD); + else if (traceHit.m_pEnt && !traceHit.m_pEnt->PassesDamageFilter(triggerInfo)) + WeaponSound(MELEE_MISS); + else + WeaponSound(MELEE_HIT); + + Hit(traceHit, GetActivity(), false); + } +} + +bool CBaseHLBludgeonWeapon::CanHolster(void) +{ + if (m_bShotDelayed) + return false; + + return BaseClass::CanHolster(); +} +#endif // MAPBASE diff --git a/sp/src/game/server/basebludgeonweapon.h b/sp/src/game/server/basebludgeonweapon.h index 52f02f9b..57f0ed11 100644 --- a/sp/src/game/server/basebludgeonweapon.h +++ b/sp/src/game/server/basebludgeonweapon.h @@ -23,6 +23,9 @@ public: CBaseHLBludgeonWeapon(); DECLARE_SERVERCLASS(); +#ifdef MAPBASE + DECLARE_DATADESC(); +#endif // MAPBASE virtual void Spawn( void ); virtual void Precache( void ); @@ -30,6 +33,9 @@ public: //Attack functions virtual void PrimaryAttack( void ); virtual void SecondaryAttack( void ); +#ifdef MAPBASE + void DelayedAttack(void); +#endif // MAPBASE virtual void ItemPostFrame( void ); @@ -46,6 +52,8 @@ public: #ifdef MAPBASE virtual int GetDamageType() { return DMG_CLUB; } + virtual float GetHitDelay() { return 0.f; } + virtual bool CanHolster(void); #endif // MAPBASE protected: @@ -56,6 +64,11 @@ private: void Swing( int bIsSecondary ); void Hit( trace_t &traceHit, Activity nHitActivity, bool bIsSecondary ); Activity ChooseIntersectionPointAndActivity( trace_t &hitTrace, const Vector &mins, const Vector &maxs, CBasePlayer *pOwner ); + +#ifdef MAPBASE + float m_flDelayedFire; + bool m_bShotDelayed; +#endif // MAPBASE }; #endif \ No newline at end of file diff --git a/sp/src/game/server/mapbase/weapon_custom_hl2.cpp b/sp/src/game/server/mapbase/weapon_custom_hl2.cpp index 86c9733b..0a5996c5 100644 --- a/sp/src/game/server/mapbase/weapon_custom_hl2.cpp +++ b/sp/src/game/server/mapbase/weapon_custom_hl2.cpp @@ -55,6 +55,8 @@ typedef struct HL2CustomMeleeData_s float m_flRefireRate; float m_flDamage; float m_flNPCDamage; + float m_flHitDelay; + Activity m_nHitActivity = ACT_INVALID; byte m_nDamageClass; bool Parse(KeyValues*); @@ -72,6 +74,7 @@ public: float GetRange(void) { return m_CustomData.m_flMeleeRange; } float GetFireRate(void) { return m_CustomData.m_flRefireRate; } + float GetHitDelay() { return m_CustomData.m_flHitDelay; } void AddViewKick(void); float GetDamageForActivity(Activity hitActivity); @@ -86,6 +89,9 @@ public: acttable_t* GetBackupActivityList() { return NULL; } int GetBackupActivityListCount() { return 0; } + //Functions to select animation sequences + virtual Activity GetPrimaryAttackActivity(void) { return m_CustomData.m_nHitActivity; } + const char* GetWeaponScriptName() { return m_iszWeaponScriptName.Get(); } virtual int GetDamageType() { return g_nDamageClassTypeBits[m_CustomData.m_nDamageClass]; } @@ -116,6 +122,16 @@ bool HL2CustomMeleeData_s::Parse(KeyValues* pKVWeapon) m_flNPCDamage = pkvData->GetFloat("damage_npc", m_flDamage); m_flMeleeRange = pkvData->GetFloat("range", 70.f); m_flRefireRate = pkvData->GetFloat("rate", 0.7f); + m_flHitDelay = pkvData->GetFloat("hitdelay"); + if (pkvData->FindKey("activity_hit")) + { + m_nHitActivity = (Activity)ActivityList_IndexForName(pkvData->GetString("activity_hit")); + } + + if (m_nHitActivity == ACT_INVALID) + { + m_nHitActivity = ACT_VM_HITCENTER; + } const char* pszDamageClass = pkvData->GetString("damage_type", nullptr); if (pszDamageClass)