CN1602 is the local client. KR is the official tree with unpacked Data, System, and Sound. Packed .wpk files stay off git.
2377 lines
92 KiB
C++
2377 lines
92 KiB
C++
#include "stdafx.h"
|
|
#include "SkillInfoParser.h"
|
|
|
|
#include <Define.h>
|
|
#include <Struct.h>
|
|
#include <ItemOptionHeader.h>
|
|
|
|
#ifdef _NA_0_20100901_SKILLTREE_SYSTEM
|
|
#include <SkillInventoryStoreParser.h>
|
|
#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<SLOTCODE>(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<SLOTCODE>(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<uint8_t>(i);
|
|
ability_info.m_wAbilityID = static_cast<WORD>(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<eABILITY_RANGE_TYPE>(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<eABILITY>(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<eATTACK_TYPE>(m_iOption1), &logger);
|
|
case eABILITY_PHYSICAL_DEFENSE_INCREASE:
|
|
return GetAttrTypeForDefence(static_cast<eATTACK_TYPE>(m_iOption1), &logger);
|
|
#if !defined(_NA001605_EP2_ATTRIBUTES_RENEWAL_)
|
|
case eABILITY_MAGIC_DEFENSE_INCREASE:
|
|
return GetAttrTypeForDefence(static_cast<eATTACK_TYPE>(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<eATTACK_TYPE>(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<eATTACK_TYPE>(m_iOption1), &logger);
|
|
|
|
case eABILITY_SKILLRANGE_INCREASE:
|
|
return GetAttrTypeForAttackRange(static_cast<eRANGE_TYPE>(m_iOption1), &logger);
|
|
|
|
#ifdef _NA_006937_20131030_ABILITY_AND_STATE_CHANGE_CRITICAL
|
|
case eABILITY_CRITICAL_RATIO_CHANGE:
|
|
return GetAttrTypeForCriticalRatio(static_cast<eATTR_APPLY_TYPE>(m_iOption1), &logger);
|
|
case eABILITY_CRITICAL_DAMAGE_CHANGE:
|
|
return GetAttrTypeForCriticalDamage(static_cast<eATTR_APPLY_TYPE>(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<eATTACK_TYPE>(m_iOption1), &logger);
|
|
case eABILITY_LOWHP_DEFENSE_CHANGE:
|
|
return GetAttrTypeForDefence(static_cast<eATTACK_TYPE>(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<eATTACK_TYPE>(m_iOption1), &logger);
|
|
case eABILITY_ATTR_DEFENSIVE_POWER:
|
|
#ifdef _NA001605_EP2_ATTRIBUTES_RENEWAL_
|
|
return GetAttrTypeForElementalResist(static_cast<eATTACK_TYPE>(m_iOption1), &logger);
|
|
#else
|
|
return GetAttrTypeForDefence(static_cast<eATTACK_TYPE>(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<eABILITY>(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<int>(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
|