#include "stdafx.h" #include "SkillInfoParser.h" #include #include #include #ifdef _NA_0_20100901_SKILLTREE_SYSTEM #include #endif SkillInfoParser::SkillInfoParser() : script_infos_(), script_infos_iterator(script_infos_.begin()), script_infos_const_iterator(script_infos_.begin()), style_infos_(), style_infos_iterator(style_infos_.begin()), style_infos_const_iterator(style_infos_.begin()) { } SkillInfoParser::~SkillInfoParser() { } bool SkillInfoParser::_LoadStyle(const bool is_reload) { if (is_reload) { style_infos_.clear(); } #pragma pack(push, 1) struct { char temp_buffer[32]; int temp_padding; } temp_buffer_block; #pragma pack(pop) typedef char temp_buffer_t[32]; ZeroMemory(&temp_buffer_block, sizeof(temp_buffer_block)); temp_buffer_t& temp_buffer = temp_buffer_block.temp_buffer; const int max_rows = GetRowSize(); for (int row = 0; row < max_rows; ++row) { const int style_code = GetDataInt("StyleCode", row); if (style_code <= 0) { SUNLOG( eCRITICAL_LOG, _T("|[%s]|Msg=index(%d) out of range|"), __FUNCTION__, style_code ); //ASSERT(false); return false; } if (GetStyleInfo(style_code) != NULL) { SUNLOG( eCRITICAL_LOG, _T("|[%s]|Msg=duplicate index(%d)|"), __FUNCTION__, style_code ); //ASSERT(false); return false; } BASE_STYLEINFO style_info; style_info.m_SkillCode = static_cast(style_code); style_info.m_byType = ROOT_SKILLINFO::STYLE_TYPE; style_info.m_SkillClassCode = GetDataWORD("StyleClassCode", row); strncpy( style_info.m_szStyleName, GetDataString("StyleName", row), _countof(style_info.m_szStyleName) ); style_info.m_szStyleName[_countof(style_info.m_szStyleName) - 1] = '\0'; style_info.m_dwStyleNCode = GetDataDWORD("StyleNCode", row); style_info.m_dwStyleDescCode = GetDataDWORD("StyleDescCode", row); style_info.m_wSkillattribute = GetDataWORD("SkillAttribute", row); style_info.m_dwStyleImage = GetDataDWORD("StyleImage", row); style_info.m_wRequireLV = GetDataWORD("RequireLV", row); style_info.m_wStyleLV = GetDataWORD("StyleLV", row); style_info.m_wMaxLV = GetDataWORD("MaxLV", row); style_info.m_wOverLV = GetDataWORD("OverLV", row); for (int i = 0; i < _countof(style_info.m_wOverStatclass); ++i) { _snprintf(temp_buffer, _countof(temp_buffer), "OverStat%dClass", i+1); style_info.m_wOverStatclass[i] = GetDataWORD(temp_buffer, row); _snprintf(temp_buffer, _countof(temp_buffer), "OverStat%d", i+1); style_info.m_wOverstat[i] = GetDataWORD(temp_buffer, row); } style_info.m_byRequireSkillPoint = GetDataBYTE("RequireSkillPoint", row); style_info.m_byClassDefine = GetDataBYTE("ClassDefine", row); style_info.m_iWeaponDefine = GetDataInt("WeaponDefine", row); // NOTE: f110304.6L, currently, the 'AttType' column is not used. style_info.m_byAttType = GetDataBYTE("AttType", row); style_info.m_fAttRange = GetDataFloat("AttRange", row); style_info.m_byMoveAttack = GetDataBYTE("MoveAttack", row); style_info.m_byStyleCheck = GetDataBYTE("StyleCheck", row); strncpy(style_info.m_wzidCodeFirst.code, GetDataString("CodeFirst", row), 4); strncpy(style_info.m_wzidCodeSecond.code, GetDataString("CodeSecond", row), 4); strncpy(style_info.m_wzidCodeThird.code, GetDataString("CodeThird", row), 4); strncpy(style_info.m_wzidCodeBack.code, GetDataString("CodeBack", row), 4); style_info.m_wTimeFirst = GetDataWORD("TimeFirst", row); style_info.m_wTimeSecond = GetDataWORD("TimeSecond", row); style_info.m_wTimeThird = GetDataWORD("TimeThird", row); for (int i = 0; i < _countof(style_info.m_iAddDamage); ++i) { BOOST_STATIC_ASSERT( _countof(style_info.m_iAddDamage) == _countof(style_info.m_fDamagePercent)); _snprintf(temp_buffer, _countof(temp_buffer), "AddDamage%d", i+1); style_info.m_iAddDamage[i] = GetDataInt(temp_buffer, row); _snprintf(temp_buffer, _countof(temp_buffer), "DamagePercent%d", i+1); style_info.m_fDamagePercent[i] = GetDataFloat(temp_buffer, row); } style_info.m_byAttRangeform = GetDataBYTE("AttRangeform", row); style_info.m_fStyleArea = GetDataFloat("StyleArea", row); style_info.m_fThirdDelay = GetDataFloat("ThirdDelay", row); style_info.m_iAttackRate = GetDataInt("AttackRate", row); style_info.m_iAvoidRate = GetDataInt("AvoidRate", row); style_info.m_iAttackSpeed = GetDataInt("AttSpeedIncrease", row); style_info.m_iBonusDefence = GetDataInt("DefenceAdd", row); style_info.m_iMagicDefenceAdd = GetDataInt("MagicDefenceAdd", row); //???????????????? ????? 814 ????? ?????????????(??????? ???????? ???????????? ????????? ?????????.) style_info.m_wCriticalBonus = GetDataWORD("CriticalBonus", row); style_info.m_fDefenseIgnore = GetDataFloat("DefenceIgnore", row); style_info.m_fPierceRate = GetDataFloat("PierceRate", row); style_info.m_fPierceRange = GetDataFloat("PierceRange", row); style_info.m_fStunRate = GetDataFloat("StunRate", row); style_info.m_wStunTime = GetDataWORD("StunTime", row); style_info.m_fKnockBackRate = GetDataFloat("KnockBackRate", row); style_info.m_fKnockBackRange = GetDataFloat("KnockBackRange", row); style_info.m_fDownRate = GetDataFloat("DownRate", row); style_info.m_fDelayReduce = GetDataFloat("DelayReduce", row); style_info.m_fDelayOccur = GetDataFloat("DelayOccur", row); style_info.m_wHPAbsorb = GetDataWORD("HPAbsorb", row); style_info.m_fHPAbsorbPer = GetDataFloat("HPAbsorbPer", row); style_info.m_wMPAbsorb = GetDataWORD("MPAbsorb", row); style_info.m_fMPAbsorbPer = GetDataFloat("MPAbsorbPer", row); style_info.m_wMaxTargetNo = GetDataWORD("MaxTargetNo", row); style_infos_[style_code] = style_info; } if (temp_buffer_block.temp_padding != 0) { FASSERT((temp_buffer_block.temp_padding == 0) && "|Msg=buffer overflow!|"); } return true; } namespace util { namespace internal { struct AbilityNameTable { AbilityNameTable() { ZeroMemory(this, sizeof(*this)); } typedef char buffer_t[32]; buffer_t id_columns[MAX_ABILITY_NUM]; buffer_t range_columns[MAX_ABILITY_NUM]; buffer_t rates_columns[MAX_ABILITY_NUM]; buffer_t option1_columns[MAX_ABILITY_NUM]; buffer_t option2_columns[MAX_ABILITY_NUM]; typedef buffer_t parameters_t[BASE_ABILITYINFO::MAX_ABILITY_PARAM_NUM]; parameters_t parameter_columns[MAX_ABILITY_NUM]; buffer_t state_id_columns[MAX_ABILITY_NUM]; void BuildString() { ZeroMemory(this, sizeof(*this)); // for (int i = 0; i < MAX_ABILITY_NUM; ++i) { _snprintf(id_columns[i], _countof(id_columns[i]), "AbilityID%d", i + 1); } for (int i = 0; i < MAX_ABILITY_NUM; ++i) { _snprintf(range_columns[i], _countof(range_columns[i]), "Ability%dRangeType", i + 1); } for (int i = 0; i < MAX_ABILITY_NUM; ++i) { _snprintf(rates_columns[i], _countof(rates_columns[i]), "Ability%dSuccessRate", i + 1); } for (int i = 0; i < MAX_ABILITY_NUM; ++i) { _snprintf(option1_columns[i], _countof(option1_columns[i]), "Ability%dOption1", i + 1); } for (int i = 0; i < MAX_ABILITY_NUM; ++i) { _snprintf(option2_columns[i], _countof(option2_columns[i]), "Ability%dOption2", i + 1); } for (int i = 0; i < MAX_ABILITY_NUM; ++i) { parameters_t& params = parameter_columns[i]; for (int param_index = 0; param_index < BASE_ABILITYINFO::MAX_ABILITY_PARAM_NUM; ++param_index) { _snprintf( params[param_index], _countof(params[param_index]), "Ability%dParameter%d", i + 1, param_index + 1 ); } } for (int i = 0; i < MAX_ABILITY_NUM; ++i) { _snprintf( state_id_columns[i], _countof(state_id_columns[i]), "Ability%dParameter5", i + 1); } } }; } // internal } // util bool SkillInfoParser::_Load(const bool is_reload) { if (is_reload) { script_infos_.clear(); } util::internal::AbilityNameTable name_table; name_table.BuildString(); #pragma pack(push, 1) struct { char temp_buffer[32]; int temp_padding; } temp_buffer_block; #pragma pack(pop) typedef char temp_buffer_t[32]; ZeroMemory(&temp_buffer_block, sizeof(temp_buffer_block)); temp_buffer_t& temp_buffer = temp_buffer_block.temp_buffer; const int max_rows = GetRowSize(); for (int row = 0; row < max_rows; ++row) { const int skill_code = GetDataInt("SkillCode", row); if (skill_code <= 0) { SUNLOG( eCRITICAL_LOG, _T("|%s|%d|skill code out of range.|Row= %d, SkillCode= %d|"), __FUNCTION__, __LINE__, row, skill_code ); FASSERT(!"skill code out of range."); return false; } if (GetSkillInfo(skill_code) != NULL) { SUNLOG( eCRITICAL_LOG, _T("|%s|%d|duplicate skill code.|Row= %d, SkillCode= %d|"), __FUNCTION__, __LINE__, row, skill_code ); FASSERT(!"duplicate skill code."); return false; } const WORD skill_class_code = GetDataWORD("SkillClassCode", row); if (skill_class_code == 0) { SUNLOG( eCRITICAL_LOG, _T("|%s|%d|skill class code out of range.|Row= %d, SkillCode= %d|"), __FUNCTION__, __LINE__, row, skill_code ); FASSERT(!"skill class code out of range."); return false; } SkillScriptInfo script_info; script_info.m_SkillCode = static_cast(skill_code); script_info.m_byType = ROOT_SKILLINFO::SKILL_TYPE; script_info.m_SkillClassCode = skill_class_code; strncpy( script_info.m_szSkillName, GetDataString("SkillName", row), _countof(script_info.m_szSkillName) ); script_info.m_szSkillName[_countof(script_info.m_szSkillName) - 1] = '\0'; script_info.m_dwSkillNcode = GetDataDWORD("SkillNcode", row); script_info.m_dwSkillDesccode = GetDataDWORD("SkillDescCode", row); script_info.m_dwSkillIconcode = GetDataDWORD("SkillIconCode", row); strncpy( script_info.m_szSkillMasterEffectName, GetDataString("SkillEffectName", row), _countof(script_info.m_szSkillMasterEffectName) ); script_info.m_szSkillMasterEffectName[_countof(script_info.m_szSkillMasterEffectName) - 1] = '\0'; #ifdef __NA001126_NEW_SKILL_SCREEN_EFFECT script_info.m_bySwayType = GetDataBYTE("SwayType", row); script_info.m_dwSwayTime = GetDataDWORD("SwayTime", row); script_info.m_bySwayNum = GetDataBYTE("SwayNum", row); script_info.m_dwSwaySize = GetDataDWORD("SwaySize", row); #endif //__NA001126_NEW_SKILL_SCREEN_EFFECT for (int i = 0; i < _countof(script_info.m_iWeaponDefine); ++i) { BOOST_STATIC_ASSERT( _countof(script_info.m_iWeaponDefine) == _countof(script_info.m_wzidAnimationCode)); _snprintf(temp_buffer, _countof(temp_buffer), "WeaponDefine%d", i+1); script_info.m_iWeaponDefine[i] = GetDataInt(temp_buffer, row); _snprintf(temp_buffer, _countof(temp_buffer), "AnimationCode%d", i+1); strncpy(script_info.m_wzidAnimationCode[i].code, GetDataString(temp_buffer, row), 4); } script_info.m_CSSyncDelay = GetDataWORD("CSSyncDelay", row); strncpy(script_info.m_wzidCastAniCode.code, GetDataString("CastAniCode", row), 4); script_info.m_dwFlyingObjectCode = GetDataDWORD("FlyingObjectCode", row); script_info.m_wFlyingLifeTime = GetDataWORD("FlyingLifeTime", row); strncpy(script_info.m_wzidFieldEffectCode.code, GetDataString("FieldEffect", row), 4); script_info.m_dwItemCode = GetDataWORD("Effect", row); // ?????? ?????????????? ???? ???????? ???? ??????? // gs_??????:?????????????????????????????????????? ??????? ???????????????????????? // ???????????????? ?????????????????? ?????????????????????. ??????????????? script_info.m_wSkillAttribute = GetDataWORD("SkillAttribute", row); script_info.m_wRequireLv = GetDataWORD("RequireLV", row); script_info.m_wSkillLv = GetDataWORD("SkillLV", row); script_info.m_wMaxLv = GetDataWORD("MaxLV", row); script_info.m_wOverLv = GetDataWORD("OverLV", row); for (int i = 0; i < _countof(script_info.m_wOverStatclass); ++i) { BOOST_STATIC_ASSERT( _countof(script_info.m_wOverStatclass) == _countof(script_info.m_wOverstat)); _snprintf(temp_buffer, _countof(temp_buffer), "OverStat%dClass", i+1); script_info.m_wOverStatclass[i] = GetDataWORD(temp_buffer, row); _snprintf(temp_buffer, _countof(temp_buffer), "OverStat%d", i+1); script_info.m_wOverstat[i] = GetDataWORD(temp_buffer, row); } script_info.m_bySkillType = GetDataBYTE("SkillType", row); script_info.m_byEtherBulletInfo = GetDataBYTE("EtherBulletInfo", row); script_info.m_bySkillUserType = GetDataBYTE("SkillUserType", row); script_info.m_dwClassDefine = GetDataDWORD("ClassDefine", row); #ifdef _NA_0_20100901_SKILLTREE_SYSTEM script_info.m_UpperSkillClass = GetDataWORD("SkillStatType", row); script_info.m_bySkillStatType = 0; #else script_info.m_bySkillStatType = GetDataBYTE("SkillStatType", row); #endif for (int i = 0; i < _countof(script_info.m_wRequireSkillStat); ++i) { _snprintf(temp_buffer, _countof(temp_buffer), "RequireSkillStat%d", i+1); script_info.m_wRequireSkillStat[i] = GetDataWORD(temp_buffer, row); } //_NA_0_20110131_SKILLTREE_SYSTEM_RENEWAL script_info.m_RequireUpperSkillLevel = script_info.m_wRequireSkillStat[0]; script_info.m_byRequireSkillPoint = GetDataBYTE("RequireSkillPoint", row); script_info.m_byTarget = GetDataBYTE("Target", row); script_info.m_byForbiddenTarget = GetDataBYTE("ForbiddenTarget", row); script_info.m_wHPSpend = GetDataWORD("HPSpend", row); script_info.m_wMPSpend = GetDataWORD("MPSpend", row); script_info.m_wSkillCasting = GetDataWORD("SkillCasting", row); script_info.m_dwCoolTime = GetDataDWORD("CoolTime", row); script_info.m_wSkillRange = GetDataWORD("SkillRange", row); script_info.m_byAttRangeform = GetDataBYTE("AttRangeform", row); script_info.m_wSkillArea = GetDataWORD("SkillArea", row); script_info.m_wChaseRange = GetDataWORD("ChaseRange", row); script_info.m_byMaxTargetNo = GetDataBYTE("MaxTargetNo", row); #ifdef _YJ_ADD_SKILL_SCRIPT_FIELD_4_AUTO_ATTACK_001212 script_info.m_btAutoAttack = GetDataBYTE("AutoAttack", row); #endif //_YJ_ADD_SKILL_SCRIPT_FIELD_4_AUTO_ATTACK_001212 // load abilities BASE_ABILITYINFO ability_info; for (int i = 0; i < MAX_ABILITY_NUM; ++i) { const int ability_id = GetDataInt(name_table.id_columns[i], row); if (ability_id == eABILITY_INVALID) { break; } if (ability_id >= eABILITY_MAX) { SUNLOG( eDEV_LOG, _T("|%s|%d|ability ID out of range.|Row= %d, SkillCode= %d, AbilityID = %d|"), __FUNCTION__, __LINE__, row, skill_code, ability_id ); //ASSERT(false); // Keep the ability so CN script IDs still load. } ability_info.m_byIndex = static_cast(i); ability_info.m_wAbilityID = static_cast(ability_id); ability_info.m_byRangeType = GetDataBYTE(name_table.range_columns[i], row); ability_info.m_wSuccessRate = GetDataWORD(name_table.rates_columns[i], row); ability_info.m_iOption1 = GetDataInt(name_table.option1_columns[i], row); ability_info.m_iOption2 = GetDataInt(name_table.option2_columns[i], row); for (int j = 0; j < BASE_ABILITYINFO::MAX_ABILITY_PARAM_NUM; ++j) { ability_info.m_iParam[j] = GetDataInt(name_table.parameter_columns[i][j], row); } ability_info.m_wStateID = GetDataWORD(name_table.state_id_columns[i], row); // CHANGES: f110309.1L if (ability_info.iff_filter.ConfigureIFF_Check( &ability_info.iff_filter, ability_info) == false) { SUNLOG( eDEV_LOG, _T("|%s|%d|ability ID out of range.|Row= %d, SkillCode= %d, AbilityID = %d|"), __FUNCTION__, __LINE__, row, skill_code, ability_id ); //ASSERT(false); } script_info.AddAbility(ability_info); } script_info.m_bySkillAcquire = GetDataBYTE("SkillAcquire", row); // ??????????? ??????????. if (CheckValidity(&script_info, row) == false) { // ????????? ????????? ????? ??????? ????????? ???????. ??????????? ???????????. //ASSERT(false); //return false; } script_infos_[skill_code] = script_info; COOLTIME_MAP::iterator it = skill_cooltime_table_.find(script_info.m_SkillCode); if (it == skill_cooltime_table_.end()) { bool cool_time_add = false; if (script_info.m_bySkillUserType != eSKILL_USER_EMOTICON) { if (script_info.m_bySkillUserType == eSKILL_USER_ACTION) { if (script_info.m_dwCoolTime != 0) { cool_time_add = true; } } else { cool_time_add = true; } } if (cool_time_add) { SKILL_COOLTIME_INFO cool_time_info; cool_time_info.m_SkillCode = script_info.m_SkillCode; cool_time_info.m_dwCoolTime = script_info.m_dwCoolTime; skill_cooltime_table_[script_info.m_SkillCode] = cool_time_info; } } else { it->second.m_SkillCode = script_info.m_SkillCode; it->second.m_dwCoolTime = script_info.m_dwCoolTime; } } #ifdef _NA_0_20100901_SKILLTREE_SYSTEM CalculateSkillLineFromSkillInventoryStoreParser(); job_tree_manager_.LoadTree(this); #endif return true; } //================================================================================================== //================================================================================================== // IFF_Filter implements // NOTE: f110309.1L, the IFF_Filter object support target select filtering in the ability // this is implemented by _NA000000_110210_ENHANCED_TARGET_SEARCH_ALGORITHM //================================================================================================== //================================================================================================== #if SUN_CODE_BACKUP bool IFF_Filter::ConfigureIFF_Check(IFF_Filter* result_iff, const eSKILL_TARGET_TYPE target_type) { BOOST_STATIC_ASSERT(SKILL_TARGET_MAX < 32); if (!(target_type != SKILL_TARGET_NONE && target_type < SKILL_TARGET_MAX)) { result_iff->validated = false; return false; }; // const IFF_Filter::value_type target_type_bit = (1 << target_type); IFF_Filter::value_type select_filter = 0; if (target_type_bit & eIFF_RelationCheckAttackerOnly) { select_filter = eIFF_AttackerOnly | eIFF_One; } else if (target_type_bit & eIFF_RelationCheckFriend) { select_filter = eIFF_Friend; } else if (target_type_bit & eIFF_RelationCheckEnemy) { select_filter = eIFF_Enemy; } else if (target_type_bit & eIFF_RelationCheckFriendCorpse) { select_filter = eIFF_Friend | eIFF_Corpse; } else { // no check about other cases }; // result_iff->value = select_filter; result_iff->validated = true; // return true; } #endif bool IFF_Filter::ConfigureIFF_Check(IFF_Filter* result_iff, const BASE_ABILITYINFO& ability_info) { const eABILITY_RANGE_TYPE range_type = static_cast(ability_info.m_byRangeType); BOOST_STATIC_ASSERT(SKILL_ABILITY_MAX < 32); if (!FlowControl::FCAssert(ability_info.m_wAbilityID != 0 && range_type != SKILL_ABILITY_NONE && range_type < SKILL_ABILITY_MAX)) { result_iff->validated = false; return false; }; // const IFF_Filter::value_type range_type_bit = (1 << range_type); IFF_Filter::value_type select_filter = 0; if (range_type_bit & eIFF_AbilityConditionActorOnly) { select_filter |= eIFF_AttackerOnly; }; if (range_type_bit & eIFF_AbilityConditionMainTargetOnly) { select_filter = eIFF_AttackerOnly | eIFF_MainTargetOnly; }; if (range_type_bit & eIFF_AbilityConditionCorpseAbilities) { select_filter |= eIFF_Corpse; }; if (range_type_bit & eIFF_AbilityConditionEnabledResurrection) { select_filter |= eIFF_Resurrection; }; if (range_type_bit & eIFF_AbilityConditionPlayer) { select_filter |= eIFF_Player; }; if (range_type_bit & eIFF_AbilityConditionSkipAbilities) { select_filter |= eIFF_CheckSkip; }; if (range_type_bit & eIFF_AbilityConditionFriendAbilities) { select_filter |= eIFF_Friend; }; if (range_type_bit & eIFF_AbilityConditionEnemyAbilities) { select_filter |= eIFF_Enemy; }; result_iff->value = select_filter; result_iff->validated = true; // return true; } //================================================================================================== //================================================================================================== // BASE_ABILITYINFO implements //================================================================================================== //================================================================================================== // CHANGES: f110214.3L, added debugging facility struct BASE_ABILITYINFO::DetailLogging { DetailLogging(bool* input_valid_check) : valid_check(true) , valid_check_reference(input_valid_check) { } ~DetailLogging() { if (valid_check_reference) { *valid_check_reference = valid_check; } } bool valid_check; bool* valid_check_reference; }; eATTR_TYPE BASE_ABILITYINFO::GetAttrTypeDetail(bool* valid_check) const { // CHANGES: f110214.3L, added debugging facility DetailLogging logger(valid_check); // CHANGES: f1101121.1L, change style const eABILITY ability_type = static_cast(m_wAbilityID); switch (ability_type) { //---------------------------------------------------------------------------------------------- case eABILITY_MAX_HP_INCREASE: return eATTR_MAX_HP; case eABILITY_CUR_HP_INCREASE: #ifdef _NA_006702_20130506_ADD_ABILITYTYPE_PUREVALUE_HP case eABILITY_VARIATION_PUREVALUE_HP: #endif //_NA_006702_20130506_ADD_ABILITYTYPE_PUREVALUE_HP return eATTR_CUR_HP; case eABILITY_RECOVER_HP_INCREASE: return eATTR_RECOVERY_HP; //---------------------------------------------------------------------------------------------- case eABILITY_MAX_MP_INCREASE: return eATTR_MAX_MP; case eABILITY_CUR_MP_INCREASE: return eATTR_CUR_MP; case eABILITY_RECOVER_MP_INCREASE: return eATTR_RECOVERY_MP; //---------------------------------------------------------------------------------------------- case eABILITY_PHYSICAL_ATTACKPOWER_INCREASE: case eABILITY_MAGIC_ATTACKPOWER_INCREASE: return GetAttrTypeForAttackpower(static_cast(m_iOption1), &logger); case eABILITY_PHYSICAL_DEFENSE_INCREASE: return GetAttrTypeForDefence(static_cast(m_iOption1), &logger); #if !defined(_NA001605_EP2_ATTRIBUTES_RENEWAL_) case eABILITY_MAGIC_DEFENSE_INCREASE: return GetAttrTypeForDefence(static_cast(m_iOption1), &logger); case eABILITY_ATTACKPOWER_BY_ARMORTYPE: return GetAttrTypeForBonusDamage((eARMOR_TYPE)m_iOption1, m_iParam[0], &logger); case eABILITY_DEFENSE_BY_ATTACKTYPE: return GetAttrTypeForBonusDefence(static_cast(m_iOption1), &logger); #endif //---------------------------------------------------------------------------------------------- case eABILITY_STAT_INCREASE: return GetAttrTypeForStat((eSTAT_TYPE)m_iOption1, &logger); //---------------------------------------------------------------------------------------------- case eABILITY_PHYSICAL_ATTACKRATE_INCREASE: return eATTR_PHYSICAL_ATTACK_SUCCESS_RATIO; case eABILITY_PHYSICAL_AVOIDRATE_INCREASE: return eATTR_PHYSICAL_ATTACK_BLOCK_RATIO; case eABILITY_MOVE_SPEED_INCREASE: case eABILITY_HIDE: return eATTR_MOVE_SPEED; case eABILITY_PHYSICAL_SPEED_INCREASE: return eATTR_ATTACK_SPEED; case eABILITY_CASTING_TIME_INCREASE: return eATTR_BONUS_CASTING_TIME; case eABILITY_DAMAGE_DECREASE: return GetAttrTypeForReduceDamage(static_cast(m_iOption1), &logger); case eABILITY_SKILLRANGE_INCREASE: return GetAttrTypeForAttackRange(static_cast(m_iOption1), &logger); #ifdef _NA_006937_20131030_ABILITY_AND_STATE_CHANGE_CRITICAL case eABILITY_CRITICAL_RATIO_CHANGE: return GetAttrTypeForCriticalRatio(static_cast(m_iOption1), &logger); case eABILITY_CRITICAL_DAMAGE_CHANGE: return GetAttrTypeForCriticalDamage(static_cast(m_iOption1), &logger); #else case eABILITY_CRITICAL_RATIO_CHANGE: return eATTR_ADD_ALL_CRITICAL_RATIO; case eABILITY_CRITICAL_DAMAGE_CHANGE: return eATTR_CRITICAL_DAMAGE_CHANGE; #endif //_NA_006937_20131030_ABILITY_AND_STATE_CHANGE_CRITICAL //---------------------------------------------------------------------------------------------- case eABILITY_LOWHP_ATTACKPOWER_CHANGE: return GetAttrTypeForAttackpower(static_cast(m_iOption1), &logger); case eABILITY_LOWHP_DEFENSE_CHANGE: return GetAttrTypeForDefence(static_cast(m_iOption1), &logger); //---------------------------------------------------------------------------------------------- case eABILITY_SKILL_COOL_TIME_INCREASE: return eATTR_BONUS_SKILL_COOL_TIME; case eABILITY_MP_SPEND_INCREASE: return eATTR_MP_SPEND_INCREASE; case eABILITY_SKILLDAMAGE_INCREASE: return eATTR_ADD_SKILL_DAMAGE_RATIO; //__NA_S00015_20080828_NEW_HOPE_SHADOW case eABILITY_ATTR_ATTACK_POWER: return GetAttrTypeForAttackpower(static_cast(m_iOption1), &logger); case eABILITY_ATTR_DEFENSIVE_POWER: #ifdef _NA001605_EP2_ATTRIBUTES_RENEWAL_ return GetAttrTypeForElementalResist(static_cast(m_iOption1), &logger); #else return GetAttrTypeForDefence(static_cast(m_iOption1), &logger); #endif case eABILITY_CHANGE_ATTR: if (FlowControl::FCAssert(m_iParam[0] < _countof(g_ITEM_OPTION))) { return g_ITEM_OPTION[m_iParam[0]]; } return eATTR_TYPE_INVALID; //end of shadow case eABILITY_RECOVERY_CHANCE: return eATTR_INCREASE_RESERVE_HP; //{_NA_001231_20081216_ADD_OPTION_KIND case eABILITY_RESIST_HOLDING: return eATTR_RESIST_HOLDING; case eABILITY_RESIST_SLEEP: return eATTR_RESIST_SLEEP; case eABILITY_RESIST_POISON: return eATTR_RESIST_POISON; case eABILITY_RESIST_KNOCKBACK: return eATTR_RESIST_KNOCKBACK; case eABILITY_RESIST_DOWN: return eATTR_RESIST_DOWN; case eABILITY_RESIST_STUN: return eATTR_RESIST_STUN; case eABILITY_DECREASE_PVPDAMAGE: return eATTR_DECREASE_PVPDAMAGE; case eABILITY_SKILL_STATE_IGNORE: // arycoat 2013.04.25. return eATTR_RESISTANCE_BADSTATUS_RATIO; //} case eABILITY_MAX_SD_INCREASE: return eATTR_MAX_SD; case eABILITY_RECOVER_SD_INCREASE: return eATTR_RECOVERY_SD; case eABILITY_CUR_SD_INCREASE: return eATTR_CUR_SD; #ifdef _NA_007330_20140620_GUILD_SYSTEM_EXTENSION case eABILITY_CRAFT_COST_RATIO: return eATTR_CRAFT_COST_RATIO; case eABILITY_CRAFT_PREVENT_EXTINCTION_MATERIAL_RATIO: return eATTR_CRAFT_PREVENT_EXTINCTION_MATERIAL_RATIO; case eABILITY_ENCHANT_COST_RATIO: return eATTR_ENCHANT_COST_RATIO; case eABILITY_ENCHANT_PREVENT_DESTROY_N_DOWNGRADE_ITEM_RATIO: return eATTR_ENCHANT_PREVENT_DESTROY_N_DOWNGRADE_ITEM_RATIO; case eABILITY_RECOVER_POTION_COOLTIME_RATIO: return eATTR_RECOVER_POTION_COOLTIME_RATIO; case eABILITY_RECOVER_POTION_RECOVERY_RATIO: return eATTR_RECOVER_POTION_RECOVERY_RATIO; case eABILITY_QUEST_REWARD_EXP_RATIO: return eATTR_QUEST_REWARD_EXP_RATIO; case eABILITY_MAX_DAMAGE_RATIO: return eATTR_MAX_DAMAGE_RATIO; case eABILITY_MONEY_RAIO: return eATTR_BONUS_MONEY_RATIO; case eABILITY_DOMINATION_MAPOBJECT_DAMAGE_RATIO: return eATTR_DOMINATION_MAPOBJECT_DAMAGE_RATIO; case eABILITY_SHOP_REPAIR_HEIM_RATIO: return eATTR_SHOP_REPAIR_HEIM_RATIO; case eABILITY_SHOP_BUY_HEIM_RATIO: return eATTR_SHOP_BUY_HEIM_RATIO; #endif //_NA_007330_20140620_GUILD_SYSTEM_EXTENSION case eABILITY_INCREASE_DAMAGE: return eATTR_INCREASE_DAMAGE_RATIO; #ifdef _NA_007992_20150127_EVENT_MONSTER_INVASION case eABILITY_MONSTER_KILL_EXP_RATIO: return eATTR_BONUS_EXP_RATIO; #endif //_NA_007992_20150127_EVENT_MONSTER_INVASION #ifdef _NA_008124_20150313_AWAKENING_SYSTEM case eABILITY_AWAKENING_PROBABILITY: return eATTR_AWAKENING_PROBABILITY; #endif #ifdef _NA_008486_20150914_TOTAL_BALANCE case eABILITY_ATTACK_DAMAGE_HP_ABSORPTION: return eATTR_ATTACK_DAMAGE_ABSORB_HP_RATIO; #endif //---------------------------------------------------------------------------------------------- default: return eATTR_TYPE_INVALID; }; } //_NA001956_110210_PERK_SWITCHABLE_REGION eATTR_EXTRA_OPTION BASE_ABILITYINFO::GetAttrExtraOption() const { #if !defined(_NA001956_110210_PERK_SWITCHABLE_REGION) return eATTR_EXTRA_OPTION_INVALID; #endif #ifdef _NA001956_110210_PERK_SWITCHABLE_REGION const eABILITY ability_type = static_cast(m_wAbilityID); switch (ability_type) { case eABILITY_TOTEM_NPC_OPTION_EMPOWERMENT: return eATTR_EXTRA_TOTEM_NPC_OPTION_EMPOWERMENT; } return eATTR_EXTRA_OPTION_INVALID; #endif } eATTR_TYPE BASE_ABILITYINFO::GetAttrTypeForAttackpower(eATTACK_TYPE attackType, DetailLogging* logging) const { // NOTE: f110125.1L, open logic before next build updating #if defined(_NA001605_EP2_ATTRIBUTES_RENEWAL_) static const eATTR_TYPE converter_static[eATTACK_TYPE_MAX] = { eATTR_TYPE_INVALID, //eATTACK_TYPE_INVALID eATTR_TYPE_INVALID, //eATTACK_TYPE_MELEE eATTR_TYPE_INVALID, //eATTACK_TYPE_RANGE eATTR_MAGICAL_WATER_ATTACK_POWER, //eATTACK_TYPE_WATER eATTR_MAGICAL_FIRE_ATTACK_POWER, //eATTACK_TYPE_FIRE eATTR_MAGICAL_WIND_ATTACK_POWER, //eATTACK_TYPE_WIND eATTR_MAGICAL_EARTH_ATTACK_POWER, //eATTACK_TYPE_EARTH eATTR_MAGICAL_DARKNESS_ATTACK_POWER,//eATTACK_TYPE_DARKNESS eATTR_TYPE_INVALID, //eATTACK_TYPE_DIVINE eATTR_OPTION_PHYSICAL_ATTACK_POWER, //eATTACK_TYPE_PHYSICAL_OPTION eATTR_MAGICAL_ALL_ATTACK_POWER, //eATTACK_TYPE_MAGIC_OPTION eATTR_TYPE_INVALID, //eATTACK_TYPE_ALL_MAGIC eATTR_TYPE_INVALID, //eATTACK_TYPE_MAGIC // }; const bool accept_flag = (((1 << attackType) & eATTACK_TYPE_ABILITY_OPTION_ALL_BITS) != 0); const eATTR_TYPE attr_type = (accept_flag && _countof(converter_static) > attackType) ? converter_static[attackType] : eATTR_TYPE_INVALID; if (attr_type == eATTR_TYPE_INVALID) { logging->valid_check = false; }; return attr_type; #else switch(attackType) { case eATTACK_TYPE_ALL_OPTION: return eATTR_OPTION_ALL_ATTACK_POWER; // case eATTACK_TYPE_MELEE: return eATTR_BASE_MELEE_MIN_ATTACK_POWER; // case eATTACK_TYPE_RANGE: return eATTR_BASE_RANGE_MIN_ATTACK_POWER; case eATTACK_TYPE_WATER: return eATTR_MAGICAL_WATER_ATTACK_POWER; case eATTACK_TYPE_FIRE: return eATTR_MAGICAL_FIRE_ATTACK_POWER; case eATTACK_TYPE_WIND: return eATTR_MAGICAL_WIND_ATTACK_POWER; case eATTACK_TYPE_EARTH: return eATTR_MAGICAL_EARTH_ATTACK_POWER; case eATTACK_TYPE_DARKNESS: return eATTR_MAGICAL_DARKNESS_ATTACK_POWER; case eATTACK_TYPE_DIVINE: return eATTR_MAGICAL_DIVINE_ATTACK_POWER; case eATTACK_TYPE_PHYSICAL_OPTION: return eATTR_OPTION_PHYSICAL_ATTACK_POWER; case eATTACK_TYPE_MAGIC_OPTION: return eATTR_OPTION_MAGICAL_ATTACK_POWER; case eATTACK_TYPE_ALL_MAGIC: return eATTR_MAGICAL_ALL_ATTACK_POWER; default: { // SUNLOG(eCRITICAL_LOG, "[GetAttrTypeForAttackpower] Invalid AttackType[%d] \n", attackType); return eATTR_OPTION_PHYSICAL_ATTACK_POWER; } } #endif } #ifdef _NA001605_EP2_ATTRIBUTES_RENEWAL_ eATTR_TYPE BASE_ABILITYINFO::GetAttrTypeForElementalResist(eATTACK_TYPE attack_type, DetailLogging* logging) const { static const eATTR_TYPE converter_static[eATTACK_TYPE_MAX] = { eATTR_TYPE_INVALID, //eATTACK_TYPE_INVALID eATTR_TYPE_INVALID, //eATTACK_TYPE_MELEE eATTR_TYPE_INVALID, //eATTACK_TYPE_RANGE eATTR_DEL_WATER_DAMAGE, //eATTACK_TYPE_WATER eATTR_DEL_FIRE_DAMAGE, //eATTACK_TYPE_FIRE eATTR_DEL_WIND_DAMAGE, //eATTACK_TYPE_WIND eATTR_DEL_EARTH_DAMAGE, //eATTACK_TYPE_EARTH eATTR_DEL_DARKNESS_DAMAGE, //eATTACK_TYPE_DARKNESS eATTR_TYPE_INVALID, //eATTACK_TYPE_DIVINE eATTR_TYPE_INVALID, //eATTACK_TYPE_PHYSICAL_OPTION eATTR_DEL_MAGICAL_ALL_DAMAGE, //eATTACK_TYPE_MAGIC_OPTION eATTR_TYPE_INVALID, //eATTACK_TYPE_ALL_MAGIC eATTR_TYPE_INVALID, //eATTACK_TYPE_MAGIC // }; const bool accept_flag = (((1 << attack_type) & eATTACK_TYPE_ABILITY_OPTION_ALL_BITS) != 0); const eATTR_TYPE attr_type = (accept_flag && _countof(converter_static) > attack_type) ? converter_static[attack_type] : eATTR_TYPE_INVALID; if (attr_type == eATTR_TYPE_INVALID) { logging->valid_check = false; }; return attr_type; } #endif eATTR_TYPE BASE_ABILITYINFO::GetAttrTypeForDefence(eATTACK_TYPE attackType, DetailLogging* logging) const { #if defined(_NA001605_EP2_ATTRIBUTES_RENEWAL_) /* static const eATTR_TYPE converter_static[eATTACK_TYPE_MAX] = { eATTR_TYPE_INVALID, //eATTACK_TYPE_INVALID eATTR_TYPE_INVALID, //eATTACK_TYPE_MELEE eATTR_TYPE_INVALID, //eATTACK_TYPE_RANGE eATTR_TYPE_INVALID, //eATTACK_TYPE_WATER eATTR_TYPE_INVALID, //eATTACK_TYPE_FIRE eATTR_TYPE_INVALID, //eATTACK_TYPE_WIND eATTR_TYPE_INVALID, //eATTACK_TYPE_EARTH eATTR_TYPE_INVALID, //eATTACK_TYPE_DARKNESS eATTR_TYPE_INVALID, //eATTACK_TYPE_DIVINE eATTR_OPTION_PHYSICAL_DEFENSE_POWER,//eATTACK_TYPE_PHYSICAL_OPTION eATTR_TYPE_INVALID, //eATTACK_TYPE_MAGIC_OPTION eATTR_TYPE_INVALID, //eATTACK_TYPE_ALL_MAGIC eATTR_TYPE_INVALID, //eATTACK_TYPE_MAGIC // }; const bool accept_flag = (((1 << attackType) & eATTACK_TYPE_ABILITY_OPTION_PHYSICAL_BITS) != 0); const eATTR_TYPE attr_type = (accept_flag && _countof(converter_static) <= attackType) ? converter_static[attackType] : eATTR_TYPE_INVALID; if (attr_type == eATTR_TYPE_INVALID) { assert(!"unexpected ability Option1 used to eATTACK_TYPE"); }; return attr_type; */ if (attackType == eATTACK_TYPE_PHYSICAL_OPTION) { return eATTR_OPTION_PHYSICAL_DEFENSE_POWER; } logging->valid_check = false; return eATTR_TYPE_INVALID; #else switch(attackType) { case eATTACK_TYPE_ALL_OPTION: return eATTR_OPTION_ALL_DEFENSE_POWER; // case eATTACK_TYPE_MELEE: return eATTR_BASE_MELEE_DEFENSE_POWER; // case eATTACK_TYPE_RANGE: return eATTR_BASE_RANGE_DEFENSE_POWER; case eATTACK_TYPE_WATER: return eATTR_MAGICAL_WATER_DEFENSE_POWER; case eATTACK_TYPE_FIRE: return eATTR_MAGICAL_FIRE_DEFENSE_POWER; case eATTACK_TYPE_WIND: return eATTR_MAGICAL_WIND_DEFENSE_POWER; case eATTACK_TYPE_EARTH: return eATTR_MAGICAL_EARTH_DEFENSE_POWER; case eATTACK_TYPE_DARKNESS: return eATTR_MAGICAL_DARKNESS_DEFENSE_POWER; case eATTACK_TYPE_DIVINE: return eATTR_MAGICAL_DIVINE_DEFENSE_POWER; case eATTACK_TYPE_PHYSICAL_OPTION: return eATTR_OPTION_PHYSICAL_DEFENSE_POWER; case eATTACK_TYPE_MAGIC_OPTION: return eATTR_OPTION_MAGICAL_DEFENSE_POWER; case eATTACK_TYPE_ALL_MAGIC: return eATTR_MAGICAL_ALL_DEFENSE_POWER; default: { // SUNLOG(eCRITICAL_LOG, "[GetAttrTypeForDefence] Invalid AttackType[%d] \n", attackType); return eATTR_OPTION_PHYSICAL_DEFENSE_POWER; } } #endif } #if !defined(_NA001605_EP2_ATTRIBUTES_RENEWAL_) eATTR_TYPE BASE_ABILITYINFO::GetAttrTypeForBonusDefence(eATTACK_TYPE attackType, DetailLogging* logging) const { switch(attackType) { case eATTACK_TYPE_ALL_OPTION: return eATTR_ADD_ALL_DEFENSE_POWER; case eATTACK_TYPE_MELEE: return eATTR_ADD_MELEE_DEFENSE_POWER; case eATTACK_TYPE_RANGE: return eATTR_ADD_RANGE_DEFENSE_POWER; case eATTACK_TYPE_WATER: return eATTR_ADD_WATER_DEFENSE_POWER; case eATTACK_TYPE_FIRE: return eATTR_ADD_FIRE_DEFENSE_POWER; case eATTACK_TYPE_WIND: return eATTR_ADD_WIND_DEFENSE_POWER; case eATTACK_TYPE_EARTH: return eATTR_ADD_EARTH_DEFENSE_POWER; case eATTACK_TYPE_DARKNESS: return eATTR_ADD_DARKNESS_DEFENSE_POWER; case eATTACK_TYPE_DIVINE: return eATTR_ADD_DIVINE_DEFENSE_POWER; case eATTACK_TYPE_PHYSICAL_OPTION: return eATTR_ADD_PHYSICAL_DEFENSE_POWER; case eATTACK_TYPE_MAGIC_OPTION: return eATTR_ADD_MAGICAL_DEFENSE_POWER; case eATTACK_TYPE_ALL_MAGIC: return eATTR_ADD_MAGICAL_ALL_DEFENSE_POWER; default: return eATTR_ADD_MELEE_DEFENSE_POWER; } } #endif eATTR_TYPE BASE_ABILITYINFO::GetAttrTypeForStat(eSTAT_TYPE statType, DetailLogging* logging) const { __TOUCHED(logging); switch (statType) { case eSTAT_TYPE_STR: return eATTR_STR; case eSTAT_TYPE_DEX: return eATTR_DEX; case eSTAT_TYPE_VIT: return eATTR_VIT; case eSTAT_TYPE_SPR: return eATTR_SPR; case eSTAT_TYPE_INT: return eATTR_INT; default: return eATTR_STR; } } //#if !defined(_NA001605_EP2_ATTRIBUTES_RENEWAL_) eATTR_TYPE BASE_ABILITYINFO::GetAttrTypeForBonusDamage(eARMOR_TYPE armorType, int iValueType, DetailLogging* logging) const { if (iValueType == VALUE_TYPE_VALUE) { switch(armorType) { case eARMOR_HARD: return eATTR_ADD_ARMOR_HARD_DAMAGE; case eARMOR_MEDIUM: return eATTR_ADD_ARMOR_MEDIUM_DAMAGE; case eARMOR_SOFT: return eATTR_ADD_ARMOR_SOFT_DAMAGE; case eARMOR_SIEGE: return eATTR_ADD_ARMOR_SIEGE_DAMAGE; case eARMOR_UNARMOR: return eATTR_ADD_ARMOR_UNARMOR_DAMAGE; default: return eATTR_ADD_ARMOR_HARD_DAMAGE; } } else if (iValueType == VALUE_TYPE_RATIO_VALUE) { switch(armorType) { case eARMOR_HARD: return eATTR_ADD_RATIO_ARMOR_HARD_DAMAGE; case eARMOR_MEDIUM: return eATTR_ADD_RATIO_ARMOR_MEDIUM_DAMAGE; case eARMOR_SOFT: return eATTR_ADD_RATIO_ARMOR_SOFT_DAMAGE; case eARMOR_SIEGE: return eATTR_ADD_RATIO_ARMOR_SIEGE_DAMAGE; case eARMOR_UNARMOR: return eATTR_ADD_RATIO_ARMOR_UNARMOR_DAMAGE; default: return eATTR_ADD_RATIO_ARMOR_HARD_DAMAGE; } } else { SUNLOG(eCRITICAL_LOG, "BASE_ABILITYINFO : [GetAttrTypeForBonusDamage] Invalid ValueType[%d]! \n", iValueType); return eATTR_ADD_ARMOR_HARD_DAMAGE; } } //#endif eATTR_TYPE BASE_ABILITYINFO::GetAttrTypeForReduceDamage(eATTACK_TYPE attackType, DetailLogging* logging) const { #if defined(_NA001605_EP2_ATTRIBUTES_RENEWAL_) static const eATTR_TYPE converter_static[eATTACK_TYPE_MAX] = { eATTR_TYPE_INVALID, //eATTACK_TYPE_INVALID eATTR_TYPE_INVALID, //eATTACK_TYPE_MELEE eATTR_TYPE_INVALID, //eATTACK_TYPE_RANGE eATTR_DEL_WATER_DAMAGE, //eATTACK_TYPE_WATER eATTR_DEL_FIRE_DAMAGE, //eATTACK_TYPE_FIRE eATTR_DEL_WIND_DAMAGE, //eATTACK_TYPE_WIND eATTR_DEL_EARTH_DAMAGE, //eATTACK_TYPE_EARTH eATTR_DEL_DARKNESS_DAMAGE, //eATTACK_TYPE_DARKNESS eATTR_TYPE_INVALID, //eATTACK_TYPE_DIVINE eATTR_DEL_PHYSICAL_DAMAGE, //eATTACK_TYPE_PHYSICAL_OPTION eATTR_DEL_MAGICAL_ALL_DAMAGE, //eATTACK_TYPE_MAGIC_OPTION eATTR_TYPE_INVALID, //eATTACK_TYPE_ALL_MAGIC eATTR_TYPE_INVALID, //eATTACK_TYPE_MAGIC // }; const bool accept_flag = (((1 << attackType) & eATTACK_TYPE_ABILITY_OPTION_ALL_BITS) != 0); const eATTR_TYPE attr_type = (accept_flag && _countof(converter_static) > attackType) ? converter_static[attackType] : eATTR_TYPE_INVALID; if (attr_type == eATTR_TYPE_INVALID) { logging->valid_check = false; }; return attr_type; #else switch(attackType) { case eATTACK_TYPE_ALL_OPTION: return eATTR_DEL_ALL_DAMAGE; case eATTACK_TYPE_MELEE: return eATTR_DEL_MELEE_DAMAGE; case eATTACK_TYPE_RANGE: return eATTR_DEL_RANGE_DAMAGE; case eATTACK_TYPE_WATER: return eATTR_DEL_WATER_DAMAGE; case eATTACK_TYPE_FIRE: return eATTR_DEL_FIRE_DAMAGE; case eATTACK_TYPE_WIND: return eATTR_DEL_WIND_DAMAGE; case eATTACK_TYPE_EARTH: return eATTR_DEL_EARTH_DAMAGE; case eATTACK_TYPE_DARKNESS: return eATTR_DEL_DARKNESS_DAMAGE; case eATTACK_TYPE_DIVINE: return eATTR_DEL_DIVINE_DAMAGE; case eATTACK_TYPE_PHYSICAL_OPTION: return eATTR_DEL_PHYSICAL_DAMAGE; case eATTACK_TYPE_MAGIC_OPTION: return eATTR_DEL_MAGICAL_DAMAGE; case eATTACK_TYPE_ALL_MAGIC: return eATTR_DEL_MAGICAL_ALL_DAMAGE; default: return eATTR_DEL_MELEE_DAMAGE; } #endif } eATTR_TYPE BASE_ABILITYINFO::GetAttrTypeForAttackRange(eRANGE_TYPE rangeType, DetailLogging* logging) const { __TOUCHED(logging); switch (rangeType) { case eRANGE_TYPE_ALL: return eATTR_ALL_ATTACK_RANGE; case eRANGE_TYPE_NORMAL: return eATTR_NORMAL_ATTACK_RANGE; case eRANGE_TYPE_SKILL: return eATTR_SKILL_ATTACK_RANGE; default: return eATTR_NORMAL_ATTACK_RANGE; } } //================================================================================================== //================================================================================================== //================================================================================================== bool SkillInfoParser::CheckValidity(SkillScriptInfo* const skill_info, const int row) const { bool is_success = true; const SLOTCODE skill_code = skill_info->m_SkillCode; // ??????? ?????????? ??????????. if (skill_info->m_wSkillLv > MAX_SKILL_OVER_LEVEL) { SUNLOG( eDEV_LOG, _T("|%s|%d|skill level out of range.|Row= %d, SkillCode= %d, SkillLevel = %d|"), __FUNCTION__, __LINE__, row, skill_code, skill_info->m_wSkillLv ); skill_info->m_wSkillLv = MAX_SKILL_OVER_LEVEL; is_success = false; //ASSERT(false); } // ????? ?????????? ??????????. if (skill_info->m_wMaxLv > MAX_SKILL_LEVEL) { SUNLOG( eDEV_LOG, _T("|%s|%d|skill max level out of range.|Row= %d, SkillCode= %d, SkillMaxLevel = %d|"), __FUNCTION__, __LINE__, row, skill_code, skill_info->m_wMaxLv ); skill_info->m_wMaxLv = MAX_SKILL_LEVEL; is_success = false; //ASSERT(false); } // ???????????? ?????????? ??????????. if (skill_info->m_wOverLv > MAX_SKILL_OVER_LEVEL) { SUNLOG( eDEV_LOG, _T("|%s|%d|skill over-level out of range.|Row= %d, SkillCode= %d, SkillOverLevel = %d|"), __FUNCTION__, __LINE__, row, skill_code, skill_info->m_wOverLv ); skill_info->m_wOverLv = MAX_SKILL_OVER_LEVEL; is_success = false; //ASSERT(false); } // ??????? ??????? ??????????. if (skill_info->m_bySkillType && skill_info->m_bySkillType != SKILL_TYPE_PASSIVE && skill_info->m_bySkillType != SKILL_TYPE_ACTIVE) { SUNLOG( eDEV_LOG, _T("|%s|%d|invalid skill type.|Row= %d, SkillCode= %d, SkillType = %d|"), __FUNCTION__, __LINE__, row, skill_code, skill_info->m_bySkillType ); skill_info->m_bySkillType = SKILL_TYPE_ACTIVE; is_success = false; //ASSERT(false); } // ??????? ??????? ??????? ??????????. switch(skill_info->m_bySkillUserType) { case eSKILL_USER_PLAYER: switch(skill_info->m_dwClassDefine) { case eCHAR_BERSERKER: if (skill_info->m_SkillClassCode < BerserkerJob1Boundary::kBegin || skill_info->m_SkillClassCode > BerserkerJob1Boundary::kEnd) { if (skill_info->m_SkillClassCode < BerserkerJob2Boundary::kBegin || skill_info->m_SkillClassCode > BerserkerJob2Boundary::kEnd) { SUNLOG( eDEV_LOG, _T("|%s|%d|player skill class out of range.|Row= %d, SkillCode= %d, SkillClassCode = %d|"), __FUNCTION__, __LINE__, row, skill_code, skill_info->m_SkillClassCode ); is_success = false; //ASSERT(false); } } break; case eCHAR_DRAGON: if (skill_info->m_SkillClassCode < DragonJob1Boundary::kBegin || skill_info->m_SkillClassCode > DragonJob1Boundary::kEnd) { if (skill_info->m_SkillClassCode < DragonJob2Boundary::kBegin || skill_info->m_SkillClassCode > DragonJob2Boundary::kEnd) { SUNLOG( eDEV_LOG, _T("|%s|%d|Dragon Knight skill class out of range.|Row= %d, SkillCode= %d, SkillClassCode = %d|"), __FUNCTION__, __LINE__, row, skill_code, skill_info->m_SkillClassCode ); is_success = false; //ASSERT(false); } } break; case eCHAR_SHADOW: if (skill_info->m_SkillClassCode < ShadowJob1Boundary::kBegin || skill_info->m_SkillClassCode > ShadowJob1Boundary::kEnd) { if (skill_info->m_SkillClassCode < ShadowJob2Boundary::kBegin || skill_info->m_SkillClassCode > ShadowJob2Boundary::kEnd) { SUNLOG( eDEV_LOG, _T("|%s|%d|Shadow skill class out of range.|Row= %d, SkillCode= %d, SkillClassCode = %d|"), __FUNCTION__, __LINE__, row, skill_code, skill_info->m_SkillClassCode ); is_success = false; //ASSERT(false); } } break; case eCHAR_VALKYRIE: if (skill_info->m_SkillClassCode < ValkyrieJob1Boundary::kBegin || skill_info->m_SkillClassCode > ValkyrieJob1Boundary::kEnd) { if (skill_info->m_SkillClassCode < ValkyrieJob2Boundary::kBegin || skill_info->m_SkillClassCode > ValkyrieJob2Boundary::kEnd) { SUNLOG( eDEV_LOG, _T("|%s|%d|Valkyrie skill class out of range.|Row= %d, SkillCode= %d, SkillClassCode = %d|"), __FUNCTION__, __LINE__, row, skill_code, skill_info->m_SkillClassCode ); is_success = false; //ASSERT(false); } } break; case eCHAR_ELEMENTALIST: if (skill_info->m_SkillClassCode < ElementalistJob1Boundary::kBegin || skill_info->m_SkillClassCode > ElementalistJob1Boundary::kEnd) { if (skill_info->m_SkillClassCode < ElementalistJob2Boundary::kBegin || skill_info->m_SkillClassCode > ElementalistJob2Boundary::kEnd) { SUNLOG( eDEV_LOG, _T("|%s|%d|Elementalist skill class out of range.|Row= %d, SkillCode= %d, SkillClassCode = %d|"), __FUNCTION__, __LINE__, row, skill_code, skill_info->m_SkillClassCode ); is_success = false; //ASSERT(false); } } break; case eCHAR_MYSTIC: // _NA_004965_20120613_NEW_CHARACTER_MYSTIC case eCHAR_HELLROID: //_NA_000000_20130812_NEW_CHARACTER_HELLROID case eCHAR_WITCHBLADE: //_NA_007514_20140828_NEW_CHARACTER_WITCHBLADE // ??????? ?????? ?????????? ?????? ????? ???????? ??????????. break; case eCHAREX_DRAGON_1stTRANS: case eCHAREX_DRAGON_2ndTRANS: case eCHAREX_BERSERKER_100LEVEL: case eCHAREX_DRAGON_KNIGHT_100LEVEL: case eCHAREX_SHADOW_100LEVEL: case eCHAREX_VALKYRIE_100LEVEL: case eCHAREX_ELEMENTALIST_100LEVEL: case eCHAREX_MYSTIC_100LEVEL: case eCHAREX_HELLROID_100LEVEL: case eCHAREX_DRAGON_1stTRANS_100LEVEL: case eCHAREX_DRAGON_2ndTRANS_100LEVEL: #ifdef _NA_007514_20140828_NEW_CHARACTER_WITCHBLADE case eCHAREX_WITCHBLADE_100LEVEL: #endif //_NA_007514_20140828_NEW_CHARACTER_WITCHBLADE default: break; } break; case eSKILL_USER_MONSTER: case eSKILL_USER_NPC: if (skill_info->m_dwClassDefine != 0) { SUNLOG( eDEV_LOG, _T("|%s|%d|class define must be 0 for this skill user type.|Row= %d, SkillCode= %d, SkillUserType = %d, ClassDefine = %d|"), __FUNCTION__, __LINE__, row, skill_code, skill_info->m_bySkillUserType, skill_info->m_dwClassDefine ); skill_info->m_dwClassDefine = 0; is_success = false; //ASSERT(false); } break; case eSKILL_USER_SUMMONED: // ???????? case eSKILL_USER_FOLLOWER: // ??????? case eSKILL_USER_ACTION: // ??????? case eSKILL_USER_EMOTICON: // ???????????? break; default: SUNLOG( eDEV_LOG, _T("|%s|%d|unknown skill user type.|Row= %d, SkillCode= %d, SkillUserType = %d|"), __FUNCTION__, __LINE__, row, skill_code, skill_info->m_bySkillUserType ); skill_info->m_bySkillUserType = eSKILL_USER_PLAYER; is_success = false; //ASSERT(false); break; } // ??????? ???????????? ??????????. for (int i = 0; i < 2; ++i) { if (skill_info->m_wRequireSkillStat[i] > 100000) { SUNLOG( eDEV_LOG, _T("|%s|%d|require skill stat too large.|Row= %d, SkillCode= %d, RequireSkillStat = %d|"), __FUNCTION__, __LINE__, row, skill_code, skill_info->m_wRequireSkillStat[i] ); is_success = false; //ASSERT(false); } } // ?????? ????? ??????? ??????????. if (skill_info->m_byTarget >= SKILL_TARGET_MAX) { SUNLOG( eDEV_LOG, _T("|%s|%d|target out of range.|Row= %d, SkillCode= %d, Target = %d|"), __FUNCTION__, __LINE__, row, skill_code, skill_info->m_byTarget ); skill_info->m_byTarget = SKILL_TARGET_ENEMY; is_success = false; //ASSERT(false); } // ??????? ?????????? ???????? ??????????. if (skill_info->m_wSkillCasting >= 20000) { SUNLOG( eDEV_LOG, _T("|%s|%d|skill casting time too large.|Row= %d, SkillCode= %d, SkillCasting = %d|"), __FUNCTION__, __LINE__, row, skill_code, skill_info->m_wSkillCasting ); skill_info->m_wSkillCasting = 20000; is_success = false; //ASSERT(false); } // ??????? ?????????? ??????????. if (skill_info->m_wSkillRange != 0) { if (skill_info->m_SkillClassCode != eSKILL_TELEPORT && (skill_info->m_wSkillRange < 10 || skill_info->m_wSkillRange > 300)) { SUNLOG( eDEV_LOG, _T("|%s|%d|skill range invalid.|Row= %d, SkillCode= %d, SkillRange = %d|"), __FUNCTION__, __LINE__, row, skill_code, skill_info->m_wSkillRange ); skill_info->m_wSkillRange = 30; is_success = false; //ASSERT(false); } } // ????????????? ??????????. if (skill_info->m_byAttRangeform >= SRF_MAX) { SUNLOG( eDEV_LOG, _T("|%s|%d|attack range form out of range.|Row= %d, SkillCode= %d, AttRangeForm = %d|"), __FUNCTION__, __LINE__, row, skill_code, skill_info->m_byAttRangeform ); skill_info->m_byAttRangeform = SRF_FOWARD_ONE; is_success = false; //ASSERT(false); } // ??????? ???????? ??????????. if (skill_info->m_byAttRangeform == SRF_FOWARD_120 || skill_info->m_byAttRangeform == SRF_FOWARD_160 || skill_info->m_byAttRangeform == SRF_FOWARD_360 || skill_info->m_byAttRangeform == SRF_PIERCE) { if (skill_info->m_wSkillArea == 0) { SUNLOG( eDEV_LOG, _T("|%s|%d|this attack range form requires a range value.|Row= %d, SkillCode= %d, AttRangeForm = %d|"), __FUNCTION__, __LINE__, row, skill_code, skill_info->m_byAttRangeform ); skill_info->m_wSkillArea = 1; is_success = false; //ASSERT(false); } } // ??????????????? ??????????. skill_info->SetFirst(); while (BASE_ABILITYINFO* ability_info = skill_info->GetNext()) { if (ability_info->m_wAbilityID == 0) { continue; } // ????????????ID??? ??????????. if (ability_info->m_wAbilityID >= eABILITY_MAX) { SUNLOG( eDEV_LOG, _T("|%s|%d|ability ID out of range.|Row= %d, SkillCode= %d, AbilityID = %d|"), __FUNCTION__, __LINE__, row, skill_code, ability_info->m_wAbilityID ); is_success = false; //ASSERT(false); } // ????? ???????? ??????????. if (ability_info->m_byRangeType >= SKILL_ABILITY_MAX) { SUNLOG( eDEV_LOG, _T("|%s|%d|ability range type out of range.|Row= %d, SkillCode= %d, AbilityID = %d, RangeType = %d|"), __FUNCTION__, __LINE__, row, skill_code, ability_info->m_wAbilityID, ability_info->m_byRangeType ); ability_info->m_byRangeType = SKILL_ABILITY_ENEMY; is_success = false; //ASSERT(false); } // ??????? ?????? ??????????. if (ability_info->m_wSuccessRate == 0) { SUNLOG( eDEV_LOG, _T("|%s|%d|skill success rate must be greater than zero.|Row= %d, SkillCode= %d, AbilityID = %d|"), __FUNCTION__, __LINE__, row, skill_code, ability_info->m_wAbilityID ); ability_info->m_wSuccessRate = 1000; is_success = false; //ASSERT(false); } // ???????????? ?????????? ????ID??? ?????????????????. const int apply_time = ability_info->m_iParam[2]; if (apply_time != 0) { if (ability_info->m_wStateID == 0 && ability_info->m_wAbilityID != eABILITY_SUMMON_CHANGE_STATUS && ability_info->m_wAbilityID != eABILITY_BUFF_RANGE_DAMAGE && ability_info->m_wAbilityID != eABILITY_DRAGON_TRANSFORMATION2 && ability_info->m_wAbilityID != eABILITY_DRAGON_TRANSFORMATION3 && ability_info->m_wAbilityID != eABILITY_SUMMON && ability_info->m_wAbilityID != eABILITY_SUMMONMASTERY && ability_info->m_wAbilityID != eABILITY_DAMAGE && ability_info->m_wAbilityID != kAbilityComboSkillEffectAddBadStatus && ability_info->m_wAbilityID != eABILITY_BONUS_DAMAGE_PER_FIGHTING_ENERGY && ability_info->m_wAbilityID != eABILITY_SUMMON_CHANGE_STATUS_EXTEND && ability_info->m_wAbilityID != eABILITY_SUMMON_IMMOVABLE) { SUNLOG( eDEV_LOG, _T("|%s|%d|apply time requires a state ID.|Row= %d, SkillCode= %d, AbilityID = %d, ApplyTime = %d|"), __FUNCTION__, __LINE__, row, skill_code, ability_info->m_wAbilityID, apply_time ); is_success = false; //ASSERT(false); } } if (ability_info->m_wAbilityID == eABILITY_DAMAGE) { if (ability_info->m_wStateID != 0) { SUNLOG( eDEV_LOG, _T("|%s|%d|damage ability must not have a state ID.|Row= %d, SkillCode= %d, AbilityID = %d, StateID = %d|"), __FUNCTION__, __LINE__, row, skill_code, ability_info->m_wAbilityID, ability_info->m_wStateID ); ability_info->m_wStateID = 0; is_success = false; //ASSERT(false); } if (ability_info->m_byRangeType == SKILL_ABILITY_FRIEND || ability_info->m_byRangeType == SKILL_ABILITY_TARGETAREA_FRIEND || ability_info->m_byRangeType == SKILL_ABILITY_MYAREA_FRIEND || ability_info->m_byRangeType == SKILL_ABILITY_ME || ability_info->m_byRangeType == SKILL_ABILITY_FIELD) { SUNLOG( eDEV_LOG, _T("|%s|%d|damage skill cannot target friends.|Row= %d, SkillCode= %d, AbilityID = %d, RangeType = %d|"), __FUNCTION__, __LINE__, row, skill_code, ability_info->m_wAbilityID, ability_info->m_byRangeType ); ability_info->m_byRangeType = SKILL_ABILITY_TARGETAREA_ENEMY; is_success = false; //ASSERT(false); } if (skill_info->m_wSkillLv < 5) { const int damage_value = ability_info->m_iParam[0]; /*if (damage_value > 10000) { SUNLOG( eDEV_LOG, _T("|%s|%d|damage value too large.|Row= %d, SkillCode= %d, AbilityID = %d, DamageValue = %d|"), __FUNCTION__, __LINE__, row, skill_code, ability_info->m_wAbilityID, damage_value ); is_success = false; //ASSERT(false); }*/ const int damage_ratio = ability_info->m_iParam[1]; if (damage_ratio > 3000) { SUNLOG( eDEV_LOG, _T("|%s|%d|damage ratio too large.|Row= %d, SkillCode= %d, AbilityID = %d, DamageRatio = %d|"), __FUNCTION__, __LINE__, row, skill_code, ability_info->m_wAbilityID, damage_ratio ); is_success = false; //ASSERT(false); } } #ifdef _NA_000000_20140103_CHANGE_DASH_AND_PIERCE_SKILL_MOVE const bool is_moving_attack = (ability_info->m_iParam[2] == 1); if (is_moving_attack) { SUNLOG( eDEV_LOG, _T("|%s|%d|damage skill no longer handles movement (1304) |Row= %d, SkillCode= %d, AbilityID = %d, is_moving_attack = %d|"), __FUNCTION__, __LINE__, row, skill_code, ability_info->m_wAbilityID, is_moving_attack ); is_success = false; //ASSERT(false); //1304 ??????????????????? ????????????????????? ????????????? ??????? ?????? ??????????????? ?????????????. } #endif //_NA_000000_20140103_CHANGE_DASH_AND_PIERCE_SKILL_MOVE } else if (ability_info->m_wAbilityID == eABILITY_DAMAGE_PER_TIME) { if (ability_info->m_wStateID == 0) { SUNLOG( eDEV_LOG, _T("|%s|%d|periodic damage requires a state ID.|Row= %d, SkillCode= %d, AbilityID = %d|"), __FUNCTION__, __LINE__, row, skill_code, ability_info->m_wAbilityID ); ability_info->m_wStateID = eCHAR_STATE_PERIODIC_DAMAGE; is_success = false; //ASSERT(false); } const int damage_value_type = ability_info->m_iParam[0]; if (damage_value_type != VALUE_TYPE_VALUE) { SUNLOG( eDEV_LOG, _T("|%s|%d|damage value type must be VALUE.|Row= %d, SkillCode= %d, AbilityID = %d, ValueType = %d|"), __FUNCTION__, __LINE__, row, skill_code, ability_info->m_wAbilityID, damage_value_type ); ability_info->m_iParam[0] = VALUE_TYPE_VALUE; is_success = false; //ASSERT(false); } const int damage_value = ability_info->m_iParam[1]; /*if (damage_value > 1000) { SUNLOG( eDEV_LOG, _T("|%s|%d|damage value too large.|Row= %d, SkillCode= %d, AbilityID = %d, DamageValue = %d|"), __FUNCTION__, __LINE__, row, skill_code, ability_info->m_wAbilityID, damage_value ); is_success = false; //ASSERT(false); }*/ } if (ability_info->m_iParam[3] && ability_info->m_iParam[2] == 0) { const int period_time = ability_info->m_iParam[3]; SUNLOG( eDEV_LOG, _T("|%s|%d|duration cannot be zero.|Row= %d, SkillCode= %d, AbilityID = %d|"), __FUNCTION__, __LINE__, row, skill_code, ability_info->m_wAbilityID ); ability_info->m_iParam[2] = period_time; is_success = false; //ASSERT(false); } if (ability_info->m_byRangeType == SKILL_ABILITY_TARGETAREA_ENEMY || ability_info->m_byRangeType == SKILL_ABILITY_TARGETAREA_FRIEND || ability_info->m_byRangeType == SKILL_ABILITY_MYAREA_ENEMY || ability_info->m_byRangeType == SKILL_ABILITY_MYAREA_FRIEND) { /*if (skill_info->m_byAttRangeform != SRF_FOWARD_120 && skill_info->m_byAttRangeform != SRF_FOWARD_160 && skill_info->m_byAttRangeform != SRF_FOWARD_360 && skill_info->m_byAttRangeform != SRF_PIERCE && ability_info->m_wAbilityID != eABILITY_BUFF_RANGE_DAMAGE) { SUNLOG( eDEV_LOG, _T("|%s|%d|if ability range is area, skill range form must be area.|Row= %d, SkillCode= %d, AbilityID = %d, AbilityRangeType = %d, SkillAttRangeForm = %d|"), __FUNCTION__, __LINE__, row, skill_code, ability_info->m_wAbilityID, ability_info->m_byRangeType, skill_info->m_byAttRangeform ); skill_info->m_byAttRangeform = SRF_FOWARD_360; is_success = false; // ????????? ?????????? ???????????? ???????? ????? ???????? ??????????. //ASSERT(false); }*/ if(skill_info->m_wSkillArea == 0 || skill_info->m_byMaxTargetNo == 0) { // ?????? ?????????? ???????????? ???????? ?? ??? ?????. SUNLOG( eDEV_LOG, _T("|%s|%d|area skill must specify range and max apply targets." \ "|Row= %d, SkillCode= %d, AbilityID = %d, m_wSkillArea = %d, m_byMaxTargetNo = %d|"), __FUNCTION__, __LINE__, row, skill_code, ability_info->m_wAbilityID, skill_info->m_wSkillArea, skill_info->m_byMaxTargetNo ); is_success = false; //ASSERT(false); } } else if (ability_info->m_byRangeType == SKILL_ABILITY_FIELD) { if (skill_info->m_byTarget != SKILL_TARGET_AREA && skill_info->m_bySkillUserType == eSKILL_USER_PLAYER) { SUNLOG( eDEV_LOG, _T("|%s|%d|if ability range is field, skill target must be field.|Row= %d, SkillCode= %d, AbilityID = %d, AbilityRangeType = %d, SkillTarget = %d|"), __FUNCTION__, __LINE__, row, skill_code, ability_info->m_wAbilityID, ability_info->m_byRangeType, skill_info->m_byTarget ); skill_info->m_byTarget = SKILL_TARGET_AREA; is_success = false; //ASSERT(false); } } else if (ability_info->m_byRangeType == SKILL_ABILITY_CORPSE_RESURRECTION) { if (skill_info->m_byTarget != SKILL_TARGET_FRIEND_CORPSE && skill_info->m_byTarget != SKILL_TARGET_AREA && skill_info->m_SkillCode != 55006) { SUNLOG( eDEV_LOG, _T("|%s|%d|friend-corpse ability not allowed with this skill target.|Row= %d, SkillCode= %d, AbilityID = %d, AbilityRangeType = %d, SkillTarget = %d|"), __FUNCTION__, __LINE__, row, skill_code, ability_info->m_wAbilityID, ability_info->m_byRangeType, skill_info->m_byTarget ); skill_info->m_byTarget = SKILL_TARGET_FRIEND_CORPSE; is_success = false; //ASSERT(false); } } else if (ability_info->m_byRangeType == SKILL_ABILITY_SUMMON) { if (skill_info->m_byTarget != SKILL_TARGET_SUMMON && skill_info->m_byTarget != SKILL_TARGET_AREA) { if (skill_info->m_byTarget != SKILL_TARGET_AREA) { SUNLOG( eDEV_LOG, _T("|%s|%d|summon-area ability not allowed with this skill target.|Row= %d, SkillCode= %d, AbilityID = %d, AbilityRangeType = %d, SkillTarget = %d|"), __FUNCTION__, __LINE__, row, skill_code, ability_info->m_wAbilityID, ability_info->m_byRangeType, skill_info->m_byTarget ); skill_info->m_byTarget = SKILL_TARGET_SUMMON; is_success = false; //ASSERT(false); } } } if (ability_info->m_wAbilityID == eABILITY_MAGIC_SHIELD) { const int shield_hp = ability_info->m_iParam[1]; const int decrese_mp = ability_info->m_iOption2; const double absorb_ratio = ability_info->m_iParam[0] / 1000.f; if (shield_hp <= 0 || decrese_mp < 0 || absorb_ratio <= 0 || absorb_ratio > 1.00001f) { SUNLOG( eDEV_LOG, _T("|%s|%d|magic shield ability inputs invalid.|Row= %d, SkillCode= %d, AbilityID = %d, ShieldHP = %d, DecreseMP = %d, AbsorbRatio = %d|"), __FUNCTION__, __LINE__, row, skill_code, ability_info->m_wAbilityID, shield_hp, decrese_mp, ability_info->m_iParam[0] ); is_success = false; if (shield_hp < 0) { ability_info->m_iParam[1] = 1; } if (decrese_mp < 0) { ability_info->m_iOption2 = -decrese_mp; } if (absorb_ratio <= 0) { ability_info->m_iParam[0] = 100; } if (absorb_ratio > 1.1f) { ability_info->m_iParam[0] = 1000; } //ASSERT(false); } } if (ability_info->m_wAbilityID == eABILITY_WIND_SHIELD) { if (ability_info->m_byRangeType != SKILL_ABILITY_ME) { SUNLOG( eDEV_LOG, _T("|%s|%d|wind-block skill must be self-targeted.|Row= %d, SkillCode= %d, AbilityID = %d, AbilityRangeType = %d|"), __FUNCTION__, __LINE__, row, skill_code, ability_info->m_wAbilityID, ability_info->m_byRangeType ); ability_info->m_byRangeType = SKILL_ABILITY_ME; is_success = false; //ASSERT(false); } } // ???????? ??????? ????? ??????????????? ??????????. if (ability_info->m_wAbilityID == eABILITY_BONUS_DAMAGE_PER_FIGHTING_ENERGY) { if (ability_info->m_iOption2 == 0) { if (ability_info->m_iParam[0] == 0 || ability_info->m_iParam[1] == 0 || ability_info->m_iParam[2] == 0) { SUNLOG( eDEV_LOG, _T("|%s|%d|fighting-energy bonus damage cannot be 0.|Row= %d, SkillCode= %d, AbilityID = %d|"), __FUNCTION__, __LINE__, row, skill_code, ability_info->m_wAbilityID ); is_success = false; //ASSERT(false); } } else { if (ability_info->m_iParam[0] == 0 && ability_info->m_iParam[1] == 0) { SUNLOG( eDEV_LOG, _T("|%s|%d|per-throw damage increment is 0.|Row= %d, SkillCode= %d, AbilityID = %d|"), __FUNCTION__, __LINE__, row, skill_code, ability_info->m_wAbilityID ); is_success = false; //ASSERT(false); } } } // ???????????? 210(???????? ?????????????)???????? 1???? ????????????????? ??????????? ?????????? if (ability_info->m_wAbilityID == eABILITY_BONUS_DAMAGE_PER_STATUS) { BASE_ABILITYINFO* damage_ability_info = skill_info->GetAbilityInfo(eABILITY_DAMAGE); if (damage_ability_info == NULL || damage_ability_info->m_byIndex <= ability_info->m_byIndex) { SUNLOG( eDEV_LOG, _T("|%s|%d|this ability must be used before AbilityID=1.|Row= %d, SkillCode= %d, AbilityID = %d|"), __FUNCTION__, __LINE__, row, skill_code, ability_info->m_wAbilityID ); is_success = false; //ASSERT(false); } } // ????????? ????????? ??????????????? ??????????. if (ability_info->m_wAbilityID == eABILITY_ENCHANT_POISON) { const int effect_ability_id = ability_info->m_iOption1; if (effect_ability_id == 0) { SUNLOG( eDEV_LOG, _T("|%s|%d|missing on-hit-while-damaged ability input.|Row= %d, SkillCode= %d, AbilityID = %d|"), __FUNCTION__, __LINE__, row, skill_code, ability_info->m_wAbilityID ); is_success = false; //ASSERT(false); } } // ????????? ????? ??????????????? ??????????. if (ability_info->m_wAbilityID == kAbilityIncreseHeal) { const int heal_type = ability_info->m_iOption1; if (heal_type != IncreseHealAbilityType::kSkill && heal_type != IncreseHealAbilityType::kItem && heal_type != IncreseHealAbilityType::kSkillAndItem) { SUNLOG( eDEV_LOG, _T("|%s|%d|invalid heal-increase type.|Row= %d, SkillCode= %d, AbilityID = %d, HealType = %d|"), __FUNCTION__, __LINE__, row, skill_code, ability_info->m_wAbilityID, heal_type ); is_success = false; //ASSERT(false); } const int heal_value = ability_info->m_iParam[0]; if (heal_value == 0) { const int heal_ratio = ability_info->m_iParam[1]; if (heal_ratio == 0) { SUNLOG( eDEV_LOG, _T("|%s|%d|heal value and ratio are both empty.|Row= %d, SkillCode= %d, AbilityID = %d|"), __FUNCTION__, __LINE__, row, skill_code, ability_info->m_wAbilityID ); is_success = false; //ASSERT(false); } } } // ?????? ??????? ????????? ??????????????? ??????????. if (ability_info->m_wAbilityID == kAbilityActiveComboSkill) { const int skill_class_code = ability_info->m_iOption1; if (skill_class_code == 0) { SUNLOG( eDEV_LOG, _T("|%s|%d|enhanced skill class code is empty.|Row= %d, SkillCode= %d, AbilityID = %d|"), __FUNCTION__, __LINE__, row, skill_code, ability_info->m_wAbilityID ); is_success = false; //ASSERT(false); } const int apply_time = ability_info->m_iParam[2]; if (apply_time == 0) { SUNLOG( eDEV_LOG, _T("|%s|%d|combo skill state duration is empty.|Row= %d, SkillCode= %d, AbilityID = %d|"), __FUNCTION__, __LINE__, row, skill_code, ability_info->m_wAbilityID ); is_success = false; //ASSERT(false); } const int state_id = ability_info->m_wStateID; if (state_id != kCharStateActiveComboSkill) { SUNLOG( eDEV_LOG, _T("|%s|%d|state is not a combo-skill active state.|Row= %d, SkillCode= %d, AbilityID = %d, StateID = %d|"), __FUNCTION__, __LINE__, row, skill_code, ability_info->m_wAbilityID, state_id ); is_success = false; //ASSERT(false); } } // ?????? ??????? ?????? ??????? ?????? ??????????????? ??????????. if (ability_info->m_wAbilityID == kAbilityComboSkillEffectAddDamage) { const int add_value = ability_info->m_iParam[0]; if (add_value == 0) { const int add_ratio = ability_info->m_iParam[1]; if (add_ratio == 0) { SUNLOG( eDEV_LOG, _T("|%s|%d|bonus damage value and ratio are both empty.|Row= %d, SkillCode= %d, AbilityID = %d|"), __FUNCTION__, __LINE__, row, skill_code, ability_info->m_wAbilityID ); is_success = false; //ASSERT(false); } } } // ?????? ??????? ?????? ???? ???? ?????? ??????????????? ??????????. if (ability_info->m_wAbilityID == kAbilityComboSkillEffectAddBadStatus) { const int state_id = ability_info->m_iOption1; if (state_id == 0) { SUNLOG( eDEV_LOG, _T("|%s|%d|enhanced state is empty.|Row= %d, SkillCode= %d, AbilityID = %d|"), __FUNCTION__, __LINE__, row, skill_code, ability_info->m_wAbilityID ); is_success = false; //ASSERT(false); } const int success_rate = ability_info->m_iParam[1]; if (success_rate == 0) { const int apply_time = ability_info->m_iParam[2]; if (apply_time == 0) { SUNLOG( eDEV_LOG, _T("|%s|%d|neither chance nor duration increase is set.|Row= %d, SkillCode= %d, AbilityID = %d|"), __FUNCTION__, __LINE__, row, skill_code, ability_info->m_wAbilityID ); is_success = false; //ASSERT(false); } } } #ifdef _SERVER // CHANGES: f110214.3L, added debugging facility bool valid_check_attr_type = false; const eATTR_TYPE attr_type = ability_info->GetAttrTypeDetail(&valid_check_attr_type); if (valid_check_attr_type == false) { SUNLOG( eDEV_LOG, _T("|%s|%d|invalid option type.|Row= %d, SkillCode= %d, AbilityID = %d, AttrIndex = %d, Option1 = %d, Option2 = %d|"), __FUNCTION__, __LINE__, row, skill_code, ability_info->m_wAbilityID, ability_info->m_byIndex, ability_info->m_iOption1, ability_info->m_iOption2 ); is_success = false; //ASSERT(false); } #else const eATTR_TYPE attr_type = ability_info->GetAttrType(); #endif if (attr_type != eATTR_TYPE_INVALID) { int option_type = ability_info->m_iParam[0]; int option_value = ability_info->m_iParam[1]; if (option_type != VALUE_TYPE_VALUE) { option_value = option_value / 10; } if (ability_info->m_wAbilityID == eABILITY_CHANGE_ATTR) { option_type = VALUE_TYPE_VALUE; } if (CheckAttrValidity(ability_info->GetAttrType(), option_type, option_value) == false) { SUNLOG( eDEV_LOG, "|%s|%d|option value check failed.|Row= %d, SkillCode= %d, AbilityID = %d, AttrIndex = %d, OptionType = %d, OptionValue = %d|", row, skill_code, ability_info->m_wAbilityID, ability_info->GetAttrType(), option_type, option_value ); //ASSERT(false); } } } if (skill_code == SKILLCODE_NORMAL_ATTACK) { SUNLOG( eDEV_LOG, _T("|%s|%d|skill code unavailable.|Row= %d, SkillCode= %d|"), __FUNCTION__, __LINE__, row, skill_code ); //ASSERT(false); return false; } return is_success; } BOOL SkillInfoParser::LoadScript(eSCRIPT_CODE script_code, BOOL is_reload) { switch(script_code) { case SCRIPT_SKILLINFO: return (_Load(is_reload == TRUE) ? TRUE : FALSE); case SCRIPT_STYLEINFO: return (_LoadStyle(is_reload == TRUE) ? TRUE : FALSE); } return false; } #ifdef _NA_0_20100901_SKILLTREE_SYSTEM void SkillInfoParser::CalculateSkillLineFromSkillInventoryStoreParser() { SkillInventoryStoreParser* skill_inventory_parser = SkillInventoryStoreParser::Instance(); ASSERT(skill_inventory_parser); if (skill_inventory_parser == NULL) return; int count = skill_inventory_parser->GetSkillInventoryStoreNum(); for (int idx = 0 ; idx < count ; ++idx) { const SkillInven_s* const skill_inventory = skill_inventory_parser->GetSkillInventoryStore(idx); ASSERT(skill_inventory); if (skill_inventory == NULL) continue; SkillTree* skill_tree = &(skill_tree_[skill_inventory->bClassID]); SkillTree::SkillDescript* skill_descript = (SkillTree::SkillDescript*)skill_tree->get_skill_descript(skill_inventory->bSkillTab2); if (skill_descript == NULL) continue; // CHANGES: f110216.1L, check boundary BOOST_STATIC_ASSERT(MAX_SKILL_INVENTORY_STORE_NUM == skill_tree->MAX_SKILLTREE_COLUMN); for (int num = 0 ; num < MAX_SKILL_INVENTORY_STORE_NUM ; ++num) { skill_descript[num].character_class_id = skill_inventory->bClassID; skill_descript[num].skill_line = skill_inventory->bSkillTab2; skill_descript[num].first_skill_code = (skill_inventory->iSkillID[num] > 0) ? skill_inventory->iSkillID[num] : 0; skill_descript[num].skill_class = 0; skill_descript[num].upper_skill_class = 0; if (skill_descript[num].first_skill_code != 0) { SkillScriptInfo* skill_info = GetSkillInfo(skill_descript[num].first_skill_code); if (skill_info) { skill_descript[num].skill_class = skill_info->m_SkillClassCode; skill_descript[num].upper_skill_class = skill_info->m_UpperSkillClass; skill_tree->skill_hashmap[skill_info->m_SkillClassCode] = &(skill_descript[num]); } } } } } #endif void SkillInfoParser::SkillJobTreeManager::LoadTree(const SkillInfoParser* skill_info_parser) { Clear(); const SkillInventoryStoreParser* const inven_parser = SkillInventoryStoreParser::Instance(); if (inven_parser == NULL) { //ASSERT(false); return; } const int index_size = static_cast(inven_parser->GetSkillInventoryStoreNum()); for (int index = 0; index < index_size; ++index) { const SkillInven_s* const inven_info = inven_parser->GetSkillInventoryStore(index); if (inven_info == NULL) { //ASSERT(false); continue; } const int char_type = inven_info->bClassID; if (char_type == 0) { continue; } for (int job_type = 0; job_type < kMaxJobSize; ++job_type) { SkillJobTree* const job_tree = GetTreeByMutable(char_type, job_type); if (job_tree == NULL) { //ASSERT(false); continue; } const int line_index = inven_info->bSkillTab2 - 1; const int col_size = job_tree->GetColumnSize(); for (int col = 0; col < col_size; ++col) { SkillJobTree::Desc* const job_desc = job_tree->GetDescByMutable(line_index, col); if (job_desc == NULL) { //ASSERT(false); continue; } const int skill_id_index = (job_type * col_size) + col; if (skill_id_index >= _countof(inven_info->iSkillID)) { //ASSERT(false); continue; } const int first_skill_code = inven_info->iSkillID[skill_id_index]; if (first_skill_code <= 0) { continue; } const SkillScriptInfo* const skill_info = skill_info_parser->GetSkillInfo(first_skill_code); if (skill_info == NULL) { //ASSERT(false); continue; } job_desc->job_type = job_type; job_desc->skill_class_code = skill_info->m_SkillClassCode; job_desc->upper_skill_class_code = skill_info->m_UpperSkillClass; job_desc->first_skill_code = first_skill_code; job_desc->line_index = line_index; if (job_tree->InsertDesc(job_desc) == false) { //ASSERT(false); continue; } } } } } #ifdef _NA_006937_20131030_ABILITY_AND_STATE_CHANGE_CRITICAL eATTR_TYPE BASE_ABILITYINFO::GetAttrTypeForCriticalRatio( eATTR_APPLY_TYPE state_type, DetailLogging* logging /*= NULL*/ ) const { __TOUCHED(logging); switch (state_type) { case eATTR_APPLY_TYPE_NORMAL : return eATTR_CRITICAL_RATIO_CHANGE; case eATTR_APPLY_TYPE_DAMAGED : return eATTR_ENEMY_CRITICAL_RATIO_CHANGE; default: break; } return eATTR_TYPE_INVALID; } eATTR_TYPE BASE_ABILITYINFO::GetAttrTypeForCriticalDamage( eATTR_APPLY_TYPE state_type, DetailLogging* logging /*= NULL*/ ) const { __TOUCHED(logging); switch (state_type) { case eATTR_APPLY_TYPE_NORMAL : return eATTR_CRITICAL_DAMAGE_CHANGE; case eATTR_APPLY_TYPE_DAMAGED : return eATTR_ENEMY_CRITICAL_DAMAGE_CHANGE; default: break; } return eATTR_TYPE_INVALID; } #endif //_NA_006937_20131030_ABILITY_AND_STATE_CHANGE_CRITICAL