Files
Sun1602/ProgramCommon/CommonCharacterFormula.cpp
2022-10-26 12:25:11 +08:00

1267 lines
39 KiB
C++

#include "stdafx.h"
#include "./CommonCharacterFormula.h"
#include <Struct.h>
#include "NumericValues.h"
//==================================================================================================
namespace ns_formula {
;
// internal interfaces
static float CalcHPRatioNum(DWORD partymemberNum);
static float CalcAdditionalHPRatio(DWORD partymemberNum);
//
//==================================================================================================
static ns_formula::SkillAttackPowerBalanceConstants kSkillAttackPowerConstants =
{
// ratio_of_conversion
#ifdef _NA_008486_20150914_TOTAL_BALANCE
{
0.0f, // eCHAR_NONE
90.0f, // eCHAR_BERSERKER
90.0f, // eCHAR_DRAGON
90.0f, // eCHAR_SHADOW
90.0f, // eCHAR_VALKYRIE
90.0f, // eCHAR_ELEMENTALIST
90.0f, // eCHAR_MYSTIC
90.0f, // eCHAR_HELLROID
90.0f, // eCHAR_WITCHBLADE
},
#else
{
0.0f, // eCHAR_NONE
90.0f, // eCHAR_BERSERKER
80.0f, // eCHAR_DRAGON
70.0f, // eCHAR_SHADOW
60.0f, // eCHAR_VALKYRIE
50.0f, // eCHAR_ELEMENTALIST
80.0f, // eCHAR_MYSTIC
90.0f, // eCHAR_HELLROID
90.0f, // eCHAR_WITCHBLADE
},
#endif //_NA_008486_20150914_TOTAL_BALANCE
};
static ns_formula::CriticalBalanceConstants kCriticalChanceConstants =
{
#ifdef _NA_008486_20150914_TOTAL_BALANCE
60.0f, // kNumberatorWeight
#else
5.0f, // kNumberatorWeight
#endif //_NA_008486_20150914_TOTAL_BALANCE
100.0f, // kDenominatorWeight
// base_probabilies
{
0.0f, // eCHAR_NONE
0.8f, // eCHAR_BERSERKER
1.7f, // eCHAR_DRAGON
1.2f, // eCHAR_SHADOW
1.0f, // eCHAR_VALKYRIE
0.2f, // eCHAR_ELEMENTALIST
1.5f, // eCHAR_MYSTIC
0.8f, // eCHAR_HELLROID
1.0f, // eCHAR_WITCHBLADE
},
};
static ns_formula::AttackRateConstants kAttackRateConstants =
{
1.0f,
#ifdef _NA_008486_20150914_TOTAL_BALANCE
{
6.0f, // eCHAR_NONE
6.0f, // eCHAR_BERSERKER
6.0f, // eCHAR_DRAGON
6.0f, // eCHAR_SHADOW
6.0f, // eCHAR_VALKYRIE
6.0f, // eCHAR_ELEMENTALIST
6.0f, // eCHAR_MYSTIC
6.0f, // eCHAR_HELLROID
6.0f, // eCHAR_WITCHBLADE
},
#else
{
4.0f, // eCHAR_NONE
4.0f, // eCHAR_BERSERKER
4.0f, // eCHAR_DRAGON
4.0f, // eCHAR_SHADOW
4.0f, // eCHAR_VALKYRIE
4.0f, // eCHAR_ELEMENTALIST
4.0f, // eCHAR_MYSTIC
4.0f, // eCHAR_HELLROID
4.0f, // eCHAR_WITCHBLADE
},
#endif //_NA_008486_20150914_TOTAL_BALANCE
};
static ns_formula::AttackAvoidRateConstants kAttackAvoidRateConstants =
{
0.2f,
#ifdef _NA_008486_20150914_TOTAL_BALANCE
{
0.0f, // eCHAR_NONE
5.0f, // eCHAR_BERSERKER
5.0f, // eCHAR_DRAGON
5.0f, // eCHAR_SHADOW
5.0f, // eCHAR_VALKYRIE
5.0f, // eCHAR_ELEMENTALIST
5.0f, // eCHAR_MYSTIC
5.0f, // eCHAR_HELLROID
5.0f, // eCHAR_WITCHBLADE
},
#else
{
0.0f, // eCHAR_NONE
8.0f, // eCHAR_BERSERKER
8.0f, // eCHAR_DRAGON
8.0f, // eCHAR_SHADOW
5.0f, // eCHAR_VALKYRIE
5.0f, // eCHAR_ELEMENTALIST
6.0f, // eCHAR_MYSTIC
8.0f, // eCHAR_HELLROID
6.0f, // eCHAR_WITCHBLADE
},
#endif //_NA_008486_20150914_TOTAL_BALANCE
};
extern const double& AttackRateConstants_EquipmentWeight =
kAttackRateConstants.kEquipmentWeight;
extern const double& AttackAvoidRateConstants_EquipmentWeight =
kAttackAvoidRateConstants.kEquipmentWeight;
//==================================================================================================
void ns_formula::BalanceConstantsChangerInProgramCommon::GetSkillAttackPower(
SkillAttackPowerBalanceConstants* const constants)
{
*constants = ns_formula::kSkillAttackPowerConstants;
}
void ns_formula::BalanceConstantsChangerInProgramCommon::ModifySkillAttackPower(
const SkillAttackPowerBalanceConstants& constants)
{
SkillAttackPowerBalanceConstants modified = constants;
modified.ratio_of_conversion[eCHAR_NONE] = 0.0f;
// > 0.0f
if (modified.ratio_of_conversion[eCHAR_BERSERKER] < 0.0f) {
modified.ratio_of_conversion[eCHAR_BERSERKER] = 90.0f;
};
if (modified.ratio_of_conversion[eCHAR_DRAGON] < 0.0f) {
modified.ratio_of_conversion[eCHAR_DRAGON] = 80.0f;
};
if (modified.ratio_of_conversion[eCHAR_SHADOW] < 0.0f) {
modified.ratio_of_conversion[eCHAR_SHADOW] = 70.0f;
};
if (modified.ratio_of_conversion[eCHAR_VALKYRIE] < 0.0f) {
modified.ratio_of_conversion[eCHAR_VALKYRIE] = 60.0f;
};
if (modified.ratio_of_conversion[eCHAR_ELEMENTALIST] < 0.0f) {
modified.ratio_of_conversion[eCHAR_ELEMENTALIST] = 50.0f;
};
// _NA_004965_20120613_NEW_CHARACTER_MYSTIC
if (modified.ratio_of_conversion[eCHAR_MYSTIC] < 0.0f)
{
modified.ratio_of_conversion[eCHAR_MYSTIC] = 70.0f;
}
// _NA_000000_20130812_NEW_CHARACTER_HELLROID
if (modified.ratio_of_conversion[eCHAR_HELLROID] < 0.0f)
{
modified.ratio_of_conversion[eCHAR_HELLROID] = 90.0f;
}
//_NA_007514_20140828_NEW_CHARACTER_WITCHBLADE
if (modified.ratio_of_conversion[eCHAR_WITCHBLADE] < 0.0f)
{
modified.ratio_of_conversion[eCHAR_WITCHBLADE] = 80.0f;
}
ns_formula::kSkillAttackPowerConstants = modified;
return;
}
void ns_formula::BalanceConstantsChangerInProgramCommon::GetCriticalChance(
CriticalBalanceConstants* const constants)
{
*constants = ns_formula::kCriticalChanceConstants;
}
void ns_formula::BalanceConstantsChangerInProgramCommon::ModifyCriticalChance(
const CriticalBalanceConstants& constants)
{
CriticalBalanceConstants modified = constants;
// > 0.0f
/* NOTE: it's dangerous if the below code was opened.
if (modified.kNumberatorWeight <= 0.0f) {
modified.kNumberatorWeight = 3.0f;
};
if (modified.kDenominatorWeight <= 0.0f) {
modified.kDenominatorWeight = 5.0f;
};
*/
modified.base_probabilies[eCHAR_NONE] = 0.0f;
if (modified.base_probabilies[eCHAR_BERSERKER] < 0.0f) {
modified.base_probabilies[eCHAR_BERSERKER] = 1.7f;
};
if (modified.base_probabilies[eCHAR_DRAGON] < 0.0f) {
modified.base_probabilies[eCHAR_DRAGON] = 3.3f;
};
if (modified.base_probabilies[eCHAR_SHADOW] < 0.0f) {
modified.base_probabilies[eCHAR_SHADOW] = 2.3f;
};
if (modified.base_probabilies[eCHAR_VALKYRIE] < 0.0f) {
modified.base_probabilies[eCHAR_VALKYRIE] = 2.0f;
};
if (modified.base_probabilies[eCHAR_ELEMENTALIST] < 0.0f) {
modified.base_probabilies[eCHAR_ELEMENTALIST] = 0.3f;
};
// _NA_004965_20120613_NEW_CHARACTER_MYSTIC
if (modified.base_probabilies[eCHAR_MYSTIC] < 0.0f) {
modified.base_probabilies[eCHAR_MYSTIC] = 2.3f;
};
// _NA_000000_20130812_NEW_CHARACTER_HELLROID
if (modified.base_probabilies[eCHAR_HELLROID] < 0.0f) {
modified.base_probabilies[eCHAR_HELLROID] = 0.8f;
};
//_NA_007514_20140828_NEW_CHARACTER_WITCHBLADE
if (modified.base_probabilies[eCHAR_WITCHBLADE] < 0.0f) {
modified.base_probabilies[eCHAR_WITCHBLADE] = 1.0f;
};
ns_formula::kCriticalChanceConstants = modified;
return;
}
void ns_formula::BalanceConstantsChangerInProgramCommon::GetAttackRate(
AttackRateConstants* const constants)
{
*constants = ns_formula::kAttackRateConstants;
}
void ns_formula::BalanceConstantsChangerInProgramCommon::ModifyAttackRate(
const AttackRateConstants& constants)
{
AttackRateConstants modified = constants;
if (modified.kEquipmentWeight < 0.0f) {
modified.kEquipmentWeight = 1.0f;
}
modified.ratio_of_conversion[eCHAR_NONE] = 0.0f;
if (modified.ratio_of_conversion[eCHAR_BERSERKER] < 0.0f) {
modified.ratio_of_conversion[eCHAR_BERSERKER] = 4.0f;
};
if (modified.ratio_of_conversion[eCHAR_DRAGON] < 0.0f) {
modified.ratio_of_conversion[eCHAR_DRAGON] = 4.0f;
};
if (modified.ratio_of_conversion[eCHAR_SHADOW] < 0.0f) {
modified.ratio_of_conversion[eCHAR_SHADOW] = 4.0f;
};
if (modified.ratio_of_conversion[eCHAR_VALKYRIE] < 0.0f) {
modified.ratio_of_conversion[eCHAR_VALKYRIE] = 4.0f;
};
if (modified.ratio_of_conversion[eCHAR_ELEMENTALIST] < 0.0f) {
modified.ratio_of_conversion[eCHAR_ELEMENTALIST] = 4.0f;
};
// _NA_004965_20120613_NEW_CHARACTER_MYSTIC
if (modified.ratio_of_conversion[eCHAR_MYSTIC] < 0.0f) {
modified.ratio_of_conversion[eCHAR_MYSTIC] = 4.0f;
};
//_NA_000000_20130812_NEW_CHARACTER_HELLROID
if (modified.ratio_of_conversion[eCHAR_HELLROID] < 0.0f) {
modified.ratio_of_conversion[eCHAR_HELLROID] = 4.0f;
};
//_NA_007514_20140828_NEW_CHARACTER_WITCHBLADE
if (modified.ratio_of_conversion[eCHAR_WITCHBLADE] < 0.0f) {
modified.ratio_of_conversion[eCHAR_WITCHBLADE] = 4.0f;
};
ns_formula::kAttackRateConstants = modified;
return;
}
void ns_formula::BalanceConstantsChangerInProgramCommon::GetAttackAvoidRate(
AttackAvoidRateConstants* const constants)
{
*constants = ns_formula::kAttackAvoidRateConstants;
}
void ns_formula::BalanceConstantsChangerInProgramCommon::ModifyAttackAvoidRate(
const AttackAvoidRateConstants& constants)
{
AttackAvoidRateConstants modified = constants;
if (modified.kEquipmentWeight < 0.0f) {
modified.kEquipmentWeight = 0.2f;
}
modified.ratio_of_conversion[eCHAR_NONE] = 0.0f;
if (modified.ratio_of_conversion[eCHAR_BERSERKER] < 0.0f) {
modified.ratio_of_conversion[eCHAR_BERSERKER] = 8.0f;
};
if (modified.ratio_of_conversion[eCHAR_DRAGON] < 0.0f) {
modified.ratio_of_conversion[eCHAR_DRAGON] = 8.0f;
};
if (modified.ratio_of_conversion[eCHAR_SHADOW] < 0.0f) {
modified.ratio_of_conversion[eCHAR_SHADOW] = 8.0f;
};
if (modified.ratio_of_conversion[eCHAR_VALKYRIE] < 0.0f) {
modified.ratio_of_conversion[eCHAR_VALKYRIE] = 3.5f;
};
if (modified.ratio_of_conversion[eCHAR_ELEMENTALIST] < 0.0f) {
modified.ratio_of_conversion[eCHAR_ELEMENTALIST] = 16.0f;
};
// _NA_004965_20120613_NEW_CHARACTER_MYSTIC
if (modified.ratio_of_conversion[eCHAR_MYSTIC] < 0.0f) {
modified.ratio_of_conversion[eCHAR_MYSTIC] = 8.0f;
}
// _NA_000000_20130812_NEW_CHARACTER_HELLROID
if (modified.ratio_of_conversion[eCHAR_HELLROID] < 0.0f) {
modified.ratio_of_conversion[eCHAR_HELLROID] = 8.0f;
}
//_NA_007514_20140828_NEW_CHARACTER_WITCHBLADE
if (modified.ratio_of_conversion[eCHAR_WITCHBLADE] < 0.0f) {
modified.ratio_of_conversion[eCHAR_WITCHBLADE] = 7.0f;
}
ns_formula::kAttackAvoidRateConstants = modified;
return;
}
//==================================================================================================
//==================================================================================================
//==================================================================================================
//==================================================================================================
/*
#if defined(_NA001605_EP2_ATTRIBUTES_RENEWAL_) && USE_DAMAGE_EXTENTION
int ns_formula::DamageEncoder::Fix(int origin_damage)
{
// 0x0000
// 2bit : 0, 1, 2, 3
// gap : 0 1 4 8
int fixed_damage = origin_damage;
if (fixed_damage < 0) {
fixed_damage = 0;
}
else if (fixed_damage > kMaxDamage) {
fixed_damage = kMaxDamage;
};
//
fixed_damage
// 4096 - 1
= (fixed_damage < 0x00001000) ? ((fixed_damage))
// 16384 - 1
: (fixed_damage < 0x00004000) ? ((fixed_damage & ~0x1))
// 65536 - 1
: (fixed_damage < 0x00010000) ? ((fixed_damage & ~0x3))
// 262144 - 1
: ((fixed_damage & ~0xF));
return fixed_damage;
}
DAMAGETYPE ns_formula::DamageEncoder::Encode(int fixed_damage)
{
assert(fixed_damage >= 0 &&
fixed_damage <= kMaxDamage);
int encode_damage
// 4096 - 1
= (fixed_damage < 0x00001000) ? ((fixed_damage))
// 16384 - 1
: (fixed_damage < 0x00004000) ? ((fixed_damage >> 1) | (0x4000))
// 65536 - 1
: (fixed_damage < 0x00010000) ? ((fixed_damage >> 2) | (0x8000))
// 262144 - 1
//(damage < 0x00040000) ? ((fixed_damage >> 4) | (0xC000))
: ((fixed_damage >> 4) | (0xC000));
return static_cast<DAMAGETYPE>(encode_damage);
}
int ns_formula::DamageEncoder::Decode(DAMAGETYPE encoded_damage)
{
int decode_damage
// 262144 - 1
= ((encoded_damage & 0xC000) == 0xC000) ? ((encoded_damage & ~0xC000) << 4)
// 65536 - 1
: ((encoded_damage & 0x8000) == 0x8000) ? ((encoded_damage & ~0x8000) << 2)
// 16384 - 1
: ((encoded_damage & 0x4000) == 0x4000) ? ((encoded_damage & ~0x4000) << 1)
// 4096 - 1
: ((encoded_damage));
assert(decode_damage >= 0 &&
decode_damage <= kMaxDamage);
return decode_damage;
}
#else //if !(defined(_NA001605_EP2_ATTRIBUTES_RENEWAL_) && USE_DAMAGE_EXTENTION)
int ns_formula::DamageEncoder::Fix(int origin_damage)
{
int fixed_damage = origin_damage;
if (fixed_damage < 0) {
fixed_damage = 0;
}
else if (fixed_damage > kMaxDamage) {
fixed_damage = kMaxDamage;
}
return fixed_damage;
}
DAMAGETYPE ns_formula::DamageEncoder::Encode(int fixed_damage)
{
assert(fixed_damage >= 0 &&
fixed_damage <= kMaxDamage);
return static_cast<DAMAGETYPE>(fixed_damage);
}
int ns_formula::DamageEncoder::Decode(DAMAGETYPE encoded_damage)
{
assert(encoded_damage >= 0 &&
encoded_damage <= kMaxDamage);
return encoded_damage;
}
#endif
*/
//==================================================================================================
DWORD ns_formula::GetStatPointPerLevel()
{
return 5;
}
DWORD ns_formula::GetSkillPoint(LEVELTYPE level)
{
#ifdef _NA_0_20100901_SKILLTREE_SYSTEM
uint temp = level % CHARACTER_SKILL_LEVEL_RATIO;
return ((temp == 0) && (level != 0)) ? 1 : 0;
#else
__UNUSED(level); // current (100221)
// i. 1~50LV시 사용 공식 = (레벨/10)+1 (소수는 내림처리한다.)
// ii. 51~135LV시 사용 공식 = (레벨/15)+3 (소수는 내림처리한다.)
// iii. 136~200LV시 사용 공식 = (레벨/20)+5 (소수는 내림처리한다.)
/*
if (level<=50)
{
return level/10 + 1;
}
else if (level<=135)
{
return level/15 + 3;
}
else if (level<=200)
{
return level/20 + 5;
}
*/
// 레벨업시 무조건 스킬포인트 1씩 획득하는 것으로 수정됨
return 1;
#endif
}
DWORD ns_formula::CalcHP(const eCHAR_TYPE char_type, const LEVELTYPE level, const short in_vitality)
{
short vitality = in_vitality;
if (vitality < 0)
{
vitality = 0;
}
#ifdef _NA001605_EP2_ATTRIBUTES_RENEWAL_
switch (char_type)
{
case eCHAR_BERSERKER:
return (DWORD)(200 + (level - 1) * 39.0f + (vitality - 27) * 11.0f);
case eCHAR_DRAGON:
return (DWORD)(180 + (level - 1) * 26.0f + (vitality - 20) * 9.0f);
case eCHAR_SHADOW:
return (DWORD)(160 + (level - 1) * 25.0f + (vitality - 16) * 9.0f);
case eCHAR_VALKYRIE:
return (DWORD)(160 + (level - 1) * 25.0f + (vitality - 15) * 9.0f);
case eCHAR_ELEMENTALIST:
return (DWORD)(150 + (level - 1) * 23.0f + (vitality - 13) * 7.0f);
case eCHAR_MYSTIC: // _NA_004965_20120613_NEW_CHARACTER_MYSTIC
return (DWORD)(160 + (level - 1) * 25.0f + (vitality - 15) * 9.0f);
case eCHAR_HELLROID: // _NA_000000_20130812_NEW_CHARACTER_HELLROID
return (DWORD)(200 + (level - 1) * 39.0f + (vitality - 27) * 12.0f);
case eCHAR_WITCHBLADE: // _NA_007514_20140828_NEW_CHARACTER_WITCHBLADE
return (DWORD)(180 + (level - 1) * 25.0f + (vitality - 24) * 9.0f);
}
#else
switch (char_type)
{
case eCHAR_BERSERKER:
return (DWORD)(200 + (level - 1) * 30.0f + (vitality - 27) * 10.0f);
case eCHAR_DRAGON:
return (DWORD)(180 + (level - 1) * 22.0f + (vitality - 20) * 7.0f);
case eCHAR_SHADOW:
return (DWORD)(160 + (level - 1) * 19.0f + (vitality - 15) * 7.0f);
case eCHAR_VALKYRIE:
return (DWORD)(160 + (level - 1) * 19.0f + (vitality - 15) * 5.0f);
case eCHAR_ELEMENTALIST:
return (DWORD)(150 + (level - 1) * 18.0f + (vitality - 13) * 5.0f);
case eCHAR_MYSTIC: // _NA_004965_20120613_NEW_CHARACTER_MYSTIC
return (DWORD)(160 + (level - 1) * 19.0f + (vitality - 15) * 7.0f);
#ifdef _NA_000000_20130812_NEW_CHARACTER_HELLROID
case eCHAR_HELLROID:
return (DWORD)(200 + (level - 1) * 39.0f + (vitality - 27) * 12.0f);
#endif //_NA_000000_20130812_NEW_CHARACTER_HELLROID
#ifdef _NA_007514_20140828_NEW_CHARACTER_WITCHBLADE
case eCHAR_WITCHBLADE:
return (DWORD)(180 + (level - 1) * 25.0f + (vitality - 24) * 9.0f);
#endif //_NA_007514_20140828_NEW_CHARACTER_WITCHBLADE
}
#endif
SASSERT(false, "Wrong Char_Type in CalcHP()");
return 1;
}
DWORD ns_formula::CalcMP(const eCHAR_TYPE char_type, const LEVELTYPE level, const short in_spirit)
{
short spirit = in_spirit;
if (spirit < 0)
{
spirit = 0;
}
switch (char_type)
{
case eCHAR_BERSERKER:
return (DWORD)( 20 + (level - 1) * 5.0f + (spirit-10) * 2.0f);
case eCHAR_DRAGON:
return (DWORD)( 25 + (level - 1) * 7.0f + (spirit-12) * 4.0f);
case eCHAR_SHADOW:
return (DWORD)( 40 + (level - 1) * 8.5f + (spirit-10) * 6.0f);
case eCHAR_VALKYRIE:
return (DWORD)( 32 + (level - 1) * 8.0f + (spirit-19) * 5.0f);
case eCHAR_ELEMENTALIST:
return (DWORD)(100 + (level - 1) * 25.0f + spirit * 6.0f);
case eCHAR_MYSTIC: // _NA_004965_20120613_NEW_CHARACTER_MYSTIC
return (DWORD)(40 + (level - 1) * 8.5f + (spirit - 10) * 6.0f);
case eCHAR_HELLROID: //_NA_000000_20130812_NEW_CHARACTER_HELLROID
return (DWORD)(100 + (level - 1) * 20.0f + (spirit * 6.0f));
case eCHAR_WITCHBLADE: //_NA_007514_20140828_NEW_CHARACTER_WITCHBLADE
return (DWORD)(30 + (level - 1) * 7.0f + ((spirit-10) * 4.0f));
}
SASSERT(false, "Wrong Char_Type in CalcMP()");
return 1;
}
// 각 케릭터 SD Point 공식
DWORD ns_formula::CalcSD(eCHAR_TYPE char_type, LEVELTYPE level)
{
__UNUSED(char_type);
float calc = static_cast<float>(level);
#ifdef _NA_004010_20120102_1201_SD_FORMULA
calc = 200.0f + pow(calc, 3) / (calc * 2);
#else
calc = 200.0f + (pow(calc, 3) / SDINCREASE_RATIO / calc);
#endif
if (calc < 0)
{
return 0;
}
return static_cast<DWORD>(util::LL_Round(calc));
}
// 최소 공격력(근거리)
DWORD ns_formula::CalcMinMeleeAttackPower(
const eCHAR_TYPE char_type, const short in_strength, const short in_dexterity)
{
short dexterity = in_dexterity;
if (dexterity < 0)
{
dexterity = 0;
}
short strength = in_strength;
if (strength < 0)
{
strength = 0;
}
#ifdef _NA_008486_20150914_TOTAL_BALANCE
switch (char_type)
{
case eCHAR_DRAGON:
return (DWORD)(strength / 5);
case eCHAR_BERSERKER:
return (DWORD)(strength / 6);
case eCHAR_SHADOW:
return (DWORD)(strength / 8);
case eCHAR_VALKYRIE:
return (DWORD)(strength / 8);
case eCHAR_ELEMENTALIST:
return (DWORD)(strength / 9);
case eCHAR_MYSTIC: // _NA_004965_20120613_NEW_CHARACTER_MYSTIC
return (DWORD)(strength / 9);
case eCHAR_HELLROID: //_NA_000000_20130812_NEW_CHARACTER_HELLROID
return (DWORD)(strength / 8);
case eCHAR_WITCHBLADE: //_NA_007514_20140828_NEW_CHARACTER_WITCHBLADE
return (DWORD)(strength / 8);
}
#else
switch (char_type)
{
case eCHAR_DRAGON:
return (DWORD)(strength / 5);
case eCHAR_BERSERKER:
return (DWORD)(strength / 6);
case eCHAR_SHADOW:
return (DWORD)(strength / 9 + dexterity / 12);
case eCHAR_VALKYRIE:
return (DWORD)(strength / 8 + dexterity / 10);
case eCHAR_ELEMENTALIST:
return (DWORD)(strength / 9);
case eCHAR_MYSTIC: // _NA_004965_20120613_NEW_CHARACTER_MYSTIC
return (DWORD)(strength / 9 + dexterity / 12);
case eCHAR_HELLROID: //_NA_000000_20130812_NEW_CHARACTER_HELLROID
return (DWORD)(strength / 8);
case eCHAR_WITCHBLADE: //_NA_007514_20140828_NEW_CHARACTER_WITCHBLADE
return (DWORD)(strength / 8 + dexterity / 12);
}
#endif //_NA_008486_20150914_TOTAL_BALANCE
SASSERT(false, "Wrong Char_Type in CalcMP()");
return 1;
}
#ifdef _NA_007514_20140828_NEW_CHARACTER_WITCHBLADE
extern PLAYERFP CalcFP( const eCHAR_TYPE char_type )
{
switch (char_type)
{
case eCHAR_WITCHBLADE:
return 10;
}
return 0;
}
#endif //_NA_007514_20140828_NEW_CHARACTER_WITCHBLADE
// 최소 공격력(원거리)
DWORD ns_formula::CalcMinRangeAttackPower(
const eCHAR_TYPE char_type, const short in_strength, const short in_dexterity)
{
short dexterity = in_dexterity;
if (dexterity < 0)
{
dexterity = 0;
}
short strength = in_strength;
if (strength < 0)
{
strength = 0;
}
switch (char_type)
{
case eCHAR_DRAGON:
case eCHAR_BERSERKER:
case eCHAR_ELEMENTALIST:
return CalcMinMeleeAttackPower(char_type, strength, dexterity);
case eCHAR_SHADOW:
return (DWORD)(strength / 8);
case eCHAR_VALKYRIE:
#ifdef _NA_008486_20150914_TOTAL_BALANCE
return (DWORD)(strength / 8);
#else
return (DWORD)(strength / 8 + dexterity / 10);
#endif //_NA_008486_20150914_TOTAL_BALANCE
case eCHAR_MYSTIC: // _NA_004965_20120613_NEW_CHARACTER_MYSTIC
return (DWORD)(strength / 8);
case eCHAR_HELLROID: // _NA_000000_20130812_NEW_CHARACTER_HELLROID
return (DWORD)(strength / 8);
case eCHAR_WITCHBLADE: // _NA_007514_20140828_NEW_CHARACTER_WITCHBLADE
return (DWORD)(strength / 8);
}
return 1;
}
// 최대 공격력(근거리)
DWORD ns_formula::CalcMaxMeleeAttackPower(
const eCHAR_TYPE char_type, const short in_strength, const short in_dexterity)
{
short dexterity = in_dexterity;
if (dexterity < 0)
{
dexterity = 0;
}
short strength = in_strength;
if (strength < 0)
{
strength = 0;
}
#ifdef _NA_008486_20150914_TOTAL_BALANCE
switch (char_type)
{
case eCHAR_DRAGON:
return (DWORD)(strength / 3);
case eCHAR_BERSERKER:
return (DWORD)(strength / 2);
case eCHAR_SHADOW:
return (DWORD)(strength / 4);
case eCHAR_VALKYRIE:
return (DWORD)(strength / 4);
case eCHAR_ELEMENTALIST:
return (DWORD)(strength / 4);
case eCHAR_MYSTIC: // _NA_004965_20120613_NEW_CHARACTER_MYSTIC
return (DWORD)(strength / 6);
case eCHAR_HELLROID: // _NA_000000_20130812_NEW_CHARACTER_HELLROID
return (DWORD)(strength / 3);
case eCHAR_WITCHBLADE: // _NA_007514_20140828_NEW_CHARACTER_WITCHBLADE
return (DWORD)(strength / 4);
}
#else
switch (char_type)
{
case eCHAR_DRAGON:
return (DWORD)(strength / 3);
case eCHAR_BERSERKER:
return (DWORD)(strength / 2);
case eCHAR_SHADOW:
return (DWORD)(strength / 6 + dexterity / 8);
case eCHAR_VALKYRIE:
return (DWORD)(strength / 4 + dexterity / 5);
case eCHAR_ELEMENTALIST:
return (DWORD)(strength / 4);
case eCHAR_MYSTIC: // _NA_004965_20120613_NEW_CHARACTER_MYSTIC
return (DWORD)(strength / 6 + dexterity / 8);
case eCHAR_HELLROID: // _NA_000000_20130812_NEW_CHARACTER_HELLROID
return (DWORD)(strength / 3);
case eCHAR_WITCHBLADE: // _NA_007514_20140828_NEW_CHARACTER_WITCHBLADE
return (DWORD)(strength / 4 + dexterity / 7);
}
#endif //_NA_008486_20150914_TOTAL_BALANCE
SASSERT(false, "Wrong Char_Type in CalcMaxMeleeAttackPower()");
return 1;
}
// 최대 공격력(원거리)
DWORD ns_formula::CalcMaxRangeAttackPower(
const eCHAR_TYPE char_type, const short in_strength, const short in_dexterity)
{
short dexterity = in_dexterity;
if (dexterity < 0)
{
dexterity = 0;
}
short strength = in_strength;
if (strength < 0)
{
strength = 0;
}
switch (char_type)
{
case eCHAR_DRAGON:
case eCHAR_BERSERKER:
case eCHAR_ELEMENTALIST:
return CalcMaxMeleeAttackPower(char_type, strength, dexterity);
case eCHAR_SHADOW:
return (DWORD)(strength / 4);
case eCHAR_VALKYRIE:
#ifdef _NA_008486_20150914_TOTAL_BALANCE
return (DWORD)(strength / 4);
#else
return (DWORD)(strength / 4 + dexterity / 5);
#endif //_NA_008486_20150914_TOTAL_BALANCE
case eCHAR_MYSTIC: // _NA_004965_20120613_NEW_CHARACTER_MYSTIC
return (DWORD)(strength / 4);
case eCHAR_HELLROID: // _NA_000000_20130812_NEW_CHARACTER_HELLROID
return (DWORD)(strength / 3);
case eCHAR_WITCHBLADE: // _NA_007514_20140828_NEW_CHARACTER_WITCHBLADE
return (DWORD)(strength / 4);
}
SASSERT(false, "Wrong Char_Type in CalcMaxRangeAttackPower()");
return 1;
}
// EP2:unused, old comment, 기본 공격력(마법)
DWORD ns_formula::CalcMagicAttackPower(BOOL bMin, short intelligence)
{
if (intelligence < 0)
{
intelligence = 0;
}
if (bMin) return intelligence / 3;
else return intelligence / 2;
}
// CHANGES: f110103.4L, changes concept of a CalcMagicAttackPower.
// added by _NA001605_EP2_ATTRIBUTES_RENEWAL_
// 기본 스킬 공격력
DWORD CalcSkillAttackPower(const eCHAR_TYPE char_type, const short in_intelligence)
{
// _NA001605_EP2_ATTRIBUTES_RENEWAL_
short intelligence = in_intelligence;
if (intelligence < 0)
{
intelligence = 0; // NOTE: set dummy penalty value if an invalid attributes value.
}
if (char_type < eCHAR_BERSERKER || char_type >= eCHAR_TYPE_MAX)
{
return 0;
}
double ratio_of_intelligence_to_skill_attack_power = \
ns_formula::kSkillAttackPowerConstants.ratio_of_conversion[char_type];
//
// formula
// ratio_of_intelligence_to_skill_attack_power
// BaseSkillAttackPower = _____________________________________________ * intelligence
// 40
#ifdef _NA_008486_20150914_TOTAL_BALANCE
double skill_attack_power = ratio_of_intelligence_to_skill_attack_power / 40 * intelligence;
#else
double skill_attack_power = ratio_of_intelligence_to_skill_attack_power / 100 * intelligence;
#endif //_NA_008486_20150914_TOTAL_BALANCE
return util::LL_Round(skill_attack_power);
}
DWORD ns_formula::CalcPhyBaseDef(const eCHAR_TYPE char_type, const short in_vitality)
{
short vitality = in_vitality;
if (vitality < 0)
{
vitality = 0;
}
switch (char_type)
{
case eCHAR_DRAGON:
return (DWORD)(vitality / 5 + 29);
case eCHAR_BERSERKER:
return (DWORD)(vitality / 5 + 29);
case eCHAR_SHADOW:
return (DWORD)(vitality / 7 + 29);
case eCHAR_VALKYRIE:
return (DWORD)(vitality / 6 + 29);
case eCHAR_ELEMENTALIST:
return (DWORD)(vitality / 10 +29);
case eCHAR_MYSTIC: // _NA_004965_20120613_NEW_CHARACTER_MYSTIC
return (DWORD)(vitality / 7 + 29);
case eCHAR_HELLROID: // _NA_000000_20130812_NEW_CHARACTER_HELLROID
return (DWORD)((vitality / 5) + 29);
case eCHAR_WITCHBLADE: // _NA_007514_20140828_NEW_CHARACTER_WITCHBLADE
return (DWORD)((vitality / 7) + 29);
}
SASSERT(false, "Wrong Char_Type in CalcPhyDef()");
return 1;
}
// EP2:unused, 각 속성 별로 분리해야 한다.
DWORD ns_formula::CalcMagicBaseDef(const eCHAR_TYPE char_type, const short in_spirit)
{
short spirit = in_spirit;
if (spirit < 0)
{
spirit = 0;
}
switch (char_type)
{
case eCHAR_DRAGON:
return (DWORD)(spirit / 9);
case eCHAR_BERSERKER:
return (DWORD)(spirit / 9);
case eCHAR_SHADOW:
return (DWORD)(spirit / 8);
case eCHAR_VALKYRIE:
return (DWORD)(spirit / 8);
case eCHAR_ELEMENTALIST:
return (DWORD)(spirit / 7);
case eCHAR_MYSTIC: // _NA_004965_20120613_NEW_CHARACTER_MYSTIC
return (DWORD)(spirit / 8);
case eCHAR_HELLROID: // _NA_000000_20130812_NEW_CHARACTER_HELLROID
return (DWORD)(spirit / 8);
case eCHAR_WITCHBLADE: // _NA_007514_20140828_NEW_CHARACTER_WITCHBLADE
return (DWORD)(spirit / 8);
}
SASSERT(false, "Wrong Char_Type in CalcMagicDef()");
return 1;
}
#ifdef _NA_008486_20150914_TOTAL_BALANCE
int ns_formula::CalcMoveSpeedRatio(int item_move_speed, int skill_move_speed,
LEVELTYPE char_level)
{
return internal::CalcMoveSpeedRatio(item_move_speed, skill_move_speed, char_level);
}
#else
int ns_formula::CalcMoveSpeedRatio(short dexterity, int item_move_speed, int skill_move_speed)
{
return internal::CalcMoveSpeedRatio(dexterity, item_move_speed, skill_move_speed);
}
#endif //_NA_008486_20150914_TOTAL_BALANCE
DWORD ns_formula::CalcPhyCriticalBaseRatio(
const eCHAR_TYPE char_type, const LEVELTYPE level, const short in_dexterity)
{
// CHANGES: f110103.2L, change critical occurrence probability
#ifdef _NA001605_EP2_ATTRIBUTES_RENEWAL_
//
__UNUSED(level);
if (char_type < eCHAR_BERSERKER || char_type >= eCHAR_TYPE_MAX)
{
return 0;
}
// change boundary
short dexterity = in_dexterity;
if (dexterity <= 0)
{
return 0;
};
typedef BalanceConstantsChangerInProgramCommon Constants;
double default_critical_probability = \
ns_formula::kCriticalChanceConstants.base_probabilies[char_type];
double dex = static_cast<double>(dexterity);
const double kNumberatorWeight = ns_formula::kCriticalChanceConstants.kNumberatorWeight;
const double kDenominatorWeight = ns_formula::kCriticalChanceConstants.kDenominatorWeight;
// formula
// (Dex * kNumberatorWeight)
// critical chance = ______________________________ + default_critical_probability
// sqrt(Dex) * kDenominatorWeight
double result = (dex * kNumberatorWeight) /
(sqrt(dex) * kDenominatorWeight);
; result += default_critical_probability;
return util::LL_Round(result);
#else
float phyValue = 0;
if (dexterity < 0)
{
dexterity = 0;
}
switch (char_type)
{
case eCHAR_DRAGON:
phyValue = 2.0f;
break;
case eCHAR_BERSERKER:
phyValue = 2.0f;
break;
case eCHAR_SHADOW:
phyValue = 3.0f;
break;
case eCHAR_VALKYRIE:
phyValue = 3.0f;
break;
case eCHAR_ELEMENTALIST:
phyValue = 4.0f;
break;
case eCHAR_MYSTIC: // _NA_004965_20120613_NEW_CHARACTER_MYSTIC
phyValue = 3.0f;
break;
case eCHAR_HELLROID: // _NA_000000_20130812_NEW_CHARACTER_HELLROID
phyValue = 3.0f;
break;
case eCHAR_WITCHBLADE: // _NA_007514_20140828_NEW_CHARACTER_WITCHBLADE
phyValue = 3.0f;
break;
default:
return 0;
}
return (DWORD)(level / 4 + dexterity / phyValue);
#endif
}
DWORD ns_formula::CalcMagicCriticalBaseRatio(
const eCHAR_TYPE char_type, const LEVELTYPE level, const short in_spirit)
{
DWORD phyValue = 0;
short spirit = in_spirit;
if (spirit < 0)
{
spirit = 0;
}
switch (char_type)
{
case eCHAR_DRAGON:
phyValue = 2;
break;
case eCHAR_BERSERKER:
phyValue = 2;
break;
case eCHAR_SHADOW:
phyValue = 2;
break;
case eCHAR_VALKYRIE:
phyValue = 2;
break;
case eCHAR_ELEMENTALIST:
phyValue = 2;
break;
case eCHAR_MYSTIC: // _NA_004965_20120613_NEW_CHARACTER_MYSTIC
phyValue = 2;
break;
case eCHAR_HELLROID: //_NA_000000_20130812_NEW_CHARACTER_HELLROID
phyValue = 2;
break;
case eCHAR_WITCHBLADE: //_NA_007514_20140828_NEW_CHARACTER_WITCHBLADE
phyValue = 2;
break;
default:
return 0;
}
return (level / 4 + spirit / phyValue);
}
// 공격 성공률
DWORD ns_formula::CalcPhysicalAttackRateBase(
const eCHAR_TYPE char_type, const LEVELTYPE level, const short in_dexterity)
{
#ifdef _NA001605_EP2_ATTRIBUTES_RENEWAL_
__UNUSED(level);
if (char_type < eCHAR_BERSERKER || char_type >= eCHAR_TYPE_MAX)
{
return 0;
}
short dexterity = in_dexterity;
if (dexterity < 0)
{
dexterity = 0;
};
// [Items...] + [Constant] * [Dex]
// [Constant] = 0.0004 * 100 -> 4%
// percentage base = 1000 * 4.0(x10000) * [Dex] / 10
double calc = static_cast<double>(dexterity);
; calc *= ns_formula::kAttackRateConstants.ratio_of_conversion[char_type];
; calc /= 100.0f; // make to percentage
return util::LL_Round(calc);
#else
float rateValue = 0;
short dexterity = in_dexterity;
if (dexterity < 0)
{
dexterity = 0;
}
switch (char_type)
{
case eCHAR_DRAGON : rateValue = 2.0f; break;
case eCHAR_BERSERKER : rateValue = 1.0f; break;
case eCHAR_SHADOW : rateValue = 3.0f; break;
case eCHAR_VALKYRIE : rateValue = 5.0f; break;
case eCHAR_ELEMENTALIST : rateValue = 1.0f; break;
case eCHAR_MYSTIC : rateValue = 3.0f; break; // _NA_004965_20120613_NEW_CHARACTER_MYSTIC
case eCHAR_HELLROID : rateValue = 3.0f; break; //_NA_000000_20130812_NEW_CHARACTER_HELLROID
case eCHAR_WITCHBLADE : rateValue = 3.0f; break; //_NA_007514_20140828_NEW_CHARACTER_WITCHBLADE
default:
{
SASSERT(false, "Wrong Char_Type in CalcPhysicalAttackRateBase()");
rateValue = 1.0f;
}
break;
}
return (DWORD)(50 + level * 10 + dexterity * rateValue);
#endif
}
int ns_formula::CalcAttackSpeedRatio(eCHAR_TYPE char_type, DWORD weapon_kind,
short dexterity, int item_attr_speed, int skill_attr_speed)
{
return internal::CalcAttackSpeedRatio(char_type, weapon_kind,
dexterity, item_attr_speed, skill_attr_speed);
}
// HP 배율수
static float ns_formula::CalcHPRatioNum(DWORD partymemberNum)
{
#ifdef _NA001605_EP2_ATTRIBUTES_RENEWAL_
if (partymemberNum == 0) return 0;
else return 0.032f; // 0.4f -> 0.032f
#else
if (partymemberNum == 0) return 0;
else return 0.7f;
#endif
}
// HP 추가비율
static float ns_formula::CalcAdditionalHPRatio(DWORD partymemberNum)
{
#ifdef _NA001605_EP2_ATTRIBUTES_RENEWAL_
const float kAdditionalRatioOfRatio = 0.072f; // 0.09f -> 0.072f
float additional_ratio = 0.0f;
if (partymemberNum != 0) {
additional_ratio = (partymemberNum - 1) * kAdditionalRatioOfRatio;
}
return additional_ratio;
#else
float fAdditionalRatio = 0.0f;
const float kAdditionalRatioOfRatio = 0.10f;
if (partymemberNum == 0) {
fAdditionalRatio = 0;
}
else if (partymemberNum <= 5) {
fAdditionalRatio = (partymemberNum - 1) * kAdditionalRatioOfRatio;
}
else {
fAdditionalRatio = CalcAdditionalHPRatio(partymemberNum - 1) +
(partymemberNum - 4) * kAdditionalRatioOfRatio;
}
return fAdditionalRatio;
#endif
}
// 파티원 수에 따른 NPC HP 증가율
float ns_formula::CalcHPIncreaseRatioAsParty(DWORD partymemberNum)
{
#ifdef _NA001605_EP2_ATTRIBUTES_RENEWAL_
float result_ratio = 1.0f;
; result_ratio += (partymemberNum - 1) * CalcHPRatioNum(partymemberNum);
; result_ratio += CalcAdditionalHPRatio(partymemberNum);
return result_ratio;
#else
float fResultRatio = 1 +
(float)(partymemberNum - 1) * CalcHPRatioNum(partymemberNum) +
CalcAdditionalHPRatio(partymemberNum);
return fResultRatio;
#endif
}
// 파티원 수에 따른 NPC 공격력 증가수치
int ns_formula::CalcAttackPowerIncreaseAsParty(DWORD partymemberNum, int iAttackPower)
{
int iIncreaseAttackPower = 0;
iIncreaseAttackPower = (int)(GetBonusAttackPower(partymemberNum) +
iAttackPower * (partymemberNum - 1) * GetBonusAttPowerRatio(partymemberNum));
return iIncreaseAttackPower;
}
// 공격회피율(물리)
#ifdef _NA_008486_20150914_TOTAL_BALANCE//---------------------------------------------------
DWORD ns_formula::CalcPhysicalAvoidRateBase(
const eCHAR_TYPE char_type, const LEVELTYPE level, const short in_vitality)
{
__UNUSED(level);
if (char_type < eCHAR_BERSERKER || char_type >= eCHAR_TYPE_MAX)
{
return 0;
}
short vitality = in_vitality;
if (vitality < 0)
{
vitality = 0;
};
// [Items...] + [Constant] * [vital]
// [Constant] = 0.0008 * 100 -> 4%
// percentage base = 1000 * 8.0(x10000) * [Dex] / 10
double calc = static_cast<double>(vitality);
; calc *= ns_formula::kAttackAvoidRateConstants.ratio_of_conversion[char_type];
; calc /= 100.0f; // make to percentage
return util::LL_Round(calc);
}
// 디버프 지속시간
INT ns_formula::CalcDebuffDuration(const short in_spirit)
{
short spirit = in_spirit;
if (spirit < 0) {
spirit = 0;
}
//전직업 공통
//정신력 1당 0.0012초(2밀리세컨드)
double calc = static_cast<double>(spirit);
calc *= 1.2f;
return util::LL_Round(calc);
}
#else //--------------------------------------------------------------------------------------------
DWORD ns_formula::CalcPhysicalAvoidRateBase(
const eCHAR_TYPE char_type, const LEVELTYPE level, const short in_dexterity)
{
#ifdef _NA001605_EP2_ATTRIBUTES_RENEWAL_
__UNUSED(level);
if (char_type < eCHAR_BERSERKER || char_type >= eCHAR_TYPE_MAX)
{
return 0;
}
short dexterity = in_dexterity;
if (dexterity < 0)
{
dexterity = 0;
};
// [Items...] + [Constant] * [Dex]
// [Constant] = 0.0008 * 100 -> 4%
// percentage base = 1000 * 8.0(x10000) * [Dex] / 10
double calc = static_cast<double>(dexterity);
; calc *= ns_formula::kAttackAvoidRateConstants.ratio_of_conversion[char_type];
; calc /= 100.0f; // make to percentage
return util::LL_Round(calc);
#else
float fRateValue = 1;
short dexterity = in_dexterity;
if (dexterity < 0)
{
dexterity = 0;
}
switch (char_type)
{
case eCHAR_DRAGON : fRateValue = 1.0f; break;
case eCHAR_BERSERKER : fRateValue = 1.0f; break;
case eCHAR_SHADOW : fRateValue = 1.0f; break;
case eCHAR_VALKYRIE : fRateValue = 1.0f; break;
case eCHAR_ELEMENTALIST : fRateValue = 1.0f; break;
case eCHAR_MYSTIC : fRateValue = 1.0f; break; // _NA_004965_20120613_NEW_CHARACTER_MYSTIC
case eCHAR_HELLROID : fRateValue = 1.0f; break; //_NA_000000_20130812_NEW_CHARACTER_HELLROID
case eCHAR_WITCHBLADE : fRateValue = 1.0f; break; //_NA_007514_20140828_NEW_CHARACTER_WITCHBLADE
default:
{
SASSERT(false, "Wrong Char_Type in CalcPhysicalAvoidRateBase()");
fRateValue = 1.0f;
}
break;
}
return (DWORD)(level + dexterity);
#endif
}
#endif //_NA_008486_20150914_TOTAL_BALANCE
}; //end of namespace 'ns_formula'
//==================================================================================================