Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions src/game/server/NextBot/Player/NextBotPlayer.h
Original file line number Diff line number Diff line change
Expand Up @@ -699,6 +699,7 @@ inline void _NextBot_BuildUserCommand( CUserCmd *cmd, const QAngle &viewangles,
#ifdef NEO
extern ConVar bot_mimic;
extern ConVar bot_mimic_yaw_offset;
extern ConVar bot_mimic_mirror;
#endif // NEO
template < typename PlayerType >
inline void NextBotPlayer< PlayerType >::PhysicsSimulate( void )
Expand Down Expand Up @@ -743,6 +744,12 @@ inline void NextBotPlayer< PlayerType >::PhysicsSimulate( void )
cmd = *pPlayerMimicked->GetLastUserCommand();
cmd.viewangles[YAW] += bot_mimic_yaw_offset.GetFloat();

if (bot_mimic_mirror.GetBool())
{
cmd.viewangles[YAW] = -cmd.viewangles[YAW];
cmd.viewangles[PITCH] = -cmd.viewangles[PITCH];
}

// allocate a new command and add it to the player's list of command to process
this->ProcessUsercmds(&cmd, 1, 1, 0, false);

Expand Down
1 change: 1 addition & 0 deletions src/game/server/NextBot/Player/NextBotPlayerBody.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,7 @@ void PlayerBody::Reset( void )
ConVar bot_mimic( "bot_mimic", "0", 0, "Bot uses usercmd of player by index." );
#ifdef NEO
ConVar bot_mimic_yaw_offset("bot_mimic_yaw_offset", "0", 0, "Offsets the bot yaw.");
ConVar bot_mimic_mirror("bot_mimic_mirror", "0", 0, "Mirrors the mimic axes.");
#endif // NEO

//-----------------------------------------------------------------------------------------------
Expand Down
2 changes: 2 additions & 0 deletions src/game/shared/gamemovement.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,11 @@
#include "decals.h"
#include "coordsize.h"
#include "rumble_shared.h"
#ifndef NEO
#ifdef CLIENT_DLL
#include "prediction.h"
#endif
#endif

#if defined(HL2_DLL) || defined(HL2_CLIENT_DLL)
#include "hl_movedata.h"
Expand Down
129 changes: 85 additions & 44 deletions src/game/shared/neo/weapons/weapon_knife.cpp
Original file line number Diff line number Diff line change
@@ -1,15 +1,27 @@
#include "cbase.h"
#include "weapon_knife.h"

#ifndef CLIENT_DLL
#ifdef GAME_DLL
#include "ilagcompensationmanager.h"
#include "effect_dispatch_data.h"
#include "te_effect_dispatch.h"
#else
#include "prediction.h"
#endif

#include "takedamageinfo.h"

// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"

static ConVar sv_neo_backstab_ignorez("sv_neo_backstab_ignorez", "1", FCVAR_REPLICATED | FCVAR_NOTIFY,
"Whether knife backstabs angle calculations should ignore the pitch component.", true, false, true, true);

// NEO NOTE (Rain): Changed to degrees to make it more intuitive for players.
// Was previously: 0.6435011 radians; // ~ asin(0.6);
static ConVar sv_neo_backstab_angle("sv_neo_backstab_angle", "37", FCVAR_REPLICATED | FCVAR_NOTIFY,
"Maximum angle away from perfectly behind the back that still counts as a backstab.", true, 0, true, 180);

#define KNIFE_VM_ATTACK_ACT ACT_VM_PRIMARYATTACK

#define KNIFE_HULL_DIM 16.0f
Expand Down Expand Up @@ -255,64 +267,93 @@ Activity CWeaponKnife::ChooseIntersectionPointAndActivity(trace_t& hitTrace, con
return KNIFE_VM_ATTACK_ACT;
}

void CWeaponKnife::Hit(trace_t& traceHit, [[maybe_unused]] Activity nHitActivity)
inline void CWeaponKnife::ApplyDamageToHitTarget(trace_t& traceHit)
{
Assert(nHitActivity == KNIFE_VM_ATTACK_ACT);
#ifdef CLIENT_DLL
if (prediction->InPrediction() && !prediction->IsFirstTimePredicted())
return;
#endif

CBasePlayer *pPlayer = ToBasePlayer(GetOwner());
if (!traceHit.m_pEnt)
return;

// Do view kick
//AddViewKick();
auto *pPlayer = assert_cast<CNEO_Player*>(GetOwner());
AssertMsg(pPlayer != traceHit.m_pEnt, "Shouldn't be able to hit self");
// NEO NOTE (Rain): client-side abs ang queries don't seem to work well,
// so I've changed the Vector forward to use the eye angles forward for
// prediction purposes. It probably feels more fair to the player as well,
// since as long as they keep their eyes on the attacker, i.e. the attacker
// is physically in front of them, they cannot be backstabbed (assuming the
// server agrees on those angles).
Vector forward;
AngleVectors(traceHit.m_pEnt->EyeAngles(), &forward);

CBaseEntity *pHitEntity = traceHit.m_pEnt;
Vector attackerToTarget = traceHit.m_pEnt->GetAbsOrigin() - pPlayer->GetAbsOrigin();

//Apply damage to a hit target
if (pHitEntity != NULL)
if (sv_neo_backstab_ignorez.GetBool())
{
// Shouldn't be able to hit self
Assert(pPlayer != pHitEntity);

Vector hitDirection;
pPlayer->EyeVectors(&hitDirection, NULL, NULL);
VectorNormalize(hitDirection);

#ifndef CLIENT_DLL

Vector forward;
AngleVectors(pHitEntity->GetAbsAngles(), &forward);

Vector2D forward2D = Vector2D(forward.x, forward.y);
forward2D.NormalizeInPlace();
forward.AsVector2D().NormalizeInPlace();
forward.z = 0;

Vector attackerToTarget = pHitEntity->GetAbsOrigin() - pPlayer->GetAbsOrigin();
Vector2D attackerToTarget2D = Vector2D(attackerToTarget.x, attackerToTarget.y);
attackerToTarget2D.NormalizeInPlace();

const float currentAngle = acos(DotProduct2D(forward2D, attackerToTarget2D));

static constexpr float maxBackStabAngle = 0.6435011; // ~ asin(0.6);
attackerToTarget.AsVector2D().NormalizeInPlace();
attackerToTarget.z = 0;
}
else
{
attackerToTarget.NormalizeInPlace();
}
AssertFloatEquals(forward.Length(), 1.f, 0.01f);
AssertFloatEquals(attackerToTarget.Length(), 1.f, 0.01f);

static constexpr int damageToOneShotSupport = MAX_HEALTH_FOR_CLASS[NEO_CLASS_SUPPORT] + 1;
const float currentAngle = RAD2DEG(acos(forward.Dot(attackerToTarget)));

CTakeDamageInfo info(GetOwner(), GetOwner(), KNIFE_DAMAGE, DMG_SLASH);
CTakeDamageInfo info(pPlayer, pPlayer, KNIFE_DAMAGE, DMG_SLASH);
Vector hitDirection;
pPlayer->EyeVectors(&hitDirection);
AssertFloatEquals(hitDirection.Length(), 1.f, 0.01f);
CalculateMeleeDamageForce(&info, hitDirection, traceHit.endpos, 0.05f);

CalculateMeleeDamageForce(&info, hitDirection, traceHit.endpos, 0.05f);
const bool isBackstab = (currentAngle <= sv_neo_backstab_angle.GetFloat());
// increase damage if backstabbing only after melee damage force has been calculated,
// so objects cannot be "backstabbed" to launch them further
if (isBackstab)
{
// If this doesn't do any damage, step ApplyMultiDamage or the below:
// traceHit.m_pEnt->GetReceivedDamageScale(pPlayer);
#if 0
const char* help = "";
#ifdef GAME_DLL
if (!traceHit.m_pEnt->GetReceivedDamageScale(pPlayer))
help = " (dmg scale 0, maybe in spawn protection?)";
#endif

if (currentAngle <= maxBackStabAngle)
{ // increase damage if backstabbing only after melee damage force has been calculated, so objects cannot be "backstabbed" to launch them further
info.SetDamage(damageToOneShotSupport);
}
DevMsg("[%s] \"%s\" backstabbed \"%s\"%s\n",
(IsServer() ? "SRV auth" : "CLI pred"),
pPlayer->GetNeoPlayerName(),
assert_cast<CNEO_Player*>(traceHit.m_pEnt)->GetNeoPlayerName(),
help
);
#endif
static constexpr float oneShotDamage = MAX_HEALTH_FOR_CLASS[NEO_CLASS_SUPPORT] + 1;
info.SetMaxDamage(info.GetMaxDamage() + oneShotDamage);
info.AddDamage(oneShotDamage);
Assert(traceHit.m_pEnt->GetMaxHealth() < info.GetDamage() + info.GetDamageBonus());
}

pHitEntity->DispatchTraceAttack(info, hitDirection, &traceHit);
ApplyMultiDamage();
traceHit.m_pEnt->DispatchTraceAttack(info, hitDirection, &traceHit);
ApplyMultiDamage();

// Now hit all triggers along the ray that...
TraceAttackToTriggers(info, traceHit.startpos, traceHit.endpos, hitDirection);
#ifdef GAME_DLL
// Now hit all triggers along that ray...
TraceAttackToTriggers(info, traceHit.startpos, traceHit.endpos, hitDirection);
#endif
WeaponSound(MELEE_HIT);
}
}

// Apply an impact effect
void CWeaponKnife::Hit(trace_t& traceHit, [[maybe_unused]] Activity nHitActivity)
{
Assert(nHitActivity == KNIFE_VM_ATTACK_ACT);
ApplyDamageToHitTarget(traceHit);
WeaponSound(MELEE_HIT);
ImpactEffect(traceHit);
}

Expand Down
5 changes: 3 additions & 2 deletions src/game/shared/neo/weapons/weapon_knife.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
#define CWeaponKnife C_WeaponKnife
#endif

#define NEO_WEP_KNIFE_RANGE 51.f;
#define NEO_WEP_KNIFE_RANGE 51.f

class CWeaponKnife : public CNEOBaseCombatWeapon
{
Expand All @@ -33,6 +33,7 @@ class CWeaponKnife : public CNEOBaseCombatWeapon
#endif

CWeaponKnife();
CWeaponKnife(const CWeaponKnife& other) = delete;

virtual void PrimaryAttack() final;
virtual void Drop(const Vector &vecVelocity) final { /* knives shouldn't drop */ }
Expand Down Expand Up @@ -63,7 +64,7 @@ class CWeaponKnife : public CNEOBaseCombatWeapon
bool ImpactWater(const Vector &start, const Vector &end);
void Hit(trace_t& traceHit, Activity nHitActivity);
private:
CWeaponKnife(const CWeaponKnife &other);
inline void ApplyDamageToHitTarget(trace_t& traceHit);
};

#endif // NEO_WEAPON_KNIFE_H
8 changes: 8 additions & 0 deletions src/game/shared/takedamageinfo.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -215,12 +215,16 @@ void ApplyMultiDamage( void )
return;

#ifndef CLIENT_DLL
#ifndef NEO
const CBaseEntity *host = te->GetSuppressHost();
te->SetSuppressHost( NULL );
#endif

g_MultiDamage.GetTarget()->TakeDamage( g_MultiDamage );

#ifndef NEO
te->SetSuppressHost( (CBaseEntity*)host );
#endif
#endif

// Damage is done, clear it out
Expand All @@ -246,7 +250,11 @@ void AddMultiDamage( const CTakeDamageInfo &info, CBaseEntity *pEntity )
g_MultiDamage.SetDamageForce( g_MultiDamage.GetDamageForce() + info.GetDamageForce() );
g_MultiDamage.SetDamagePosition( info.GetDamagePosition() );
g_MultiDamage.SetReportedPosition( info.GetReportedPosition() );
#ifdef NEO
g_MultiDamage.SetMaxDamage( Max( g_MultiDamage.GetMaxDamage(), info.GetMaxDamage() ) );
#else
g_MultiDamage.SetMaxDamage( MAX( g_MultiDamage.GetMaxDamage(), info.GetDamage() ) );
#endif
g_MultiDamage.SetAmmoType( info.GetAmmoType() );
g_MultiDamage.SetCritType( info.GetCritType() );

Expand Down
Loading