Суть проблемы
В методе
Formulas.calcMagicDam присутствовал баг, из-за которого к каждому магическому удару добавлялся лишний урон равный power скилла. Код выглядел так:
Java:
info.damage += attacker.getStat().calc(Stats.M_SKILL_POWER,
(attacker.isServitor() ? Config.SERVITOR_M_SKILL_POWER_MODIFIER : 1.) * power);
Проблема в том, что второй аргумент
calc() — это init (начальное значение калькулятора). Если на персонаже нет ни одной функции для стата M_SKILL_POWER, калькулятор пустой и метод просто возвращает init как есть — то есть power скилла. В итоге к урону всегда прибавлялось значение power, даже без каких-либо XML-бонусов.В вакуумных условиях теста — голый персонаж без бонусов, без бафов, без экипировки — завышение составляло +19% до +25%. В реальных условиях игры с бонусами к магическому урону картина другая — об этом ниже.
Анализ retail L2Server.exe через IDA Pro
Для верификации были изучены следующие функции из retail бинаря:
L2SkillFunc::CalcAndApplyMagicAttackDamage — точка входа расчёта магического урона. Базовая формула:
C++:
v15 = sqrt(attackerInfo.m_MagicPower * SoulBonus);
damage = v15 * skillPower * 91.0 / targetInfo.m_MDefend * targetInfo.m_AttrResist;
L2SkillFunc::GetMagicAttackerInfo — сбор данных атакующего.
m_MagicPower = m_dParam[3] (полный mAtk с бонусами).L2SkillFunc::GetMagicTargetInfo — сбор данных цели.
m_MDefend = m_dParam[1] (полный mdef), затем умножается на m_dMagicalPenetrateFactor.L2SkillFunc::CalcFinalDamage — применение PvP/PvE бонусов, magic resist, weapon random damage, крит.
L2SkillFunc::ApplyBonusToAttackDamage — финальный множитель для магических скиллов (
isMagic == 1):
C++:
return dDamage * Mods[54].Per + Mods[54].Diff;
CSkillEffect_p_spell_power::Pump — эффект бонуса к магическому урону:
C++:
L2SkillFunc::AddBonus(pCreature, PSpellPower, this->m_sfct, this->m_dBonus);
L2SkillFunc::AddBonus — при
SFCT_PER:
C++:
*perValue = (dBonus + 100.0) / 100.0 * *perValue;
// p_spell_power;2;per → Mods[54].Per *= 1.02
Таким образом
p_spell_power влияет на Mods[54].Per — финальный множитель урона. В Java это реализовано через Stats.M_SKILL_POWER как мультипликативный стат.Сравнение урона до и после фикса
Условия теста: голый персонаж без бонусов и бафов, НПС mdef=520, 150 attribute resist ALL. Разброс урона отключён.
| Условие | PTS | Java (было) | Java (стало) |
|---|---|---|---|
| 518 mAtk, 0 attr, no element | 447 | 558 (+24.8%) | 446 ✓ |
| 518 mAtk, 0 attr, fire 10 | 454 | 567 (+24.9%) | 453 ✓ |
| 898 mAtk, 450 dark, no element | 871 | 1035 (+18.8%) | 869 ✓ |
| 898 mAtk, 450 dark, fire 10 | 598 | 710 (+18.7%) | 596 ✓ |
Атрибутная система работала корректно — расхождение было исключительно в базовой формуле.
Верификация p_spell_power (+2% к магическому урону)
| Условие | PTS без бонуса | PTS с бонусом | Java без бонуса | Java с бонусом |
|---|---|---|---|---|
| 518 mAtk, no element | 447 | 456 (+2.01%) | 446 | 455 (+2.02%) ✓ |
| 898 mAtk, no element | 871 | 888 (+1.95%) | 869 | 886 (+1.96%) ✓ |
Расхождение в 1-2 единицы — округление
int.Видео сравнения
Проверка магического урона на нашем сервере:
Проверка магического урона на Retail Server:
Разница между нашим сервером и ретейлом составляет 1-2 единицы урона — исключительно за счёт округления
int. Формула верифицирована по retail L2Server.exe.Для игроков — нерф или не нерф?
Коротко: это не нерф, это исправление бага.
Цифры +19-25% из таблицы выше — это вакуумный тест: голый персонаж, никаких бонусов, никаких бафов. В реальных условиях игры картина совсем другая, а учитывая разброс урона вы это даже не заметите.
Суть бага была в том, что бонусы к магическому урону (
mSkillPower) почти не работали — они применялись к маленькому числу (power скилла) вместо полного урона. Теперь всё работает правильно, и это частично или полностью компенсирует снижение базового урона.Чем выше mAtk и чем больше бонус к магическому урону — тем заметнее положительный эффект. Маги с хорошей экипировкой и прокачанными пассивками могут бить сильнее, чем раньше.
Верификация магического урона — SS Extra + SS Bonus
Условия теста: SS extra +7% (энчант оружия), SS bonus +20% (камень Сапфир 5 ур.), цель mdef=512, защита атрибута 150, атака атрибута 340. Разброс урона отключён.
| Условие | PTS | Java | Погрешность |
|---|---|---|---|
| mAtk=268 872, обычный удар | 60 476 | 60 396 | 0.13% ✓ |
| mAtk=268 872, критический удар | 195 973 | 195 690 | 0.14% ✓ |
| mAtk=534 809, обычный удар | 85 292 | 85 180 | 0.13% ✓ |
| mAtk=534 809, критический удар | 276 039 | 275 650 | 0.14% ✓ |
Расхождение 0.13–0.14% является нормой — это результат округления
int при финальном расчёте урона, а также незначительной разницы в mAtk между двумя клиентами. Поведение полностью соответствует retail.Видео сравнения:
Проверка магического урона на нашем сервере:
Проверка магического урона Retail Server:
Last edited: