Add combat target reacquire telemetry
This commit is contained in:
@@ -161,6 +161,16 @@ void CHARACTER::Initialize()
|
||||
m_iFishingPatternTightSequence = 0;
|
||||
m_dwMiningWindowStart = 0;
|
||||
m_iMiningWindowCount = 0;
|
||||
m_dwCombatPatternWindowStart = 0;
|
||||
m_dwLastCombatPatternTime = 0;
|
||||
m_dwLastCombatPatternVictimVID = 0;
|
||||
m_lLastCombatPatternVictimX = 0;
|
||||
m_lLastCombatPatternVictimY = 0;
|
||||
m_iCombatPatternSampleCount = 0;
|
||||
m_iCombatPatternMinIntervalMs = 0;
|
||||
m_iCombatPatternMaxIntervalMs = 0;
|
||||
m_iCombatPatternMinStep = 0;
|
||||
m_iCombatPatternMaxStep = 0;
|
||||
|
||||
m_iLastPMPulse = 0;
|
||||
m_iPMCounter = 0;
|
||||
|
||||
@@ -2073,6 +2073,16 @@ class CHARACTER : public CEntity, public CFSM, public CHorseRider
|
||||
int m_iFishingPatternTightSequence;
|
||||
DWORD m_dwMiningWindowStart;
|
||||
int m_iMiningWindowCount;
|
||||
DWORD m_dwCombatPatternWindowStart;
|
||||
DWORD m_dwLastCombatPatternTime;
|
||||
DWORD m_dwLastCombatPatternVictimVID;
|
||||
long m_lLastCombatPatternVictimX;
|
||||
long m_lLastCombatPatternVictimY;
|
||||
int m_iCombatPatternSampleCount;
|
||||
int m_iCombatPatternMinIntervalMs;
|
||||
int m_iCombatPatternMaxIntervalMs;
|
||||
int m_iCombatPatternMinStep;
|
||||
int m_iCombatPatternMaxStep;
|
||||
void ClearPMCounter(void) { m_iPMCounter = 0; }
|
||||
void IncreasePMCounter(void) { m_iPMCounter++; }
|
||||
void SetLastPMPulse(void);
|
||||
|
||||
@@ -41,6 +41,119 @@
|
||||
#include <random>
|
||||
#include <algorithm>
|
||||
|
||||
namespace
|
||||
{
|
||||
constexpr DWORD kCombatPatternWindowMs = 10 * 60 * 1000;
|
||||
constexpr int kCombatPatternMinSamples = 10;
|
||||
constexpr int kCombatPatternMaxIntervalMs = 8000;
|
||||
constexpr int kCombatPatternMaxIntervalSpreadMs = 280;
|
||||
constexpr int kCombatPatternMaxStepSpread = 480;
|
||||
constexpr int kCombatPatternMinRouteStep = 250;
|
||||
|
||||
void ResetCombatPatternWindow(LPCHARACTER ch, LPCHARACTER victim, DWORD now)
|
||||
{
|
||||
if (!ch)
|
||||
return;
|
||||
|
||||
ch->m_dwCombatPatternWindowStart = now;
|
||||
ch->m_dwLastCombatPatternTime = now;
|
||||
ch->m_dwLastCombatPatternVictimVID = victim ? victim->GetVID() : 0;
|
||||
ch->m_lLastCombatPatternVictimX = victim ? victim->GetX() : 0;
|
||||
ch->m_lLastCombatPatternVictimY = victim ? victim->GetY() : 0;
|
||||
ch->m_iCombatPatternSampleCount = 0;
|
||||
ch->m_iCombatPatternMinIntervalMs = 0;
|
||||
ch->m_iCombatPatternMaxIntervalMs = 0;
|
||||
ch->m_iCombatPatternMinStep = 0;
|
||||
ch->m_iCombatPatternMaxStep = 0;
|
||||
}
|
||||
|
||||
void ObserveCombatTargetPattern(LPCHARACTER ch, LPCHARACTER victim, DWORD now)
|
||||
{
|
||||
if (!ch || !victim || !ch->IsPC())
|
||||
return;
|
||||
|
||||
if (!victim->IsMonster() && !victim->IsStone())
|
||||
return;
|
||||
|
||||
if (0 == ch->m_dwCombatPatternWindowStart || now - ch->m_dwCombatPatternWindowStart >= kCombatPatternWindowMs)
|
||||
{
|
||||
ResetCombatPatternWindow(ch, victim, now);
|
||||
return;
|
||||
}
|
||||
|
||||
if (0 == ch->m_dwLastCombatPatternVictimVID)
|
||||
{
|
||||
ResetCombatPatternWindow(ch, victim, now);
|
||||
return;
|
||||
}
|
||||
|
||||
if (ch->m_dwLastCombatPatternVictimVID == victim->GetVID())
|
||||
{
|
||||
ch->m_dwLastCombatPatternTime = now;
|
||||
ch->m_lLastCombatPatternVictimX = victim->GetX();
|
||||
ch->m_lLastCombatPatternVictimY = victim->GetY();
|
||||
return;
|
||||
}
|
||||
|
||||
const int iIntervalMs = static_cast<int>(now - ch->m_dwLastCombatPatternTime);
|
||||
const int iStep = DISTANCE_APPROX(victim->GetX() - ch->m_lLastCombatPatternVictimX,
|
||||
victim->GetY() - ch->m_lLastCombatPatternVictimY);
|
||||
|
||||
ch->m_dwLastCombatPatternTime = now;
|
||||
ch->m_dwLastCombatPatternVictimVID = victim->GetVID();
|
||||
ch->m_lLastCombatPatternVictimX = victim->GetX();
|
||||
ch->m_lLastCombatPatternVictimY = victim->GetY();
|
||||
|
||||
if (iIntervalMs <= 0 || iIntervalMs > kCombatPatternMaxIntervalMs)
|
||||
{
|
||||
ResetCombatPatternWindow(ch, victim, now);
|
||||
return;
|
||||
}
|
||||
|
||||
if (0 == ch->m_iCombatPatternSampleCount)
|
||||
{
|
||||
ch->m_iCombatPatternSampleCount = 1;
|
||||
ch->m_iCombatPatternMinIntervalMs = iIntervalMs;
|
||||
ch->m_iCombatPatternMaxIntervalMs = iIntervalMs;
|
||||
ch->m_iCombatPatternMinStep = iStep;
|
||||
ch->m_iCombatPatternMaxStep = iStep;
|
||||
return;
|
||||
}
|
||||
|
||||
++ch->m_iCombatPatternSampleCount;
|
||||
ch->m_iCombatPatternMinIntervalMs = MIN(ch->m_iCombatPatternMinIntervalMs, iIntervalMs);
|
||||
ch->m_iCombatPatternMaxIntervalMs = MAX(ch->m_iCombatPatternMaxIntervalMs, iIntervalMs);
|
||||
ch->m_iCombatPatternMinStep = MIN(ch->m_iCombatPatternMinStep, iStep);
|
||||
ch->m_iCombatPatternMaxStep = MAX(ch->m_iCombatPatternMaxStep, iStep);
|
||||
|
||||
if (ch->m_iCombatPatternSampleCount < kCombatPatternMinSamples)
|
||||
return;
|
||||
|
||||
const int iIntervalSpread = ch->m_iCombatPatternMaxIntervalMs - ch->m_iCombatPatternMinIntervalMs;
|
||||
const int iStepSpread = ch->m_iCombatPatternMaxStep - ch->m_iCombatPatternMinStep;
|
||||
if (iIntervalSpread > kCombatPatternMaxIntervalSpreadMs ||
|
||||
iStepSpread > kCombatPatternMaxStepSpread ||
|
||||
ch->m_iCombatPatternMaxStep < kCombatPatternMinRouteStep)
|
||||
return;
|
||||
|
||||
char szDetail[160];
|
||||
snprintf(szDetail,
|
||||
sizeof(szDetail),
|
||||
"samples=%d interval=%d..%d step=%d..%d target=%u",
|
||||
ch->m_iCombatPatternSampleCount,
|
||||
ch->m_iCombatPatternMinIntervalMs,
|
||||
ch->m_iCombatPatternMaxIntervalMs,
|
||||
ch->m_iCombatPatternMinStep,
|
||||
ch->m_iCombatPatternMaxStep,
|
||||
victim->GetVID());
|
||||
ch->RecordAntiCheatViolation("TARGET_REACQUIRE_PATTERN",
|
||||
iIntervalSpread <= 140 && iStepSpread <= 280 ? 2 : 1,
|
||||
szDetail);
|
||||
|
||||
ResetCombatPatternWindow(ch, victim, now);
|
||||
}
|
||||
}
|
||||
|
||||
DWORD AdjustExpByLevel(const LPCHARACTER ch, const DWORD exp)
|
||||
{
|
||||
if (PLAYER_EXP_TABLE_MAX < ch->GetLevel())
|
||||
@@ -271,6 +384,9 @@ bool CHARACTER::Attack(LPCHARACTER pkVictim, BYTE bType)
|
||||
// sys_log(0, "%s Attack %s type %u ret %d", GetName(), pkVictim->GetName(), bType, iRet);
|
||||
if (iRet == BATTLE_DAMAGE || iRet == BATTLE_DEAD)
|
||||
{
|
||||
if (IsPC() && 0 == bType)
|
||||
ObserveCombatTargetPattern(this, pkVictim, dwCurrentTime);
|
||||
|
||||
OnMove(true);
|
||||
pkVictim->OnMove();
|
||||
|
||||
|
||||
Reference in New Issue
Block a user