Validate ranged targets server-side
This commit is contained in:
@@ -21,6 +21,7 @@
|
||||
#include "sectree.h"
|
||||
#include "ani.h"
|
||||
#include "locale_service.h"
|
||||
#include "skill.h"
|
||||
|
||||
int battle_hit(LPCHARACTER ch, LPCHARACTER victim, int & iRetDam);
|
||||
|
||||
@@ -60,6 +61,51 @@ bool battle_distance_valid(LPCHARACTER ch, LPCHARACTER victim)
|
||||
return battle_distance_valid_by_xy(ch->GetX(), ch->GetY(), victim->GetX(), victim->GetY());
|
||||
}
|
||||
|
||||
int battle_get_ranged_target_max_distance(LPCHARACTER ch, BYTE attackType)
|
||||
{
|
||||
int maxDistance = 3500;
|
||||
|
||||
if (!ch)
|
||||
return maxDistance;
|
||||
|
||||
if (attackType == 0)
|
||||
{
|
||||
maxDistance += MAX(0, ch->GetPoint(POINT_BOW_DISTANCE)) * 100;
|
||||
return maxDistance;
|
||||
}
|
||||
|
||||
if (attackType > 1)
|
||||
{
|
||||
if (CSkillProto* pkSk = CSkillManager::instance().Get(attackType))
|
||||
{
|
||||
if (pkSk->dwTargetRange > 0)
|
||||
return pkSk->dwTargetRange + 300;
|
||||
}
|
||||
}
|
||||
|
||||
if (!ch->IsPC())
|
||||
maxDistance = MAX(maxDistance, static_cast<int>(ch->GetMobAttackRange() * 1.5f));
|
||||
|
||||
return maxDistance;
|
||||
}
|
||||
|
||||
bool battle_ranged_target_valid(LPCHARACTER ch, LPCHARACTER victim, BYTE attackType, int* outDistance, int* outMaxDistance)
|
||||
{
|
||||
if (!ch || !victim)
|
||||
return false;
|
||||
|
||||
const int distance = DISTANCE_APPROX(ch->GetX() - victim->GetX(), ch->GetY() - victim->GetY());
|
||||
const int maxDistance = battle_get_ranged_target_max_distance(ch, attackType);
|
||||
|
||||
if (outDistance)
|
||||
*outDistance = distance;
|
||||
|
||||
if (outMaxDistance)
|
||||
*outMaxDistance = maxDistance;
|
||||
|
||||
return distance <= maxDistance;
|
||||
}
|
||||
|
||||
bool timed_event_cancel(LPCHARACTER ch)
|
||||
{
|
||||
if (ch->m_pkTimedEvent)
|
||||
|
||||
@@ -24,6 +24,8 @@ extern void battle_end(LPCHARACTER ch);
|
||||
|
||||
extern bool battle_distance_valid_by_xy(long x, long y, long tx, long ty);
|
||||
extern bool battle_distance_valid(LPCHARACTER ch, LPCHARACTER victim);
|
||||
extern int battle_get_ranged_target_max_distance(LPCHARACTER ch, BYTE attackType);
|
||||
extern bool battle_ranged_target_valid(LPCHARACTER ch, LPCHARACTER victim, BYTE attackType, int* outDistance = nullptr, int* outMaxDistance = nullptr);
|
||||
extern int battle_count_attackers(LPCHARACTER ch);
|
||||
|
||||
extern void NormalAttackAffect(LPCHARACTER pkAttacker, LPCHARACTER pkVictim);
|
||||
|
||||
@@ -2990,10 +2990,23 @@ class CFuncShoot
|
||||
if (!battle_is_attackable(m_me, pkVictim))
|
||||
return;
|
||||
|
||||
if (m_me->IsNPC())
|
||||
int rangedDistance = 0;
|
||||
int rangedLimit = 0;
|
||||
if (!battle_ranged_target_valid(m_me, pkVictim, m_bType, &rangedDistance, &rangedLimit))
|
||||
{
|
||||
if (DISTANCE_APPROX(m_me->GetX() - pkVictim->GetX(), m_me->GetY() - pkVictim->GetY()) > 5000)
|
||||
return;
|
||||
if (m_me->IsPC())
|
||||
{
|
||||
char szDetail[160];
|
||||
snprintf(szDetail,
|
||||
sizeof(szDetail),
|
||||
"type=%u distance=%d max=%d victim=%u",
|
||||
m_bType,
|
||||
rangedDistance,
|
||||
rangedLimit,
|
||||
pkVictim->GetVID());
|
||||
m_me->RecordAntiCheatViolation("RANGED_RANGE", rangedDistance > rangedLimit + 800 ? 18 : 8, szDetail, rangedDistance > rangedLimit + 800);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
LPITEM pkBow, pkArrow;
|
||||
@@ -3275,6 +3288,12 @@ void CHARACTER::FlyTarget(DWORD dwTargetVID, long x, long y, uint16_t wHeader)
|
||||
LPCHARACTER pkVictim = CHARACTER_MANAGER::instance().Find(dwTargetVID);
|
||||
TPacketGCFlyTargeting pack;
|
||||
|
||||
if (IsPC() && !pkVictim)
|
||||
{
|
||||
sys_log(1, "FlyTarget reject empty player target %s vid %u x %ld y %ld", GetName(), dwTargetVID, x, y);
|
||||
return;
|
||||
}
|
||||
|
||||
//pack.header = GC::FLY_TARGETING;
|
||||
pack.header = (wHeader == CG::FLY_TARGETING) ? GC::FLY_TARGETING : GC::ADD_FLY_TARGETING;
|
||||
pack.length = sizeof(pack);
|
||||
|
||||
@@ -2092,6 +2092,49 @@ int CInputMain::SyncPosition(LPCHARACTER ch, const char * c_pcData, size_t uiByt
|
||||
void CInputMain::FlyTarget(LPCHARACTER ch, const char * pcData, uint16_t wHeader)
|
||||
{
|
||||
TPacketCGFlyTargeting * p = (TPacketCGFlyTargeting *) pcData;
|
||||
|
||||
if (ch && ch->IsPC())
|
||||
{
|
||||
LPCHARACTER victim = CHARACTER_MANAGER::instance().Find(p->dwTargetVID);
|
||||
|
||||
if (!victim)
|
||||
{
|
||||
sys_log(1, "FLY_TARGET_INVALID: %s target=%u missing", ch->GetName(), p->dwTargetVID);
|
||||
return;
|
||||
}
|
||||
|
||||
if (ch == victim)
|
||||
{
|
||||
char szDetail[128];
|
||||
snprintf(szDetail, sizeof(szDetail), "target=%u x=%ld y=%ld", p->dwTargetVID, static_cast<long>(p->x), static_cast<long>(p->y));
|
||||
ch->RecordAntiCheatViolation("FLY_TARGET_INVALID", 4, szDetail);
|
||||
return;
|
||||
}
|
||||
|
||||
switch (victim->GetCharType())
|
||||
{
|
||||
case CHAR_TYPE_WARP:
|
||||
case CHAR_TYPE_GOTO:
|
||||
ch->RecordAntiCheatViolation("FLY_TARGET_INVALID", 6, victim->GetName(), true);
|
||||
return;
|
||||
}
|
||||
|
||||
int distance = 0;
|
||||
int maxDistance = 0;
|
||||
if (!battle_ranged_target_valid(ch, victim, 0, &distance, &maxDistance))
|
||||
{
|
||||
char szDetail[160];
|
||||
snprintf(szDetail,
|
||||
sizeof(szDetail),
|
||||
"target=%s distance=%d max=%d",
|
||||
victim->GetName(),
|
||||
distance,
|
||||
maxDistance);
|
||||
ch->RecordAntiCheatViolation("FLY_TARGET_RANGE", distance > maxDistance + 800 ? 12 : 4, szDetail, distance > maxDistance + 800);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
ch->FlyTarget(p->dwTargetVID, p->x, p->y, wHeader);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user