Files
2022-10-26 12:25:11 +08:00

246 lines
9.8 KiB
C++

#pragma once
#ifndef PROGRAMCOMMON_PERKDATA_CONTAINER_H
#define PROGRAMCOMMON_PERKDATA_CONTAINER_H
#include <StructInPacket.h>
//==================================================================================================
#ifdef _NA002217_100728_EP2_PERK_SYSTEM_
#include "Attribute.h"
class SCPerkSlotContainer;
namespace nsSkill {
;
class PerkManager;
//==================================================================================================
// PerkSlot Container placement
// <- 14 ->|
// [00][01]...[13]|
struct PerkDataNode : public PerkData
{
const PerkInfo* perk_info_;
POSTYPE pos_in_container_;
//
};
struct IPerkControlEvent
{
virtual void OnChangeAttributes() = 0;
virtual void OnChangeSlotContainer() = 0;
virtual void OnLevelup() = 0;
//_NA_001990_ACSYSTEM_ADD
virtual void OnLevelup(const PerkID& perk_id) = 0;
};
struct IPerkControlMessenger
{
virtual SCPerkSlotContainer* GetPerkSlotContainer() = 0;
virtual Attributes* GetOwnerAttributes() = 0;
virtual IPerkControlEvent* GetPerkControlEvent() = 0;
};
//==================================================================================================
class PerkDataContainer
{
union ServerStorage;
struct TouchList {
enum { None = 0, Selected, Skipped, Counts };
typedef uint8_t check_type;
// NOTE: f110602.3L, added to write a game log
struct ChangedInfo {
int perk_group;
int64_t prev_exp, next_exp;
};
//
check_type touches[PerkDataList::kNumberOfActiveSlots];
#ifdef _SERVER
ChangedInfo changed_infos[PerkDataList::kNumberOfActiveSlots];
#endif
};
public:
typedef STLX_HASH_MAP<ulong, PerkDataNode> PerkTable;
//
#ifdef _SERVER
static const bool kServerLogic = true;
#else
static const bool kServerLogic = false;
#endif
static const bool kClientLogic = !kServerLogic;
struct ActiveSlotPresenter {
uint8_t number_of_overlaps_[PerkDataList::kNumberOfActiveSlots];
const PerkInfo* perk_infos_[PerkDataList::kNumberOfActiveSlots];
};
//
PerkDataContainer();
virtual ~PerkDataContainer();
void Clear();
void set_pass_key(DWORD pass_key);
//
const PerkTable& GetPerkTable() const;
const PerkDataNode* FindPerkData(const PerkID& perk_id) const;
// D->G or G->C update stream
void StorePerk(const PerkDataList& perk_data_list, IPerkControlMessenger* perk_messenger);
// G->C send stream
void LoadPerk(PerkDataList* perk_data_list) const;
// register a cash perk slot using a cash item
bool RequestPlants(PerkControl* req_info, const POSTYPE from_inven_item_pos,
IPerkControlMessenger* const perk_messenger);
// unregister a registered cash perk so that a cash perk move to item in inventory
bool RequestUproot(PerkControl* req_info,
const PerkID& uprooting_perk_id, const POSTYPE to_inven_empty_pos,
IPerkControlMessenger* const perk_messenger);
// move to an active slot so that change to active
bool RequestRegister(PerkControl* req_info,
const PerkID& from_perk_id, const PerkID& to_perk_id,
IPerkControlMessenger* const perk_messenger);
// move from an active slot so that change to inactive
bool RequestUnregister(PerkControl* req_info, const PerkID& perk_id,
IPerkControlMessenger* const perk_messenger);
// NOTE: f100902.5L, this is a single side command by server
// if a cash perk containing the expiration date is expired.
// but, the result_code value of a req_info is not established
// because a reason of deletion may have several situations.
bool RequestDeletion(PerkControl* req_info, const PerkID& perk_id,
IPerkControlMessenger* const perk_messenger);
//
bool ProcessReplyMessage(const PerkControl& reply_header, PerkControlData* data,
IPerkControlMessenger* perk_messenger);
//
bool ProcessEventMessage(const PerkControl& update_header, PerkStatusData* data,
IPerkControlMessenger* perk_messenger);
//
#if SUN_CODE_BACKUP // NOTE: f110413.2L
const ActiveSlotPresenter& GetActiveSlotPresenter() const;
#endif
// NOTE: f101029.1L, a check routine for a client whether a player request already a perk process
bool IsRequestTransaction() const;
// NOTE: f101026.2L, add a factility for single attribute application on first enter field event
bool ApplyAttributes(IPerkControlMessenger* perk_messenger);
private:
// the result_index have a range eActiveGroup01 with eActiveGroup10.
// if a result is fails, the result is 0.
// the plan rule is below.
// a default perk can select multiple to regist to active slot.
//bool AllocFromFreeActiveSlot(PerkID* alloced_active_id, const PerkDataNode* perk_data_node);
bool AllocActiveSlot(const PerkID& active_slot_id, const PerkDataNode* perk_data_node);
bool FreeActiveSlot(const PerkID& alloced_active_id, const PerkDataNode* test_node);
bool IsActivatedSlot(PerkID* one_of_selected_activated_slot_id,
const PerkDataNode* perk_data_node) const;
// the result_index have a range 0 with kNumberOfCashSlots.
// if a result is fails, the result is kNumberOfCashSlots.
// the major premise is below.
// you should be find a same group perk before calling a this method.
// a cash perk using a perk item must be have the unique group code,
// because the key of a perk table is managed by a group code.
int AllocFromFreeCashSlot(const PerkDataNode* perk_cash_node);
bool FreeCashSlot(const PerkDataNode* free_cash_node);
int GetIndexInCashSlot(const PerkDataNode* perk_data_node) const;
// NOTE: the perk system experience rule, add only battle experience value.
// CHANGES: f101108.3L, add a function related to level control by GM commands
bool ModifyExpOrLevel(int changed_value, bool is_level, TouchList* result_list);
//
// (NOTE) if the value of a 'is_add' is false, do batched process subtract attributes
void BatchCalculateAttrActivePerks(bool is_add, IPerkControlMessenger* const perk_messenger);
//
bool ProcessPlants(const PerkControl& reply_header, PerkControlData* data,
IPerkControlMessenger* perk_messenger);
bool ProcessUproot(const PerkControl& reply_header, PerkControlData* data,
IPerkControlMessenger* perk_messenger);
bool ProcessRegister(const PerkControl& reply_header, PerkControlData* data,
IPerkControlMessenger* perk_messenger);
bool ProcessUnregister(const PerkControl& reply_header, PerkControlData* data,
IPerkControlMessenger* perk_messenger);
bool ProcessDelete(const PerkControl& reply_header, PerkControlData* data,
IPerkControlMessenger* perk_messenger);
bool ProcessEvent(const PerkControl& reply_header, PerkStatusData* data,
IPerkControlMessenger* perk_messenger);
//
PerkTable perk_table_;
struct InterData {
DWORD pass_key_; // use char_guid in server, client...
int number_of_aligned_cashes_;
int number_of_aligned_actives_;
const PerkDataNode* cash_slots_[PerkDataList::kNumberOfCashSlots];
const PerkDataNode* active_slots_[PerkDataList::kNumberOfActiveSlots];
// to support an empty slot transaction related to a plants action
//int plants_trans_;
// to support a multi-purpose operation like a targeting active position register operation
PerkControl request_info_;
#if SUN_CODE_BACKUP
// NOTE: f110413.2L, removed the unused codes that is to support client presenting data, but
// the client has other implementation.
ActiveSlotPresenter active_slot_presenter_;
#endif
} inter_;
//
union ServerStorage {
struct {
PerkDataNode* uprooting_node;
PerkDataNode* active_node_if_registered;
} uproot;
struct {
PerkDataNode* registering_node;
PerkDataNode* active_node;
} regist;
struct {
PerkDataNode* active_node_for_unregist;
PerkDataNode* unregistering_node;
} unregist;
struct {
PerkDataNode* deleting_node;
PerkDataNode* active_node_if_registered;
} deletion;
} server_data_;
friend class PerkManager;
};
//==================================================================================================
// implements
inline void PerkDataContainer::set_pass_key(DWORD pass_key) {
inter_.pass_key_ = pass_key;
}
inline const PerkDataContainer::PerkTable& PerkDataContainer::GetPerkTable() const {
return perk_table_;
}
inline const PerkDataNode* PerkDataContainer::FindPerkData(const PerkID& perk_id) const
{
PerkTable::const_iterator found = perk_table_.find(perk_id.group_);
if (found == perk_table_.end()) {
return NULL;
}
//
const PerkDataNode* control = &found->second;
return control;
}
#if SUN_CODE_BACKUP // NOTE: f110413.2L
inline const PerkDataContainer::ActiveSlotPresenter&
PerkDataContainer::GetActiveSlotPresenter() const
{
return inter_.active_slot_presenter_;
}
#endif
// NOTE: f101029.1L, a check routine for a client whether a player request already a perk process
inline bool PerkDataContainer::IsRequestTransaction() const
{
return (inter_.request_info_.request != inter_.request_info_.eReq_None);
}
//--------------------------------------------------------------------------------------------------
}; //end of namespace
#endif //_NA002217_100728_EP2_PERK_SYSTEM_
//==================================================================================================
#endif //PROGRAMCOMMON_PERKDATA_CONTAINER_H