//////////////////////////////////////////////////////////////////////////////////////////////////// /// /// @file RandomItemParser.h /// @author hukim /// @email silped@gmail.com /// @brief [2011/11/22 by hukim] This is created.\n /// //////////////////////////////////////////////////////////////////////////////////////////////////// #pragma once #ifndef PROGRAMCOMMON_RANDOMITEMPARSER_H_ #define PROGRAMCOMMON_RANDOMITEMPARSER_H_ #ifdef _SERVER #include #endif // _SERVER #include "ScriptCode.IParser.h" #include "Singleton.h" #include "ItemOptionHeader.h" #include "SCSlotStruct.h" #include "RatioSelector.h" struct MSG_CG_ITEM_RANDOMIZE_SYN; class CCSunOnline; class SCItemSlot; class SCItemSlotContainer; // 랜덤 아이템 파서 class RandomItemParser : public util::Singleton, public IParser { //////////////////////////////////////////////////////////////////////////////////////////////// // REGION : Define //////////////////////////////////////////////////////////////////////////////////////////////// public: struct OptionParam { #ifdef _NA_003740_20210624_ADDITEMRANDOM_ITEM6 enum { kMaxKeySize = 6 }; #else enum { kMaxKeySize = 5 }; #endif typedef uint16_t Key; OptionParam() : is_valid(false), size(0) { ::ZeroMemory(keys, sizeof(keys)); for (int i = 0; i < _countof(grades); ++i) { grades[i] = RandomValueGrade::kNone; } } bool is_valid; uint8_t size; Key keys[kMaxKeySize]; RandomValueGrade::Value grades[kMaxKeySize]; }; // OptionParam //////////////////////////////////////////////////////////////////////////////////////////////// // REGION : Constructor & Destructor //////////////////////////////////////////////////////////////////////////////////////////////// public: RandomItemParser(); ~RandomItemParser(); //////////////////////////////////////////////////////////////////////////////////////////////// // REGION : Public //////////////////////////////////////////////////////////////////////////////////////////////// public: virtual void Release() {} virtual BOOL LoadScript(eSCRIPT_CODE script_code, BOOL is_reload); // 랜덤화 가능한지 검사한다. bool EnableRandomize(const BASE_ITEMINFO& item_info) const; // 옵션을 랜덤화 한다. OptionParam RandomizeOption( const RandomValueTypeGrade::Value value_type_grade, const BASE_ITEMINFO& item_info) const; // 아이템 정보에 옵션을 만든다. bool CreateOption(OptionParam& INOUT param, BASE_ITEMINFO& OUT item_info) const; // 랜덤화 아이템이 사용 가능한지 검사한다. bool EnableItemRandomize( const SCItemSlotContainer& inventory, const POSTYPE request_item_pos, const POSTYPE target_item_pos, SCItemSlot*& OUT request_item, SCItemSlot*& OUT target_item) const; // 랜덤화 아이템 사용 요청을 만든다. bool GetItemRandomizeRequest( const SCItemSlotContainer& inventory, const POSTYPE request_item_pos, const POSTYPE target_item_pos, MSG_CG_ITEM_RANDOMIZE_SYN& OUT request) const; // 메모리풀에서 아이템 정보를 생성한다. BASE_ITEMINFO* ConstructItemInfo() { #ifdef _SERVER #ifdef _NA_000000_20140103_MALLOC_CHANGE_TO_TALLOCATE_CREATEITEM BASE_ITEMINFO* const item_info = TAllocNew(BASE_ITEMINFO); #else BASE_ITEMINFO* const item_info = item_info_pool_.construct(); #endif //_NA_000000_20140103_MALLOC_CHANGE_TO_TALLOCATE_CREATEITEM #else BASE_ITEMINFO* const item_info = new BASE_ITEMINFO; #endif // _SERVER if (item_info != NULL) { if (created_item_infos_.find(item_info) != created_item_infos_.end()) { // 새로 생성 했는데 같은 주소를 사용하는 객체가 이미 존재한다. return NULL; } created_item_infos_.insert(item_info); } return item_info; } // 메모리풀에서 아이템 정보를 삭제한다. void DestroyItemInfo(BASE_ITEMINFO* const item_info) { if (item_info == NULL) { return; } CreatedItemInfos::iterator it = created_item_infos_.find(item_info); if (it == created_item_infos_.end()) { // 여기서 생성한 객체가 아닌데 삭제하려고 시도했다. return; } created_item_infos_.erase(it); #ifdef _SERVER #ifdef _NA_000000_20140103_MALLOC_CHANGE_TO_TALLOCATE_CREATEITEM TAllocDelete(BASE_ITEMINFO, item_info); #else item_info_pool_.destroy(item_info); #endif //_NA_000000_20140103_MALLOC_CHANGE_TO_TALLOCATE_CREATEITEM #else delete item_info; #endif // _SERVER } //////////////////////////////////////////////////////////////////////////////////////////////// // REGION : Private //////////////////////////////////////////////////////////////////////////////////////////////// private: template struct IHasParts { typedef typename PartT::Order PartOrder; typedef typename PartT::Ratio PartRatio; typedef STLX_VECTOR Parts; typedef RatioSelector PartSelector; const PartT* GetPart(const PartOrder order) const { if (order < PartT::kMinOrder || order > PartT::kMaxOrder || order > parts.size()) { return NULL; } return &(parts[order-1]); } const PartT* SelectPart() const { const PartRatio ratio = rand() % part_selector.GetTotalRatio(); PartOrder order = 0; if (part_selector.Select(ratio, order) == false) { return NULL; } return GetPart(order); } Parts parts; PartSelector part_selector; }; // IHasParts //////////////////////////////////////////////////////////////////////////////////////////////// // 랜덤값 //////////////////////////////////////////////////////////////////////////////////////////////// struct RandomValuePart { enum OrderBoundary { kMinOrder = 1, kMaxOrder = 10 }; enum ValueBoundary { #ifdef _NA_008540_20151027_ADD_ITEMOPTION_ELITE4 kMinValue = -10000, kMaxValue = 100000 #else kMinValue = -100, kMaxValue = 9999 #endif //_NA_008540_20151027_ADD_ITEMOPTION_ELITE4 }; enum RatioBoundary { kMinRatio = 1, kMaxRatio = 1000 }; typedef uint8_t Order; typedef int Value; typedef uint16_t Ratio; Order order; // 순서 Value my_value; // 값 Ratio ratio; // 발생확률 RandomValueGrade::Value grade; // 등급 RandomValuePart() : order(0), my_value(0), ratio(0), grade(RandomValueGrade::kNone) { } }; // RandomValuePart struct RandomValue : public IHasParts { enum IndexBoundary { kMinIndex = 1, kMaxIndex = 99999 }; typedef uint16_t Index; RandomValue() : index(0) { } Index index; }; // RandomValue //////////////////////////////////////////////////////////////////////////////////////////////// // 랜덤값 관리자 //////////////////////////////////////////////////////////////////////////////////////////////// class RandomValueManager { public: RandomValueManager() {} ~RandomValueManager() {} public: bool LoadScript(const RandomItemParser& parser, const bool is_reload); const RandomValue* GetValue(const RandomValue::Index index) const { RandomValues::const_iterator it = random_values_.find(index); if (it != random_values_.end()) { return &(it->second); } return NULL; } private: typedef STLX_HASH_MAP RandomValues; RandomValues random_values_; __DISABLE_COPY(RandomValueManager); }; // RandomValueManager //////////////////////////////////////////////////////////////////////////////////////////////// // 랜덤옵션 //////////////////////////////////////////////////////////////////////////////////////////////// struct RandomOptionPart { enum OrderBoundary { kMinOrder = 1, kMaxOrder = 100 }; enum ValueGrade { kValueGrade0 = 0, kValueGrade1 = 1, kValueGradeSize }; enum RatioBoundary { kMinRatio = 1, kMaxRatio = 1000 }; typedef uint8_t Order; typedef uint8_t ActiveType; typedef uint16_t Kind; typedef uint8_t ValueType; typedef uint16_t Ratio; Order order; // 순서 bool is_empty; // 빈옵션 여부 ActiveType active_type; // 옵션발동조건 Kind kind; // 옵션종류 ValueType value_type; //옵션값종류 const RandomValue* random_values[kValueGradeSize]; // 캐시수준별랜덤값 Ratio ratio; // 발생확률 RandomOptionPart() : order(0), is_empty(false), active_type(0), kind(0), value_type(0), ratio(0) { ::ZeroMemory(random_values, sizeof(random_values)); } const RandomValue* GetValue(const RandomValueTypeGrade::Value grade) const { if ((grade-1) < kValueGrade0 || (grade-1) >= kValueGradeSize) { return NULL; } return random_values[grade-1]; } }; // RandomOptionPart struct RandomKey; struct RandomOption : public IHasParts { enum IndexBoundary { kMinIndex = 1, kMaxIndex = 99999 }; typedef uint16_t Index; typedef STLX_MAP Keys; RandomOption() : index(0) { } Index index; Keys keys; }; // RandomOption //////////////////////////////////////////////////////////////////////////////////////////////// // 랜덤옵션 관리자 //////////////////////////////////////////////////////////////////////////////////////////////// class RandomOptionManager { public: RandomOptionManager() {} ~RandomOptionManager() {} public: bool LoadScript(const RandomItemParser& parser, const bool is_reload); const RandomOption* GetOption(const RandomOption::Index index) const { RandomOptions::const_iterator it = random_options_.find(index); if (it != random_options_.end()) { return &(it->second); } return NULL; } private: typedef STLX_HASH_MAP RandomOptions; RandomOptions random_options_; __DISABLE_COPY(RandomOptionManager); }; // RandomOptionManager //////////////////////////////////////////////////////////////////////////////////////////////// // 랜덤아이템 //////////////////////////////////////////////////////////////////////////////////////////////// struct RandomItem { #ifdef _NA_003740_20210624_ADDITEMRANDOM_ITEM6 enum { kMaxOptionSize = 6 }; #else enum { kMaxOptionSize = 5 }; #endif typedef uint32_t ItemCode; typedef STLX_VECTOR Options; RandomItem() : item_code(0) { } const RandomOption* GetOption(const size_t index) const { if (index < 0 || index >= kMaxOptionSize || index >= options.size()) { return NULL; } return options[index]; } ItemCode item_code; Options options; }; // RandomItem //////////////////////////////////////////////////////////////////////////////////////////////// // 랜덤아이템 관리자 //////////////////////////////////////////////////////////////////////////////////////////////// class RandomKeyManager; class RandomItemManager { public: RandomItemManager() {} ~RandomItemManager() {} public: bool LoadScript(const RandomItemParser& parser, const bool is_reload); const RandomItem* GetItem(const RandomItem::ItemCode item_code) const { RandomItems::const_iterator it = random_items_.find(item_code); if (it != random_items_.end()) { return &(it->second); } return NULL; } private: typedef STLX_MAP RandomItems; RandomItems random_items_; __DISABLE_COPY(RandomItemManager); friend class RandomKeyManager; friend class CCSunOnline; }; // RandomItemManager //////////////////////////////////////////////////////////////////////////////////////////////// // 랜덤키 관리자 //////////////////////////////////////////////////////////////////////////////////////////////// struct RandomKey { enum KeyBoundary { kMinKey = 1, kMaxKey = 0xFFFF // 주의!! 2^16 초과하면 스트림 확장 필요하다. }; typedef uint16_t Key; RandomKey() : key(0), option_part(NULL), value_part(NULL) { } Key key; const RandomOptionPart* option_part; const RandomValuePart* value_part; }; // RandomKey class RandomKeyManager { public: RandomKeyManager() {} ~RandomKeyManager() {} public: bool LoadScript(RandomItemParser& parser, const bool is_reload); const RandomKey* GetKey(const RandomKey::Key key) const { RandomKeys::const_iterator it = random_keys_.find(key); if (it != random_keys_.end()) { return &(it->second); } return NULL; } const RandomKey* GetKey( const RandomOption::Index option_index, const RandomOptionPart::Order option_order, const RandomValue::Index value_index, const RandomValuePart::Order value_order) const { const KeyData key_data = CreateKeyData(option_index, option_order, value_index, value_order); KeyDatas::const_iterator it = key_datas_.find(key_data); if (it != key_datas_.end()) { return it->second; } return NULL; } private: typedef uint64_t KeyData; typedef STLX_MAP RandomKeys; typedef STLX_HASH_MAP KeyDatas; KeyData CreateKeyData( const RandomOption::Index option_index, const RandomOptionPart::Order option_order, const RandomValue::Index value_index, const RandomValuePart::Order value_order) const { BOOST_STATIC_ASSERT(sizeof(RandomOption::Index) <= 2); BOOST_STATIC_ASSERT(sizeof(RandomOptionPart::Order) <= 2); BOOST_STATIC_ASSERT(sizeof(RandomValue::Index) <= 2); BOOST_STATIC_ASSERT(sizeof(RandomValuePart::Order) <= 2); BOOST_STATIC_ASSERT(sizeof(KeyData) == sizeof(uint64_t)); const uint32_t option_part = MAKELONG(option_index, option_order); const uint32_t value_part = MAKELONG(value_index, value_order); return static_cast(option_part | (static_cast(value_part) << 32)); } bool InsertKeysToOption(RandomItemParser& parser) const; RandomKeys random_keys_; KeyDatas key_datas_; __DISABLE_COPY(RandomKeyManager); friend class CCSunOnline; }; // RandomKeyManager private: RandomValueManager value_manager_; RandomOptionManager option_manager_; RandomItemManager item_manager_; RandomKeyManager key_manager_; typedef STLX_HASH_SET CreatedItemInfos; CreatedItemInfos created_item_infos_; #ifdef _NA_000000_20140103_MALLOC_CHANGE_TO_TALLOCATE_CREATEITEM #else #ifdef _SERVER enum { kItemInfoPoolSize = 1024 }; typedef boost::object_pool ItemInfoPool; ItemInfoPool item_info_pool_; #endif // _SERVER #endif //_NA_000000_20140103_MALLOC_CHANGE_TO_TALLOCATE_CREATEITEM friend class CCSunOnline; }; // RandomItemParser #endif // PROGRAMCOMMON_RANDOMITEMPARSER_H_