#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; // ij¸¯ÅÍÀÇ ºñÀ²(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); };