Files
Sun1602/Server/GameServer/Npcai/TargetFinder.h
T
2022-10-26 12:25:11 +08:00

455 lines
11 KiB
C++

#pragma once
#include <PublicMath.h>
#include "Character.h"
#include "AIParamParser.h"
#include "MovingPlanner.h"
// 화일이름 바꿔야 한다. -_-;
//==================================================================================================
//
// TargetFinder
//
//==================================================================================================
// @history
// - ~~~~~
// - 09/12/13|waverix|add skip tile filter for _NA001415_091123_CHANGE_MOB_AI_IN_SAFETY_AREA_
//─────────────────────────────────────────
// <TargetFinder>
// - 특정 상태의 캐릭터를 찾는다.
//_NA_0_20100222_UNIT_TRIGGERS_FRIEND_MONSTER
struct TargetFinderArg
{
Character* owner_;
eTARGET_SEARCH_TYPE search_type_;
eSKILL_TARGET_TYPE target_type_;
REGENID unitID_;
DWORD mapobjectID_;
MONSTERCODE npc_code_;
};
class TargetFinder
{
public:
TargetFinder()
: m_pOwner( 0 )
, m_pTarget( 0 )
, m_eTargetType( SKILL_TARGET_NONE )
, m_SkipTileAttr(0)
, m_fOwnerSight( .0f )
, m_fOwnerSightX2( .0f )
, m_fBetweenOwnerWithTargetX2( .0f ) {}
virtual ~TargetFinder() { }
public:
//_NA_0_20100222_UNIT_TRIGGERS_FRIEND_MONSTER
TargetFinder(const TargetFinderArg& arg)
: m_pOwner( 0 )
, m_pTarget( 0 )
, m_eTargetType( SKILL_TARGET_NONE )
, m_SkipTileAttr(0)
, m_fOwnerSight( .0f )
, m_fOwnerSightX2( .0f )
, m_fBetweenOwnerWithTargetX2( .0f ) { SetFinder(arg); }
virtual void SetFinder(const TargetFinderArg& finder_arg )
{
ASSERT(finder_arg.owner_);
m_pOwner = finder_arg.owner_;
m_fOwnerSight = m_pOwner->GetSightRange();
m_fOwnerSightX2 = m_fOwnerSight*m_fOwnerSight;
m_vOwnerPos = *m_pOwner->GetPosPtr();
m_eTargetType = finder_arg.target_type_;
switch(m_eTargetType)
{
case SKILL_TARGET_ENEMY:
case SKILL_TARGET_REACHABLE_ENEMY:
case SKILL_TARGET_ENEMY_PLAYER:
case SKILL_TARGET_ENEMY_CORPSE:
case SKILL_TARGET_AREA_ENEMY_CORPSE:
m_SkipTileAttr = PTA_SAFETY_ZONE;
break;
default:
break;
}
}
// Result
inline Character* GetTarget() { return m_pTarget; }
public:
// <INTERFACE>
virtual bool operator () ( Character* const pCharacter ) = 0;
protected: bool CheckTarget( Character* const pTarget )
{
if( !( pTarget && (m_pOwner != m_pTarget) ) )
return false;
m_vTargetPos = *pTarget->GetPosPtr();
WzVector diff = m_vTargetPos;
; diff -= m_vOwnerPos;
m_fBetweenOwnerWithTargetX2 = Math_Vector2DLength2(&diff);
WORD skip_check_tile_attr_for_target = 0;
if (pTarget->IsEqualObjectKind(MAPNPC_OBJECT))
{
skip_check_tile_attr_for_target = PTA_NO_WALK;
}
if( !nsAI::PlanEventObject::AcceptableTarget(pTarget, m_SkipTileAttr,
skip_check_tile_attr_for_target))
{
return false;
}
if( !m_pOwner->IsCoincidentWithTargetType( pTarget, m_eTargetType ) )
return false;
return true;
}
bool IsCheckTargetCasebyAlive( Character* const pTarget )
{
if( !CheckTarget( pTarget ) )
return false;
if( pTarget->IsDead()
|| (!pTarget->CanBeAttacked())
)
return false;
return true;
}
protected:
Character* m_pOwner;
Character* m_pTarget;
eSKILL_TARGET_TYPE m_eTargetType; // 찾아야할 타겟 타입
WORD m_SkipTileAttr;//_NA001415_091123_CHANGE_MOB_AI_IN_SAFETY_AREA_
#pragma warning(push)
#pragma warning(disable : 4201)
struct { // SetOwner 호출 이후 계산되는 값
FLOAT m_fOwnerSight; //
FLOAT m_fOwnerSightX2; // (OwnerSight*OwnerSight)
};
struct { // CheckTarget 호출 이후 계산되는 값
FLOAT m_fBetweenOwnerWithTargetX2; // 둘 사이의 거리
WzVector m_vOwnerPos;
WzVector m_vTargetPos;
};
#pragma warning(pop)
};
//─────────────────────────────────────────
// <NearestTargetFinder>
//
class NearestTargetFinder : public TargetFinder
{
public: NearestTargetFinder()
: m_TargetDistX2(999999.f)
{
}
//_NA_0_20100222_UNIT_TRIGGERS_FRIEND_MONSTER
NearestTargetFinder(const TargetFinderArg& arg)
: TargetFinder(arg),
m_TargetDistX2(999999.f) {}
public:
virtual bool operator () ( Character* const pCharacter )
{
if( !IsCheckTargetCasebyAlive( pCharacter ) )
return false;
if( m_fBetweenOwnerWithTargetX2 >= m_TargetDistX2 )
return false;
m_pTarget = pCharacter;
m_TargetDistX2 = m_fBetweenOwnerWithTargetX2;
return false; // continue 유지 목적?
}
protected:
FLOAT m_TargetDistX2;
};
//─────────────────────────────────────────
// <LowHPRatioTargetFinder>
//
class LowHPRatioTargetFinder : public TargetFinder
{
public: LowHPRatioTargetFinder() : m_LowHPRatio(ULONG_MAX)
{}
//_NA_0_20100222_UNIT_TRIGGERS_FRIEND_MONSTER
LowHPRatioTargetFinder(const TargetFinderArg& arg)
: TargetFinder(arg),
m_LowHPRatio(ULONG_MAX) {}
public:
virtual bool operator () ( Character* const pCharacter )
{
if( !IsCheckTargetCasebyAlive( pCharacter ) )
return false;
DWORD targetHP = pCharacter->GetMaxHP();
targetHP = targetHP ? targetHP : 1;
const DWORD targetHPRatio = (DWORD)( pCharacter->GetHP() * 100 / targetHP );
if( targetHPRatio >= m_LowHPRatio )
return false;
m_pTarget = pCharacter;
m_LowHPRatio = targetHPRatio;
// not found --> continue
return false; // continue 유지 목적?
}
private :
DWORD m_LowHPRatio;
};
//─────────────────────────────────────────
// <LowHPTargetFinder>
//
class LowHPTargetFinder : public TargetFinder
{
public: LowHPTargetFinder() : m_LowHP(ULONG_MAX) {}
//_NA_0_20100222_UNIT_TRIGGERS_FRIEND_MONSTER
LowHPTargetFinder(const TargetFinderArg& arg)
: TargetFinder(arg),
m_LowHP(ULONG_MAX) {}
public:
virtual bool operator () ( Character* const pCharacter )
{
if( !IsCheckTargetCasebyAlive( pCharacter ) )
return false;
const DWORD targetHP = pCharacter->GetHP();
if( targetHP >= m_LowHP )
return false;
m_pTarget = pCharacter;
m_LowHP = targetHP;
// not found --> continue
return false; // continue 유지 목적?
}
private :
DWORD m_LowHP;
};
//─────────────────────────────────────────
// <LowLevelTargetFinder>
//
class LowLevelTargetFinder : public TargetFinder
{
public: LowLevelTargetFinder() : m_LowLevel(USHRT_MAX) {}
//_NA_0_20100222_UNIT_TRIGGERS_FRIEND_MONSTER
LowLevelTargetFinder(const TargetFinderArg& arg)
: TargetFinder(arg),
m_LowLevel(USHRT_MAX) {}
public :
virtual bool operator () ( Character* const pCharacter )
{
if( !IsCheckTargetCasebyAlive( pCharacter ) )
return false;
const LEVELTYPE targetLevel = pCharacter->GetLevel();
if( targetLevel >= m_LowLevel )
return false;
m_pTarget = pCharacter;
m_LowLevel = targetLevel;
// not found --> continue
return false; // continue 유지 목적?
}
private :
LEVELTYPE m_LowLevel;
};
//─────────────────────────────────────────
// <HighMPTargetFinder>
//
class HighMPTargetFinder : public TargetFinder
{
public: HighMPTargetFinder() : m_HighMP(0) {}
//_NA_0_20100222_UNIT_TRIGGERS_FRIEND_MONSTER
HighMPTargetFinder(const TargetFinderArg& arg)
: TargetFinder(arg),
m_HighMP(0) {}
public:
virtual bool operator () ( Character* const pCharacter )
{
if( !IsCheckTargetCasebyAlive( pCharacter ) )
return false;
const DWORD targetMP = pCharacter->GetMP();
if( targetMP <= m_HighMP )
return false;
m_pTarget = pCharacter;
m_HighMP = targetMP;
// not found --> continue
return false; // continue 유지 목적?
}
private :
DWORD m_HighMP;
};
//─────────────────────────────────────────
// <HighMPTargetFinder>
//
class DeadTargetFinder : public TargetFinder
{
public: DeadTargetFinder() {}
//_NA_0_20100222_UNIT_TRIGGERS_FRIEND_MONSTER
DeadTargetFinder(const TargetFinderArg& arg) : TargetFinder(arg) {}
public:
virtual bool operator () ( Character* const pCharacter )
{
if( !CheckTarget( pCharacter ) )
return false;
if( pCharacter->IsAlive() )
return false;
m_pTarget = pCharacter;
return true; // 가장 죽은...이라는 의미는 없으므로 바로 true
}
};
//─────────────────────────────────────────
// 해당 regenID(몬스터)
//_NA_0_20100222_UNIT_TRIGGERS_FRIEND_MONSTER
class UnitIDTargetFinder : public TargetFinder
{
public:
UnitIDTargetFinder() {}
UnitIDTargetFinder(const TargetFinderArg& arg)
: TargetFinder(arg),
unitID_(arg.unitID_) {}
virtual bool operator () (Character* const pCharacter)
{
if (!IsCheckTargetCasebyAlive(pCharacter))
return false;
if (pCharacter->IsEqualObjectKind(NPC_OBJECT) == FALSE)
return false;
NPC* const npc = static_cast<NPC*>(pCharacter);
const REGENID unitID = npc->GetRegenID();
if (unitID == unitID_)
{
m_pTarget = pCharacter;
return true;
}
return false;
}
protected:
REGENID unitID_;
};
class MapNpcObjectTargetFinder : public TargetFinder
{
public:
MapNpcObjectTargetFinder() {}
MapNpcObjectTargetFinder(const TargetFinderArg& arg)
: TargetFinder(arg),
mapobjectID_(arg.mapobjectID_) {}
virtual bool operator () (Character* const pCharacter)
{
if (!IsCheckTargetCasebyAlive(pCharacter))
return false;
if (pCharacter->IsEqualObjectKind(MAPNPC_OBJECT) == FALSE)
return false;
MapNpc* const npc = static_cast<MapNpc*>(pCharacter);
const DWORD mapobjectID = npc->GetMapObjectID();
if (mapobjectID == mapobjectID_)
{
m_pTarget = pCharacter;
return true;
}
return false;
}
protected:
DWORD mapobjectID_;
};
class NearestMonsterCodeTargetFinder : public TargetFinder
{
public:
NearestMonsterCodeTargetFinder() : target_distX2_(999999.f) {}
NearestMonsterCodeTargetFinder(const TargetFinderArg& arg)
: TargetFinder(arg),
target_distX2_(999999.f),
monster_code_(arg.npc_code_) {}
virtual bool operator () (Character* const pCharacter)
{
if (!IsCheckTargetCasebyAlive(pCharacter))
return false;
if (pCharacter->IsEqualObjectKind(NPC_OBJECT) == FALSE)
return false;
const NPC* const npc = static_cast<NPC*>(pCharacter);
const BASE_NPCINFO* const base_info = npc->GetBaseInfo();
const MONSTERCODE monster_code = base_info->m_MonsterCode;
if (monster_code == monster_code_)
{
if( m_fBetweenOwnerWithTargetX2 >= target_distX2_ )
return false;
target_distX2_ = m_fBetweenOwnerWithTargetX2;
m_pTarget = pCharacter;
}
return false;
}
protected:
FLOAT target_distX2_;
MONSTERCODE monster_code_;
};