#include "stdafx.h" #include "./ItemAttrCalculator.h" #if defined(_NA_002289_20110322_EQUIPMENTS_CALCULATOR_CHANGES_FOR_IMPROVEMENT) #if !defined(_NA001605_EP2_ATTRIBUTES_RENEWAL_) || \ !defined(_NA_000251_20100727_SOCKET_SYSTEM) || \ !defined(_NA_001699_20110104_SOCKET_OPTION_POINT) || \ !defined(_NA_0_20100517_ITEMSLOTCONTAINER_EQUIPGROUP_DETECTION) #error "Impossible Build!! - Reason: Violation Dependency Chain" #endif //================================================================================================== // @history // - ~~~ // - 09/10/24, waverix, code arrangement, remove warnings, Riding system // - ~10/08/10, anybody, major changes: worked about special accessory option calculations // - ~11/03/22, anybody, major changes: EP2 contents={perk, socket, preview} // - 11/03/22, waverix, item attributes calucator refactoring to reduce item dependency chains. // - version control : __NA_001062_20080623_STRENGTH_PENALTY { China(x) } // remove '_ForeachAttrByRank' // - 11/03/29, waverix, updates renewaled code, // remains = { __NA_001062_20080623_STRENGTH_PENALTY, Socket, enable_option with time }; #define PROGRAMCOMMON_ITEM_ATTR_CALCULATOR_INTER_UTIL #include "./ItemAttrCalculator_Util.hxx" #undef PROGRAMCOMMON_ITEM_ATTR_CALCULATOR_INTER_UTIL #include #include "ItemFormula.h" // #include #include #ifdef _NA_002935_20110704_ITEM_SCORE #include #endif //================================================================================================== //================================================================================================== //================================================================================================== // [eVALUE_TYPE] const eATTR_KIND ItemAttrCalculator::kAttrKindByValueTypes[6] = { eATTR_KIND_ITEM, // 0: undefined eATTR_KIND_ITEM, // 1: VALUE_TYPE_VALUE // °íÁ¤ ¼öÄ¡ eATTR_KIND_ITEM_RATIO, // 2: VALUE_TYPE_PERCENT_PER_CUR // ÇöÀçÄ¡ ´ëºñ ºñÀ² eATTR_KIND_ITEM_RATIO, // 3: VALUE_TYPE_PERCENT_PER_MAX // ÃÖ´ëÄ¡ ´ëºñ ºñÀ² eATTR_KIND_ITEM, // 4: undefined eATTR_KIND_ITEM, // 5: VALUE_TYPE_RATIO_VALUE // ¼öÄ¡°¡ ºñÀ²°ªÀÎ °æ¿ì(À̵¿¼ÓµµÀ²) }; const ns_formula::EquipSlotsManageInfo::ItemSocketOption ns_formula::EquipSlotsManageInfo::ItemSocketOption::kDefault = { eATTR_TYPE_INVALID, //eATTR_TYPE attr_option_code; eATTR_TYPE_INVALID, //ItemOptionCode item_option_code; 0, //OptionPoint option_point; VALUE_TYPE_VALUE, //eVALUE_TYPE option_type; 0 //OptionValue option_value; }; //================================================================================================== //================================================================================================== //================================================================================================== // 2013.01.18. - arycoat // Àκ¥Å丮¿¡ ÀÖ´Â ¼ÒÁöÇϰí Àֱ⸸ ÇØµµ ¿É¼ÇÀ» Àû¿ëÇÏ´ø ÇÔ¼ö¿¡¼­ // Àκ¥Å丮¿¡¼­ »ç¿ë/ÁßÁö °¡´ÉÇÑ ¾ÆÀÌÅÛÀÇ ¿É¼Çµµ Àû¿ëÇÒ¼ö ÀÖµµ·Ï ¼öÁ¤. bool InvenItemOptionCalculator::ApplyInvenItemOption( PlayerAttributes& attributes, const SCItemSlot& item_slot, int changed_num, bool pc_room_status, bool use_update_ex) { if (changed_num == 0) { return false; }; const nsSlot::ItemRuleInfo& item_rule_info = item_slot.GetItemRuleInfo(); if (item_rule_info.is_valid_item == false) { return false; }; const BASE_ITEMINFO* item_info = item_slot.GetItemInfo(); bool exist_inven_option = item_info->IsExistInvenOptions(); bool exist_equip_option = item_info->IsExistEquipOptions(); if ( exist_inven_option == false && exist_equip_option == false ) { return false; }; // success ... //---------------------------------------------------------------------------------------------- Attributes::OperationRecord option_records[BASE_ITEMINFO::_MAX_OPTION_NUM * 2] = { 0, }; Attributes::OperationRecord* record_it = option_records; const Attributes::Operation::eOper oper_type \ = (changed_num > 0) ? Attributes::Operation::eOper_Add : Attributes::Operation::eOper_Sub; //---------------------------------------------------------------------------------------------- // (NOTE) calculate item option by script // (CHANGES) (WAVERIX) changes to more simple code const int upperbound_selector = pc_room_status ? 2 : 1; //Normal|PC option groups for (int selector = 0; selector < upperbound_selector; ++selector) { //const BASE_ITEMINFO::OptionEffects* __option_effects = selector == 0 ? // &item_info->m_byOptionExEffect : &item_info->m_byPCOptionExEffect; //const BASE_ITEMINFO::OptionEffects& option_effects = *__option_effects; /*bool apply = (selector == 0 ? exist_inven_option : exist_equip_option); if (apply == false) { continue; }*/ const BASE_ITEMINFO::OptionIndexes* __option_indexes = (selector == 0) ? &item_info->m_wOptionIndex : &item_info->m_wPCOptionIndex; const BASE_ITEMINFO::OptionTypes* __option_types = (selector == 0) ? &item_info->m_byOptionType : &item_info->m_byPCOptionType; const BASE_ITEMINFO::OptionValues* __option_values = (selector == 0) ? &item_info->m_iOptionValue : &item_info->m_iPCOptionValue; // const BASE_ITEMINFO::OptionIndexes& option_indexes = *__option_indexes; const BASE_ITEMINFO::OptionTypes& option_types = *__option_types; const BASE_ITEMINFO::OptionValues& option_values = *__option_values; for (int op = 0; op < _countof(option_indexes); ++op) { bool is_valid_values = option_indexes[op] != 0 && option_values[op] != 0 && option_indexes[op] < _countof(g_ITEM_OPTION) && option_types[op] < _countof(ItemAttrCalculator::kAttrKindByValueTypes); if (is_valid_values == false) { continue; } // notice about 'record_it' if (Attributes::OperationRecord* record = record_it++) { uint8_t attr_kind = static_cast(\ ItemAttrCalculator::kAttrKindByValueTypes[option_types[op]]); // change to skill attribute attr_kind = attr_kind == eATTR_KIND_ITEM ? eATTR_KIND_SKILL : attr_kind == eATTR_KIND_ITEM_RATIO ? eATTR_KIND_SKILL_RATIO : attr_kind; record->operate = static_cast(oper_type); record->attr_kind = attr_kind; record->attr_type = static_cast(g_ITEM_OPTION[option_indexes[op]]); record->attr_value = option_values[op]; }; }; //end 'for option in options' }; // const int number_of_options = static_cast(record_it - option_records); if (number_of_options == 0) { return true; }; const int loop_counter = std::abs(changed_num); for (int index = 0; index < loop_counter; ++index) { attributes.GroupBatchOperate(option_records, number_of_options); } //---------------------------------------------------------------------------------------------- if (use_update_ex) { attributes.UpdateEx(); } else { attributes.Update(); } return true; } //================================================================================================== //================================================================================================== //================================================================================================== // ItemAttrCalculator::ItemAttrCalculator(PlayerAttributes& attributes, IEquipmentRestriction* equipment_accessor) : attributes_(attributes) , socket_attributes_(attributes_.GetSocketOptionAttributes()) , equip_container_(*equipment_accessor->GetEquipmentSlotContainer()) , equipment_accessor_(equipment_accessor) , slot_cache_info_(equipment_accessor->GetEquipmentManageInfo()) , pc_room_status_(false) , use_update_ex_(false) , inter_control_mode_(ns_formula::eInterControl_Default) { WAVERIX_WRAPPER((WAVERIX_LC_CALL1("waverix_log_trace", __FUNCTION__))); } ItemAttrCalculator::~ItemAttrCalculator() { WAVERIX_WRAPPER((WAVERIX_LC_CALL1("waverix_log_trace", __FUNCTION__))); } void ItemAttrCalculator::Clear() { WAVERIX_WRAPPER((WAVERIX_LC_CALL1("waverix_log_trace", __FUNCTION__))); // f100720.3L socket_attributes_.Clear(); #ifdef _NA_002935_20110704_ITEM_SCORE attributes_.GetSetOptionAttributes().Clear(); #endif attributes_.ClearRelatedAttrKind(eATTR_KIND_ITEM); attributes_.Update(); } // NOTE: f100812.2L, add an interface to support external module can access add rule filter void ItemAttrCalculator::ModifyAttrKindAndCalculatedValue(uint8_t value_type, //eVALUE_TYPE uint8_t* attr_kind, //eATTR_KIND int * value) { __TOUCHED(value); *attr_kind = eATTR_KIND_ITEM; //float calced_value = static_cast(*value); if (value_type == VALUE_TYPE_PERCENT_PER_MAX || value_type == VALUE_TYPE_PERCENT_PER_CUR) { *attr_kind = eATTR_KIND_ITEM_RATIO; } // //*value = static_cast(calced_value); } //================================================================================================== ItemAttrCalculator::EquipSlotNode::EquipSlotNode( const SCItemSlot& input_slot, const BASE_ITEMINFO* input_item_info, const nsSlot::ItemRuleInfo& input_item_rule_info) : item_slot(input_slot) , item_info(input_item_info) , item_rule_info(input_item_rule_info) { } bool ItemAttrCalculator::EquipSlotNode::Initialize( eDetailedResult* result, EquipSlotNode* using_buffer, const SCItemSlot* slot) { WAVERIX_WRAPPER((WAVERIX_LC_CALL1("waverix_log_trace", __FUNCTION__))); // ZeroMemory(using_buffer, sizeof(*using_buffer)); if (slot == NULL) { *result = eResult_CantProcess; return false; }; const SCItemSlot& item_slot = (*slot); const BASE_ITEMINFO* item_info = item_slot.GetItemInfo(); if (item_info->m_Code == 0) { *result = eResult_CantProcess; return false; }; const nsSlot::ItemRuleInfo& item_rule_info = item_slot.GetItemRuleInfo(); if (item_rule_info.is_valid_item == false) { *result = eResult_CantProcess; return false; }; // regenerate new (using_buffer) EquipSlotNode(item_slot, item_info, item_rule_info); // if is_accessory_wings then assert(is_accessory_special) const bool default_equips = item_rule_info.is_weapon || item_rule_info.is_armor || item_rule_info.is_accessory || item_rule_info.is_accessory_special; // NOTE: f100406.2L, waverix, fix up missing process on the inventory option effect // item which is not equal equip item that need applied option ; // success process if (default_equips == false) { if (item_info->IsExistEquipOptions() == false) { using_buffer->init_result = eResult_NoOptions; *result = eResult_NoOptions; return true; } using_buffer->init_result = eResult_OptionsOnly; *result = eResult_OptionsOnly; return true; } // using_buffer->init_result = eResult_AllProcess; *result = eResult_AllProcess; return true; } bool ItemAttrCalculator::UpdateEquipSlotsLatestInfo( bool activated, const EquipSlotNode& info_node, ns_formula::EquipSlotsManageInfo::Node* const work_node) const { ZeroMemory(work_node, sizeof(*work_node)); work_node->position = info_node.position; work_node->activated = activated; work_node->duration = info_node.duration; // return true; } // static bool ItemAttrCalculator::LoadPlayerLimits(ns_formula::ItemAttrStats* const player_stats, const PlayerAttributes& attributes, LEVELTYPE player_level) { const ns_formula::ItemAttrStats& kIndex = *player_stats; __TOUCHED(kIndex); // player_stats->level = player_level; player_stats->stats[kIndex.eSTAT_STR] = attributes[eATTR_STR]; player_stats->stats[kIndex.eSTAT_DEX] = attributes[eATTR_DEX]; player_stats->stats[kIndex.eSTAT_VIT] = attributes[eATTR_VIT]; player_stats->stats[kIndex.eSTAT_INT] = attributes[eATTR_INT]; player_stats->stats[kIndex.eSTAT_SPR] = attributes[eATTR_SPR]; player_stats->stats[kIndex.eSTAT_DEC_LIMITS] = attributes[eATTR_DECREASE_LIMIT_STAT]; // for (AttrValue* it = player_stats->stats; it != &player_stats->stats[_countof(player_stats->stats)]; ++it) { it->skill_value_.value_ = 0; it->skill_ratio_.value_ = 0; // CHANGES: f110810.1L, fixed the unexpected option value calculation // that occur when a player has stat increasing buffs (skill) it->Update(); } // return true; } //static bool ItemAttrCalculator::LoadEquipmentLimits(ns_formula::ItemLimitations* const item_limits, const SCItemSlot& item_slot) { // enum eLimitField { eLimitDefault = 0, eLimitDivine, eLimitLimited, eLimitCounts }; const int limits_selector = item_slot.IsDivine() ? eLimitDivine : item_slot.IsLimited() ? eLimitLimited : eLimitDefault; // const BASE_ITEMINFO* const item_info = item_slot.GetItemInfo(); const ns_formula::ItemLimitations& kIndex = *item_limits;__TOUCHED(kIndex); short level = item_info->m_LimitEqLevel; ZeroMemory(item_limits, sizeof(*item_limits)); ;{ bool is_divine = (limits_selector == eLimitDivine); item_limits->limits[kIndex.eSTAT_STR] = is_divine ? item_info->m_wDivLimitStr : item_info->m_wLimitStr; item_limits->limits[kIndex.eSTAT_DEX] = is_divine ? item_info->m_wDivLimitDex : item_info->m_wLimitDex; item_limits->limits[kIndex.eSTAT_VIT] = is_divine ? item_info->m_wDivLimitVit : item_info->m_wLimitVit; item_limits->limits[kIndex.eSTAT_INT] = is_divine ? item_info->m_wDivLimitInt : item_info->m_wLimitInt; item_limits->limits[kIndex.eSTAT_SPR] = is_divine ? item_info->m_wDivLimitSpr : item_info->m_wLimitSpr; }; if (limits_selector == eLimitLimited) { const float ratio = static_cast(item_slot.GetLimitValueRatio()); // NOTE: 0.001f = FLT_EPSILON const float kCorrection = (ratio < 0) ? (-0.5f - 0.001f) : (0.5f + 0.001f); if (level != 0) { float calc_limit = level + ((level * ratio) / 100.0f) + kCorrection; level = static_cast(calc_limit); }; // ranges = [eSTAT_STR:0, eSTAT_SPR:4] for (short* it = item_limits->limits; it != &item_limits->limits[kIndex.eSTAT_SIMUL_COUNTS - 1]; ++it) { const short limit = *it; if (limit == 0) { continue; }; float calc_limit = limit + ((limit * ratio) / 100.0f) + kCorrection; *it = static_cast(calc_limit); } }; const bool is_weapon = (item_info->IsWeapon() != false); const bool is_armor = (is_weapon == false) && item_info->IsArmor(); #ifdef _NA002823_WINGS_EQUIPMENTS_EXTENTION const bool is_wings = (item_info->m_wType == eITEMTYPE_WINGS); #else const bool is_wings = false; #endif // etc... accessories and enabled equip facility (pc room item, autobot, sign item...) if (is_weapon || is_armor || is_wings) { const BYTE enchant = item_slot.GetEnchant(); const LEVELTYPE item_level = item_info->m_LV; float limit_ratio = 0.0f; if (EnchantParser* enchant_parser = EnchantParser::Instance()) { limit_ratio = enchant_parser->GetLimitRatio(item_level, enchant, is_weapon, (limits_selector == eLimitLimited)); } // ranges = [eSTAT_STR:0, eSTAT_SPR:4] for (short* it = item_limits->limits; it != &item_limits->limits[kIndex.eSTAT_SIMUL_COUNTS - 1]; ++it) { const short limit = *it; if (limit == 0) { continue; }; if (is_weapon) { *it = ::ns_formula::CalcLimitStatWeapon(\ limit, enchant, RANK_E, item_level, limit_ratio); } else if (is_armor || is_wings) { *it = ::ns_formula::CalcLimitStatArmor(\ limit, enchant, RANK_E, item_level, limit_ratio); } } }; // item_limits->level = level; // return true; } //static bool ItemAttrCalculator::CanEquipmentStatComparison(const ns_formula::ItemAttrStats& player_stats, const ns_formula::ItemLimitations& item_limits) { if (player_stats.level < item_limits.level) { return false; }; #if defined(_NA_002935_20110704_ITEM_SCORE) && !defined(_SERVER) //// Ŭ¶óÀÌ¾ðÆ®¿¡¼­ ÁÖº¯ Ç÷¹À̾î Á¤º¸¸¦ ¹ÞÀ»¶§ ½ºÅÝ Á¤º¸´Â ¹ÞÁö ¾Ê±â ¶§¹®¿¡ ½ºÅÝÀº 0À¸·Î ÃʱâÈ­ µÇ¾î ÀÖ´Ù. //// ÇÏÁö¸¸ Àåºñ °è»ê Á¤º¸´Â ´Ù¸¥ ÄÁÅÙÃ÷¿¡¼­ »ç¿ëÇϱ⠶§¹®¿¡ ¼º°ø ó¸®ÇÑ´Ù. // Ŭ¶óÀÌ¾ðÆ®¿¡¼­ »ó´ë¹æ Àåºñº¸±â ÀÛ¾÷ Áß ´Ù¸¥ Ç÷¹À̾îÀÇ ½ºÅÈ¿¡ ´ëÇÑ Àåºñ °è»êÀ» ÇØ¾ß ÇÒ Çʿ䰡 »ý°Ü¼­, // È÷¾î·Î°¡ ¾Æ´Ñ ½ºÅÈ °è»ê¿¡¼­´Â true¸¦ ¸®ÅÏÇÑ´Ù.(È÷¾î·Î°¡ ¾Æ´Ñ Ç÷¹À̾î´Â ½ºÅÈÁ¤º¸°¡ 0À¸·Î ÃʱâÈ­µÇ¾î ÀÖ´Ù.) const bool is_other_player = ( (player_stats.stats[player_stats.eSTAT_STR]).base_value_.value_ == 0 && (player_stats.stats[player_stats.eSTAT_DEX]).base_value_.value_ == 0 && (player_stats.stats[player_stats.eSTAT_VIT]).base_value_.value_ == 0 && (player_stats.stats[player_stats.eSTAT_INT]).base_value_.value_ == 0 && (player_stats.stats[player_stats.eSTAT_SPR]).base_value_.value_ == 0); if (is_other_player) { return true; } #endif //defined(_NA_002935_20110704_ITEM_SCORE) && !defined(_SERVER) // const int decrease_limits = player_stats.stats[\ player_stats.eSTAT_DEC_LIMITS].calc_value_.value_; // if (const AttrValue* limits = &player_stats.stats[player_stats.eSTAT_STR]) { if (limits->calc_value_.value_ + decrease_limits < item_limits.limits[item_limits.eSTAT_STR]) { return false; } }; if (const AttrValue* limits = &player_stats.stats[player_stats.eSTAT_DEX]) { if (limits->calc_value_.value_ + decrease_limits < item_limits.limits[item_limits.eSTAT_DEX]) { return false; } }; if (const AttrValue* limits = &player_stats.stats[player_stats.eSTAT_VIT]) { if (limits->calc_value_.value_ + decrease_limits < item_limits.limits[item_limits.eSTAT_VIT]) { return false; } }; if (const AttrValue* limits = &player_stats.stats[player_stats.eSTAT_INT]) { if (limits->calc_value_.value_ + decrease_limits < item_limits.limits[item_limits.eSTAT_INT]) { return false; } }; if (const AttrValue* limits = &player_stats.stats[player_stats.eSTAT_SPR]) { if (limits->calc_value_.value_ + decrease_limits < item_limits.limits[item_limits.eSTAT_SPR]) { return false; } }; return true; } bool ItemAttrCalculator::CanEquipmentValidStats( const SCItemSlot& item_slot, const PlayerAttributes& player_attr, LEVELTYPE player_level) { ns_formula::ItemLimitations item_limits; ns_formula::ItemAttrStats player_stats; LoadPlayerLimits(&player_stats, player_attr, player_level); // if (LoadEquipmentLimits(&item_limits, item_slot) == false) { return false; } if (CanEquipmentStatComparison(player_stats, item_limits) == false) { return false; } return true; } // use : info_node.context bool ItemAttrCalculator::CanEquipmentValidStatsInternal(const EquipSlotNode& info_node) { ns_formula::ItemAttrContext* const context = info_node.context; if (context->calculated_stats == false) { if (LoadEquipmentLimits(&context->limits, info_node.item_slot) == false) { return false; }; context->calculated_stats = true; }; //---------------------------------------------------------------------------------------------- ns_formula::ItemAttrContextList* parent = info_node.context->parent; if (parent->calculated_total_stats == false) { LoadPlayerLimits(&parent->total_stats, attributes_, player_level_); parent->calculated_total_stats = true; } //parent->total_records // already updated if (CanEquipmentStatComparison(parent->total_stats, context->limits) == false) { return false; } return true; } bool ItemAttrCalculator::UpdatePlayerSimulationStatsByItemStats(const EquipSlotNode& info_node) { WAVERIX_WRAPPER((WAVERIX_LC_CALL1("waverix_log_trace", __FUNCTION__))); // NOTE: apply simulation stat ns_formula::ItemAttrStats* const total_stats = &info_node.context->parent->total_stats; for (AttrValue* it = total_stats->stats; it != &total_stats->stats[_countof(total_stats->stats)]; ++it) { it->Update(); } WAVERIX_WRAPPER((WAVERIX_LC_CALL4("waverix_log_trace2", "|Player current stats|{Str,Dex,Vit}=", total_stats->stats[total_stats->eSTAT_STR].calc_value_.value_, total_stats->stats[total_stats->eSTAT_DEX].calc_value_.value_, total_stats->stats[total_stats->eSTAT_VIT].calc_value_.value_))); WAVERIX_WRAPPER((WAVERIX_LC_CALL4("waverix_log_trace2", "|Player current stats|{Int,Spr,DecAll}=", total_stats->stats[total_stats->eSTAT_INT].calc_value_.value_, total_stats->stats[total_stats->eSTAT_SPR].calc_value_.value_, total_stats->stats[total_stats->eSTAT_DEC_LIMITS].calc_value_.value_))); return true; }; // NOTE: f110415.7L, add check interfaces to support switchable test bool ItemAttrCalculator::CheckExistLimits(const ns_formula::ItemLimitations& item_limits) { if (item_limits.level) { return true; }; for (const short* limit_it = item_limits.limits; limit_it != &item_limits.limits[_countof(item_limits.limits)]; ++limit_it) { // CHANGES: f110521.3L, fixed checking of value existence if (*limit_it) { return true; }; }; return false; } //================================================================================================== //================================================================================================== //================================================================================================== bool ItemAttrCalculator::Equip2( const SCItemSlot& IN slot, bool is_pc_room, bool use_update_ex, LEVELTYPE player_level) { WAVERIX_WRAPPER((WAVERIX_LC_CALL1("waverix_log_trace", __FUNCTION__))); __TOUCHED((&slot)); //---------------------------------------------------------------------------------------------- // NOTE: f110420.3L, changes logic to support nested update when the result of unit calculation // needs nested updates. ;{ pc_room_status_ = is_pc_room; use_update_ex_ = use_update_ex; player_level_ = player_level; }; ;{ slot_cache_info_->ClearEquipCounterInfo(); }; bool result = CalculateTotalConditionalEquipments(eInterControlHint_EquipOne, slot.GetPos()); //---------------------------------------------------------------------------------------------- // if (use_update_ex) { attributes_.UpdateEx(); } else { attributes_.Update(); }; //---------------------------------------------------------------------------------------------- return result; } bool ItemAttrCalculator::Unequip2( const SCItemSlot* slot, POSTYPE slot_pos, bool is_pc_room, bool use_update_ex, LEVELTYPE player_level) { WAVERIX_WRAPPER((WAVERIX_LC_CALL1("waverix_log_trace", __FUNCTION__))); __TOUCHED((slot)); // ;{ pc_room_status_ = is_pc_room; use_update_ex_ = use_update_ex; player_level_ = player_level; }; ;{ // clear process Clear(); // total stacked calculation // slot_cache_info_->ClearAll(); }; bool result = CalculateTotalConditionalEquipments(eInterControlHint_Unequip, slot_pos); //---------------------------------------------------------------------------------------------- // if (use_update_ex) { attributes_.UpdateEx(); } else { attributes_.Update(); }; // return result; } //-------------------------------------------------------------------------------------------------- bool ItemAttrCalculator::EquipAll(bool is_pc_room, bool use_update_ex, LEVELTYPE player_level) { WAVERIX_WRAPPER((WAVERIX_LC_CALL1("waverix_log_trace", __FUNCTION__))); // ;{ pc_room_status_ = is_pc_room; use_update_ex_ = use_update_ex; player_level_ = player_level; }; ;{ // clear process Clear(); // total stacked calculation // slot_cache_info_->ClearAll(); }; bool result = CalculateTotalConditionalEquipments(eInterControlHint_TotalEquips, 0); //---------------------------------------------------------------------------------------------- // if (use_update_ex) { attributes_.UpdateEx(); } else { attributes_.Update(); }; //---------------------------------------------------------------------------------------------- return result; } // changed item durability, change time expiration, etc... bool ItemAttrCalculator::ChangeItemDurabilityStatus( const SCItemSlot& IN slot, POSTYPE slot_pos, bool is_pc_room, bool use_update_ex, LEVELTYPE player_level) { WAVERIX_WRAPPER((WAVERIX_LC_CALL1("waverix_log_trace", __FUNCTION__))); // ;{ pc_room_status_ = is_pc_room; use_update_ex_ = use_update_ex; player_level_ = player_level; }; const bool duration_type = (slot.WithDura() != false); if (FlowControl::FCAssert(duration_type) == false) { return false; } const ns_formula::EquipSlotsManageInfo::Node& last_updated_info = \ slot_cache_info_->slots[slot_pos]; const DURATYPE duration = slot.GetDura(); enum { eProcess_NoChanges = 0, eProcess_Activation, eProcess_EquipAll, eProcess_ChangeOption, }; int what_to_do = eProcess_EquipAll; ;{ if (last_updated_info.duration == duration) { if (last_updated_info.duration == 0) { assert(last_updated_info.activated == false); }; what_to_do = eProcess_NoChanges; } else if (last_updated_info.duration) { // change duration if (duration == 0) { // disable (total calculation) what_to_do = eProcess_EquipAll; } else { #ifdef __NA_001062_20080623_STRENGTH_PENALTY // change attack power or defense power ... what_to_do = eProcess_ChangeOption; #else what_to_do = eProcess_NoChanges; #endif } } else if (duration) { if (last_updated_info.duration == 0) { what_to_do = eProcess_Activation; } else { #ifdef __NA_001062_20080623_STRENGTH_PENALTY // change attack power or defense power ... what_to_do = eProcess_ChangeOption; #else what_to_do = eProcess_NoChanges; #endif } } }; if (what_to_do == eProcess_NoChanges) { // update latest info. if (last_updated_info.duration != duration) { const_cast(\ &last_updated_info)->duration = duration; } return false; }; // switch (what_to_do) { case eProcess_Activation: ;{ ;{ pc_room_status_ = is_pc_room; use_update_ex_ = use_update_ex; player_level_ = player_level; }; bool result = CalculateTotalConditionalEquipments( eInterControlHint_ChangedToActivates, slot_pos); //---------------------------------------------------------------------------------------------- // if (use_update_ex) { attributes_.UpdateEx(); } else { attributes_.Update(); }; return result; }; case eProcess_EquipAll: return this->EquipAll(is_pc_room, use_update_ex, player_level); }; #if !defined(__NA_001062_20080623_STRENGTH_PENALTY) // update latest info. if (last_updated_info.duration != duration) { const_cast(\ &last_updated_info)->duration = duration; } return false; #else //if defined(__NA_001062_20080623_STRENGTH_PENALTY) // if (what_to_do != eProcess_ChangeOption) { assert(what_to_do == eProcess_ChangeOption); return false; } //---------------------------------------------------------------------------------------------- const DURATYPE max_duration = slot.GetMaxDura(); if (const BASE_ITEMINFO* item_info = slot.GetItemInfo()) { const DWORD penalty_index = item_info->m_dwStrengthPenaltyIdx; if (penalty_index == 0) { // update latest info. if (last_updated_info.duration != duration) { const_cast(\ &last_updated_info)->duration = duration; } return false; }; // StrengthPenaltyParser* const penalty_parser = StrengthPenaltyParser::Instance(); const sSTRENGTH_PENALTY* strength_penalty_prev = \ penalty_parser->GetStrengthPenaltyInfo(\ penalty_index, max_duration, last_updated_info.duration); const sSTRENGTH_PENALTY* strength_penalty_curr = \ penalty_parser->GetStrengthPenaltyInfo(\ penalty_index, max_duration, duration); if (strength_penalty_prev == strength_penalty_curr) { return false; }; }; //---------------------------------------------------------------------------------------------- // activated -> activated assert(duration != 0 && last_updated_info.duration != 0); // ns_formula::EquipSlotNodeBuffer info_node_buffer; EquipSlotNode* const info_node = info_node_buffer.GetInstance(); // EquipSlotNode::eDetailedResult init_result; if (EquipSlotNode::Initialize( &init_result, info_node, &slot) == false) { return false; }; // ;{ // configure operator info_node->current_operate = Attributes::Operation::eOper_Sub; info_node->position = slot_pos; info_node->duration = last_updated_info.duration; // subtract previous options info_node->max_duration = max_duration; }; // skip. //slot_cache_info_->IncreaseEquipInfo(slot); ns_formula::EquipSlotsManageInfo::Node* const work_node = \ &slot_cache_info_->slots[info_node->position]; // ns_formula::ItemAttrContextList contexts; // ns_formula::ItemLimitations* prev_limits = NULL; for (int loop_counter = 0; loop_counter < 2; ++loop_counter) { if (loop_counter == 0) { // 1st UpdateEquipSlotsLatestInfo(false, *info_node, work_node); info_node->context = contexts.BeginContext(info_node->position); } else { // 2nd info_node->current_operate = Attributes::Operation::eOper_Add; info_node->duration = duration; // 'duration' is changed value UpdateEquipSlotsLatestInfo(false, *info_node, work_node); info_node->context = contexts.BeginContext(info_node->position); info_node->context->calculated_stats = true; info_node->context->limits = *prev_limits; }; // if (CanEquipmentValidStatsInternal(*info_node) == false) { contexts.RollbackContext(); } else if (init_result == info_node->eResult_NoOptions) { work_node->activated = true; //------------------------------------------- contexts.RollbackContext(); } else { // (init_result == info_node->eResult_OptionsOnly) || // (init_result == info_node->eResult_AllProcess) work_node->activated = true; //------------------------------------------- CalculateEquipments(*info_node); //------------------------------------------- contexts.CommitContext(); } //------------------------------------------------------------------------------------------ UpdateEquipSlotsLatestInfo(work_node->activated, *info_node, work_node); //------------------------------------------------------------------------------------------ if (loop_counter == 0) { assert(info_node->context->calculated_stats); prev_limits = &info_node->context->limits; } }; if (contexts.number_of_total_records) { attributes_.GroupBatchOperate(contexts.total_records, contexts.number_of_total_records); }; //---------------------------------------------------------------------------------------------- // if (use_update_ex) { attributes_.UpdateEx(); } else { attributes_.Update(); }; //---------------------------------------------------------------------------------------------- // return true; #endif //__NA_001062_20080623_STRENGTH_PENALTY } //================================================================================================== // NOTE: f110415.7L, test whether new inserting item enabled equips instead of origin equipments bool ItemAttrCalculator::TestSwitchableEquipments( const SCItemSlot* equip_test_item, const POSTYPE to_slot_pos, bool is_pc_room, bool use_update_ex, LEVELTYPE player_level) { WAVERIX_WRAPPER((WAVERIX_LC_CALL1("waverix_log_trace", __FUNCTION__))); // if (bool out_of_ranges = (to_slot_pos >= eEQUIPCONTAINER_MAX)) { return false; }; // if (equip_test_item->CanEquip() == false) { return false; }; // ns_formula::EquipSlotNodeBuffer info_node_buffer_insert_test; EquipSlotNode* const info_node_insert_test = info_node_buffer_insert_test.GetInstance(); // EquipSlotNode::eDetailedResult init_result_insert_test; if (EquipSlotNode::Initialize( &init_result_insert_test, info_node_insert_test, equip_test_item) == false) { return false; }; ItemLimitations inven_item_limits; if (LoadEquipmentLimits(&inven_item_limits, *equip_test_item) == false) { return false; }; if (CheckExistLimits(inven_item_limits) == false) { // no-check ok. return true; }; //---------------------------------------------------------------------------------------------- // ns_formula::eInterControl_LimitsTestOnly support default attributes calculation skipping // in CalculateOptionNode wrapping with REGISTER_ATTR_NODE ns_formula::ItemAttrCalculatorInterControlAutoVariable auto_trans( &inter_control_mode_, ns_formula::eInterControl_LimitsTestOnly); // NOTE: f110415.7L, this algorithm use pre-calculating limitations. // AutoDependencyRevert is used to rollback temporary calculation result // that is used to support equips simulation without un-equips operation. struct AutoDependencyRevert { AutoDependencyRevert(ns_formula::EquipSlotsManageInfo* slot_cache_info) : slot_cache_info_(\ static_cast(slot_cache_info)) , modified_slot(NULL) {} ~AutoDependencyRevert() { if (modified_slot != NULL) { slot_cache_info_->IncreaseEquipInfoSimulation(*modified_slot); }; } ns_formula::EquipSlotsManageInfoInterController* slot_cache_info_; const SCItemSlot* modified_slot; } auto_revert(slot_cache_info_); //---------------------------------------------------------------------------------------------- ;{ pc_room_status_ = is_pc_room; use_update_ex_ = use_update_ex; player_level_ = player_level; }; // ns_formula::EquipSlotNodeBuffer info_node_buffer[MAX_EQUIPMENT_SLOT_NUM]; ns_formula::EquipWorkingSlots equip_slots = { 0, }; int number_of_item_contains = 0; ;{ ns_formula::EquipWorkingSlots::Node* dest_it = equip_slots.slots; ns_formula::EquipSlotsManageInfo::Node* work_node_it = slot_cache_info_->slots; typedef SCItemSlotContainer::SLOT_LINEAR_LIST SLOT_LINEAR_LIST; const SLOT_LINEAR_LIST& slot_list = equip_container_.GetSlotList(); SLOT_LINEAR_LIST::const_iterator it = slot_list.begin(), end = slot_list.end(); for (POSTYPE pos = 0; it != end; ++pos, ++dest_it, ++work_node_it, ++it) { const SCItemSlot* item_slot = static_cast(it->slot); const SLOTCODE item_code = item_slot->GetItemCode(); if (item_code == 0) { continue; }; // // NOTE: f110415.7L, this operation has only test. this calling can only be called // under already calculated attributes. so that this don't check external conditions. // no check = { slot_cache_info_->CheckEquipDefaultValidationWithoutStats } // no update = { UpdateEquipSlotsLatestInfo } const bool is_target_slot = (to_slot_pos == pos); if (is_target_slot) { // the reason of the activated check faster calling than decrease dependencies have // dependencies even though a checking item is inactivated. auto_revert.slot_cache_info_->DecreaseEquipInfoSimulation(*item_slot); auto_revert.modified_slot = item_slot; // the validation of this condition passed because new insert item test only if (equipment_accessor_->CheckEquipDefaultValidationWithoutStats( pos, *equip_test_item) == false) { return false; } continue; }; if (work_node_it->activated == false) { continue; }; // EquipSlotNode* info_node = info_node_buffer[pos].GetInstance(); EquipSlotNode::eDetailedResult init_result; // if (EquipSlotNode::Initialize( &init_result, info_node, item_slot) == false) { continue; } ;{ // configure operator info_node->current_operate = Attributes::Operation::eOper_Add; }; ;{ // setup info_node info_node->position = pos; if (item_slot->WithDura()) { info_node->duration = item_slot->GetDura(); info_node->max_duration = item_slot->GetMaxDura(); }; // NOTE: f110415.7L, this calling has only stat limitation check. // no update to external cache information. //UpdateEquipSlotsLatestInfo(false, *info_node, work_node_it); }; // dest_it->item_slot = item_slot; dest_it->info_node = info_node; dest_it->work_node = work_node_it; ++number_of_item_contains; } }; // // all equipments 'can equip' tests and apply options // except remove reservation item by 'to_slot_pos' ns_formula::ItemAttrContextList contexts; // int number_of_total_activates = 0; while (bool loop_until_has_not_calculate_anymore = (number_of_item_contains > number_of_total_activates)) { int number_of_activates = 0; ns_formula::EquipWorkingSlots::Node* equip_it = equip_slots.slots, * const equip_end = &equip_slots.slots[_countof(equip_slots.slots)]; for (; equip_it != equip_end; ++equip_it) { EquipSlotNode* const info_node = equip_it->info_node; if (equip_it->equipped || info_node == NULL) { continue; } bool activated = false; // info_node->context = contexts.BeginContext(info_node->position); if (CanEquipmentValidStatsInternal(*info_node) == false) { contexts.RollbackContext(); } else if (info_node->init_result == info_node->eResult_NoOptions) { activated = true; //------------------------------------------- contexts.RollbackContext(); } else if (info_node->init_result == info_node->eResult_OptionsOnly) { activated = true; //------------------------------------------- CalculateOptionList(*info_node); //------------------------------------------- UpdatePlayerSimulationStatsByItemStats(*info_node); // contexts.CommitContext(); } else { assert(info_node->init_result == info_node->eResult_AllProcess); activated = true; // equip process //------------------------------------------- //------------------------------------------- // NOTE: f110415.7L, this calling has only stat limitation check. //CalculateEquipments(*info_node); //------------------------------------------- CalculateOptionList(*info_node); //------------------------------------------- if (info_node->item_info->set_group_code) { CalculateSetItemOptions(*info_node, &equip_slots); }; //------------------------------------------- // NOTE: f110415.7L, this calling has only stat limitation check. // the socket options has not limitations. //CalculateSocketOptions(*info_node); //------------------------------------------- UpdatePlayerSimulationStatsByItemStats(*info_node); // contexts.CommitContext(); }; //-------------------------------------------------------------------------------------- //UpdateEquipSlotsLatestInfo(work_node->activated, *info_node, work_node); //-------------------------------------------------------------------------------------- if (activated) { equip_it->equipped = true; ++number_of_activates; } // NOTE: f110415.7L, this calling has only stat limitation check. // don't call attributes_.GroupBatchOperate. it is real calculator. // // NOTE: 'RecycleContexts' method is used in all equip process //contexts.RecycleContexts(); //-------------------------------------------------------------------------------------- } //end 'foreach item_slot in equip_container' // number_of_total_activates += number_of_activates; if (number_of_activates == 0) { break; }; }; //---------------------------------------------------------------------------------------------- // current state: at this point, all items that related to limitations calculated // except the slot of target position that will be inserted. // final test: whether the insertion test item enables really insertable considering limitations ;{ ns_formula::ItemAttrContext* context = contexts.BeginContext(to_slot_pos); context->calculated_stats = true; context->limits = inven_item_limits; // use pre-calculated info. // info_node_insert_test->context = context; if (CanEquipmentValidStatsInternal(*info_node_insert_test) == false) { return false; }; // WARNING: don't use a context closure because contexts don't be managed any longer. // but, if the contexts that is collection of context has operations since at this point, // use it like 'contexts.CommitContext' or 'contexts.RollbackContext'. }; //---------------------------------------------------------------------------------------------- return true; } //================================================================================================== //================================================================================================== // arguments: 'hint' = { eItemAttrCalculatorInterControlHint }; bool ItemAttrCalculator::CalculateTotalConditionalEquipments(const int hint, const int hint_arg) { __TOUCHED((hint_arg)); WAVERIX_WRAPPER((WAVERIX_LC_CALL1("waverix_log_trace", __FUNCTION__))); // ns_formula::EquipSlotNodeBuffer info_node_buffer[MAX_EQUIPMENT_SLOT_NUM]; ns_formula::EquipWorkingSlots equip_slots = { 0, }; typedef SCItemSlotContainer::SLOT_LINEAR_LIST SLOT_LINEAR_LIST; int number_of_item_contains = 0; ;{ ns_formula::EquipWorkingSlots::Node* dest_it = equip_slots.slots; ns_formula::EquipSlotsManageInfo::Node* work_node_it = slot_cache_info_->slots; const SLOT_LINEAR_LIST& slot_list = equip_container_.GetSlotList(); SLOT_LINEAR_LIST::const_iterator it = slot_list.begin(), end = slot_list.end(); for (POSTYPE pos = 0; it != end; ++pos, ++dest_it, ++work_node_it, ++it) { const SCItemSlot* item_slot = static_cast(it->slot); const SLOTCODE item_code = item_slot->GetItemCode(); if (item_code == 0) { continue; }; // ;;;; if ((hint == eInterControlHint_EquipOne)) { // NOTE: restrict_table_ of the slot_cache_info_ has cleared a reference counter. // ref: 'ClearEquipCounterInfo()' if (equipment_accessor_->CheckEquipDefaultValidationWithoutStats( pos, *item_slot) == false) { slot_cache_info_->IncreaseEquipInfo(*item_slot); continue; } slot_cache_info_->IncreaseEquipInfo(*item_slot); if (work_node_it->activated) { continue; }; } else if ((hint == eInterControlHint_TotalEquips) || (hint == eInterControlHint_Unequip)) { if (equipment_accessor_->CheckEquipDefaultValidationWithoutStats( pos, *item_slot) == false) { // NOTE: this process means already exist in container slot_cache_info_->IncreaseEquipInfo(*item_slot); continue; } slot_cache_info_->IncreaseEquipInfo(*item_slot); } else if ((hint == eInterControlHint_ChangedToActivates)) { // NOTE: when change durability, this case is selected. // changes inactivated slots to activated slots. // the case of changed durability event has no-list control // because of recalculation in single transaction. if (work_node_it->activated) { continue; }; if (equipment_accessor_->CheckEquipDefaultValidationWithoutStats( pos, *item_slot) == false) { continue; } }; // EquipSlotNode* info_node = info_node_buffer[pos].GetInstance(); EquipSlotNode::eDetailedResult init_result; // if (EquipSlotNode::Initialize( &init_result, info_node, item_slot) == false) { continue; } ;{ // configure operator info_node->current_operate = Attributes::Operation::eOper_Add; }; ;{ // setup info_node info_node->position = pos; if (item_slot->WithDura()) { info_node->duration = item_slot->GetDura(); info_node->max_duration = item_slot->GetMaxDura(); }; // UpdateEquipSlotsLatestInfo(false, *info_node, work_node_it); }; // dest_it->item_slot = item_slot; dest_it->info_node = info_node; dest_it->work_node = work_node_it; ++number_of_item_contains; } }; // // all equipments 'can equip' tests and apply options ns_formula::ItemAttrContextList contexts; // int number_of_total_activates = 0; float set_option_value = 0.0f; while (bool loop_until_has_not_calculate_anymore = (number_of_item_contains > number_of_total_activates)) { int number_of_activates = 0; ns_formula::EquipWorkingSlots::Node* equip_it = equip_slots.slots, * const equip_end = &equip_slots.slots[_countof(equip_slots.slots)]; for (; equip_it != equip_end; ++equip_it) { EquipSlotNode* const info_node = equip_it->info_node; if (equip_it->equipped || info_node == NULL) { continue; } ns_formula::EquipSlotsManageInfo::Node* const work_node = equip_it->work_node; // info_node->context = contexts.BeginContext(info_node->position); if (CanEquipmentValidStatsInternal(*info_node) == false) { contexts.RollbackContext(); } else if (info_node->init_result == info_node->eResult_NoOptions) { work_node->activated = true; //------------------------------------------- contexts.RollbackContext(); } else if (info_node->init_result == info_node->eResult_OptionsOnly) { work_node->activated = true; //------------------------------------------- CalculateOptionList(*info_node); //------------------------------------------- UpdatePlayerSimulationStatsByItemStats(*info_node); // contexts.CommitContext(); } else { assert(info_node->init_result == info_node->eResult_AllProcess); work_node->activated = true; // equip process //------------------------------------------- //------------------------------------------- CalculateEquipments(*info_node); //------------------------------------------- CalculateOptionList(*info_node); //------------------------------------------- #ifdef _NA_006731_20130521_ENCHANT_ADD_OPTION CalculateEnchantOption(*info_node); #endif // _NA_006731_20130521_ENCHANT_ADD_OPTION if (info_node->item_info->set_group_code ) { CalculateSetItemOptions(*info_node, &equip_slots); }; //------------------------------------------- // socket CalculateSocketOptions(*info_node); //------------------------------------------- UpdatePlayerSimulationStatsByItemStats(*info_node); // contexts.CommitContext(); }; //-------------------------------------------------------------------------------------- UpdateEquipSlotsLatestInfo(work_node->activated, *info_node, work_node); //-------------------------------------------------------------------------------------- if (work_node->activated) { equip_it->equipped = true; ++number_of_activates; //_NA_002935_20110704_ITEM_SCORE // °³º° Àåºñ Æò°¡ Á¡¼ö¸¦ °è»êÇÑ´Ù. ns_formula::EquipSlotsManageInfo::ItemScoreInfo& item_score_info = slot_cache_info_->item_score_info; if (work_node->position < _countof(item_score_info.each_item_score)) { item_score_info.each_item_score[work_node->position] = ItemScoreParser::Instance()->CalculateSingleScore( *(equip_it->item_slot), pc_room_status_); } } //-------------------------------------------------------------------------------------- } //end 'foreach item_slot in equip_container' // //_NA_002935_20110704_ITEM_SCORE if (number_of_activates > 0) { // ¼ÒÄϰú ¼¼Æ® ¿É¼Ç °ü·Ã Àåºñ Æò°¡ Á¡¼ö¸¦ °è»êÇÑ´Ù. ns_formula::EquipSlotsManageInfo::ItemScoreInfo& item_score_info = slot_cache_info_->item_score_info; ItemScoreParser::Instance()->CalculateTotalEquipScore( attributes_, item_score_info.socket_score, set_option_value); } // number_of_total_activates += number_of_activates; if (number_of_activates == 0) { break; }; }; //ÃÖÁ¾ Àåºñ ÆòÁ¡ °è»êÀº ¹Ø¿¡¼­ ÇÑ´Ù slot_cache_info_->item_score_info.set_option_score = set_option_value; slot_cache_info_->item_score_info.UpdateTotalScore(); //---------------------------------------------------------------------------------------------- if (contexts.number_of_total_records) { attributes_.GroupBatchOperate(contexts.total_records, contexts.number_of_total_records); #if USE_CLIENT_SOCKET_OPTION_TABLE // NOTE: f110530.3L this->slot_cache_info_->CalculateSocketOptionMappingTable(); #endif }; //---------------------------------------------------------------------------------------------- // return true; } //================================================================================================== //================================================================================================== #define REGISTER_ATTR_NODE(_attr_type_, _attr_kind_, _attr_value_) \ CalculateOptionNode(info_node, _attr_type_, _attr_kind_, _attr_value_) bool ItemAttrCalculator::CalculateOptionNode(const EquipSlotNode& info_node, eATTR_TYPE attr_type, eATTR_KIND attr_kind, int attr_value) { if (attr_value == 0) { return false; } if (bool out_range = !(eATTR_TYPE_INVALID < attr_type && attr_type < eATTR_MAX)) { return false; } ns_formula::ItemAttrContext& records = *info_node.context; // CHANGES: f110630.2L, fixed specific stat increasing option calculation problem //---------------------------------------------------------------------------------------------- if (const bool default_attr = (attr_type != eATTR_INCREASE_STAT_POINT) && (attr_type != eATTR_DECREASE_LIMIT_STAT) && (attr_type > eATTR_SPR)) { // NOTE: f110415.7L, if this operation is a test transaction // whether new inserting item enabled equips instead of origin equipments, this means // the below process that related to default attributes calcuation no longer have process. if (inter_control_mode_ != ns_formula::eInterControl_LimitsTestOnly) { if (Attributes::OperationRecord* record = records.BeginRecord()) { // assert(attr_value != 0); record->operate = info_node.current_operate; record->attr_kind = static_cast(attr_kind); record->attr_type = static_cast(attr_type); record->attr_value = attr_value; records.CommitRecord(); }; }; return true; } //---------------------------------------------------------------------------------------------- else if (FlowControl::FCAssert(attr_kind == eATTR_KIND_ITEM) == false) { return false; } //---------------------------------------------------------------------------------------------- else if (attr_type == eATTR_DECREASE_LIMIT_STAT) { if (inter_control_mode_ != ns_formula::eInterControl_LimitsTestOnly) { if (Attributes::OperationRecord* record = records.BeginRecord()) { // assert(attr_value != 0); record->operate = info_node.current_operate; record->attr_kind = static_cast(attr_kind); record->attr_type = static_cast(eATTR_DECREASE_LIMIT_STAT); record->attr_value = attr_value; records.CommitRecord(); }; }; if (ns_formula::ItemAttrStats* const player_stats = &records.parent->total_stats) { bool add_op = (info_node.current_operate == Attributes::Operation::eOper_Add); if (AttrValue* dest = &player_stats->stats[player_stats->eSTAT_DEC_LIMITS]) { dest->item_value_.value_ += (add_op ? attr_value : -attr_value); }; }; return true; } //---------------------------------------------------------------------------------------------- else if ((attr_type == eATTR_STR) || (attr_type == eATTR_DEX) || (attr_type == eATTR_VIT) || (attr_type == eATTR_INT) || (attr_type == eATTR_SPR)) { if (inter_control_mode_ != ns_formula::eInterControl_LimitsTestOnly) { if (Attributes::OperationRecord* record = records.BeginRecord()) { // assert(attr_value != 0); record->operate = info_node.current_operate; record->attr_kind = static_cast(attr_kind); record->attr_type = static_cast(attr_type); record->attr_value = attr_value; records.CommitRecord(); }; }; if (ns_formula::ItemAttrStats* const player_stats = &records.parent->total_stats) { BOOST_STATIC_ASSERT((player_stats->eSTAT_STR == eATTR_STR - 1) && (player_stats->eSTAT_DEX == eATTR_DEX - 1) && (player_stats->eSTAT_VIT == eATTR_VIT - 1) && (player_stats->eSTAT_INT == eATTR_INT - 1) && (player_stats->eSTAT_SPR == eATTR_SPR - 1)); bool add_op = (info_node.current_operate == Attributes::Operation::eOper_Add); if (AttrValue* dest = &player_stats->stats[attr_type - 1]) { dest->item_value_.value_ += (add_op ? attr_value : -attr_value); }; }; } //---------------------------------------------------------------------------------------------- else if (attr_type == eATTR_INCREASE_STAT_POINT) { if (inter_control_mode_ != ns_formula::eInterControl_LimitsTestOnly) { if (Attributes::OperationRecord* record = records.BeginRecord()) { // assert(attr_value != 0); record->operate = info_node.current_operate; record->attr_kind = static_cast(attr_kind); record->attr_type = static_cast(eATTR_STR); record->attr_value = attr_value; records.CommitRecord(); }; if (Attributes::OperationRecord* record = records.BeginRecord()) { // assert(attr_value != 0); record->operate = info_node.current_operate; record->attr_kind = static_cast(attr_kind); record->attr_type = static_cast(eATTR_DEX); record->attr_value = attr_value; records.CommitRecord(); }; if (Attributes::OperationRecord* record = records.BeginRecord()) { // assert(attr_value != 0); record->operate = info_node.current_operate; record->attr_kind = static_cast(attr_kind); record->attr_type = static_cast(eATTR_VIT); record->attr_value = attr_value; records.CommitRecord(); }; if (Attributes::OperationRecord* record = records.BeginRecord()) { // assert(attr_value != 0); record->operate = info_node.current_operate; record->attr_kind = static_cast(attr_kind); record->attr_type = static_cast(eATTR_INT); record->attr_value = attr_value; records.CommitRecord(); }; if (Attributes::OperationRecord* record = records.BeginRecord()) { // assert(attr_value != 0); record->operate = info_node.current_operate; record->attr_kind = static_cast(attr_kind); record->attr_type = static_cast(eATTR_SPR); record->attr_value = attr_value; records.CommitRecord(); }; }; if (ns_formula::ItemAttrStats* const player_stats = &records.parent->total_stats) { bool add_op = (info_node.current_operate == Attributes::Operation::eOper_Add); AttrValue* it = player_stats->stats; //without eSTAT_SIMUL_COUNTS for (; it != &player_stats->stats[_countof(player_stats->stats) - 1]; ++it) { it->item_value_.value_ += (add_op ? attr_value : -attr_value); }; }; } else { ASSERT(!"unexpected status"); }; //---------------------------------------------------------------------------------------------- return true; } bool ItemAttrCalculator::CalculateEquipments(const EquipSlotNode& info_node) { WAVERIX_WRAPPER((WAVERIX_LC_CALL1("waverix_log_trace", __FUNCTION__))); // // DONE: check time expiration, duration is zero, ... 'f110331.5L' const BASE_ITEMINFO* const item_info = info_node.item_info; const nsSlot::ItemRuleInfo& item_rule_info = info_node.item_rule_info; //---------------------------------------------------------------------------------------------- //---------------------------------------------------------------------------------------------- REGISTER_ATTR_NODE(eATTR_PHYSICAL_ATTACK_SUCCESS_RATIO, eATTR_KIND_ITEM, item_info->m_wPhyAttRate); REGISTER_ATTR_NODE(eATTR_PHYSICAL_ATTACK_BLOCK_BASE_ARMOR_RATIO, eATTR_KIND_ITEM, item_info->m_wPhyAvoid); REGISTER_ATTR_NODE(eATTR_ATTACK_SPEED, eATTR_KIND_ITEM, item_info->m_wPhyAttSpeed); REGISTER_ATTR_NODE(eATTR_MOVE_SPEED, eATTR_KIND_ITEM, item_info->m_wSpeed); //---------------------------------------------------------------------------------------------- //---------------------------------------------------------------------------------------------- ;;;; if (item_rule_info.is_weapon) { CalculateWeapon(info_node); } else if (item_rule_info.is_armor) { CalculateArmor(info_node); } #ifdef _NA002823_WINGS_EQUIPMENTS_EXTENTION else if (item_rule_info.is_accessory_wings) { CalculateArmor(info_node); } #endif else if (item_rule_info.is_accessory || item_rule_info.is_accessory_special) { CalculateAccessory(info_node); } return true; } //================================================================================================== bool ItemAttrCalculator::CalculateWeapon(const EquipSlotNode& info_node) { WAVERIX_WRAPPER((WAVERIX_LC_CALL1("waverix_log_trace", __FUNCTION__))); // ns_formula::InterAttackPowerCalculator calc_slot = { 0, }; const BASE_ITEMINFO* item_info = info_node.item_info; // if (info_node.item_slot.IsDivine()) { calc_slot.SetDefault(item_info->m_wDivPhyMinDamage, item_info->m_wDivPhyMaxDamage); } else if (info_node.item_info->IsElite()) { calc_slot.SetDefault(item_info->m_wElitePhyMinDamage, item_info->m_wElitePhyMaxDamage); } else if (info_node.item_info->IsUnique()) { calc_slot.SetDefault(item_info->m_wUniPhyMinDamage, item_info->m_wUniPhyMaxDamage); } else { calc_slot.SetDefault(item_info->m_wMinDamage, item_info->m_wMaxDamage); } // const SCItemSlot& item_slot = info_node.item_slot; if (item_slot.IsLimited()) { calc_slot.AddRatioWeight_Limited(static_cast(item_slot.GetDamageRatio())); } else if (item_slot.IsFateItem()) { calc_slot.AddRatioWeight_Fate(static_cast(item_slot.GetFateAtkDefRatio())); } // ;{ BYTE enchant = item_slot.GetEnchant(); DWORD weights_power = ::ns_formula::CalcAttackPower(enchant, item_info->m_LV); calc_slot.AddWeightValue(weights_power); }; #ifdef _NA_008124_20150313_AWAKENING_SYSTEM { BYTE awakening = item_slot.GetAwakening(); DWORD weights_power = ::ns_formula::CalcAwakeningWeapon(item_slot.GetCode(), awakening); calc_slot.AddWeightValue(weights_power); } #endif // _NA_008124_20150313_AWAKENING_SYSTEM #ifdef __NA_001062_20080623_STRENGTH_PENALTY ;{ const DWORD penalty_index = item_info->m_dwStrengthPenaltyIdx; if (penalty_index != 0) { const sSTRENGTH_PENALTY* strength_penalty = \ StrengthPenaltyParser::Instance()->GetStrengthPenaltyInfo(\ penalty_index, info_node.max_duration, info_node.duration); // calc_slot.AddRatioWeight_Strength(strength_penalty->m_fStrengthPro); } }; #endif //---------------------------------------------------------------------------------------------- //---------------------------------------------------------------------------------------------- REGISTER_ATTR_NODE(eATTR_BASE_MELEE_MIN_ATTACK_POWER, eATTR_KIND_ITEM, calc_slot.sum_of_min_power); REGISTER_ATTR_NODE(eATTR_BASE_MELEE_MAX_ATTACK_POWER, eATTR_KIND_ITEM, calc_slot.sum_of_max_power); REGISTER_ATTR_NODE(eATTR_BASE_RANGE_MIN_ATTACK_POWER, eATTR_KIND_ITEM, calc_slot.sum_of_min_power); REGISTER_ATTR_NODE(eATTR_BASE_RANGE_MAX_ATTACK_POWER, eATTR_KIND_ITEM, calc_slot.sum_of_max_power); return true; } bool ItemAttrCalculator::CalculateArmor(const EquipSlotNode& info_node) { WAVERIX_WRAPPER((WAVERIX_LC_CALL1("waverix_log_trace", __FUNCTION__))); // ns_formula::InterDefensePowerCalculator calc_slot = { 0, }; const BASE_ITEMINFO* item_info = info_node.item_info; // if (info_node.item_slot.IsDivine()) { calc_slot.SetDefault(item_info->m_wDivPhyDef); } else if (info_node.item_info->IsElite()) { calc_slot.SetDefault(item_info->m_wElitePhyDef); } else if (info_node.item_info->IsUnique()) { calc_slot.SetDefault(item_info->m_wUniPhyDef); } else { calc_slot.SetDefault(item_info->m_wPhyDef); }; const SCItemSlot& item_slot = info_node.item_slot; const BYTE enchant = item_slot.GetEnchant(); calc_slot.sum_of_defense_power = ::ns_formula::CalcPhyDef(calc_slot.sum_of_defense_power, enchant, item_info->m_LV); #ifdef _NA_008124_20150313_AWAKENING_SYSTEM const BYTE awakening = item_slot.GetAwakening(); calc_slot.sum_of_defense_power += ::ns_formula::CalcAwakeningArmor(item_slot.GetCode(), awakening); #endif // _NA_008124_20150313_AWAKENING_SYSTEM // CHANGES: f110831.3L, do not update anymore if the selected defense power is zero if (calc_slot.sum_of_defense_power == 0) { return true; }; // if (item_slot.IsLimited()) { calc_slot.AddRatioWeight_Limited(static_cast(item_slot.GetDamageRatio())); } else if (item_slot.IsFateItem()) { calc_slot.AddRatioWeight_Fate(static_cast(item_slot.GetFateAtkDefRatio())); } #ifdef __NA_001062_20080623_STRENGTH_PENALTY ;{ const DWORD penalty_index = item_info->m_dwStrengthPenaltyIdx; if (penalty_index != 0) { const sSTRENGTH_PENALTY* strength_penalty = \ StrengthPenaltyParser::Instance()->GetStrengthPenaltyInfo(\ penalty_index, info_node.max_duration, info_node.duration); // calc_slot.AddRatioWeight_Strength(strength_penalty->m_fStrengthPro); } }; #endif //---------------------------------------------------------------------------------------------- //---------------------------------------------------------------------------------------------- REGISTER_ATTR_NODE(eATTR_BASE_MELEE_DEFENSE_POWER, eATTR_KIND_ITEM, calc_slot.sum_of_defense_power); REGISTER_ATTR_NODE(eATTR_BASE_RANGE_DEFENSE_POWER, eATTR_KIND_ITEM, calc_slot.sum_of_defense_power); return true; } bool ItemAttrCalculator::CalculateAccessory(const EquipSlotNode& info_node) { WAVERIX_WRAPPER((WAVERIX_LC_CALL1("waverix_log_trace", __FUNCTION__))); // ns_formula::ItemAttrContext& records = *info_node.context; __UNUSED((info_node, records)); return true; } bool ItemAttrCalculator::CalculateOptionList(const EquipSlotNode& info_node) { WAVERIX_WRAPPER((WAVERIX_LC_CALL1("waverix_log_trace", __FUNCTION__))); // const SCItemSlot& item_slot = info_node.item_slot; const nsSlot::ItemRuleInfo& item_rule_info = info_node.item_rule_info; const BASE_ITEMINFO* item_info = info_node.item_info; // NOTE: extra-stone option // CHANGES: f100406.2L, waverix, add filter condition // because inventory effect item is not equip but can apply option if (item_rule_info.IsEnableExtraOption()) { if (int n_option_attr_index = item_slot.GetNOptionAttrIndex()) { const sEXTRASTONE_OPT_INFO* extra_option = item_slot.GetNOptionAttrDesc(); if (extra_option && extra_option->m_byValueType < _countof(kAttrKindByValueTypes)) { REGISTER_ATTR_NODE(item_slot.GetNOptionAttr(), kAttrKindByValueTypes[extra_option->m_byValueType], item_slot.GetNOptionAttrValue()); } } } //end extra option part // (NOTE) calculate item option by script // (CHANGES) (WAVERIX) changes to more simple code const int upperbound_selector = pc_room_status_ ? 2 : 1; //Normal|PC option groups for (int selector = 0; selector < upperbound_selector; ++selector) { const BASE_ITEMINFO::OptionEffects* __option_effects = selector == 0 ? &item_info->m_byOptionExEffect : &item_info->m_byPCOptionExEffect; const BASE_ITEMINFO::OptionEffects& option_effects = *__option_effects; bool apply = ARR_CHECK_IS_CONTAIN(BASE_ITEMINFO::OPTION_EFFECT_EQUIP_MASK::MASK, option_effects); if (apply == false) { continue; } const BASE_ITEMINFO::OptionIndexes* __option_indexes = (selector == 0) ? &item_info->m_wOptionIndex : &item_info->m_wPCOptionIndex; const BASE_ITEMINFO::OptionTypes* __option_types = (selector == 0) ? &item_info->m_byOptionType : &item_info->m_byPCOptionType; const BASE_ITEMINFO::OptionValues* __option_values = (selector == 0) ? &item_info->m_iOptionValue : &item_info->m_iPCOptionValue; // const BASE_ITEMINFO::OptionIndexes& option_indexes = *__option_indexes; const BASE_ITEMINFO::OptionTypes& option_types = *__option_types; const BASE_ITEMINFO::OptionValues& option_values = *__option_values; for (int op = 0; op < _countof(option_indexes); ++op) { bool is_valid_values = option_indexes[op] != 0 && option_values[op] != 0 && option_indexes[op] < _countof(g_ITEM_OPTION) && option_types[op] < _countof(kAttrKindByValueTypes); if (is_valid_values == false) { continue; } REGISTER_ATTR_NODE(g_ITEM_OPTION[option_indexes[op]], kAttrKindByValueTypes[option_types[op]], option_values[op]); } } return true; } // NOTE: f110906.2L, added 'working_slot_root' to prevent a special option duplicated calculation. bool ItemAttrCalculator::CalculateSetItemOptions(const EquipSlotNode& info_node, ns_formula::EquipWorkingSlots* const working_slot_root) { WAVERIX_WRAPPER((WAVERIX_LC_CALL1("waverix_log_trace", __FUNCTION__))); // WORD set_item_group = info_node.item_info->set_group_code; if (set_item_group == 0) { assert(!"need precedence check"); return false; }; // SetItemOptionInfoParser* const set_item_parser = SetItemOptionInfoParser::Instance(); const SETITEM_OPTION_INFO* const set_item_option_info = set_item_parser->Find(set_item_group); // replaced by _SOLAR_SLOT_INTEGRITY_CONTAINER_PROCESS_ //ÇöÀç ÀåÂøµÇ¾î ÀÖ´Â ¾ÆÀÌÅÛÁß ÇØ´ç ŸÀÔÀÇ ¼¼Æ® ¾ÆÀÌÅÛÀ» °¡Áö°í ¿Â´Ù. // (CHANGES) find related set item, to support special accessory multi-link SCItemSlot* temp_set_item_slot_array[MAX_INVENTORY_SLOT_NUM]; SCItemSlotContainer::SameSetItemSlotsResult find_result = \ equip_container_.GetSameSetItemSlots(temp_set_item_slot_array, _countof(temp_set_item_slot_array), info_node.item_info, true); // compatible set if (find_result.number_of_same_set_items == 0) { return true; } SCItemSlot* temp_set_item_slot_array2[MAX_INVENTORY_SLOT_NUM]= { 0, }; SCItemSlotContainer::SameSetItemSlotsResult find_result_Total = \ equip_container_.GetSameSetItemTotalSlots(temp_set_item_slot_array2, _countof(temp_set_item_slot_array2), info_node.item_info, true); int number_of_same_set_items = find_result.number_of_same_set_items; set_item_group = find_result.set_item_code; // replacing // activated_set_items is sequential order ns_formula::EquipSlotsManageInfo::Node* activated_set_items[MAX_EQUIPMENT_SLOT_NUM] = { 0, }; ;{ ns_formula::EquipSlotsManageInfo::Node** dest_it = activated_set_items; SCItemSlot** it = temp_set_item_slot_array, ** end = temp_set_item_slot_array + number_of_same_set_items; for ( ; it != end; ++it) { int pos = (*it)->GetPos(); if (ns_formula::EquipSlotsManageInfo::Node* node = &slot_cache_info_->slots[pos]) { if (node->activated == false) { continue; } *dest_it++ = node; }; } // CHANGES: f110419.4L, modify numbers to current activated set items number_of_same_set_items = static_cast(dest_it - activated_set_items); }; //---------------------------------------------------------------------------------------------- const BASE_ITEMINFO* const item_info = info_node.item_info; bool is_special_accessory_process = \ (item_info->m_bySetOptionType == item_info->eSetItem_Special); //---------------------------------------------------------------------------------------------- BOOST_STATIC_ASSERT(SETITEM_OPTION_LEVEL_NONE == 0); const eSETITEM_OPTION_LEVEL changed_level = (number_of_same_set_items <= 0) ? SETITEM_OPTION_LEVEL_NONE : set_item_parser->GetSetItemOptionLevel(number_of_same_set_items); if (changed_level == SETITEM_OPTION_LEVEL_NONE) { return true; }; const eSETITEM_OPTION_LEVEL prev_level = ((number_of_same_set_items - 1) <= 0) ? SETITEM_OPTION_LEVEL_NONE : set_item_parser->GetSetItemOptionLevel(number_of_same_set_items - 1); // const bool changed_option_level = (prev_level != changed_level); //---------------------------------------------------------------------------------------------- // NOTE: incremental update routine, the new inserted item to apply set option has not // pre-historical update options so that basically set options of the item apply until latest grade if (is_special_accessory_process == false) { for (int level = SETITEM_OPTION_LEVEL_FIRST; changed_option_level ? (level < changed_level) : (level <= changed_level); ++level) { WAVERIX_WRAPPER((WAVERIX_LC_CALL3("waverix_log_trace2", "|Apply Single|{Pos, Level}=", info_node.position, level))); const SET_ITEM_OPTION* set_item_option = set_item_parser->GetCurrentSetItemOption(set_item_option_info, info_node.position, static_cast(level)); if (set_item_option == NULL) { continue; }; if (set_item_option->m_byOptionKind == 0 || set_item_option->m_byOptionKind >= _countof(g_ITEM_OPTION) || set_item_option->m_nOption == 0 || set_item_option->m_byUseType == 0 || set_item_option->m_byUseType >= _countof(kAttrKindByValueTypes)) { continue; } //_NA_002935_20110704_ITEM_SCORE attributes_.GetSetOptionAttributes().AddAttr( g_ITEM_OPTION[set_item_option->m_byOptionKind], kAttrKindByValueTypes[set_item_option->m_byUseType], set_item_option->m_nOption); REGISTER_ATTR_NODE(g_ITEM_OPTION[set_item_option->m_byOptionKind], kAttrKindByValueTypes[set_item_option->m_byUseType], set_item_option->m_nOption); }; }; //---------------------------------------------------------------------------------------------- // apply option effects for all same set items (including inserted now slot) if ((changed_option_level) && (is_special_accessory_process == false)) { // s ns_formula::EquipSlotsManageInfo::Node** it = activated_set_items, ** end = &activated_set_items[_countof(activated_set_items)]; for ( ; it != end; ++it) { // activated_set_items is sequential order if (*it == NULL) { break; } WAVERIX_WRAPPER((WAVERIX_LC_CALL3("waverix_log_trace2", "|Apply grade option|{Pos, Level}=", (*it)->position, changed_level))); const SET_ITEM_OPTION* set_item_option = set_item_parser->GetCurrentSetItemOption(set_item_option_info, (*it)->position, static_cast(changed_level)); if (set_item_option == NULL) { continue; }; // if (set_item_option->m_byOptionKind == 0 || set_item_option->m_byOptionKind >= _countof(g_ITEM_OPTION) || set_item_option->m_nOption == 0 || set_item_option->m_byUseType == 0 || set_item_option->m_byUseType >= _countof(kAttrKindByValueTypes)) { continue; }; //_NA_002935_20110704_ITEM_SCORE attributes_.GetSetOptionAttributes().AddAttr( g_ITEM_OPTION[set_item_option->m_byOptionKind], kAttrKindByValueTypes[set_item_option->m_byUseType], set_item_option->m_nOption); REGISTER_ATTR_NODE(g_ITEM_OPTION[set_item_option->m_byOptionKind], kAttrKindByValueTypes[set_item_option->m_byUseType], set_item_option->m_nOption); }; }; // //---------------------------------------------------------------------------------------------- // full option const bool is_full_option = set_item_parser->IsFullOptionCount( set_item_option_info, number_of_same_set_items); // if ((is_full_option) && (is_special_accessory_process == false)) { SetOptionAttributes& setoption_attrs = attributes_.GetSetOptionAttributes(); const SET_ITEM_OPTION* it = set_item_option_info->m_FullOption, * const end = &set_item_option_info->m_FullOption[\ _countof(set_item_option_info->m_FullOption)]; #ifdef _NA_000000_20160204_MODIFY_SETOPTION_APPLIED_LIST if (setoption_attrs.IsAppliedThisSetOption(set_item_group) == false) { // ¼¼Æ®¿É¼Ç ¹ÌÀû¿ë»óÅÂÀÏ °æ¿ì¿¡¸¸ Àû¿ë½ÃŲ´Ù setoption_attrs.SetSetGroupCode(set_item_group); for ( ; it != end; ++it) { WAVERIX_WRAPPER((WAVERIX_LC_CALL1("waverix_log_trace2", "|Apply full option|{}="))); bool is_valid_attr_info = it->m_byOptionKind != 0 && it->m_byOptionKind < _countof(g_ITEM_OPTION) && it->m_nOption != 0 && it->m_byUseType != 0 && it->m_byUseType < _countof(kAttrKindByValueTypes); if (is_valid_attr_info == false) { continue; }; int value_double = static_cast(find_result.number_of_same_set_items) - static_cast(find_result_Total.number_of_same_set_items); //Ç®¼ÂÀÇ °æ¿ì Áߺ¹ Àû¿ëµÇ´Â °æ¿ì°¡ ÀÖÀ½. //À̸¦ ¹æÁöÇÔ (ƯÈ÷ ¾Ç¼¼»ç¸®) //¼ÂÆ® optionÀÇ ÃÖ´ëÄ¡´Â ¸îÀϱî? //_NA_008664_20160129_MODIFY_SETITEMOPTION_CONDITION // ¼¼Æ®¿É¼Ç Àû¿ëÁ¶°Ç º¯°æ //if(value_double == 0 && attributes_.GetSetOptionAttributes().GetAttrValue(g_ITEM_OPTION[it->m_byOptionKind]).fix_value < it->m_nOption) attributes_.GetSetOptionAttributes().AddAttr( g_ITEM_OPTION[it->m_byOptionKind], kAttrKindByValueTypes[it->m_byUseType], it->m_nOption); REGISTER_ATTR_NODE(g_ITEM_OPTION[it->m_byOptionKind], kAttrKindByValueTypes[it->m_byUseType], it->m_nOption); }; } #else for ( ; it != end; ++it) { WAVERIX_WRAPPER((WAVERIX_LC_CALL1("waverix_log_trace2", "|Apply full option|{}="))); bool is_valid_attr_info = it->m_byOptionKind != 0 && it->m_byOptionKind < _countof(g_ITEM_OPTION) && it->m_nOption != 0 && it->m_byUseType != 0 && it->m_byUseType < _countof(kAttrKindByValueTypes); if (is_valid_attr_info == false) { continue; }; #ifdef _NA_002935_20110704_ITEM_SCORE #ifdef _NA_006655_20130422_BUG_ACCESSORY_SETOPTION #else //_NA_006655_20130422_BUG_ACCESSORY_SETOPTION attributes_.GetSetOptionAttributes().AddAttr( g_ITEM_OPTION[it->m_byOptionKind], kAttrKindByValueTypes[it->m_byUseType], it->m_nOption); #endif //_NA_006655_20130422_BUG_ACCESSORY_SETOPTION int value_double = static_cast(find_result.number_of_same_set_items) - static_cast(find_result_Total.number_of_same_set_items); //Ç®¼ÂÀÇ °æ¿ì Áߺ¹ Àû¿ëµÇ´Â °æ¿ì°¡ ÀÖÀ½. //À̸¦ ¹æÁöÇÔ (ƯÈ÷ ¾Ç¼¼»ç¸®) //¼ÂÆ® optionÀÇ ÃÖ´ëÄ¡´Â ¸îÀϱî? #ifdef _NA_006655_20130422_BUG_ACCESSORY_SETOPTION //_NA_008664_20160129_MODIFY_SETITEMOPTION_CONDITION // ¼¼Æ®¿É¼Ç Àû¿ëÁ¶°Ç º¯°æ //if(value_double == 0 && attributes_.GetSetOptionAttributes().GetAttrValue(g_ITEM_OPTION[it->m_byOptionKind]).fix_value < it->m_nOption) if(value_double == 0) { attributes_.GetSetOptionAttributes().AddAttr( g_ITEM_OPTION[it->m_byOptionKind], kAttrKindByValueTypes[it->m_byUseType], it->m_nOption); REGISTER_ATTR_NODE(g_ITEM_OPTION[it->m_byOptionKind], kAttrKindByValueTypes[it->m_byUseType], it->m_nOption); } #else //_NA_008664_20160129_MODIFY_SETITEMOPTION_CONDITION // ¼¼Æ®¿É¼Ç Àû¿ëÁ¶°Ç º¯°æ //if(value_double == 0 && attributes_.GetSetOptionAttributes().GetAttrValue(g_ITEM_OPTION[it->m_byOptionKind]).fix_value < it->m_nOption) if(value_double == -1) { attributes_.GetSetOptionAttributes().AddAttr( g_ITEM_OPTION[it->m_byOptionKind], kAttrKindByValueTypes[it->m_byUseType], it->m_nOption * -1); } REGISTER_ATTR_NODE(g_ITEM_OPTION[it->m_byOptionKind], kAttrKindByValueTypes[it->m_byUseType], it->m_nOption); #endif //_NA_006655_20130422_BUG_ACCESSORY_SETOPTION #endif // _NA_002935_20110704_ITEM_SCORE }; #endif //_NA_000000_20160204_MODIFY_SETOPTION_APPLIED_LIST // CHANGES: f110623.4L, fixed the special accessory item unexpected ordering // calulation problem that doesn't applied additional special options // when a full set item equipped. is_special_accessory_process = true; }; // //---------------------------------------------------------------------------------------------- // special accessory option if ((is_full_option) && (is_special_accessory_process)) { bool apply_special_accessory_full_set_options = false; const SPECIAL_EQUIP_ACTIVE_OPTION& special_option = set_item_option_info->m_SpecialEquipOptionItem; // search same item group to regard multi-equippable cases. //if (special_option.m_wItemCode == item_info->m_Code) // apply_special_accessory_full_set_options = true; //-------------------------------------------------------------------------- // NOTE: if special accessory is already equipped, // the actor that is the equip calulation item has not the main agent // for full option calculating. // NOTE: action, the changes related to sun:r58153~ implemented by jaykang // process a item that is matched with the finding item in same type ranges. const SCItemSlot& matched_special_item = equip_container_.GetItemOfType(\ special_option.m_EqPos, special_option.m_wItemCode); SLOTCODE item_code = matched_special_item.GetItemCode(); if (item_code != 0 && item_code == special_option.m_wItemCode) { POSTYPE pos = matched_special_item.GetPos(); ns_formula::EquipSlotsManageInfo::Node* node = &slot_cache_info_->slots[pos]; if (node->activated && working_slot_root->slots[pos].applied_special_fullset_option == false) { apply_special_accessory_full_set_options = true; working_slot_root->slots[pos].applied_special_fullset_option = true; }; }; if (apply_special_accessory_full_set_options) { WAVERIX_WRAPPER((WAVERIX_LC_CALL3("waverix_log_trace2", "|Apply special option|{Pos, Code}=", special_option.m_EqPos, special_option.m_wItemCode))); const SET_ITEM_OPTION* it = special_option.m_ActiveOption, * const end = &special_option.m_ActiveOption[\ _countof(special_option.m_ActiveOption)]; for ( ; it != end; ++it) { bool is_valid_attr_info = it->m_byOptionKind != 0 && it->m_byOptionKind < _countof(g_ITEM_OPTION) && it->m_nOption != 0 && it->m_byUseType != 0 && it->m_byUseType < _countof(kAttrKindByValueTypes); if (is_valid_attr_info == false) { continue; }; //_NA_002935_20110704_ITEM_SCORE attributes_.GetSetOptionAttributes().AddAttr( g_ITEM_OPTION[it->m_byOptionKind], kAttrKindByValueTypes[it->m_byUseType], it->m_nOption); REGISTER_ATTR_NODE(g_ITEM_OPTION[it->m_byOptionKind], kAttrKindByValueTypes[it->m_byUseType], it->m_nOption); }; } } //---------------------------------------------------------------------------------------------- return true; } // bool ItemAttrCalculator::CalculateSocketOptions(const EquipSlotNode& info_node) { WAVERIX_WRAPPER((WAVERIX_LC_CALL1("waverix_log_trace", __FUNCTION__))); // Æ÷ÀÎÆ® ¹æ½Ä °è»ê¿¡¼­´Â ÀåÂø ÁßÀÎ ¸ðµç ¾ÆÀÌÅÛÀÇ ¿É¼Ç Æ÷ÀÎÆ®ÇÕÀ» ±âÁØÀ¸·Î ½ÇÁ¦ ¿É¼Ç°ªÀ¸·Î º¯È¯ÇØ¾ß ÇÑ´Ù. // ¾ÆÀÌÅÛÀÇ Âø¿ë »óŰ¡ º¯°æµÉ ¶§ ´ÙÀ½°ú °°ÀÌ °è»êÇÑ´Ù. // 1. Âø¿ë »óÅ º¯°æ Àü¿¡ Àû¿ëµÈ ¿É¼Ç°ªÀ» Á¦°ÅÇÑ´Ù. // 2. Âø¿ë »óÅ º¯°æ ÈÄÀÇ ¿É¼Ç Æ÷ÀÎÆ®¸¦ °è»êÇØ¼­ ¿É¼Ç°ªÀ¸·Î º¯È¯ÇÑ ÈÄ Àû¿ëÇÑ´Ù. // ÀåÂø ¶Ç´Â ÇØÁ¦ÇÏ·Á´Â ¾ÆÀÌÅÛ¸¸ÀÇ ¿É¼Ç Æ÷ÀÎÆ®¸¦ °è»êÇÑ´Ù. using ns_formula::SocketSearchBoard; SocketSearchBoard search_board; if (search_board.SearchSocketOptionPoint(info_node.item_slot, &search_board) == false) { return false; }; #if USE_CLIENT_SOCKET_OPTION_TABLE // CHANGES: f110530.3L assert(info_node.position < _countof(this->slot_cache_info_->item_socket_option_list)); EquipSlotsManageInfo::ItemSocketOptionList* const option_list = &this->slot_cache_info_->item_socket_option_list[info_node.position]; option_list->resize(0); option_list->reserve(search_board.number_of_registered); #endif // const SocketSearchBoard::RegistNode* regist_it = search_board.registered_nodes, * regist_end = &search_board.registered_nodes[search_board.number_of_registered]; for ( ; regist_it != regist_end; ++regist_it) { SocketSearchBoard::node_type* result_node = regist_it->link_node; // const eATTR_TYPE attr_type = result_node->attr_option_code; assert(attr_type > eATTR_TYPE_INVALID && attr_type < eATTR_MAX); // ¿É¼Ç°ªÀ» °è»êÇÑ´Ù. //CalculateItemOptionValue(is_add, item_calc_result_pair.second, item_calculator); // ÀÌÀü °è»ê °á°ú¸¦ Á¦°ÅÇÑ´Ù. SocketOptionAttributes::AttrValue& prev_attr_value = socket_attributes_.GetAttrValueByMutable(attr_type); if (prev_attr_value.calc_value != 0) { ;{ // configure operator assert(info_node.current_operate == Attributes::Operation::eOper_Add); info_node.current_operate = Attributes::Operation::eOper_Sub; }; REGISTER_ATTR_NODE(attr_type, kAttrKindByValueTypes[result_node->option_type], prev_attr_value.calc_value); ;{ // configure operator info_node.current_operate = Attributes::Operation::eOper_Add; }; }; // update point prev_attr_value.point += result_node->option_point; prev_attr_value.calc_value = 0; // const ZardOptionInfo* zard_option = regist_it->option_info; if (const ZardOptionInfo::OptionValueInfo* zard_option_value = \ zard_option->Find(prev_attr_value.point)) { prev_attr_value.calc_value = zard_option_value->value; } // »õ·Î¿î °è»ê °á°ú¸¦ Àû¿ëÇÑ´Ù. if (prev_attr_value.calc_value != 0) { REGISTER_ATTR_NODE(attr_type, kAttrKindByValueTypes[result_node->option_type], prev_attr_value.calc_value); #if USE_CLIENT_SOCKET_OPTION_TABLE // CHANGES: f110530.3L typedef EquipSlotsManageInfo::ItemSocketOption CastType; const SocketSearchBoard::node_type* node = regist_it->link_node; option_list->push_back(*node); #endif } }; return true; } // static bool ItemAttrCalculator::SocketOptionCalculator::CalculateItemOptionPoint( const SCItemSlot& item_slot, CalculationResultMap& OUT item_calc_result_list) { WAVERIX_WRAPPER((WAVERIX_LC_CALL1("waverix_log_trace", __FUNCTION__))); // Æ÷ÀÎÆ® ¹æ½Ä °è»ê¿¡¼­´Â ÀåÂø ÁßÀÎ ¸ðµç ¾ÆÀÌÅÛÀÇ ¿É¼Ç Æ÷ÀÎÆ®ÇÕÀ» ±âÁØÀ¸·Î ½ÇÁ¦ ¿É¼Ç°ªÀ¸·Î º¯È¯ÇØ¾ß ÇÑ´Ù. // ¾ÆÀÌÅÛÀÇ Âø¿ë »óŰ¡ º¯°æµÉ ¶§ ´ÙÀ½°ú °°ÀÌ °è»êÇÑ´Ù. // 1. Âø¿ë »óÅ º¯°æ Àü¿¡ Àû¿ëµÈ ¿É¼Ç°ªÀ» Á¦°ÅÇÑ´Ù. // 2. Âø¿ë »óÅ º¯°æ ÈÄÀÇ ¿É¼Ç Æ÷ÀÎÆ®¸¦ °è»êÇØ¼­ ¿É¼Ç°ªÀ¸·Î º¯È¯ÇÑ ÈÄ Àû¿ëÇÑ´Ù. item_calc_result_list.resize(0); // ÀåÂø ¶Ç´Â ÇØÁ¦ÇÏ·Á´Â ¾ÆÀÌÅÛ¸¸ÀÇ ¿É¼Ç Æ÷ÀÎÆ®¸¦ °è»êÇÑ´Ù. using ns_formula::SocketSearchBoard; SocketSearchBoard search_board; if (search_board.SearchSocketOptionPoint(item_slot, &search_board) == false) { return false; } // item_calc_result_list.reserve(search_board.number_of_registered); // const SocketSearchBoard::RegistNode* regist_it = search_board.registered_nodes, * regist_end = &search_board.registered_nodes[search_board.number_of_registered]; for ( ; regist_it != regist_end; ++regist_it) { typedef ItemAttrCalculator::SocketOptionCalculator::CalculationResult CastType; const SocketSearchBoard::node_type* node = regist_it->link_node; item_calc_result_list.push_back(CalculationResultMap::value_type(\ node->attr_option_code, static_cast(*node))); } return true; } #ifdef _NA_006731_20130521_ENCHANT_ADD_OPTION bool ItemAttrCalculator::CalculateEnchantOption(const EquipSlotNode& info_node) { const SCItemSlot& item_slot = info_node.item_slot; const nsSlot::ItemRuleInfo& item_rule_info = info_node.item_rule_info; const BASE_ITEMINFO* item_info = info_node.item_info; const bool is_weapon = item_info->IsWeapon(); // 0:¹«±â, 1:¹æ¾î±¸ const LEVELTYPE item_level = item_info->m_LV; // ¾ÆÀÌÅÛ µî±Þ const uint8_t enchant_grade = item_slot.GetEnchant(); // wing item..Á¦¿Ü. if (item_info->IsSpecialAccessory()) { return false; } const EnchantParser* const enchant_parser = EnchantParser::Instance(); const MATERIALS_FOR_LEVEL* const enchant_info = \ enchant_parser->GetEnchantInfo(is_weapon, item_level, enchant_grade); if (enchant_info == NULL) { return false; } for (int op = 0; op < _countof(enchant_info->add_option_kind_); ++op) { bool is_valid_values = enchant_info->add_option_kind_[op] != 0 && enchant_info->add_option_value_[op] != 0 && enchant_info->add_option_kind_[op] < _countof(g_ITEM_OPTION) && enchant_info->add_option_type_[op] < _countof(kAttrKindByValueTypes); if (is_valid_values == false) { continue; } REGISTER_ATTR_NODE(g_ITEM_OPTION[enchant_info->add_option_kind_[op]], kAttrKindByValueTypes[enchant_info->add_option_type_[op]], enchant_info->add_option_value_[op]); } return true; } #endif // _NA_006731_20130521_ENCHANT_ADD_OPTION //================================================================================================== //================================================================================================== //================================================================================================== //================================================================================================== //================================================================================================== #endif //_NA_002289_20110322_EQUIPMENTS_CALCULATOR_CHANGES_FOR_IMPROVEMENT