knightonline/server/AIServer/Npc.h

458 lines
14 KiB
C++

#pragma once
#include "NpcTable.h"
#include "NpcMagicProcess.h"
#define MAX_PATH_SIZE 100
#define NPC_MAX_USER_LIST 5
#define NPC_ATTACK_SHOUT 0
#define NPC_SUBTYPE_LONG_MON 1
#define NPC_TRACING_STEP 100
#define NPC_HAVE_USER_LIST 100
#define NPC_HAVE_ITEM_LIST 6
#define NPC_PATTEN_LIST 5
#define NPC_PATH_LIST 50
#define NPC_MAX_PATH_LIST 10000
#define NPC_EXP_RANGE 50.0f
#define NPC_EXP_PERSENT 50
#define NPC_SECFORMETER_MOVE 4
#define NPC_SECFORMETER_RUN 4
#define NPC_VIEW_RANGE 100.0f
#define MAX_MAGIC_TYPE3 20
#define MAX_MAGIC_TYPE4 9
struct _NpcSkillList
{
short sSid;
uint8 tLevel;
uint8 tOnOff;
};
struct _NpcDamagedList
{
uint16 GetID;
int Damage;
uint32 lastdamagedt;
INLINE void Reset()
{
GetID = -1;
Damage = 0;
lastdamagedt = 0;
}
};
struct _NpcGiveItem
{
int sSid; // item serial number
short count; // item 갯수(돈은 단위)
};
struct _Target
{
uint16 id; // 공격대상 User uid
bool bSet;
float x; // User의 x pos
float y; // User의 y pos
float z; // User의 z pos
};
struct _PattenPos
{
short x;
short z;
};
struct _PathList
{
_PattenPos pPattenPos[NPC_MAX_PATH_LIST];
};
struct _TargetHealer
{
short sNID; // npc nid
short sValue; // 점수
};
class MAP;
#include "../GameServer/Unit.h"
enum MonSearchType
{
MonSearchSameFamily, // find any available mobs of the same family
MonSearchAny, // find any available mob
MonSearchNeedsHealing // find any mob that needs healing
};
enum CloseTargetResult
{
CloseTargetInvalid,
CloseTargetNotInRange,
CloseTargetInGeneralRange,
CloseTargetInAttackRange
};
enum NpcSpecialType
{
NpcSpecialTypeNone = 0,
NpcSpecialTypeCycleSpawn = 7,
NpcSpecialTypeKarusWarder1 = 90,
NpcSpecialTypeKarusWarder2 = 91,
NpcSpecialTypeElmoradWarder1 = 92,
NpcSpecialTypeElmoradWarder2 = 93,
NpcSpecialTypeKarusKeeper = 98,
NpcSpecialTypeElmoradKeeper = 99
};
struct __Vector3;
class CNpc : public Unit
{
public:
uint16 GetID() { return m_sNid; }
INLINE uint16 GetProtoID() { return GetProto()->m_sSid; }
std::string & GetName() { return GetProto()->m_strName; }
int32 GetHealth() { return m_iHP; }
int32 GetMaxHealth() { return GetProto()->m_iMaxHP; }
int32 GetMana() { return m_sMP; }
int32 GetMaxMana() { return GetProto()->m_sMaxMP; }
void GetInOut(Packet &, uint8) {}
void AddToRegion(int16 sRegionX, int16 sRegionZ) {}
void HpChange(int amount, Unit *pAttacker = nullptr, bool bSendToGameServer = true);
void MSpChange(int amount) {}
void NpcCalling(float fDis,float fDistance, __Vector3 oPos, __Vector3 cPost);
INLINE CNpcTable * GetProto() { return m_proto; }
INLINE uint8 GetType() { return GetProto()->m_tNpcType; }
INLINE bool isHealer() { return GetType() == NPC_HEALER; }
INLINE bool isGuard()
{
return GetType() == NPC_GUARD || GetType() == NPC_PATROL_GUARD || GetType() == NPC_STORE_GUARD;
}
INLINE bool isGate()
{
return GetType() == NPC_GATE
|| GetType() == NPC_GATE2
|| GetType() == NPC_PHOENIX_GATE
|| GetType() == NPC_SPECIAL_GATE
|| GetType() == NPC_VICTORY_GATE
|| GetType() == NPC_GATE_LEVER
|| GetType() == NPC_BORDER_MONUMENT;
}
INLINE bool isArtifact()
{
return GetType() == NPC_ARTIFACT
|| GetType() == NPC_DESTROYED_ARTIFACT
|| GetType() == NPC_ARTIFACT1
|| GetType() == NPC_ARTIFACT2
|| GetType() == NPC_ARTIFACT3
|| GetType() == NPC_ARTIFACT4;
}
INLINE bool isNonAttackingObject() { return isGate() || GetType() == NPC_GATE_LEVER || isArtifact() || GetType() == NPC_SCARECROW || GetType() == NPC_BORDER_MONUMENT || GetType() == NPC_CHAOS_STONE; }
INLINE bool isNonAttackableObject() { return GetType() == NPC_GATE_LEVER || GetType() == NPC_BORDER_MONUMENT; }
INLINE bool isDead() { return m_NpcState == NPC_DEAD || m_iHP <= 0; }
INLINE bool isAlive() { return !isDead(); }
INLINE bool isMonster() { return m_bMonster; }
INLINE int GetMyPath() { return (m_sRealPathCount < 0) ? -m_sRealPathCount : m_sRealPathCount;}
INLINE bool hasTarget() { return m_Target.bSet; }
CNpcTable *m_proto;
_Target m_Target; // 공격할 유저 저장,,
short m_ItemUserLevel; // 죽을때 매직 이상 아이템를 떨구기위해 참조해야하는 유저의레벨
_NpcDamagedList m_DamagedUserList[NPC_HAVE_USER_LIST]; // max NPC_HAVE_USER_LIST?
std::recursive_mutex m_damageListLock;
int m_TotalDamage;
short m_sMaxDamageUserid; // 나에게 최고의 데미지를 준 유저의 아이디 저장..
_PathList m_PathList; // Npc의 패스 리스트
_PattenPos m_pPattenPos; // Npc의 패턴,,
//int m_iPattenNumber; // 현재의 패턴번호
short m_iPattenFrame; // 패턴의 현재 위치..
uint8 m_byMoveType; // NPC의 행동타입(이동관련)
uint8 m_byInitMoveType; // NPC의 초기 행동타입(이동관련)
short m_sMaxPathCount, m_sRealPathCount; // NPC의 PathList Max Count
bool nIsPet;
std::string strPetName, strUserName;
uint16 UserId;
uint64 nSerial;
bool m_bFirstLive; // NPC 가 처음 생성되는지 죽었다 살아나는지 판단.
uint8 m_OldNpcState, m_NpcState;
short m_sNid;
float m_nInitX; // 처음 생성된 위치 X
float m_nInitY; // 처음 생성된 위치 Y
float m_nInitZ; // 처음 생성된 위치 Z
float m_fPrevX; // Prev X Pos;
float m_fPrevY; // Prev Y Pos;
float m_fPrevZ; // Prev Z Pos;
int m_DamagedUserListCount; // dmgx
//
// PathFind Info
//
short m_min_x;
short m_min_y;
short m_max_x;
short m_max_y;
typedef struct { long cx; long cy; } Size;
Size m_vMapSize;
float m_fStartPoint_X, m_fStartPoint_Y;
float m_fEndPoint_X, m_fEndPoint_Y;
short m_sStepCount;
CPathFind m_vPathFind;
_PathNode *m_pPath;
int m_nInitMinX; // 초기위치
int m_nInitMinY;
int m_nInitMaxX;
int m_nInitMaxY;
time_t m_fHPChangeTime;
time_t m_tFaintingTime;
time_t LastChangeTimeCC;
//----------------------------------------------------------------
// MONSTER DB 쪽에 있는 변수들
//----------------------------------------------------------------
short m_sSize; // 캐릭터의 비율(100 퍼센트 기준)
int m_iWeapon_1; // 착용 무기
int m_iWeapon_2; // 착용 무기
uint8 m_byActType; // 행동패턴
uint8 m_byRank; // 작위
uint8 m_byTitle; // 지위
int m_iSellingGroup; // 아이템 그룹(물건매매 담당 NPC의 경우만)
int m_iMaxHP; // 최대 HP
short m_sMaxMP; // 최대 MP
short m_sAttack; // 공격값(지금 사용하지 않음..)
short m_sAttackDelay; // 공격딜레이
short m_sSpeed; // 이동속도
float m_fSpeed_1; // 기본 이동 타입 (1초에 갈 수 있는 거리)
float m_fSpeed_2; // 뛰는 이동 타입.. (1초에 갈 수 있는 거리)
short m_sStandTime; // 서있는 시간
uint8 m_bySearchRange; // 적 탐지 범위
uint8 m_byAttackRange; // 사정거리
uint8 m_byTracingRange; // 추격 거리
int m_iMoney; // 떨어지는 돈
int m_iItem; // 떨어지는 아이템
int m_iHP; // 현재 HP
short m_sMP; // 현재 MP
float m_fSecForMetor; // 초당 갈 수 있는 거리..
//----------------------------------------------------------------
// MONSTER AI에 관련된 변수들
//----------------------------------------------------------------
uint8 m_tNpcAttType; // 공격 성향 : 선공(1), 후공(0)
bool m_bHasFriends; // When set, monsters behave in groups (defined by their family type) and will seek out help from nearby similar mobs.
uint8 m_byAttackPos; // User의 어느 부분에서 공격하느지를 판단(8방향)
uint8 m_byBattlePos; // 어떤 진형을 선택할 것인지를 판단..
bool m_byGateOpen; // 성문일 경우에.. 사용... Gate Npc Status -> 1 : open 0 : close
uint8 m_byMaxDamagedNation; // 나를 죽인 유저의 국가를 저장.. (1:카루스, 2:엘모라드)
uint8 m_byObjectType; // 보통은 0, object타입(성문, 레버)은 1
uint8 m_byDungeonFamily; // 던젼에서 같은 패밀리 묶음 (같은 방)
NpcSpecialType m_bySpecialType; // 몬스터의 형태가 변하는지를 판단(0:변하지 않음, 1:변하는 몬스터,
// 2:죽는경우 조정하는 몬스터(대장몬스터 죽을경우 성문이 열림),
// 3:대장몬스터의 죽음과 관련이 있는 몬스터(대장몬스터가 죽으면 관계되는 몬스터는 같이 죽도록)
// 4:변하면서 죽는경우 조정하는 몬스터 (m_sControlSid)
// 5:처음에 죽었있다가 출현하는 몬스터,,
// 6:일정시간이 지난 후에 행동하는 몬스터,,
// 100:죽었을때 데미지를 많이 입힌 유저를 기록해 주세여
uint8 m_byTrapNumber; // 던젼에서 트랩의 번호,,
uint8 m_byChangeType; // 0:정상상태, 1:변하기 위한 준비, 2:다른몬스터로 변함, 3:몬스터의 출현, 100:몬스터의 죽음
uint8 m_byRegenType; // 0:정상적으로 리젠이 됨.. , 1:한번 죽으면 리젠이 안되는 특수 몸, 2:리젠이 안됨
uint8 m_byDeadType; // 0:살아 있는 경우, 100:전쟁이벤트중 죽은 경우
//----------------------------------------------------------------
// MONSTER_POS DB 쪽에 있는 변수들
//----------------------------------------------------------------
time_t m_Delay; // this doesn't really need to be time_t, but we'll use it (at least for now) for consistency
time_t m_fDelayTime; // Npc Thread체크 타임...
uint8 m_byType;
int m_sRegenTime; // NPC 재생시간
int16 m_byDirection;
int m_nLimitMinX; // 활동 영역
int m_nLimitMinZ;
int m_nLimitMaxX;
int m_nLimitMaxZ;
bool m_bIsEventNpc;
float m_fAdd_x;
float m_fAdd_z;
float m_fBattlePos_x;
float m_fBattlePos_z;
float m_fSecForRealMoveMetor; // 초당 갈 수 있는 거리..(실제 클라이언트에 보내주는 거리)
bool m_bPathFlag; // 패스 파인드 실행여부 체크 변수..
//----------------------------------------------------------------
// NPC 이동 관련
//----------------------------------------------------------------
_NpcPosition m_pPoint[MAX_PATH_LINE]; // 이동시 참고 좌표
short m_iAniFrameIndex;
short m_iAniFrameCount;
uint8 m_byPathCount; // 패스를 따라 이동하는 몬스터 끼리 겹치지 않도록,,
bool m_bStopFollowingTarget; // when set, indicates that an NPC should stop following its target
uint8 m_byActionFlag; // 행동변화 플래그 ( 0 : 행동변화 없음, 1 : 공격에서 추격)
bool m_bTracing;
float m_fTracingStartX, m_fTracingStartZ;
short m_iFind_X[4]; // find enemy에서 찾을 Region검사영역
short m_iFind_Y[4];
float m_fOldSpeed_1; // 기본 이동 타입 (1초에 갈 수 있는 거리)
float m_fOldSpeed_2; // 뛰는 이동 타입.. (1초에 갈 수 있는 거리)
bool m_bMonster;
uint32 m_nActiveSkillID; // ID of skill currently being cast
int16 m_sActiveTargetID; // ID of the target of the skill currently being cast
uint16 m_sActiveCastTime; // Cast time of the skill currently being cast (in seconds)
bool m_bDelete; // when set, will remove the NPC from the server after execution.
int16 m_oSocketID; // owner user
uint16 m_bEventRoom;
int UnixGateOpen, UnixGateClose;
public:
CNpc();
virtual ~CNpc();
void Init(); // NPC 기본정보 초기화
void InitTarget(void);
void InitUserList();
void InitPos();
void Load(uint16 sNpcID, CNpcTable * proto, bool bMonster, uint8 nation = 0);
void SendMoveResult(float fX, float fY, float fZ, float fSpeed = 0.0f);
protected:
void ClearPathFindData(void);
public:
void FillNpcInfo(Packet & result);
void NpcStrategy(uint8 type);
int FindFriend(MonSearchType type = MonSearchSameFamily);
void FindFriendRegion(int x, int z, MAP* pMap, _TargetHealer* pHealer, MonSearchType type = MonSearchSameFamily);
bool IsCloseTarget(CUser *pUser, int nRange);
void SendExpToUserList();
INLINE void SetNPCEventRoom(uint16 nEventRoom) { m_bEventRoom = nEventRoom; }
void RecvAttackReq(int nDamage, uint16 sAttackerID, AttributeType attributeType = AttributeNone);
void ChangeTarget(int nAttackType, CUser *pUser);
void ChangeNTarget(CNpc *pNpc);
bool ResetPath();
bool GetTargetPos(float& x, float& z);
bool IsChangePath();
time_t Attack();
time_t LongAndMagicAttack();
void TracingAttack();
int GetTargetPath(int option = 0);
CloseTargetResult IsCloseTarget(int nRange, AttackType attackType);
bool StepMove();
bool StepNoPathMove();
bool IsMovingEnd();
int IsSurround(CUser* pUser);
bool IsDamagedUserList(CUser *pUser);
bool IsPathFindCheck(float fDistance);
void IsNoPathFind(float fDistance);
void GiveNpcHaveItem();
time_t NpcLive();
time_t NpcTracing();
time_t NpcAttacking();
time_t NpcMoving();
time_t NpcSleeping();
time_t NpcFainting();
time_t NpcHealing();
time_t NpcCasting();
time_t NpcStanding();
time_t NpcBack();
bool SetLive();
void ChaosCubeControl();
bool isInSpawnRange(int nX, int nZ);
bool RandomMove();
bool RandomBackMove();
bool IsInPathRange();
int GetNearPathPoint();
short GetDamage(Unit *pTarget, _MAGIC_TABLE *pSkill = nullptr, bool bPreviewOnly = false);
short GetDamage(CUser *pTarget, _MAGIC_TABLE *pSkill = nullptr, bool bPreviewOnly = false);
short GetDamage(CNpc *pTarget, _MAGIC_TABLE *pSkill = nullptr, bool bPreviewOnly = false);
void SendAttackRequest(int16 tid);
bool RegisterRegion(float x, float z);
void SendInOut(InOutType type);
void SendNpcInfo();
void SendRegionUpdate();
void Dead(Unit * pKiller = nullptr, bool bSendDeathPacket = true);
bool isShowBox();
bool FindEnemy();
bool CheckFindEnemy();
int FindEnemyRegion();
float FindEnemyExpand(int nRX, int nRZ, float fCompDis, UnitType unitType);
int GetMyField();
int GetDir(float x1, float z1, float x2, float z2);
void NpcMoveEnd();
void GetVectorPosition(__Vector3 & vOrig, __Vector3 & vDest, float fDis, __Vector3 * vResult);
void CalcAdaptivePosition(__Vector3 & vPosOrig, __Vector3 & vPosDest, float fAttackDistance, __Vector3 * vResult);
void ComputeDestPos(__Vector3 & vCur, float fDegree, float fDistance, __Vector3 * vResult);
void Yaw2D(float fDirX, float fDirZ, float& fYawResult);
float GetDistance(__Vector3 & vOrig, __Vector3 & vDest);
int PathFind(CPoint start, CPoint end, float fDistance);
bool GetUserInView();
bool GetUserInViewRange(int x, int z);
void MoveAttack();
void HpChange();
int ItemProdution(int item_number);
int GetItemGrade(int item_grade);
int GetItemCodeNumber(int level, int item_type);
int GetWeaponItemCodeNumber(bool bWeapon);
int GetPartyExp( int party_level, int man, int nNpcExp );
void ChangeAbility(int iChangeType);
bool Teleport();
bool isHostileTo(Unit * pTarget);
};