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

316 lines
12 KiB
C++

#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<BOOL, BaseStatus*> ALLOC_STATUS_PAIR;
//==================================================================================================
// <StatusManager>
//
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<DWORD, STATUS_NODE> 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