#ifndef __GAMESERVER_STATUS_MANAGER_H #define __GAMESERVER_STATUS_MANAGER_H #pragma once //================================================================================================== // @history // - |~09/10/11| // - |09/10/11|waverix|make DEL_LIST to cheap routine // - |10/02/16|waverix|CHANGES=code refactoring about status manager| // |CHANGES=delete macro '__NA_S00015_20080828_NEW_HOPE_SHADOW (902)'\ // '__NA_S00028_SHADOW_ADD_WORK (902)'| // |UPDATES=changes status manager which is had recursive graph call,\ // that can remove only in remove routine to simple transaction| // - |10/02/18|waverix|CHANGES=code refactoring about status manager|STEP=2nd| // |CHANGES=fix up invalid operation removed flag by test value| // - TODO : unify delete_reserved and BaseStatus::StopStatus // - |10/08/22|waverix|CHANGES=change a name of AllocAbility to AllocAbilityStatus #include "BaseStatus.h" #include "Status_Operator.h" #include "AnimationDelayControl.h" //__NA001003_080527_PLAYER_ANIMATION_TIME_CONTROL__ class Character; class Ability; class AbilityStatus; class StatusFactory; class SkillInfoParser; struct STATE_INFO; typedef std::pair ALLOC_STATUS_PAIR; //================================================================================================== // // class StatusManager { typedef DWORD64 RESTRICT_STATUS_BITFIELD; struct InterState; struct Transaction; friend struct Transaction; struct STATUS_NODE { BOOLEAN delete_reserved; //BOOLEAN reserved sections[3]; BaseStatus* status; }; typedef STLX_MAP STATUS_TABLE; public: //-------------------------------------------------------------------------------------------------- StatusManager(Character* owner); ~StatusManager(); void Release(); void Update(DWORD delta_tick); #ifdef _NA_006728_20130520_SKILL_BALANCE_MODIFY void UpdateReflect(Character* attacker, DamageArgs* damage_arg); #else void UpdateReflect(Character* attacker, DAMAGETYPE damage); #endif // _NA_006728_20130520_SKILL_BALANCE_MODIFY #ifdef _NA_007667_20141001_WITCHBLADE_SKILL void UpdateStatusByAttack(Character* target); #endif //_NA_007667_20141001_WITCHBLADE_SKILL ALLOC_STATUS_PAIR AllocStatus(eCHAR_STATE_TYPE state_id, int expire_time = BASE_EXPIRE_TIME_INFINITY, int period = 0, int regen_hp = 0, int regen_mp = 0); AbilityStatus* AllocAbilityStatus(Character* attacker, Ability* ability); // (NOTE) change paradigm from 'delete node' action to 'delete reserved' tagging BOOLEAN Remove(eCHAR_STATE_TYPE state_id); void CureAll(eSTATE_TYPE state_type); // ±âŸ »ç¿ë ÇÔ¼öµé bool CanAttack(); // °ø°ÝÇÒ ¼ö ÀÖ´Â »óÅÂÀΰ¡ bool CanBeAttacked(); bool CanMove(const eCHAR_STATE_TYPE exception_type = eCHAR_STATE_INVALID); // CHANGES: f110315.2L, check whether request action is acceptable like a riding or spread wings. bool CanSpecialAction(const eCHAR_STATE_TYPE exception_type = eCHAR_STATE_INVALID) const; BaseStatus* FindStatus(eCHAR_STATE_TYPE state_id) const; // added by __NA_S00015_20080828_NEW_HOPE_SHADOW // |RETURNS=real stopped status| BYTE StopStatusByStateType(eSTATE_TYPE state_type, BYTE number_of_stops); BOOLEAN IsDBSaveStatus(eCHAR_STATE_TYPE state_id); //!~ _NA_000000_20130812_NEW_CHARACTER_HELLROID bool IsAuroraStatus(eCHAR_STATE_TYPE state_id); BaseStatus* FindAuroraStatus(); //~! _NA_000000_20130812_NEW_CHARACTER_HELLROID #ifdef _NA_007667_20141001_WITCHBLADE_SKILL BaseStatus* FindToggleFPStatus(); #endif //_NA_007667_20141001_WITCHBLADE_SKILL // Static »óÅ °ü·Ã eCHAR_CONDITION GetCondition() const { return current_condition_; } void SetCondition(eCHAR_CONDITION condition); // »óŸ¦ ¹Ù²Ù°í ÁÖº¯¿¡ ¾Ë¸°´Ù. RC::eCONDITION_RESULT ChangeCondition(eCHAR_CONDITION condition); // SSQ Field¿¡¼­ °ø°Ý/ÇÇ°Ý ºÒ°¡´É »óŸ¦ °­Á¦ ¼³Á¤Çϱâ À§ÇØ Ãß°¡µÊ. // º°µµÀÇ ½ÇÁ¦ »óÅ °´Ã¼¸¦ °¡Áö´Â °Ô ¾Æ´Ï´Ù. void ChangeInterState(const eCHAR_STATE_TYPE state, const BOOLEAN is_add); void RemoveNonCashStatus(); // special interface, 1Â÷ ·¹º§¿¡¼­¸¸ »ç¿ëÇÒ °Í. --> cleared VOID RemoveCashStatus(); RC::eSKILL_RESULT CanUseSkill(); BOOLEAN CanEnchant(); void AllocFightingStatus(); //__NA_001290_20090525_SHIELD_SYSTEM void ActEmotion(); // Emotion µ¿ÀÛÀ» ½ÃÀÛÇÑ´Ù. void ChangeHP(); void Move(); void SerialzieStatusInfo(STATE_TOTAL_INFO& OUT state_total_info_out, BOOL is_in_village = false); void SerialzieStatusDetailInfo(STATE_DETAIL_TOTAL_INFO& INOUT state_total_info, eSERIALIZE se); //__NA_001290_20090525_SHIELD_SYSTEM_NOTIFY_NOTABILITY_STATE BYTE SerialzieEtcStatusInfo(ETC_STATE_TOTAL_INFO& OUT etc_state_total_info_out); //__NA_S00028_SHADOW_ADD_WORK void UpdateExpiredTime(eCHAR_STATE_TYPE state_type, DWORD expired_time); void RemoveEventStatus(BYTE event_code); // ÇöÀç µ¥¹ÌÁö ¸é¿ª»óÅÂÀÎÁö üũ #ifdef _NA_008486_20150914_TOTAL_BALANCE bool isImmunityDamageState(Character* attacker) const; #else bool isImmunityDamageState() const; #endif //_NA_008486_20150914_TOTAL_BALANCE #ifdef _NA_007667_20141001_WITCHBLADE_SKILL // °¢ÀλóŸ¦ °Ç´Ù. µ¿½Ã¿¡ °¢Àνà Á¦°ÅµÇ¾î¾ß ÇÒ »óŵ鵵 Á¦°Å ALLOC_STATUS_PAIR AllocStampStatus(const DWORD collecting_time); void Attack(Character* target, DAMAGETYPE damage); // Owner°¡ °ø°ÝÀ» °³½ÃÇÒ ¶§ ó¸® #else void Attack(DAMAGETYPE damage); // Owner°¡ °ø°ÝÀ» °³½ÃÇÒ ¶§ ó¸® #endif //_NA_007667_20141001_WITCHBLADE_SKILL void Attacked(); // Owner°¡ °ø°ÝÀ» ¹Þ¾ÒÀ» ¶§ ó¸® // Owner°¡ µ¥¹ÌÁö¸¦ ¹Þ¾ÒÀ» ¶§ ó¸® #ifdef _NA_006728_20130520_SKILL_BALANCE_MODIFY void Damaged(Character* attacker, DamageArgs* damage_arg); #else void Damaged(Character* attacker, eATTACK_TYPE attack_type, DAMAGETYPE& damage); #endif // _NA_006728_20130520_SKILL_BALANCE_MODIFY void DamagedAbsorb(const DAMAGETYPE damage); //_NA_6260_20100507_BUG_FIX_SPDAMAGED_ABSORB #ifdef _NA_008069_20150210_ADD_SPA_SYSTEM bool IsDragonTransforming() {return Status.IsDragonTransforming(); } BOOL RemoveDragonTransformStatus(); #endif //_NA_008069_20150210_ADD_SPA_SYSTEM #ifdef _NA_008132_20150316_MONDSCHEIN_TEXTLOG std::string PrintLogStatusList(); #endif //_NA_008132_20150316_MONDSCHEIN_TEXTLOG private: // (CHANGES) »èÁ¦ ´ë±â »óÅÂÀÇ ¸ñ·ÏµéÀ» Àϰý »èÁ¦ÇÑ´Ù. // assert(transaction_depth == 0)ÀÎ »óÅ¿¡¼­ È£Ãâ ÇÊ¿ä. void ReleaseDeleteReservedList(); BOOLEAN Remove(const STATUS_TABLE::iterator& delete_it); // desired must be success, shared logic to support 'AllocStatus' and 'AllocAbility' void ReplaceToNewStatus(BOOLEAN need_replace, eCHAR_STATE_TYPE state_id, BaseStatus* new_status, STATUS_TABLE::iterator* if_need_replace_then_support_pos); void OnDead(); // (NOTE) ordered fields based on access used frequency public: // (Property) StatusField Status; // Property <- °¢Á¾ Á¤Ã¥ Á¦¾î private: // (Fields) Character* const owner_; eCHAR_CONDITION current_condition_; // À¯ÀÏÇÏ°Ô °¡Áú ¼ö ÀÖ´Â ÇöÀç »óÅ STATUS_TABLE status_table_; // - ƯÁ¤ »óÅ¿¡¼­ ÇØ´ç ¾×¼ÇÀÌ Çã¿ëµÇ´ÂÁö ¿©ºÎ °Ë»ç¿ë RESTRICT_STATUS_BITFIELD check_status_field_; int transaction_depth_; // prevent recursive loop to deleted iterators public: AnimationDelayControl AnimationDelay; private: static StatusFactory* status_allocator_static_; __DISABLE_COPY(StatusManager); }; //================================================================================================== // struct StatusManager::Transaction { Transaction(StatusManager* status_manager) : status_manager_(status_manager) { ++status_manager_->transaction_depth_; }; ~Transaction() { assert(status_manager_->transaction_depth_ > 0); if (status_manager_->transaction_depth_ > 0) { --status_manager_->transaction_depth_; } } StatusManager* const status_manager_; __DISABLE_COPY(Transaction); }; struct StatusManager::InterState { enum eCHECK_STATE; static void ClearField(RESTRICT_STATUS_BITFIELD& field); static bool IsCanAttack(const RESTRICT_STATUS_BITFIELD& field); static bool IsCanBeAttacked(const RESTRICT_STATUS_BITFIELD& field); static bool IsCanMove(const RESTRICT_STATUS_BITFIELD& field); static bool IsCanSpecialAction(const RESTRICT_STATUS_BITFIELD& field); static RC::eSKILL_RESULT IsCanUseSkill(const RESTRICT_STATUS_BITFIELD& field); // (CHANGES) (100218) (WAVERIX) fix up invalid operation removed flag by test value // specification : if status_field is not null then default processing // else then simulate based on current state static void AddRestrictStatus(const eCHAR_STATE_TYPE state_id, RESTRICT_STATUS_BITFIELD& INOUT field, StatusField* status_field); static void DelRestrictStatus(const eCHAR_STATE_TYPE state_id, RESTRICT_STATUS_BITFIELD& INOUT field, StatusField* status_field); }; //================================================================================================== inline BaseStatus* StatusManager::FindStatus(eCHAR_STATE_TYPE state_id) const { // (NOTE) ignore 'delete_reserved' STATUS_TABLE::const_iterator it = status_table_.find(state_id); if (it != status_table_.end()) { const STATUS_NODE& node = it->second; return node.status; } return NULL; } inline BOOLEAN StatusManager::Remove(eCHAR_STATE_TYPE state_id) { STATUS_TABLE::iterator it = status_table_.find(state_id); if (it != status_table_.end()) { return Remove(it); } return false; } inline bool StatusManager::CanAttack() // °ø°ÝÇÒ ¼ö ÀÖ´Â »óÅÂÀΰ¡ { const bool is_can_attack = !(Status.FIELD & Status.ENABLE_GM_TRANSPARENT) && InterState::IsCanAttack(check_status_field_); return is_can_attack; } inline bool StatusManager::CanBeAttacked() { // Åõ¸í »óÅ¿¡¼­µµ °ø°ÝÀº ¹ÞÀ»¼ö ÀÖ´Ù. ŸÄÏÀº ÀâÈ÷Áö ¾Ê´Â´Ù. - (1002xx~) const bool is_can_be_attacked = !(Status.FIELD&Status.ENABLE_GM_TRANSPARENT) && InterState::IsCanBeAttacked(check_status_field_); return is_can_be_attacked; } inline bool StatusManager::CanMove(const eCHAR_STATE_TYPE excepted_type) { RESTRICT_STATUS_BITFIELD filtered = check_status_field_; if (eCHAR_STATE_INVALID != excepted_type) { // (CHANGES) (100218) (WAVERIX) fix up invalid operation removed flag by test value InterState::DelRestrictStatus(excepted_type, filtered, NULL); } bool is_can_move = InterState::IsCanMove(filtered); return is_can_move; } inline RC::eSKILL_RESULT StatusManager::CanUseSkill() { return InterState::IsCanUseSkill(check_status_field_); } // CHANGES: f110315.2L, check whether request action is acceptable like a riding or spread wings. inline bool StatusManager::CanSpecialAction(const eCHAR_STATE_TYPE excepted_type) const { //return InterState::IsCanSpecialAction(check_status_field_); RESTRICT_STATUS_BITFIELD filtered = check_status_field_; if (eCHAR_STATE_INVALID != excepted_type) { // (CHANGES) (100218) (WAVERIX) fix up invalid operation removed flag by test value InterState::DelRestrictStatus(excepted_type, filtered, NULL); } bool can_special_action = InterState::IsCanSpecialAction(filtered); return can_special_action; } inline void StatusManager::ChangeInterState(const eCHAR_STATE_TYPE state, const BOOLEAN is_add) { if(is_add) { InterState::AddRestrictStatus(state, check_status_field_, &Status); } else { InterState::DelRestrictStatus(state, check_status_field_, &Status); } } #endif //__GAMESERVER_STATUS_MANAGER_H