- исправлены квест и диалоги EN RU квеста Роль смотрителя
- исправлены квест EN RU диалоги квеста Исследование бедствий Долины Драконов
- исправлен эффект t_hp_magical_attack, следующий умений: Воспламенение, Клеймо Слабости, Клеймо Пустоты, Клеймо Чумы, Клеймо Хитрости, Четверной Стихийный Импульс
- исправлен эффект i_m_attack_by_abnormal_slot, следующий умений: Снятие Клейма, Натиск Ветра
- исправлены умения с эффектом i_align_direction (второпрофный эффект разворовота, например в bluff)
- исправлены умения с эффектом p_align_direction (85+ эффект разворота)
- исправлены умения параметром debuff=2/3 из retail skilldata.txt — заменено 441 скилл
- исправлен, удален спавн Гленхинчи при убийстве Хюмеля, в Крепости Астатина (вызывается захватом базы, которая реализована ранее)
[*]исправлен IsthinaAI.EffectCheckTask.run: добавлен return после отмены задачи при _npc == null, чтобы исключить NPE на последующих обращениях к _npc
[*]исправлен AI.Quest421FairyTree.onEvtAttacked: добавлена ранняя проверка attacker на null перед isPet
[*]исправлен PathfinderInstance.getRewardList: добавлена проверка rewards на null перед split, чтобы отсутствие reward_lvl_N в InstantZone params не приводило к NPE при выдаче награды в соло-камалоке
[*]исправлен ChamberlainInstance.onBypassFeedback: добавлена проверка targetDoorObject на null в команде upgrade_door, чтобы неверный или несуществующий id двери не приводил к NPE
[*]исправлен квесты _10771_Volatile_Power.onTalk, _10776_TheWrathoftheGiants.onEvent, _10787_ASpyMission.onEvent убраны избыточная проверка на null, поле всегда инициализировано
[*]исправлен FunEvent.getCalendar: переход с TimeUtils.SIMPLE_FORMAT.parse на thread-safe TimeUtils.parseSimpleFormat
[*]исправлена команда ServerInfo.useVoicedCommand: DATE_FORMAT обёрнут в ThreadLocal для устранения race на статическом DateFormat
[*]исправлен AuctioneerInstance: DATE_FORMAT обёрнут в ThreadLocal для устранения race на статическом SimpleDateFormat
[*]исправлены плагины для голосования: HopZoneSite, L2TopSite, MmoTopSite, MmoVoteSite - обёрнут в ThreadLocal с инициализацией TimeZone в lambda для устранения race на статическом DateFormat
[*]исправлен квест _10407_LetsGoFishing.onTalk: 14 идентичных case-веток для SANTIAGO0..13 объединены в один fallthrough-блок, устранён dead store на htmltext и копипаст
[*]исправлен квест _462_StuffedAncientHeroes.onTalk: исправлена потерянная строка после String.replace, чтобы плейсхолдер %name% реально подменялся именем игрока в стартовом диалоге
[*]исправлен квест _462_StuffedAncientHeroes: исправлено забытое присваивание после String.replace в onTalk и логическая ошибка ||→&& в onKill, без которой квест не переходил между стадиями
[*]исправен TheornInstance: убран дубликат проверки STAR_GAMBLE2 в showChatWindow и onBypassFeedback (оба условия в || были идентичны)
[*]исправлен квест _928_100daySubjugationOperation: убраны дубли в условиях event.equalsIgnoreCase, исправлен off-by-one в счётчике дней (инкремент перенесён до проверки), чтобы 100-й проход корректно закрывал квест как ONETIME без выдачи лишней награды
Правки ядра - исправлен Creature.onReduceCurrentHp — DoT-урон рисует floating урон через StatusUpdatePacket(DAMAGED) с CUR_HP
- исправлен эффект t_hp_magical_attack: перенос эффекта с ретейла (CSkillEffect_t_hp_magical_attack::Tick), отображение floating-урона через isDot, урон сверен с ретейлом
- удален самописный эффект t_hp_magic, заменен ретейл t_hp_magical_attack
- исправлен эффект p_disappear_target.onStart/onExit: фикс broadcast для саммонов/петов — Servitor использует NpcInfo с компонентами, а не CharInfo
- реализована механика "стака" Dot умений. В Skill.<init>: добавлено поле _subordinationAbnormal и его парсинг из xml (subordination_abnormal)
Skill.getSubordinationAbnormal: новый геттер для retail-параметра subordination_abnormal
AbnormalList.add: retail-логика subordination_abnormal — несколько одинаковых дебафов от разных кастеров - исправлена логика AbnormalList.tryBreakStun, защита в первую секунду, шансы остались неизменны (ролл 35% pvp / 14% pve), в retail нет списка Stun умений которые невозможно сбить
- исправлен DebuffType: добавлен enum (retail m_eDebuff: DB_GOOD/DB_BAD/DB_PHYSICAL_MES/DB_MENTAL_MES) + статический parse
Skill.<init>: парсинг debuff расширен до 4 значений (true/false/0/1/2/3) через DebuffType.parse, с обратной совместимостью
Skill.getDebuffType: новый геттер для retail-параметра m_eDebuff - реализован скрытый резист дебафам/умений с параметром debuff=2, debuff=3. Резист в течении 15с, с каждым успешным прохождением шанс снижается (100%, 60%, 30%)
Исправлен DebuffType: добавлены retail-константы MES_WINDOW_MS (15s) и MES_CHANCE_MOD ([1.0, 0.6, 0.3])
Skill.getDebuffType: новый геттер для retail-параметра m_eDebuff
Creature.getMesCount/registerMesSuccess/mesCheckTimeout: счётчик mes-успехов с lazy-таймаутом окна
Formulas.getMesAdjustProb: retail CSkillInfo::GetMesAdjustProb для mes-штрафа
Formulas.calcEffectsSuccess: применение mes-штрафа и регистрация успеха для DB_PHYSICAL_MES/DB_MENTAL_MES - удален эффект EffectNegateMark
- реализован эффект i_m_attack_by_abnormal_slot
- AbnormalType: удалён неиспользуемый флаг stackable и второй конструктор — стек дебаффов от разных кастеров обеспечивается полем subordination_abnormal в Skill
- исправлен эффект i_align_direction
- реализован эффект p_align_direction
- исправлен Skill.checkCondition: проверка HP только если скилл потребляет HP.
[*]ExFactionLevelUpNotify: исправлена бесконечная рекурсия в конструкторе (поле STATIC сделано static, конструктор приватным)
[*]ItemInstance.canBeTraded, canBeSold: исправлено сравнение List.equals(int) на List.contains(int) для проверки whitelist-списков предметов
[*]SkillAcquireHolder.getAcquirableSkillListByClass: убраны ложные nullcheck-и player после фактического разыменования
[*]Skill.<init>: заменён виртуальный вызов isDebuff() на прямое чтение _isDebuff в конструкторе (UR в Summon._summonType)
[*]OfflineBufferManager.showStoreWindow: убран лишний Math.round при целочисленном делении уровня баффера на 10
[*]Player.addExpAndCheckBonus: заменён ошибочный Math.round(long→float) на прямой cast (int) при пересчёте vitality result
[*]AdminOldBan.ban: исправлено отбрасывание результата String.trim, теперь reason-строка реально обрезается
[*]Quest.showTutorialHtmlFile: исправлено отбрасывание результата String.replace, плейсхолдеры в туториальных HTM теперь подменяются
[*]Zone.checkEffects: исправлен дубль getDamageOnHP в условии запуска DamageTimer (теперь зоны с MP-уроном тоже запускают таймер)
[*]CastleSiegeEvent.canResurrect: упрощено избыточное условие проверки зоны (логически эквивалентно !targetInZone)
FortressSiegeEvent.canResurrect: упрощено избыточное условие проверки зоны (логически эквивалентно !targetInZone)
[*]AddItemAction.performAction: исправлен дубль BlessedSpiritShotItemHandler на корректный SpiritShotItemHandler во втором instanceof
FakePlayerUtils.checkAutoShots: исправлен дубль BlessedSpiritShotItemHandler на корректный SpiritShotItemHandler во втором instanceof
[*]SkillUtils.getSubSkillLevel: исправлен дубль enchantLevel в условии — первая проверка должна быть на enchantType
[*]BotCheckManager.loadBotQuestions: добавлена проверка doc на null перед parseBotQuestions, чтобы сбойный парсинг XML не приводил к NPE
[*]FakePlayer.OwnerAttakListener.onAttack: добавлена ранняя проверка target на null, чтобы не передавать null в notifyOwerStartAttak
FakePlayer.OwnerAttakListener.onMagicUse: добавлена ранняя проверка target на null перед вызовом notifyOwerStartMagicUse
[*]Player.onDeath: добавлена защита от NPE при null killer перед вызовом killer.getPlayer
[*]CreatureMovement.buildPathTo: исправлен NPE на _moveList после переприсваивания из GeoEngine.MoveList в ветке выхода из воды на берег
[*]ChaosFestivalArenaObject.onDamage: добавлена ранняя проверка attacker на null перед attacker.getPlayer
[*]OlympiadGame.tie: объединены проверки _member1 и _member2 в один блок, чтобы не разыменовывать один при null-проверке другого
OlympiadGame.winGame: добавлена недостающая проверка looseMember на null в reward-блоке
[*]GameClient.loadCharFromDisk: вызов savehwidtobase перенесён в ветку успешной загрузки, чтобы не дёргать character.getName на null
[*]RequestExEnchantSkillRouteChange.runImpl: добавлена ранняя проверка skillEntry на null перед обращением к getLevel
[*]HtmlMessage.packet: добавлен ранний return при отсутствии и _html, и _filename, чтобы не разыменовывать null content
[*]OlympiadGame: защищены финальные Log.add в tie и winGame от разыменования null _member/looseMember
[*]Party: synchronized-блоки переведены с CopyOnWriteArrayList _members на отдельный _membersLock, чтобы убрать антипаттерн синхронизации на конкурентной коллекции
[*]Boat: synchronized-блоки переведены с CopyOnWriteArraySet _players на отдельный _playersLock, чтобы убрать антипаттерн синхронизации на конкурентной коллекции
[*]ScriptRunner: заменить System.err.println на LOGGER.error, убрать @SuppressWarnings("UseOfSystemOutOrSystemErr")
[*]Version: исправить утечку ресурса JarFile, использовать try-with-resources, убрать @SuppressWarnings("resource")
AdminPolymorph: убрать @SuppressWarnings("fallthrough")
RewardList: убрать @SuppressWarnings("serial")
[*]RndSelector.RndNode.compareTo: исправлено бессмысленное сравнение поля с самим собой, сортировка теперь по убыванию веса
[*]Net.hashCode: исправлен identity-хэш массивов на Arrays.hashCode для _address и _mask
[*]HandysBlockCheckerManager: _arenaStatus переведён на eager init, убрана ленивая инициализация в конструкторе
[*]ItemAuctionManager.getInstance: добавлен synchronized для устранения race при первой ленивой инициализации singleton
[*]NaiaTowerManager: getInstance синхронизирован, lockedRooms и _roomMobs переведены на eager init
[*]ClanPenalty: DATE_FORMAT обёрнут в ThreadLocal для устранения race на статическом SimpleDateFormat
[*]Time.useUserCommand: sf обёрнут в ThreadLocal для устранения race на статическом SimpleDateFormat
[*]ItemAuctionInstance: DATE_FORMAT обёрнут в ThreadLocal для устранения race на статическом SimpleDateFormat
[*]HeroDiary: SIMPLE_FORMAT обёрнут в ThreadLocal для устранения race на статическом SimpleDateFormat
[*]TimeUtils.toSimpleFormat: внутренние вызовы переведены на приватный ThreadLocal-formatter, публичное поле SIMPLE_FORMAT сохранено для backward compat
[*]Macro.toString: использован Arrays.toString для commands вместо мусорного toString массива, заодно добавлен пробел перед name=
[*]TimeUtils: добавлен thread-safe parseSimpleFormat для парсинга строк через приватный ThreadLocal-formatter, чтобы убрать race на public SIMPLE_FORMAT