DragonNest/Server/DNGameServer/DnMonsterActor.h
2024-12-19 09:48:26 +08:00

408 lines
16 KiB
C++

#pragma once
#include "DnActor.h"
#include "DnMonsterState.h"
#include "MAAiBase.h"
#include "MAAiReceiver.h"
#include "DnDropItem.h"
#include "PerfCheck.h"
class CDnMonsterActor : public CDnActor, public MAAiReceiver, public CDnMonsterState
{
public:
CDnMonsterActor( CMultiRoom *pRoom, int nClassID );
virtual ~CDnMonsterActor();
static int s_nPositionRevisionTime;
protected:
SOBB m_GenerationArea;
DNVector(CDnItem::DropItemStruct) m_VecDropItemList;
int m_nMonsterClassID;
TDUNGEONDIFFICULTY m_AIDifficult;
float m_fScale;
float m_fRevisionWeight;
int m_nMonsterWeightTableID;
bool m_bTimeMonster; // 특정 시간이 지나면 사라지는 몬스터인가.?
bool m_bNoDamage;
LOCAL_TIME m_nDestroyTime; // 얼마나 시간이 지난후 사라질지?
ElementEnum m_eElementType; // 몬스터는 플레이어와는 다르게 자체적으로 ElementType 을 갖고 있다.
#if defined( PRE_MOD_LOCK_TARGET_LOOK )
int m_nLockLookEventArea;
#endif // #if defined( PRE_MOD_LOCK_TARGET_LOOK )
bool m_bLockLookTarget;
char* m_pszCanBumpActionName;
bool m_bCanBumpWall; // 벽에 부딪혀서 특정 액션 수행할지 플래그
LOCAL_TIME m_LastSendMoveMsg;
float m_fRotateResistance;
int m_nPartyComboCount;
int m_nPartyComboDelay;
DnActorHandle m_hPartyHitActor;
bool m_bIsTriggerMonster; // 트리거에 의해 생성된 몬스터
int m_iTriggerRandomSeed; // 트리거에 의해 생성된 몬스터 RandomSeed 값
#ifdef PRE_MOD_DARKLAIR_RECONNECT
int m_nEventAreaUniqueID; // 트리거에서 생성할 때의 EventAreaID
#endif // PRE_MOD_DARKLAIR_RECONNECT
DnPropHandle m_hProp;
UINT m_uiForcePositionRevisionTick;
UINT m_uiPrevForcePositionRevisionTick;
float m_fForcePositionRevisionDelta;
bool m_bEnableDropItem;
DnActorHandle m_hSummonerPlayerActor;
bool m_bSuicideWhenSummonerDie;
bool m_bFollowSummonerStage;
DWORD m_dwSummonerActorID;
int m_iSummonGroupID;
float m_fLimitSummonerDistanceSQ;
int m_nBirthAreaHandle;
bool m_bSummoned;
bool m_bReCreatedFollowStageMonster;
std::map<int,int> m_mUseSkillCount;
#ifdef PRE_ADD_MONSTER_CATCH
string m_strCatchBoneName;
string m_strTargetActorCatchBoneName;
string m_strCatchedActorAction;
int m_iCatchedActorActionIndex;
struct S_CATCH_ACTOR_INFO
{
DnActorHandle hCatchedActor;
int iCatchCantMoveBlowID;
int iCatchCantActionBlowID;
S_CATCH_ACTOR_INFO( void ) : iCatchCantMoveBlowID( 0 ), iCatchCantActionBlowID( 0 ) {};
};
vector<S_CATCH_ACTOR_INFO> m_vlCatchedActors;
set<DWORD> m_setCatchCheckedActorIDs;
#endif //#ifdef PRE_ADD_MONSTER_CATCH
std::map<int,int> m_mOrderCount;
#if defined( PRE_FIX_MOVEBACK )
bool m_bNearMoveBack; // 액션 실행시 처리
bool m_bPrevMoveBack; // 강제로 Move_Back 실행
#endif
int m_nAutoRecallRange;
bool m_bChangeAxisOnFinishAction;
#ifdef PRE_ADD_TRANSFORM_MONSTER_ACTOR
int m_nSwapActorID;
#endif
protected:
void GenerationDropItem();
// Movement Message
virtual void OnDrop( float fCurVelocity );
virtual void OnStop( EtVector3 &vPosition );
virtual void OnBeginNaviMode();
void DropItems();
virtual void ProcessDie( LOCAL_TIME LocalTime, float fDelta );
virtual void OnHitSuccess( LOCAL_TIME LocalTime, DnActorHandle hActor, HitStruct *pStruct );
// 한번의 HitSignal 체크가 끝나고 불려진다. 때리는 놈 입장에서 콜
virtual void OnHitFinish( LOCAL_TIME LocalTime, HitStruct *pStruct );
void CalcMonsterWeightIndex();
void CalcItemDropTableID();
std::string GetAIFileName();
bool CheckPositionRevision();
bool CheckSignalPositionRevision( float fDelta );
void ResetPositionRevision();
void ProcessPositionRevision( float fDelta );
void ProcessPartyCombo( LOCAL_TIME LocalTime, float fDelta );
void OnPartyCombo( DnActorHandle hHitter, int nComboDelay );
void Process_AutoRecallRange();
private:
public:
void SendProjectile( CDnProjectile *pProjectile, ProjectileStruct* pStruct, MatrixEx& LocalCross, int iSignalIndex );
// #15557 이슈 관련. 몬스터가 발사체에서 발사체를 쏘는 경우.
// 기본적으로 클라이언트의 LocalPlayerActor 가 보내는 내용과 같다.
// 클라이언트 측에선 파티원이 쏜 발사체와 역시 동일하게 패킷을 처리한다.
// 따라서 반드시 CDnLocalPlayerActor::OnProjectile() 쪽도 같이 수정해야 함.
void SendProjectileFromProjectile( CDnProjectile* pProjectile, int nSignalIndex );
void SetGenerationArea( SOBB &Box );
SOBB *GetGenerationArea();
void SetBirthAreaHandle( int nIndex ) { m_nBirthAreaHandle = nIndex; }
int GetBirthAreaHandle() { return m_nBirthAreaHandle; }
virtual void SetTeam( int nValue );
void SetAIDifficult( TDUNGEONDIFFICULTY Level ) { m_AIDifficult = Level; }
void SetPropHandle( DnPropHandle hProp ){ m_hProp = hProp; }
void SetMonsterClassID( int nValue ) { m_nMonsterClassID = nValue; }
int GetMonsterClassID() { return m_nMonsterClassID; }
int GetMonsterWeightTableID() { return m_nMonsterWeightTableID; }
float GetThreatRange();
float GetCognizanceThreatRange();
float GetCognizanceThreatRangeSq();
void EnableNoDamage( bool bEnable ) { m_bNoDamage = bEnable; }
bool IsEnableNoDamage() { return m_bNoDamage; }
void SetScale( float fValue );
float GetScale() { return m_fScale; }
virtual float GetWeight();
virtual float GetRotateAngleSpeed();
virtual bool IsMonsterActor(){ return true; }
virtual bool IsSummonedMonster(){return m_bSummoned;}
virtual bool IsCannonMonsterActor(){ return false; }
DnPropHandle GetPropHandle(){ return m_hProp; }
void SetTimeMonster(bool bEnable, LOCAL_TIME nTime) { m_bTimeMonster = bEnable; m_nDestroyTime = nTime; }
LOCAL_TIME GetRemainDestroyTime( void ) { return m_nDestroyTime; };
bool _bIsCheckVaildPosition( EtVector3& vTargetPos );
void _SendCmdMoveNavi( EtVector3& vTargetPos, float fMinDistance, const char* szActionName, int nLoopCount );
int GetUseSkillCount( int iSkillID );
// Actor Command
virtual void CmdMove( EtVector3 &vPos, const char *szActionName, int nLoopCount = 0, float fBlendFrame = 3.f );
virtual void CmdMove( DnActorHandle hActor, float fMinDistance, const char *szActionName, int nLoopCount = 0, float fBlendFrame = 3.f );
virtual void CmdMoveNavi( DnActorHandle hActor, float fMinDistance, const char *szActionName, int nLoopCount = 0, float fBlendFrame = 3.f );
virtual void CmdMoveNavi( EtVector3& vTargetPos, float fMinDistance, const char *szActionName, int nLoopCount = 0, float fBlendFrame = 3.f );
virtual void CmdStop( const char *szActionName, int nLoopCount = 0, float fBlendFrame = 3.f, float fStartFrame = 0.f );
virtual void CmdLook( EtVector2 &vVec, bool bForce = false );
virtual void CmdLook( DnActorHandle hActor, bool bLock = true );
virtual void CmdAction( const char *szActionName, int nLoopCount = 0, float fBlendFrame = 3.f, bool bCheckOverlapAction = true, bool bFromStateBlow = false, bool bSkillChain = false );
virtual int CmdAddStateEffect( const CDnSkill::SkillInfo* pParentSkill, STATE_BLOW::emBLOW_INDEX emBlowIndex, int nDurationTime, const char *szParam, bool bOnPlayerInit = false, bool bCheckCanBegin = true , bool bEternity = false );
virtual void CmdRemoveStateEffect( STATE_BLOW::emBLOW_INDEX emBlowIndex, bool bRemoveFromServerToo = true );
virtual void SendRemoveStateEffect( STATE_BLOW::emBLOW_INDEX emBlowIndex );
virtual void CmdSuicide( bool bDropItem, bool bDropExp );
virtual void CmdMixedAction( const char *szActionBone, const char *szMaintenanceBone, const char *szActionName, float fFrame, float fBlendFrame = 3.f );
virtual void CmdWarp( EtVector3 &vPos, EtVector2 &vLook, CDNUserSession* pGameSession=NULL, bool bCheckPlayerFollowSummonedMonster=false );
virtual void SyncClassTime( LOCAL_TIME LocalTime );
virtual bool Initialize();
virtual void ResetActor();
virtual bool IsHittable( DnActorHandle hHitter, LOCAL_TIME LocalTime, HitStruct *pHitSignal = NULL, int iHitUniqueID = -1 );
// Actor Message
virtual void ProcessAI(LOCAL_TIME LocalTime, float fDelta);
virtual void Process( LOCAL_TIME LocalTime, float fDelta );
virtual void ProcessLook( LOCAL_TIME LocalTime, float fDelta );
virtual void OnDamage( CDnDamageBase *pHitter, SHitParam &HitParam, HitStruct *pHitStruct );
virtual void OnDie( DnActorHandle hHitter );
virtual void OnBeginStateBlow( DnBlowHandle hBlow );
virtual void ReTransmitSlaveMsg(CDNUserSession* pBreakIntoSession); // 동기맞추기위해 난입 유저에게 보내줄때 사용.
virtual void SlaveOf( DWORD dwSummonerActorUniqueID, bool bSummoned = false, bool bSuicideWhenSummonerDie = false, bool bFollowSummonerStage = false, bool bReCreateFollowStageMonster = false );
virtual void SlaveRelease( void );
virtual void AttachWeapon( DnWeaponHandle hWeapon, int nEquipIndex = 0, bool bDelete = false );
virtual void RequestDamageFromStateBlow( DnBlowHandle hFromBlow, int iDamage );
// MASkillUser
#ifdef PRE_FIX_GAMESERVER_OPTIMIZE
virtual bool AddSkill( int nSkillTableID, int nLevel = 1, int iSkillLevelApplyType = CDnSkill::PVE );
virtual void OnAddSkill( DnSkillHandle hSkill, bool isInitialize = false );
#endif // #ifdef PRE_FIX_GAMESERVER_OPTIMIZE
virtual bool ExecuteSkill( DnSkillHandle hSkill, LOCAL_TIME LocalTime, float fDelta );
virtual CDnSkill::UsingResult UseSkill( int nSkillTableID, bool bCheckValid = true, bool bAutoUseFromServer = false, int nLuaSkillIndex=-1 );
// TransAction Message
virtual void OnChangeAction( const char *szPrevAction );
virtual void OnFinishAction(const char* szPrevAction, LOCAL_TIME time);
virtual bool OnPreAiProcess(const char* szPrevAction, LOCAL_TIME time) { return false; }
void _CheckActionWithProcessPassiveActionSkill( const char* szPrevAction );
// AI
virtual bool bIsAILook(){ return (m_pAi) ? m_pAi->bIsAILook() : false; }
virtual bool bIsTurnOnAILook(){ return true; }
virtual bool bIsProjectileTargetSignal(){ return m_pAi ? m_pAi->bIsProjectileTargetSignal() : false; }
virtual bool OnAINonTarget();
virtual void OnBumpWall();
// CDnActionBase
virtual void OnSignal( SignalTypeEnum Type, void *pPtr, LOCAL_TIME LocalTime, LOCAL_TIME SignalStartTime, LOCAL_TIME SignalEndTime, int nSignalIndex );
// 플레이어가 소환하는 렐릭 몬스터 타입(CDnClericRelicMonster)이면 true
virtual bool IsClericRelicMonster( void ) { return false; };
// 로그관련 임시코드 090226
//void QueryLogStage(int nRoomID, int nMapIndex);
ElementEnum GetElementType( void ) { return m_eElementType; };
void SetMonsterElementType( ElementEnum eType ) { m_eElementType = eType; }
// AI
void SetNaviDestination( SOBB* pOBB, UINT uiMoveFrontRate );
int GetWaitOrderCount( int iSkillID );
void AddWaitOrderCount( int iSkillID );
void DelWaitOrderCount( int iSkillID );
// Trigger
void SetTriggerMonster( const int iRandomSeed ){ m_bIsTriggerMonster = true; m_iTriggerRandomSeed = iRandomSeed; }
bool bIsTriggerMonster(){ return m_bIsTriggerMonster; }
int GetTriggerRandomSeed(){ return m_iTriggerRandomSeed; }
#ifdef PRE_MOD_DARKLAIR_RECONNECT
void SetEventAreaUniqueID( int nEventAreaUniqueID ) { m_nEventAreaUniqueID = nEventAreaUniqueID; }
int GetEventAreaUniqueID() { return m_nEventAreaUniqueID; }
#endif // PRE_MOD_DARKLAIR_RECONNECT
void EnableDropItem( bool bEnable ) { m_bEnableDropItem = bEnable; }
// 소환 몬스터에게 능력치 복사할 때 따로 백업했다가 복구해줄 때만 쓰임.
void SetRevisionWeight( float fRevisionWeight ) { m_fRevisionWeight = fRevisionWeight; };
DnActorHandle GetSummonerPlayerActor( void ) { return m_hSummonerPlayerActor; };
// 몬스터 어그로 리셋 (#21673)
void ResetAggro( void );
void ResetAggro( DnActorHandle hActor );
#ifdef PRE_ADD_MONSTER_CATCH
void ProcessCatchActor( LOCAL_TIME LocalTime, float fDelta );
void CatchActor( CatchActorStruct* pCatchActor, int nSignalIndex );
void _CatchThisActor( DnActorHandle hResultActor, int nSignalIndex );
void ReleaseAllActor( void );
void ReleaseThisActor( S_CATCH_ACTOR_INFO& CatchActorInfo );
void ReleaseThisActor( DnActorHandle hActor );
#endif // #ifdef PRE_ADD_MONSTER_CATCH
#ifdef PRE_ADD_TRANSFORM_MONSTER_ACTOR
virtual void SwapActor( int nActorIndex ) {}
#endif
bool IsFollowSummonerStage( void ) { return m_bFollowSummonerStage; };
void SetLimitSummonerDistance( float fLimitSummonerDistance ) { m_fLimitSummonerDistanceSQ = fLimitSummonerDistance*fLimitSummonerDistance; };
void SetSummonGroupID( int iSummonGroupID ) { m_iSummonGroupID = iSummonGroupID; };
int GetSummonGroupID( void ) { return m_iSummonGroupID; };
void SetAutoRecallRange( int nAutoRecallRange ) { m_nAutoRecallRange = nAutoRecallRange; }
protected:
LOCAL_TIME m_RequestSummonTime; //Summon몬스터 생성 시간
public:
void SetRequestSummonTime(LOCAL_TIME localTime) { m_RequestSummonTime = localTime; }
LOCAL_TIME GetRequestSummonTime() { return m_RequestSummonTime; }
#if defined( PRE_FIX_MOVEBACK )
void SetPrevMoveBack( bool bMoveBack ) { m_bPrevMoveBack = bMoveBack; }
void SetNearMoveBack() { m_bNearMoveBack = m_bPrevMoveBack; }
bool IsNearMoveBack() { return m_bNearMoveBack; }
bool IsPrevMoveBack() { return m_bPrevMoveBack; }
#endif
#if defined(PRE_FIX_51048)
protected:
struct PassiveStateEffectInfo
{
const CDnSkill::SkillInfo* pParentSkill;
STATE_BLOW::emBLOW_INDEX emBlowIndex;
int nDurationTime;
std::string szParam;
PassiveStateEffectInfo()
{
pParentSkill = NULL;
emBlowIndex = STATE_BLOW::BLOW_NONE;
nDurationTime = 0;
}
};
std::list<PassiveStateEffectInfo> m_PassiveStateEffectInfoList;
//몬스터 생성시점에 이 플래그가 켜저 있으면 리스트에 담았다가 SendGameGenerationMonsterMsg 호출후에 ApplyPassiveStateEffect함수 호출로 상태효과 적용 시킨다.
//플래그가 설정 되어 있지 않으면 기존과 동일하게..
bool m_EnablePassiveStateEffect;
public:
//패시브 상태효과를 리스트에 담아서 나중에 처리 할지 여부를 설정한다.
void SetEnablePassiveStateEffectList(bool bSet) { m_EnablePassiveStateEffect = bSet; }
bool GetEnablePassiveStateEffectList() { return m_EnablePassiveStateEffect; }
void AddPassiveStateEffectInfo(PassiveStateEffectInfo& stateEffectInfo); //ApplyPassiveSkill에서
void InitPassiveStateEffectInfo(); //리스트 초기화
void ApplyPassiveStateEffect(); //패시브 스킬의 상태효과 적용.
virtual bool ApplyPassiveSkill( DnSkillHandle hSkill, bool isInitialize = false );
#endif // PRE_FIX_51048
#if defined(PRE_FIX_61382)
// 상태효과 측에서 데미지를 가하는 경우. 우선 데미지 반사에서만 쓰임. 데미지 값은 양수로 받는다. #23104
virtual void RequestDamageFromStateBlow( DnBlowHandle hFromBlow, int iDamage, CDnDamageBase::SHitParam* pHitParam = NULL );
#endif // PRE_FIX_61382
protected:
bool m_isPuppetSummonMonster;
public:
void SetPuppetSummonMonster(bool bFlag) { m_isPuppetSummonMonster = bFlag; }
bool IsPuppetSummonMonster() { return m_isPuppetSummonMonster; }
#if defined(PRE_FIX_64312)
public:
void SendApplySummonMonsterExSkill(int nBaseSkillID, int nLevel, int nSelectedType, DWORD dwMasterUniqueID, int nMasterExSkillID);
#endif // PRE_FIX_64312
};
template <class RenderType, class DamageType>
class TDnMonsterActor : public CDnMonsterActor, virtual public RenderType, virtual public DamageType
{
public:
TDnMonsterActor( CMultiRoom *pRoom, int nClassID ) : CDnMonsterActor( pRoom, nClassID )
{
}
virtual ~TDnMonsterActor() {}
protected:
public:
virtual void Process( LOCAL_TIME LocalTime, float fDelta ) {
CDnMonsterActor::Process( LocalTime, fDelta );
RenderType::PreProcess( LocalTime, fDelta );
// #39347 PreProcess 호출되고 나서 AniDistance 값이 다시 생김.
if( 0 < GetCantXZMoveSEReferenceCount() )
m_vAniDistance.x = m_vAniDistance.z = 0.0f;
m_pMovement->Process( LocalTime, fDelta );
RenderType::Process( m_Cross, LocalTime, fDelta );
}
virtual void Look( EtVector2 &vVec, bool bForceRotate=true )
{
MAMovementInterface::Look( vVec, bForceRotate );
if( bForceRotate )
{
if( strstr( m_hActor->GetCurrentAction(), "Turn" ) )
{
CmdAction( "Stand" );
}
}
}
};
class IBoostPoolDnMonsterActor : public CDnMonsterActor, public TBoostMemoryPool< IBoostPoolDnMonsterActor >
{
public:
IBoostPoolDnMonsterActor( CMultiRoom *pRoom, int nClassID ):CDnMonsterActor( pRoom, nClassID ){}
virtual ~IBoostPoolDnMonsterActor(){}
};