From ed5fea5192c28d070994d642507f937ad2d039bf Mon Sep 17 00:00:00 2001 From: AlexCube Date: Thu, 17 Sep 2026 23:24:25 +0300 Subject: [PATCH] =?UTF-8?q?1.3.0:=20=D1=88=D0=BA=D0=B0=D0=BB=D0=B0=2020=20?= =?UTF-8?q?=D1=83=D0=B1=D0=B8=D0=B9=D1=81=D1=82=D0=B2=20=D0=B7=D0=B0=20?= =?UTF-8?q?=D1=83=D1=80=D0=BE=D0=B2=D0=B5=D0=BD=D1=8C,=20=D0=B4=D0=B2?= =?UTF-8?q?=D0=B0=20=D0=B8=D0=BD=D0=B4=D0=B8=D0=BA=D0=B0=D1=82=D0=BE=D1=80?= =?UTF-8?q?=D0=B0,=20=D0=BC=D0=B8=D1=80=20=D0=BC=D0=B5=D0=B6=D0=B4=D1=83?= =?UTF-8?q?=20=D0=BF=D0=BE=D0=B4=D1=87=D0=B8=D0=BD=D1=91=D0=BD=D0=BD=D1=8B?= =?UTF-8?q?=D0=BC=D0=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Уровень навыка игра хранит ОДНИМ БАЙТОМ (ProgressionValue.Write/Read), поэтому старая шкала "одно убийство - один уровень" при max_level=5000 на каждом сохранении откатывала уровень на 256 назад. Снаружи это выглядело как самопроизвольно закрывающиеся рецепты (жалоба со стрима: Слёзы мертвеца открыты, Пир падальщика под замком при 250+ убитых), а тиры 500/2000/3000/5000 были недостижимы в принципе. Подтверждено на двух живых сейвах: sezon8 - 384 убийства при уровне 129, test8 - 303 при уровне 48. Шкала переведена на 20 убийств = 1 уровень, max_level=250 - влезает в байт с запасом. Уровень больше не накапливается, а вычисляется из necroZombieKillsCVar (float, сохраняется честно) и на каждом убийстве, и постфиксом на PlayerDataFile.ToPlayer - последнее чинит старые сейвы само, без команд и новой игры. Открытое при этом не теряется: в старой шкале уровень всегда был не больше счётчика, так что пересчёт может только вернуть украденное переполнением. Отдельно закрыт случай "счётчик пуст, а уровень есть" - счётчик восстанавливается из уровня по старой шкале. Все пороги пересчитаны в уровни, числа убийств не тронуты, кроме воды: 30 на сетку шагом 20 не ложится, по указанию пользователя мод переехал на 20 - туда же, где браслет и Кровавая сфера. Тег necroNecromancyLvl30 удалён. Сходимость всех 18 рецептов (тег -> RecipeTagUnlocked -> unlock_tier) проверена скриптом. Два индикатора: череп в статус-баре показывает уровень (раньше - общее число убийств), фиолетовая шкала над полосой опыта - продвижение внутри уровня, 0..20. Шкала сделана вёрсткой, а не баффом (бафф умеет число, но не полосу), заполнение привязано через XUi-выражение cvar(). Закрывающая скобка у выражения - одна "}", а не "%}": лишний "%" NCalc читает как остаток от деления и ждёт правый операнд, на чём первая проверка в игре и споткнулась. Третья правка: подчинённые зомби больше не дерутся между собой. Девиация выдаёт приказ "бей зомби", а подчинённый сам EntityZombie, и в targetClasses выражается только тип. Постфикс на EAITarget.check вычёркивает подчинённого из кандидатов (зомби выбирает следующего, настоящего врага), префикс на EntityAlive.SetAttackTarget гасит цель на путях мимо выбора - прежде всего месть, когда подчиняют уже дерущихся. Тексты на 13 языках, README (RU+EN), описания для сайта и Nexus приведены к новой шкале. Co-Authored-By: Claude Opus 5 --- Config/Localization.csv | 8 +- Config/XUi_InGame/windows.xml | 46 +++++ Config/buffs.xml | 20 ++- Config/progression.xml | 173 ++++++++++++------- Config/recipes.xml | 27 +-- HarmonySrc/CharmPatch.cs | 99 +++++++++++ HarmonySrc/ModEntry.cs | 25 +++ HarmonySrc/NecromancyKillCreditPatch.cs | 217 +++++++++++++++++++++--- ModInfo.xml | 2 +- NEXUS_DESCRIPTION.bbcode | 6 +- NecromancerHarmony.dll | Bin 94208 -> 96256 bytes NecromancerHarmony.pdb | Bin 29776 -> 30300 bytes README.md | 127 ++++++++++---- SITE_DESCRIPTION.html | 8 +- 14 files changed, 613 insertions(+), 145 deletions(-) diff --git a/Config/Localization.csv b/Config/Localization.csv index aba1314..170a2f0 100644 --- a/Config/Localization.csv +++ b/Config/Localization.csv @@ -1,10 +1,10 @@ Key,File,Type,UsedInMainMenu,NoTranslate,KeepLoaded,english,Context / Alternate Text,german,spanish,french,italian,japanese,koreana,polish,brazilian,russian,turkish,schinese,tchinese -buffNecroZombieKillTrackerDisplay,buffs,Buff,,,,Zombie Kill Tracker,,Zähler getöteter Zombies,Contador de zombis eliminados,Compteur de zombies tués,Contatore di zombie uccisi,ゾンビ討伐カウンター,좀비 처치 기록기,Licznik zabitych zombie,Contador de zumbis mortos,Счётчик убитых зомби,Öldürülen Zombi Sayacı,僵尸击杀计数器,殭屍擊殺計數器 -buffNecroZombieKillTrackerDisplayName,buffs,Buff,,,,Total Zombie Kills,,Getötete Zombies insgesamt,Total de zombis eliminados,Total de zombies tués,Zombie uccisi in totale,ゾンビ討伐総数,총 좀비 처치 수,Łącznie zabitych zombie,Total de zumbis mortos,Всего убито зомби,Toplam Öldürülen Zombi,僵尸击杀总数,殭屍擊殺總數 -buffNecroZombieKillTrackerDisplayDesc,buffs,Buff,,,,Tracks the total number of zombies you have killed. Never resets.,,"Zählt, wie viele Zombies du insgesamt getötet hast. Wird nie zurückgesetzt.",Cuenta el número total de zombis que has eliminado. Nunca se reinicia.,Compte le nombre total de zombies que tu as tués. Ne se réinitialise jamais.,Conta il numero totale di zombie che hai ucciso. Non si azzera mai.,あなたが倒したゾンビの総数を数える。リセットされることはない。,당신이 처치한 좀비의 총수를 셉니다. 절대 초기화되지 않습니다.,Liczy łączną liczbę zabitych przez ciebie zombie. Nigdy się nie zeruje.,Conta o número total de zumbis que você matou. Nunca é reiniciado.,Считает общее количество убитых вами зомби. Никогда не сбрасывается.,Öldürdüğün toplam zombi sayısını takip eder. Asla sıfırlanmaz.,统计你击杀的僵尸总数。永不重置。,統計你擊殺的殭屍總數。永不重置。 +buffNecroZombieKillTrackerDisplay,buffs,Buff,,,,Necromancy Level,,Nekromantie-Stufe,Nivel de Nigromancia,Niveau de Nécromancie,Livello di Negromanzia,降霊術レベル,강령술 레벨,Poziom Nekromancji,Nível de Necromancia,Уровень некромантии,Nekromansi Seviyesi,亡灵法术等级,亡靈法術等級 +buffNecroZombieKillTrackerDisplayName,buffs,Buff,,,,Necromancy Level,,Nekromantie-Stufe,Nivel de Nigromancia,Niveau de Nécromancie,Livello di Negromanzia,降霊術レベル,강령술 레벨,Poziom Nekromancji,Nível de Necromancia,Уровень некромантии,Nekromansi Seviyesi,亡灵法术等级,亡靈法術等級 +buffNecroZombieKillTrackerDisplayDesc,buffs,Buff,,,,Your Necromancy level. Every 20 zombies you put to rest raise it by one; the purple bar beside the experience bar shows how far you are into the current level.,,Deine Nekromantie-Stufe. Je 20 zur Ruhe gebettete Zombies bringen eine Stufe; der violette Balken neben der Erfahrungsleiste zeigt den Fortschritt innerhalb der aktuellen Stufe.,Tu nivel de Nigromancia. Cada 20 zombis que devuelves al descanso suben un nivel; la barra morada junto a la de experiencia muestra tu progreso dentro del nivel actual.,Ton niveau de Nécromancie. Chaque tranche de 20 zombies mis au repos donne un niveau ; la barre violette près de la barre d'expérience indique ta progression dans le niveau en cours.,Il tuo livello di Negromanzia. Ogni 20 zombie messi a riposo valgono un livello; la barra viola accanto a quella dell'esperienza mostra i tuoi progressi nel livello attuale.,降霊術のレベル。ゾンビを20体葬るごとに1レベル上がる。経験値バーの隣にある紫のバーは、現在のレベル内での進み具合を示す。,"당신의 강령술 레벨입니다. 좀비 20마리를 잠재울 때마다 1레벨씩 오르며, 경험치 막대 옆의 보라색 막대가 현재 레벨의 진행도를 보여줍니다.","Twój poziom Nekromancji. Każde 20 uśpionych zombie daje jeden poziom, a fioletowy pasek obok paska doświadczenia pokazuje postęp w obecnym poziomie.",Seu nível de Necromancia. A cada 20 zumbis levados ao descanso você sobe um nível; a barra roxa ao lado da barra de experiência mostra o progresso dentro do nível atual.,"Твой уровень некромантии. Каждые 20 упокоенных зомби поднимают его на единицу, а фиолетовая шкала рядом с полосой опыта показывает продвижение внутри текущего уровня.",Nekromansi seviyen. Huzura kavuşturduğun her 20 zombi bir seviye kazandırır; deneyim çubuğunun yanındaki mor çubuk mevcut seviyedeki ilerlemeni gösterir.,你的亡灵法术等级。每安息 20 只僵尸提升一级,经验条旁边的紫色进度条显示当前等级内的进度。,你的亡靈法術等級。每安息 20 隻殭屍提升一級,經驗條旁邊的紫色進度條顯示目前等級內的進度。 craftingNecroNecromancyName,progression,Attribute,,,,Necromancy,,Nekromantie,Nigromancia,Nécromancie,Negromanzia,降霊術,강령술,Nekromancja,Necromancia,Некромантия,Nekromansi,亡灵法术,亡靈法術 craftingNecroNecromancyDesc,progression,Attribute,,,,Levels up as you kill zombies.,,"Steigt, während du Zombies tötest.",Sube de nivel a medida que matas zombis.,Progresse à mesure que tu tues des zombies.,Sale di livello man mano che uccidi zombie.,ゾンビを倒すほどレベルが上がる。,좀비를 처치할수록 레벨이 오릅니다.,Rośnie w miarę zabijania zombie.,Sobe de nível conforme você mata zumbis.,Растёт по мере убийства зомби.,Zombi öldürdükçe seviye kazanır.,随着击杀僵尸而提升。,隨著擊殺殭屍而提升。 -craftingNecroNecromancyLongDesc,progression,Attribute,,,,"Every zombie you kill adds a level to this skill, up to 5000. Its recipes unlock in 5 groups by total zombies killed: Adept from the start, Journeyman at 500, Apprentice at 2000, Necromancer at 3000, Master at 5000.",,"Jeder getötete Zombie bringt dieser Fertigkeit eine Stufe, bis zu 5000. Ihre Rezepte schalten sich in 5 Gruppen frei, nach der Gesamtzahl getöteter Zombies: Adept von Anfang an, Geselle bei 500, Lehrling bei 2000, Nekromant bei 3000, Meister bei 5000.","Cada zombi que matas añade un nivel a esta habilidad, hasta 5000. Sus recetas se desbloquean en 5 grupos según el total de zombis eliminados: Adepto desde el principio, Oficial a los 500, Aprendiz a los 2000, Nigromante a los 3000, Maestro a los 5000.","Chaque zombie tué ajoute un niveau à cette compétence, jusqu'à 5000. Ses recettes se débloquent en 5 groupes selon le total de zombies tués : Adepte dès le début, Compagnon à 500, Apprenti à 2000, Nécromancien à 3000, Maître à 5000.","Ogni zombie che uccidi aggiunge un livello a questa abilità, fino a 5000. Le sue ricette si sbloccano in 5 gruppi in base al totale di zombie uccisi: Adepto fin dall'inizio, Artigiano a 500, Apprendista a 2000, Negromante a 3000, Maestro a 5000.",ゾンビを1体倒すごとに、このスキルのレベルが1上がる(上限5000)。レシピは討伐総数に応じて5つのグループで解放される。アデプトは最初から、ジャーニーマンは500、見習いは2000、ネクロマンサーは3000、マスターは5000。,"좀비를 하나 처치할 때마다 이 기술의 레벨이 1씩 오릅니다(최대 5000). 제작법은 누적 처치 수에 따라 5개 그룹으로 해금됩니다. 숙련자는 처음부터, 직인은 500, 도제는 2000, 강령술사는 3000, 명인은 5000.","Każdy zabity zombie dodaje poziom tej umiejętności, aż do 5000. Jej receptury odblokowują się w 5 grupach według łącznej liczby zabitych zombie: Adept od początku, Czeladnik przy 500, Uczeń przy 2000, Nekromanta przy 3000, Mistrz przy 5000.","Cada zumbi que você mata adiciona um nível a esta habilidade, até 5000. Suas receitas são desbloqueadas em 5 grupos conforme o total de zumbis mortos: Adepto desde o início, Oficial aos 500, Aprendiz aos 2000, Necromante aos 3000, Mestre aos 5000.","Каждый убитый зомби добавляет уровень этому навыку, максимум 5000. Рецепты открываются 5 группами по общему числу убитых зомби: Адепт — с самого начала, Подмастерье — 500, Ученик — 2000, Некромант — 3000, Мастер — 5000.","Öldürdüğün her zombi bu yeteneğe bir seviye ekler, en fazla 5000'e kadar. Tarifleri, toplam öldürülen zombi sayısına göre 5 grup hâlinde açılır: Ehil en baştan, Kalfa 500'de, Çırak 2000'de, Nekromant 3000'de, Usta 5000'de.",每击杀一只僵尸,此技能便提升一级,上限 5000。其配方按击杀总数分 5 组解锁:修习者一开始即可用,熟手 500,学徒 2000,亡灵法师 3000,宗师 5000。,每擊殺一隻殭屍,此技能便提升一級,上限 5000。其配方按擊殺總數分 5 組解鎖:修習者一開始即可用,熟手 500,學徒 2000,亡靈法師 3000,宗師 5000。 +craftingNecroNecromancyLongDesc,progression,Attribute,,,,"Every 20 zombies you kill add a level to this skill, up to level 250 (5000 zombies). Its recipes unlock in 5 groups by level: Adept from the start, Journeyman at 25, Apprentice at 100, Necromancer at 150, Master at 250.",,"Je 20 getötete Zombies bringen dieser Fertigkeit eine Stufe, bis zu Stufe 250 (5000 Zombies). Ihre Rezepte schalten sich in 5 Gruppen nach Stufe frei: Adept von Anfang an, Geselle bei 25, Lehrling bei 100, Nekromant bei 150, Meister bei 250.","Cada 20 zombis que matas añaden un nivel a esta habilidad, hasta el nivel 250 (5000 zombis). Sus recetas se desbloquean en 5 grupos según el nivel: Adepto desde el principio, Oficial a los 25, Aprendiz a los 100, Nigromante a los 150, Maestro a los 250.","Chaque tranche de 20 zombies tués ajoute un niveau à cette compétence, jusqu'au niveau 250 (5000 zombies). Ses recettes se débloquent en 5 groupes selon le niveau : Adepte dès le début, Compagnon à 25, Apprenti à 100, Nécromancien à 150, Maître à 250.","Ogni 20 zombie uccisi aggiungono un livello a questa abilità, fino al livello 250 (5000 zombie). Le sue ricette si sbloccano in 5 gruppi in base al livello: Adepto fin dall'inizio, Artigiano a 25, Apprendista a 100, Negromante a 150, Maestro a 250.",ゾンビを20体倒すごとに、このスキルのレベルが1上がる(上限250、ゾンビ5000体)。レシピはレベルに応じて5つのグループで解放される。アデプトは最初から、ジャーニーマンは25、見習いは100、ネクロマンサーは150、マスターは250。,"좀비 20마리를 처치할 때마다 이 기술의 레벨이 1씩 오릅니다(최대 250, 좀비 5000마리). 제작법은 레벨에 따라 5개 그룹으로 해금됩니다. 숙련자는 처음부터, 직인은 25, 도제는 100, 강령술사는 150, 명인은 250.","Każde 20 zabitych zombie dodaje poziom tej umiejętności, aż do poziomu 250 (5000 zombie). Jej receptury odblokowują się w 5 grupach według poziomu: Adept od początku, Czeladnik przy 25, Uczeń przy 100, Nekromanta przy 150, Mistrz przy 250.","A cada 20 zumbis mortos você ganha um nível nesta habilidade, até o nível 250 (5000 zumbis). Suas receitas são desbloqueadas em 5 grupos conforme o nível: Adepto desde o início, Oficial aos 25, Aprendiz aos 100, Necromante aos 150, Mestre aos 250.","Каждые 20 убитых зомби добавляют уровень этому навыку, максимум 250 (5000 зомби). Рецепты открываются 5 группами по уровню: Адепт — с самого начала, Подмастерье — 25, Ученик — 100, Некромант — 150, Мастер — 250.","Öldürdüğün her 20 zombi bu yeteneğe bir seviye ekler, en fazla 250. seviyeye kadar (5000 zombi). Tarifleri, seviyeye göre 5 grup hâlinde açılır: Ehil en baştan, Kalfa 25'te, Çırak 100'de, Nekromant 150'de, Usta 250'de.",每击杀 20 只僵尸,此技能便提升一级,上限 250 级(5000 只僵尸)。其配方按等级分 5 组解锁:修习者一开始即可用,熟手 25 级,学徒 100 级,亡灵法师 150 级,宗师 250 级。,每擊殺 20 隻殭屍,此技能便提升一級,上限 250 級(5000 隻殭屍)。其配方按等級分 5 組解鎖:修習者一開始即可用,熟手 25 級,學徒 100 級,亡靈法師 150 級,宗師 250 級。 craftingNecroNecromancyTier1Name,progression,Attribute,,,,Adept,,Adept,Adepto,Adepte,Adepto,アデプト,숙련자,Adept,Adepto,Адепт,Ehil,修习者,修習者 craftingNecroNecromancyTier2Name,progression,Attribute,,,,Journeyman,,Geselle,Oficial,Compagnon,Artigiano,ジャーニーマン,직인,Czeladnik,Oficial,Подмастерье,Kalfa,熟手,熟手 craftingNecroNecromancyTier3Name,progression,Attribute,,,,Apprentice,,Lehrling,Aprendiz,Apprenti,Apprendista,見習い,도제,Uczeń,Aprendiz,Ученик,Çırak,学徒,學徒 diff --git a/Config/XUi_InGame/windows.xml b/Config/XUi_InGame/windows.xml index e7ad249..d7d2ee5 100644 --- a/Config/XUi_InGame/windows.xml +++ b/Config/XUi_InGame/windows.xml @@ -116,4 +116,50 @@ + + + + + + diff --git a/Config/buffs.xml b/Config/buffs.xml index d6d3e01..f88c0d4 100644 --- a/Config/buffs.xml +++ b/Config/buffs.xml @@ -10,12 +10,28 @@ - + - + - + - + - + necroNecromancyLvl20 стоит на level="1,250" ниже, а tier 2 в + unlock_level="0,1,3,5,15" - это тот же уровень 1. Разойдись они, замок на + панели скилла разошёлся бы с реальной доступностью рецепта. + + 2026-09-17, СМЕНА ШКАЛЫ (20 убийств = 1 уровень, см. шапку файла): «уровень + 20» превратился в «уровень 1», убийств за ним по-прежнему 20. Сюда же, на + эту ступень, переехал мод ножа на воду - см. следующий комментарий. --> + - - - - + тот же день, есть - позже. + + ПЕРЕСЧИТАНО 2026-09-17 ПОД ШКАЛУ 20-ЗА-УРОВЕНЬ (см. шапку файла). Сами + пороги в убийствах не тронуты, кроме воды: 30 убийств на сетке с шагом 20 не + выражается, и по прямому указанию вода уехала ВНИЗ, на 20 - то есть на одну + ступень с браслетом и Кровавой сферой, а не вверх на 40. Ступеней в группе + теперь пять, а не шесть, и мод на воду стоит в строке tier 2 выше: + ур. 0 (0 убийств) - Камень духов, Нож, Синий портал, Пирамида + ур. 1 (20 убийств) - Браслет, Кровавая сфера, ВОДА + ур. 3 (60 убийств) - еда + ур. 5 (100 убийств) - покой + ур. 15 (300 убийств) - чутьё + Тег necroNecromancyLvl30 вместе с этим удалён - им больше никто не + пользуется, вода сидит на necroNecromancyLvl20. --> + + + - + - + - + - + - - + + - - - - - - - - - - + пользуется (Тёмное чутьё уехало на 300, Могильный покой на 100). + + ЗНАЧЕНИЯ level= ПЕРЕСЧИТАНЫ 2026-09-17 В УРОВНИ (шкала 20 убийств = 1 + уровень, см. шапку файла). ИМЕНА ТЕГОВ ОСТАЛИСЬ В УБИЙСТВАХ и менять их не + надо: necroNecromancyLvl60 - это «60 убийств», а стоит он на level="3,250". + Верхняя граница у всех теперь 250, а не 5000 - это max_level скилла, выше + него уровень не поднимется, и диапазон обязан его накрывать. --> + + + + + + + + + diff --git a/Config/recipes.xml b/Config/recipes.xml index 3f8283a..97da9e6 100644 --- a/Config/recipes.xml +++ b/Config/recipes.xml @@ -296,16 +296,23 @@ трупа, к этому моменту бесполезен. Теперь порог у мода стоит там, где мод реально нужен, а не там, где он "по силе" смотрится ровно. - Итоговая раскладка: - 30 - Слёзы мертвеца (вода) группа 1 "Адепт" - 60 - Пир падальщика (еда) группа 1 - 100 - Могильный покой (тепло/холод) группа 1 - 300 - Тёмное чутьё (радар) группа 1 - 1400 - Хватка мертвеца (замедление) группа 2 "Подмастерье" - 1700 - Мёртвая буря (силовая) группа 2 + Итоговая раскладка (убийства; в скобках уровень скилла в шкале 20-за-уровень, + введённой 2026-09-17 - см. шапку progression.xml): + 20 - Слёзы мертвеца (вода) группа 1 "Адепт" ур. 1 + 60 - Пир падальщика (еда) группа 1 ур. 3 + 100 - Могильный покой (тепло/холод) группа 1 ур. 5 + 300 - Тёмное чутьё (радар) группа 1 ур. 15 + 1400 - Хватка мертвеца (замедление) группа 2 "Подмастерье" ур. 70 + 1700 - Мёртвая буря (силовая) группа 2 ур. 85 Первые четыре - выживание и информация, они переехали в группу 1 к самому ножу (он там и - доступен с уровня 1). Последние два - чистый бой, остались в группе 2 на прежних порогах: - пользователь про них сказал "дальше уже не так принципиально". + доступен с нулевого уровня). Последние два - чистый бой, остались в группе 2 на прежних + порогах: пользователь про них сказал "дальше уже не так принципиально". + + ВОДА ПЕРЕЕХАЛА С 30 УБИЙСТВ НА 20, 2026-09-17. Причина не балансовая, а арифметическая: + новая шкала идёт шагом в 20 убийств, и 30 на неё не ложится. Из двух соседних узлов (20 + или 40) пользователь выбрал 20 - "мод на воду нужен на самом начальном этапе". Тега + necroNecromancyLvl30 больше нет, рецепт сидит на necroNecromancyLvl20 - том же теге, что + браслет и Кровавая сфера. Двигать - тройка "тег в рецепте + RecipeTagUnlocked в progression.xml + unlock_tier в display_entry", все три должны совпадать, иначе замок на панели соврёт. --> @@ -325,7 +332,7 @@ призывов и не должны требовать верстак. Тег learnable, как у остальных гейтованных рецептов мода, чтобы рецепт не светился в меню до открытия группы. --> - + diff --git a/HarmonySrc/CharmPatch.cs b/HarmonySrc/CharmPatch.cs index 507b69e..2bb8007 100644 --- a/HarmonySrc/CharmPatch.cs +++ b/HarmonySrc/CharmPatch.cs @@ -131,4 +131,103 @@ namespace NecromancerTome Debug.Log("[NecromancerTome] CharmZombie: done, attack target cleared for " + zombie.EntityName); } } + /// + /// ПОДЧИНЁННЫЕ НЕ ДЕРУТСЯ МЕЖДУ СОБОЙ, 2026-09-17. Баг-репорт пользователя: "Камень духов и + /// прочие вешают на зомби девиацию. С этим есть баг. Зомби под девиацией не должны бить других + /// зомби под девиацией." + /// + /// ОТКУДА БАГ. CharmZombie() выше переписывает обе задачи ИИ на targetClasses = + /// typeof(EntityZombie) - "бей зомби". Подчинённый зомби сам остаётся EntityZombie, и никакого + /// признака "свой" в этом списке классов выразить нельзя: targetClasses оперирует ТИПАМИ, а + /// подчинение - это бафф на конкретной особи. Поэтому два подчинённых видели друг в друге + /// законную цель, и чем больше игрок подчинял, тем чаще они дрались между собой вместо + /// настоящих врагов. + /// + /// ПОЧЕМУ ЗАПЛАТКИ ДВЕ, А НЕ ОДНА. Цель у зомби появляется двумя разными путями, и закрыть + /// надо оба, иначе починится половина: + /// + /// 1. ВЫБОР цели. EAISetNearestEntityAsTarget.FindTarget() собирает всех подходящих по типу + /// через GetEntitiesInBounds, сортирует и берёт ПЕРВОГО, кто прошёл EAITarget.check(_e). + /// Постфикс на check - самое точное место: подчинённый просто не считается кандидатом, и + /// цикл идёт дальше по списку, то есть зомби выбирает СЛЕДУЮЩЕГО, настоящего врага, а не + /// остаётся без цели. Фильтровать позже, на присвоении, так не получится: там уже некуда + /// "идти дальше", кандидат один. + /// + /// 2. ПРИСВОЕНИЕ цели мимо выбора. Главный такой путь - месть: EntityAlive.DamageEntity на + /// получателе урона зовёт SetRevengeTarget(бивший) и aiManager.DamagedByEntity(), после + /// чего задача мести ставит обидчика целью. Сюда же любые внешние вызовы. Все они + /// сходятся в одну точку - EntityAlive.SetAttackTarget, - и префикс на ней гасит цель, + /// если и бьющий, и цель подчинены. + /// + /// ЗАЧЕМ ВТОРАЯ, ЕСЛИ ПЕРВАЯ УЖЕ НЕ ДАЁТ ИМ СЦЕПИТЬСЯ. Затем, что подчинить можно зомби, + /// которые УЖЕ дерутся друг с другом (Пирамида духов подчиняет пачкой, Рой кусает по одному). + /// CharmZombie() сбрасывает цель тому, кого подчинили прямо сейчас, но не второму участнику + /// драки - его цель погасит именно префикс. + /// + /// ЧЕГО ЗДЕСЬ НАМЕРЕННО НЕТ. Урон между подчинёнными не блокируется отдельно: если они друг + /// друга не выбирают и не получают целью, бить им друг друга нечем. Блокировка урона поверх + /// этого спрятала бы будущие дыры в прицеливании вместо того, чтобы их показать. + /// + /// ЦЕНА НА ГОРЯЧЕМ ПУТИ. check() зовётся для каждого кандидата каждого ищущего зомби в мире, + /// поэтому порядок проверок в постфиксе - от самой дешёвой к самой дорогой: сначала отсев по + /// типу (кандидат вообще не зомби - выходим, а для обычного зомби, который ищет игрока, это + /// как раз общий случай), только потом два обращения к баффам. + /// + public static class NecroCharmSide + { + public static bool IsCharmed(EntityAlive _entity) + { + return _entity != null && _entity.Buffs != null && + _entity.Buffs.HasBuff(Patch_EntityBuffs_AddBuff_DeviatorCharm.CharmBuffName); + } + } + + [HarmonyPatch(typeof(EAITarget), "check")] + public static class Patch_EAITarget_check_CharmedIgnoresCharmed + { + public static void Postfix(EAITarget __instance, EntityAlive _e, ref bool __result) + { + if (!__result || __instance == null) + { + return; + } + // Дешёвый отсев первым: подчиняется (и, значит, может оказаться "своим") только + // EntityZombie - зомби-звери на другой ветке иерархии и под девиацию не попадают, + // см. большой комментарий о humanoid-only выше. + if (!(_e is EntityZombie)) + { + return; + } + if (!NecroCharmSide.IsCharmed(__instance.theEntity)) + { + return; + } + if (!NecroCharmSide.IsCharmed(_e)) + { + return; + } + __result = false; + } + } + + [HarmonyPatch(typeof(EntityAlive), "SetAttackTarget", new System.Type[] { typeof(EntityAlive), typeof(int) })] + public static class Patch_EntityAlive_SetAttackTarget_CharmedIgnoresCharmed + { + public static void Prefix(EntityAlive __instance, ref EntityAlive _attackTarget) + { + if (__instance == null || _attackTarget == null) + { + return; + } + if (!NecroCharmSide.IsCharmed(__instance) || !NecroCharmSide.IsCharmed(_attackTarget)) + { + return; + } + // null, а не "оставить как было": цель именно гасится, чтобы задача выбора на + // следующем тике пошла искать настоящего врага. Вторая заплатка на этом же методе + // (SwarmTargetPatch, перенацеливание Роя с игрока на зомби) с этой не пересекается: + // Рой сам никогда не подчинён, так что до этой строки он не доходит. + _attackTarget = null; + } + } } diff --git a/HarmonySrc/ModEntry.cs b/HarmonySrc/ModEntry.cs index 0f5fbe2..088b7dc 100644 --- a/HarmonySrc/ModEntry.cs +++ b/HarmonySrc/ModEntry.cs @@ -42,6 +42,31 @@ namespace NecromancerTome // another in-game death. VerifyPrefixAttached(typeof(EntityAlive), "dropItemOnDeath"); VerifyPrefixAttached(typeof(Entity), "DropBagServer"); + + // Добавлено 2026-09-17 вместе с правкой "подчинённые не дерутся между собой" + // (CharmPatch.cs). Метод EAITarget.check в исходнике protected и назван со строчной + // буквы - если он когда-нибудь переименуется или сменит сигнатуру, PatchAll упадёт + // ещё на загрузке, но эта строка отвечает на тот же вопрос в логе явно и без + // раскопок: резолвится ли метод и висит ли на нём наш постфикс. + VerifyPatchAttached(typeof(EAITarget), "check"); + } + + /// То же, что VerifyPrefixAttached, но печатает и префиксы, и постфиксы - для + /// заплаток, которые стоят постфиксом (у VerifyPrefixAttached постфикс всегда выглядел бы + /// как "0 prefix patch(es)", то есть как ненайденная заплатка). + public static void VerifyPatchAttached(System.Type type, string methodName) + { + MethodBase method = AccessTools.Method(type, methodName); + if (method == null) + { + Debug.LogWarning("[NecromancerTome] ModEntry: could not resolve " + type.Name + "." + methodName + " via AccessTools - method not found"); + return; + } + Patches info = Harmony.GetPatchInfo(method); + int prefixCount = info != null && info.Prefixes != null ? info.Prefixes.Count : 0; + int postfixCount = info != null && info.Postfixes != null ? info.Postfixes.Count : 0; + Debug.Log("[NecromancerTome] ModEntry: " + type.Name + "." + methodName + " resolved, has " + + prefixCount + " prefix and " + postfixCount + " postfix patch(es) attached after PatchAll"); } public static void VerifyPrefixAttached(System.Type type, string methodName) diff --git a/HarmonySrc/NecromancyKillCreditPatch.cs b/HarmonySrc/NecromancyKillCreditPatch.cs index 8fe0291..92d84a3 100644 --- a/HarmonySrc/NecromancyKillCreditPatch.cs +++ b/HarmonySrc/NecromancyKillCreditPatch.cs @@ -61,6 +61,52 @@ namespace NecromancerTome /// follows vanilla's decision, it does not make it. Whether it does is NOT verified and is the /// specific thing to watch for in game; if pets turn out not to be credited, that is a separate /// piece of work (giving the pet's DamageSource an owner), not a bug in this file. + /// + /// + /// ============================================================================================ + /// ШКАЛА ПЕРЕДЕЛАНА 2026-09-17: 20 УБИЙСТВ = 1 УРОВЕНЬ, И УРОВЕНЬ БОЛЬШЕ НЕ ХРАНИТСЯ + /// ============================================================================================ + /// + /// Баг, найденный на стриме: "Рецепты отображались в скилле серым и с замком, хотя при этом + /// должен был бы быть доступным" - при 250+ убитых зомби Слёзы мертвеца (30) были открыты, а + /// Пир падальщика (60) стоял под замком. + /// + /// ПРИЧИНА - ВАНИЛЬНАЯ СЕРИАЛИЗАЦИЯ, А НЕ НАША РАСКЛАДКА. ProgressionValue пишет и читает + /// уровень ОДНИМ БАЙТОМ: + /// + /// public void Write(BinaryWriter _writer, bool _IsNetwork) { ... _writer.Write((byte)level); ... } + /// public void Read(BinaryReader _reader) { ... level = _reader.ReadByte(); ... } + /// + /// Всё выше 255 при сохранении обрезается по модулю 256. Подтверждено не только декомпиляцией, + /// но и на живом сейве пользователя (New Xisema Mountains/sezon8, 17.09.2026): в файле игрока + /// necroZombieKillsCVar = 384, а уровень craftingNecroNecromancy = 129, то есть ровно 384-256. + /// Со старой шкалой "одно убийство - один уровень" (max_level 5000) это означало, что уровень + /// откатывался назад на каждом переходе через 256, панель скилла заново вешала замки на уже + /// открытые рецепты, а группы 500/2000/3000/5000 были недостижимы в принципе. В ванили предел + /// не всплывает: атрибуты идут до 10, перки до 5, крафтовые скиллы до 100. + /// + /// РЕШЕНИЕ (продиктовано пользователем): "пусть уровень навыка будет 1/20 от количества убитых + /// зомби", то есть 20 убийств = 1 уровень, максимум 250 - влезает в байт с запасом. Чинится + /// сама шкала, а не сериализация поверх неё. + /// + /// ЕДИНСТВЕННЫЙ ИСТОЧНИК ПРАВДЫ - necroZombieKillsCVar. Это float, он сохраняется честно (те + /// самые 384 в сейве) и переполнению не подвержен. Уровень из него ВЫЧИСЛЯЕТСЯ, а не + /// накапливается: и на каждом убийстве (ниже), и при загрузке игрока + /// (Patch_PlayerDataFile_ToPlayer_NecromancyLevel). Второе важнее, чем кажется: оно чинит уже + /// испорченные сейвы без ручного вмешательства - тот же sezon8 при первой же загрузке получит + /// уровень 19 вместо сломанных 129. Именно поэтому здесь не "+1 к уровню", а "уровень = + /// убийства / 20": прибавка к испорченному значению оставила бы его испорченным навсегда. + /// + /// ДВА ИНДИКАТОРА (указание пользователя от 2026-09-17). Оба значения пишутся здесь же, в + /// CVar'ы, а рисуются данными: + /// necroNecromancyLevelCVar - уровень Некромантии, показывает бафф с черепом + /// (buffs.xml, buffNecroZombieKillTrackerDisplay). + /// necroNecromancyProgressCVar - сколько зомби упокоено внутри текущего уровня, 0..19. + /// Это фиолетовая шкала в HUD рядом с полосой опыта + /// (Config/XUi_InGame/windows.xml), она заполняется каждые + /// 20 зомби и обнуляется вместе с повышением уровня. + /// Оба пишутся ВСЕГДА, в том числе когда уровень не изменился - иначе шкала стояла бы на + /// месте девятнадцать убийств подряд и дёргалась раз в двадцатое. /// [HarmonyPatch(typeof(EntityPlayer), "AddKillXP")] public static class Patch_EntityPlayer_AddKillXP_NecromancyCount @@ -68,6 +114,22 @@ namespace NecromancerTome public const string NecromancySkillName = "craftingNecroNecromancy"; public const string KillsCVarName = "necroZombieKillsCVar"; + /// Сколько упокоенных зомби стоит один уровень Некромантии. Менять это число в + /// одиночку НЕЛЬЗЯ: на нём завязаны и max_level="250" скилла, и все пороги + /// RecipeTagUnlocked/unlock_level в Config/progression.xml (они записаны в уровнях), и + /// делитель фиолетовой шкалы в Config/XUi_InGame/windows.xml. Двадцатка выбрана не на + /// глаз: 5000 убийств / 20 = 250 уровней, а 250 - это максимум, который переживает + /// однобайтовую сериализацию уровня (см. большой комментарий выше). + public const int KillsPerLevel = 20; + + /// Значения для двух индикаторов. Держатся в CVar'ах игрока, а не вычисляются в + /// XML, по двум причинам: (1) уровень обязан совпадать с ProgressionValue.Level бит в бит, + /// иначе череп и панель скилла разойдутся; (2) деление в ModifyCVar дало бы дробь (19.2), а + /// display_value показывает значение как есть. + public const string LevelCVarName = "necroNecromancyLevelCVar"; + + public const string ProgressCVarName = "necroNecromancyProgressCVar"; + /// The tag every zombie carries, humanoid and animal alike. Checked against the /// real data rather than assumed: zombieBiker/zombieArlene/zombieBoe/zombieSpider all /// declare "entity,zombie,..." and the five zombie animals declare @@ -92,31 +154,34 @@ namespace NecromancerTome return; } - AddKillsCVar(__instance); - AddNecromancyLevel(__instance); + float kills = AddKillsCVar(__instance); + SyncNecromancyLevel(__instance, kills); } /// necroZombieKillsCVar += 1 - the same thing the removed ModifyCVar action did, /// and the reason it is here rather than left in XML is that it shared the broken /// requirement with the progression effect. GetCVar/SetCVar are public on EntityAlive and - /// are the same storage the buffs.xml formula reads. - private static void AddKillsCVar(EntityPlayer _player) + /// are the same storage the buffs.xml formula reads. Возвращает новое значение, чтобы + /// уровень считался ровно от него, а не от повторного чтения. + private static float AddKillsCVar(EntityPlayer _player) { - _player.SetCVar(KillsCVarName, _player.GetCVar(KillsCVarName) + 1f); + float kills = _player.GetCVar(KillsCVarName) + 1f; + _player.SetCVar(KillsCVarName, kills); + return kills; } - /// +1 level of Necromancy, replicating MinEventActionAddProgressionLevel.Execute - /// step for step rather than inventing a shorter version of it - its IL was read for this: - /// GetProgressionValue, Level + amount, clamp to ProgressionClass.MaxLevel, then (for a - /// crafting skill) the level-up toast and HandleCheckCrafting, then the two dirty flags. + /// Приводит уровень Некромантии и оба индикатора в соответствие числу убийств. + /// Идемпотентна: вызывай сколько угодно раз, результат зависит только от _kills. /// - /// HandleCheckCrafting is the part that would be easy to drop and expensive to miss: it is - /// what the game calls on a crafting-skill level change, and skipping it risks recipes not - /// noticing they became available. Both it and AddCraftingSkillNotification are public. + /// Тело повторяет MinEventActionAddProgressionLevel.Execute шаг в шаг (его IL для этого + /// читался): GetProgressionValue, новое значение, кламп по ProgressionClass.MaxLevel, + /// затем - для крафтового скилла - тост о повышении и HandleCheckCrafting, затем два + /// флага "изменилось". /// - /// The clamp matters for a different reason than it looks: max_level is 5000, and without - /// the clamp Level would keep climbing past it forever, because nothing else limits it. - private static void AddNecromancyLevel(EntityPlayer _player) + /// HandleCheckCrafting - та часть, которую легко выкинуть и дорого не заметить: именно её + /// игра зовёт при смене уровня крафтового скилла, и без неё рецепты рискуют не заметить, + /// что стали доступны. И она, и AddCraftingSkillNotification публичные. + public static void SyncNecromancyLevel(EntityPlayer _player, float _kills) { Progression progression = _player.Progression; if (progression == null) @@ -135,18 +200,31 @@ namespace NecromancerTome return; } - int oldLevel = pv.Level; - int maxLevel = pv.ProgressionClass.MaxLevel; - int newLevel = oldLevel + 1; - if (newLevel > maxLevel) + int kills = (int)_kills; + if (kills < 0) { - newLevel = maxLevel; + kills = 0; } + + int maxLevel = pv.ProgressionClass.MaxLevel; + int newLevel = kills / KillsPerLevel; + int progressInLevel = kills - newLevel * KillsPerLevel; + if (newLevel >= maxLevel) + { + // На потолке шкала остаётся залитой доверху, а не сбрасывается в ноль: уровней + // больше не будет, и пустая полоса читалась бы как "вот-вот повысишься". + newLevel = maxLevel; + progressInLevel = KillsPerLevel; + } + + // Оба индикатора обновляются независимо от того, сменился уровень или нет - шкала + // должна ползти на каждом убийстве. + SetCVarSafe(_player, LevelCVarName, newLevel); + SetCVarSafe(_player, ProgressCVarName, progressInLevel); + + int oldLevel = pv.Level; if (newLevel == oldLevel) { - // Already at 5000. The CVar above still went up on purpose - the knife's damage is - // not capped by the skill's max_level, and the player who is past the cap should - // keep getting stronger knives. return; } pv.Level = newLevel; @@ -154,9 +232,14 @@ namespace NecromancerTome EntityPlayerLocal local = _player as EntityPlayerLocal; if (pv.ProgressionClass.IsCrafting && local != null) { - // true = add the notification only if one is not already up, so a horde night does - // not stack a fresh toast per corpse. - local.PlayerUI?.xui?.CollectedItemList?.AddCraftingSkillNotification(pv, true); + if (newLevel > oldLevel) + { + // true = add the notification only if one is not already up, so a horde night + // does not stack a fresh toast per corpse. Только на РОСТЕ уровня: при + // загрузке испорченного сейва уровень может поехать вниз (129 -> 19), и + // поздравлять с этим игрока не за что. + local.PlayerUI?.xui?.CollectedItemList?.AddCraftingSkillNotification(pv, true); + } pv.ProgressionClass.HandleCheckCrafting(local, oldLevel, newLevel); } @@ -168,5 +251,87 @@ namespace NecromancerTome _player.bPlayerStatsChanged = true; } } + + /// SetCVar идёт через EntityBuffs, а он на момент загрузки игрока может быть ещё + /// не создан - в ToPlayer буфы читаются отдельным блоком и только если они в файле есть. + /// Ронять из-за индикатора загрузку персонажа нельзя, поэтому проверка явная. + private static void SetCVarSafe(EntityPlayer _player, string _name, float _value) + { + if (_player.Buffs == null) + { + return; + } + _player.SetCVar(_name, _value); + } + } + + /// + /// Пересчёт уровня Некромантии при загрузке игрока - вторая половина фикса однобайтового + /// уровня (см. большой комментарий в Patch_EntityPlayer_AddKillXP_NecromancyCount). + /// + /// ПОЧЕМУ ИМЕННО PlayerDataFile.ToPlayer И ИМЕННО POSTFIX. Уровень восстанавливается из + /// necroZombieKillsCVar, а CVar'ы лежат в EntityBuffs. В теле ToPlayer порядок жёсткий: + /// сначала Progression.Read, следом Buffs.Read. Postfix - единственная точка, где уже готовы + /// ОБА, и заодно это уже проверенный в этом моде хук: на том же методе висит + /// SpatialVaultPersistence (две разные заплатки на один метод Harmony складывает без + /// конфликта). + /// + /// ЧТО ЭТО ДАЁТ. Сейв, испорченный старой шкалой, чинится сам при первом входе: было 384 + /// убийства и уровень 129 - станет уровень 19 и все четыре мода ножа снова открыты. Ручных + /// команд, сброса скилла или новой игры не требуется. Проверено на двух реальных сейвах + /// пользователя (17.09): sezon8 - 384 убийства при уровне 129, test8 - 303 при уровне 48. + /// Ни в одном из них счётчик убийств не пострадал, потому что он float и переполняться ему + /// нечем; портился только уровень. + /// + /// СТАРЫЙ СЕЙВ НИКОГДА НЕ ТЕРЯЕТ ОТКРЫТОЕ. В прежней шкале уровень был равен числу убийств + /// (с поправкой на переполнение), то есть уровень ВСЕГДА был не больше счётчика. Пересчёт из + /// счётчика поэтому может только вернуть украденное переполнением, но не отнять: тот же test8 + /// на 303 убийствах получает Тёмное чутьё (порог 300), которое сломанный уровень 48 держал + /// под замком. + /// + /// ЕДИНСТВЕННЫЙ СЛУЧАЙ, КОГДА ПЕРЕСЧЁТ МОГ БЫ НАВРЕДИТЬ, - счётчик пуст, а уровень есть. + /// Тогда "уровень = убийства / 20" дало бы ноль и стёрло прогресс. Живьём такого сейва не + /// видели (счётчик и уровень всегда росли одной и той же строкой кода, а CVar'ы при смерти не + /// чистятся - в EntityBuffs нет ни одного сброса словаря CVars), но цена ошибки тут - чужой + /// прогресс, поэтому случай обработан явно: счётчик восстанавливается из старого уровня по + /// прежнему правилу "1 убийство = 1 уровень" и дальше всё идёт обычным путём. Оценка выйдет + /// заниженной (переполнение из уровня уже не вытащить), но это лучше, чем ноль. + /// + [HarmonyPatch(typeof(PlayerDataFile), "ToPlayer")] + public static class Patch_PlayerDataFile_ToPlayer_NecromancyLevel + { + public static void Postfix(EntityPlayer _player) + { + if (_player == null || _player.Buffs == null) + { + return; + } + + float kills = _player.GetCVar(Patch_EntityPlayer_AddKillXP_NecromancyCount.KillsCVarName); + ProgressionValue pv = _player.Progression != null + ? _player.Progression.GetProgressionValue(Patch_EntityPlayer_AddKillXP_NecromancyCount.NecromancySkillName) + : null; + int oldLevel = pv != null ? pv.Level : 0; + + if (kills < 1f && oldLevel > 0) + { + kills = oldLevel; + _player.SetCVar(Patch_EntityPlayer_AddKillXP_NecromancyCount.KillsCVarName, kills); + Debug.LogWarning("[NecromancerTome] NecromancyLevel: счётчик убийств пуст при уровне " + + oldLevel + " - восстановлен из уровня по старой шкале"); + } + + Patch_EntityPlayer_AddKillXP_NecromancyCount.SyncNecromancyLevel(_player, kills); + + // Одна строка в лог на загрузку игрока - по ней видно, что конверсия старого сейва + // произошла и во что именно (вопрос пользователя 2026-09-17: "не сломают ли новые + // правки старые сейвы"). + int newLevel = pv != null ? pv.Level : 0; + if (newLevel != oldLevel) + { + Debug.Log("[NecromancerTome] NecromancyLevel: уровень пересчитан из счётчика убийств " + + (int)kills + ": было " + oldLevel + ", стало " + newLevel); + } + } } } diff --git a/ModInfo.xml b/ModInfo.xml index 28df8a7..c5db89c 100644 --- a/ModInfo.xml +++ b/ModInfo.xml @@ -4,6 +4,6 @@ - + diff --git a/NEXUS_DESCRIPTION.bbcode b/NEXUS_DESCRIPTION.bbcode index 24f4848..4ebf87c 100644 --- a/NEXUS_DESCRIPTION.bbcode +++ b/NEXUS_DESCRIPTION.bbcode @@ -17,11 +17,11 @@ To uninstall, delete the folder. The mod adds items and one block, so a save tha [size=5][b]Main features[/b][/size] -[b]A skill that levels from kills, not perk points.[/b] Necromancy counts every zombie you put down. Five tiers, 5000 kills to the top, each threshold opening part of the arsenal: +[b]A skill that levels from kills, not perk points.[/b] Necromancy counts every zombie you put down: twenty of them make one level, up to level 250 (5000 zombies). The skull in the status bar shows the level, the purple bar beside the experience bar shows the progress inside it. Five tiers, each threshold opening part of the arsenal (zombie counts, level in brackets): [list] -[*][b]Adept[/b] (from the start) - Spirit Stone, Necromancer's Knife, Blue Portal Stone, Pyramid of Spirits, Blood Sphere -[*][b]Adept[/b] (20 / 30 / 60 / 100 / 300) - Spatial Bracelet, then four knife mods: Tears of the Dead, Scavenger's Feast, Grave's Repose, Dark Sense +[*][b]Adept[/b] (from the start, level 0) - Spirit Stone, Necromancer's Knife, Blue Portal Stone, Pyramid of Spirits +[*][b]Adept[/b] (20 / 60 / 100 / 300, levels 1 / 3 / 5 / 15) - Spatial Bracelet and Blood Sphere, then four knife mods: Tears of the Dead, Scavenger's Feast, Grave's Repose, Dark Sense [*][b]Journeyman[/b] (500 / 1400 / 1700) - Scroll of Deviation, knife mods Dead Man's Grip and Dead Storm [*][b]Apprentice[/b] (2000) - Summon Zombie Dog, Beetles of the Lord, Summon Zombie Griffin, Blood Stone [*][b]Necromancer[/b] (3000) - Summon Zombie Bear, Summon Zombie Wolf, Banshee's Scroll diff --git a/NecromancerHarmony.dll b/NecromancerHarmony.dll index aee7bc9dfb8ed7ffdf1bad6868602442b4c37496..cbd5398a4b7a9aa75e30bad9c4dfec8bfccbd78e 100644 GIT binary patch delta 37769 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 mCh=1N#UY%}0Gh=872K^jG}Tr0>eZ`Puio7q zQirUmkF0C1D9_%$`c=yOd_?7?4ylglEQv@pnX4~fd(TwY;L9aCff+YT^p>)=EZ6yr zL{8AgWfDzEm&uXz45^=e-F##$1^cY@l~Rp#cKTtdpLAY&pHv<^4;uJq41Q&@((K<7 zz5ElAv|;Wdsd?KZd7dP#Pd}v0mez0cSllv*O7&*Is1{7`Q;!EbsvTq*k8QJeJu-%T z@hKXezd7X~viPsMJ^iBX3`o`52g|O4I)z4}KqR@1CF$>+EmB^(F6*qM9~Fz|WzqR= ziy`p-j9Ue+EgMN>x5dYTW%wYNt7^+ef#tTuXLR$bv}L22WsN^!$%s|CRbPL3-w0Jp zu!4?@0f2MPj)aMGmX2ja1$NaJ>j0s-RU;Qg7+!#Vy6%g0rU$srDr!W<93DyONI^(W zj1bvxV{Xw^>(h_8?mo2(tdQDq2|wb)bLjkz3EWfZ0`JH6Bq<+~T40Rl@*b^at>U zRpaXPDLISLC~xL$1U%Q>4!GaFG`R-pPF;>2=Y(~Pe(@oO1Jdoq6m zt!}F};B&>NYl0{1lVPwK2!DfRn?ruf=1?HM45g*t z@f-_FN^>Vl*QL+Py&`!%YrX+sF&b7{9AP(Wk%3xb6L^uR`HY{1c#7S~oB}Oz6P|(7 zB5o}t(2}1{>tL2=q>0Rj+Xho)MSI*|VT(j>sOa zZQq=}#2ZT9id28>Hb7sh7z#T}0Aja;miYd7?Ipg&MYei z@~N@AfLDb_Z49OiAL0?GeSb|5GjXVoRBIMkr*2dV~$QL*A==^NS=m*?v zp?iSY)u`gFaj5YzNR2_A9lp}F*nR1ld6migK*xR$0IfEHw+ON0Zr_Yj?W)poKFU+& zjz#=PFcg(g)dVLL9E<(W{9|56}7`AdmPFw`R| zT%xw$&pG{hYJy9MDuEiwXFR~BzS_w?RvM(RY?MP%j%@+^KdSGGZ3SBq4HAA#x%2N&=oaY6cVUy0P7Zav$dR1=&eToDomgiHgr z!+5h$$U`Ek#oq#}#v1<)52tXFZhD0~P{u2IJRhmTfNno!ynsgS@j|BR-0YL;WEu;E zf6VspEk5=jS2>aw_xho;8iWY1*fwC{_?m8}Y=od&B>7^urFZ)CCvJy?U5%jQJ_Ib{ zh#LWD;GrSxcgTr{nVDlgRn6y(JpzV9^VJ9B#G{!seu}gmX(KS&`xwX+cZ9IrAGZ6# zrv@-2bp`5^k0T-Ki0`j3!$S=#zStAs#hwJPtMQ*W;VIw|U-@+#Hx5gokuCnXtrF}g z><(kpXIzLl{qeFs2?Ki*e0>u<64ynI7IZ$Ht`B;fpMmjBD zAv)h9#T)T3b~0lKV;sk^XVS}pg@r)XPPVDMp`oF*G26^`8>AqxJ!s?(f&jWY%S9?x zUwtVG{W_R$h(dXkQ3<}HAdfPv$8NMi)FJegIN_!G{C)v0dUGfkZ|TRwVZMjrX8<#H zrq9pMlLn?Q&yOabg-Di15xs45sKgQffMpF74^sic7s@4(lG@lV;3c8hbIfNSE5;u< zwOBTu=chUDjfX}2)A<5;otSkjp=fTE_lVj6+uC0QGn8U(Y&WO>5#YE^%t_r+16b-M zA;sL-%Rs|_>4b7i>=n*|VcHUVm9a|3USq6+vDec}3#z3(>01lR=JHr*4z@gMWrFt& zFhyu4-UJqv!am2K)v#0*v=(~{+{F_y3pn-2Vms zVcp!lpsI|4(4c!PMiZV9Pak==CH6KXH2-vmW|k3q2XyP)pMU-t^+Ef|)Qo2V55S2o z)FEOspR1#?FAOyOaAD)=?;?+XhP|ersHPfw4|F04X)pIabg>NoeGn=HvGDkl>6;Hk zP6u+btF+iY&Y9?&)8v1co>){|+lXO6_QzDB8hFW~3L{jb1=XtZIeIlZ)zu5y_op`& zl_sBov!W-s)!4_-oU6ID$OyN#Ix>)jhAfEvpv{SfSWrpFpOA-BaS|p4;~u9LzSq9Qz9r6Ms#&6;F{qNUtw$ z@}2;j>^_IjiN%7h=+~jgwx&NS_Rjkhl9~uonNEk>G5EWCW5}0@BGcQBnh~N7n(($$ z@9XcZObYwE#&0I+39gsXoSt5CyiIszsUG_{{Xj`Y^fQQ=EfsCS0&g(avko<9ehPD} zCBCzo&hKO_wl@89NsIJ(x}~(Av^G7rw5s11kcwo<@z-iFDloy3(TR4qppG?Ij9%xI z_1G8b`%8^8zC<#Hy#o+cVqbxfJ25|4jA1C!p=H({K{fu*Ze0WrmQe2tjdw&xe(=45~*^$rZ=le^i3SwH<5|HiKp}=7RYfX z`X*k+iC=St;tw%8Rg@1wruquL*DGj?Vvrk(3d!+MHyXZNR)iBHejtaSFyjoyb1?h0V=&Z6H)>ZiXnu>nE5k;LY+hTu5mRyV5lK2NBR%~^wVmzPO!3^1k zf#h2tB3M1@kvxo%vIi>*?#dq3#+wK{{T&_R>9%%s0zruVGrgjs(jkhOC%d)Scj-qf z%9^<$|BEX0Pg9q#TbJIeE2lDWtk5;OPdG*f$??Y#PiTdk%@{EgL6^2=qGBxkZ#G}) zqYlK%ztZPb7AG@<)1a#mKEfPxd_rIAGeTu$Qa*&uHNVjlT*F91rqHAQ`R*_OUJVt-5LhbpDd(ygI#(_y(XynZOXFqB{UZxrs}-A65UAF;!r z@*9d6{T^tpD#O!<()Wahjrsv}L{`IIhu3NR2qH_49fyY;8w2R`1&p8YM29tw;Heuw zi?m*ed|x}IBUQyoNn-JsjE5Fe0CO!|{(Ltg9BW?5>m*j!3dn<&c z?I+Mxqnf)yM`sNhQHwc|D`LZTN%R>h+&%<(oNA0)BFmR+t68GDZKnI}jB%UfI&?jj zg^a#BEzT=nte2%)M4k&gw_Q9+2FJ1sm~^Z<3Du3|0Iza8@*66286t<$P9sps@>Omd zHkUTH%{E}U+5NeH@>&9d92aAZije3Gb#7NYiehB9%k0P5p6q4ZZM&CQYmA|#LbAr4 z6F(xcWKQfmHrVZPcME-GRJnvu&rqK(tIm_M(#_SS*t1Tr9${Y(gF`+<-P-hR)oGs_ zR;DW8t#%J%Jdx*P#Wyir2l>u$xWSZ1l==+M zT04ZVb0xBM4O-2l;qLnhG*gdoo^vT-dkEu{P-C&3lJn1Qo1a<6Vr4m8rR> zPz`QRu@y}e0*flX8iyv(SP^Jv&vC%+|D{$Lz-1PAWTOxhF-k3rS1`*g2_}nGZgF~Q zv?5RfwKdo*mg0#SaWWDk8p!n8XxT9jg9=40Ro)t_Q3e5HJX{jZY;L*}%DWT7{;*gD zqVG{S{Z-U&uRu~Xq9-b)bnBQrEfE48zbGB9EuV+>LI~z55v)V2n0*y2*YurOy!*ySaWC)NPkJhEs6hJE7$;F>|C#Rh`q)MA{HXi5TR>FEFH^0s=# z#!nrm1R8pNGt%V6h!H8*YRbn3ffX6$wq^#s!RVqbV1=SeRZWp`w+INJp2Xm8uBQ2o zV?dY+_(aPR8v=}FWyikh}>g=hGj z;kQV^Il~qFu<&V~MYVQZ$q$#MW2JanJ64IO+JRXYe60ifA3XJrtMTl_8r*_dN`}=0 zE6c1}gKC0x#@E4y%*jGe)Wz>%!?=HlLjd#as=W<{hT_wjaKtzQsKZpJ`EeqH5kPIn zDXiTX1>iFW1}i;+iK`ZsQ4*siN_MZ8U2@`BNcBtuCTUJVFF?C#27-%op|Nr5AkOZ% z(FGF!7o^1D9c%_cf$+gs+r`t}8OmE)? zyF;BV;3d`obYki=G44IB#&IaWgA+0`Yk_t!$k5j?%^)NKwj&J`%H4WY6H05WLSrsY zh{i}Kb+1d!6E|=Wm16<;w6n()Kzftki65FWeVV>c!PI|murJhS&2CxT_1WQsFe*k9X#Np}jExlWHWWSrca zJkyv8f|=9$GN&^$X*Xuznd|U4jG2sNxw9g6cUGXbaS*~4qnq$;uFK=w`NMshsa$al)G=gaXp`WvVIdYZ$XZJdTAD91`3`0`g?o-j<*TpT2|{{}K;FwjQiMv1 z!>vcl%ccTWb(9t!b2Fw0v^(Bz9&Re(hz?(8p37i$(0$@EgS+I5JWQpSE6!!Yn>$;% z$n8mvds!TRbgbh%iiuy#lBdHB7>i_TLhA+4fFe_D9@uQ`Loay;lKQw#?9{+eV3FpvW1J;p+Fwn0@gSm>C&_5!}>p zCaM)b1-(*V#`QI)w|kq@Uo{5AkN|&}& z1r{MK#kECfXmkncT8CzBe<*!w%Q3;&*v4P5knN&)dVN>j{JFkUfiUfj>Tb8m6>WdIo#X9z|GeM z=3_BGI9 z5r_NYz#fK_w($XR>S;YQi~5a=p@-){Ub&pak&T~t>tHO0;#^^wn=dK%txzn1EV7XW zTa@_sd=4*`Wtz-4OE`WoPU8m@+6e0=s%OtX3KlOAHo_n^!LZk?_(LeI`@Z0ZK6vKt zUl18$1T9Xs#Zmx^=!_8>;dqV)zz8|E42GK*10BGk1LU|m zfn%+31Bv}mk6i0<`jRa&hF#*PQFaVByoTY<7c)hGxjH{4S76K8hrWc@rWFf-T zIow=v+!n4DLYxWgq_L2tjI%lQJl1hFlCl051&GYX8ny?gY8GQHXH{a?;9**j!G#5U zQ^5ld|Dc#O>xn;&+Q#1mKp$>D8MXGy#yX_Lt`*7qlbrsq|C%lhLvkL#uV=6LU&-M+ zV6xR^aamoeu^z=$xvcRmUR--B#tE<_wgJ5K_F*~UfpBqVa><-U$j0xGXoi#;+Xy^@ z<)(36`ftMmNgg5{LSBtG!vf8?9vqHS>KqHVw%-6Uwh2H^91mKJ-3T1ph^3` z6qqR@c2gfkHv{ii#lfM`J}APR{OgvptyhoC*y?i*!hk?J_oeM^Gs_2lzk0~bEX`)z z0(Ib>4<6FVW^C?Zw4)PbW&?}Is*1i?8u;<&pY<7Pq6=citpLIc*bA|TqKz3UJ{C^F zYZmZI@_)Dm+1M}GgE{q*oYvFK3lknCe*;^Z|69#)B0kcC(C5KH7^MA&LAu#ua3FfK zUGL*TJ;ola61O!aIRhTebb2g_X%GsOd)C*oSY9icg*Ecv(gdwmg9G_NMLe@>*Ts0H z?exgzLR-l!v1PIR<%>36{ifU6N|GECIPkTCHw!$m-tAuLDtOO7UMkFZ`__q7O8b2 z^^V@uJ2{ne+||pwyE{j^ZbV_S1^#Nk2Q0fBE%sm4Ax^FkMyXa2OYQd}={Dx_G0J@) z9KNiYJk54B^OpS{jL`AQ%&9nn%d%;>1o|X!6%KcC`X#Du>bReE2(G`In`&(r+$6KH zs?%Z*KnSxT6=3|?AQNF3jk70X3)sKt)S@@Wwj#klBUi0iV0KTO>^=xqu4aa>W(Lo( z-PAUuxy|WEgxe7rFEZrn>2V`{{mf?JS7(F0bl*{jV{HP^?QcV@ak*O0o1^ zBMYZJ1mX6F0kV|WF{w-9d`-8-9s#Q=FV|v=Jqiqmpp!f{V+W%+-dx5@xx`}tnt(HM z9o@{w1@rNA!KkX_6TqW)?sIu;M|f#e5X(g`c;9Ww!|{eFGuNuT9_c9*{ZN#Or&;Ep z_Ys4cV#NzHyoYOf0Zez6SSb&FT;O8K((-`7`1 zwNac$_n3u63f50OMsOOJCJIBELycNBUblBv--?R=>Tb-b^Y%>BmDsbW^y2okaa^(R zH&=oEjvWU-B7En?i~|3 z&5%M7uWy8+g{)|$sfdMsp{O!%7p$`QPt2T4$zst`lP(+6BLAy3J$p<=@;M0j8?ucq zXo?0^V==3Cqo)_6%CQmv;}WoZ*!$S%7PxjOyH*@VnrE|iaT;kfKo8$2`uOT&AP9%X zQ*de9EOBV+)O~fia=dK#(JSO|vJ=|`i@6`iG4LOdF?vzwRPaJktx9iy9*iuTU^GnV zK2nd*fEt{r+hQ*uIoE=B75c$YK3ey+aZ1n@d-3R${J6m>y~p2~a+AElw8eHqx~A6D zr}q!pV&$COsvCdgC$7f$J-yWnjF&+2E&t1S_8i1Fi8B3t7W!<-YSR*&z?-(^$L|-M z0^Hx5oWl4)SNg}X*~vTD)prBPw)n>o@*A%}fBZ+FnVpQc^LpVDe^uvoK#r(SqD|Ug zg;XfTDPEuP8VIxFYT~WXVcbr!*TMA=8e+@{V-N5s8ezzYqZ=VRj3xIQNQ}J+V7!&y zIIb-DCzuoY72&WhhB0v%oEyIos=7xmLu^WQu?LrXcj8zcpm?GV?3ysmnwxU_-ijf0 zxJ={%V}Ayy;W>UUkStTdR2woqGhD1m#6I148;RhhT6=l9792F2dw2O)cF%Ecm_Dr% zUpFFs_4xd8??6+E!!C?@R2HxNw!&HM?}Bev+uy^(q4{I)<0*TOC{9g}eE?j?r3kKc zfoZW10oB+?>3@uGOAcp8M=Ua4FY$(DU;BQfLCwc_IJDRSJe<0}c4SZRZimkhya<@M7c*NQnIvd^0p;!tRmU*y5-fpNw+DvWRuNxRG?=+K0PT>{9^Im&7fj zEP9j4oP|7sS*5lthc3L9vQ$m#*Jarv=hK5P(?qgUu0<~2#i(TsnZ-OKGzIpEFAu;AuiI+jG@phDqVZT5THzIfkl}Dn8Q#|bP zt2tFxjf>&ip5}ZH%rnuRO7CRNZ7PitZK@gx2;-s;hw4$ zm`6uGJ;g*k2q9evi4F9=lC1cmQRzdI@+4dO;PIu&kw?|)5Nc)GjDWS9A%NlZOSmHv zv?VwSFjHx98ZBm-Nq9JFO4Uf7SwWY0IOBNh8+_gCj4Q_i)8PQ_C#I`(bCh%o)-aP7 z`wAsgsS#CAv8Q^5#PP`fUwxt*iS*7B`UQ7E$c=GcTrQdm8UvwX*wWIZk|{W+aAzt) zq9SG+;T>D9jYH9lCGf2AHyEHr?eXJ}!%+kGlzk=6xMK{Q_iKtTm{dA@G<(kY8u>6^ zIpb>}Yr6Op)mRFZ4!rupEv!XUP1Gu0KNf4R)eEryF^?ke1g(jNHD4B}7R6@8pB&2# zl(a$hJ_<`YXcYWRnL;H6SRXyuc_s|U5QYOJk8ub>f-!?Rtxb3f3P|ed6bs=Nl{e5D z9g&HSg}v?1z#u;I!a~HNM6lfW2Kl2nKV?RI_&C&I1w_JF$tVBIQpKT(Yb4H)_&ajr zr9fRz{G+d)3wreE%f3ZI;-3K6JjcGnQ_QpfVsRTLTs~FkDZe)#Qj(mM_%{S2<3Ju} zq%D&p@jWPB3jKiR|CeG7xy;%cm!qPn3Km2^LW{4y+Y9%Z*5iCHjN*Pm8lP!n!DKaG z-R+k9b5AWbTSnz?O_do6D_ndQ;TDBp-uJg3fv(uk06jJKj_>xkZd}IVnt24<{xqL2 zhD=2rSeaWwwvHS5;kNLr@%*y-&4ScAZoyNW&mMhno2$F^&dn@izGk`{>czorD8*cH zeCyV6e!H_fA#;4oEsKNDDX^6n6K>6|i;#*R3uBKuqRrIP2?f2cAg+NF`mC9D^kDY+ z`1D&R)g{d_ttb;4_`=0*NC12T7k5s8LtqgmwBooA1m3%~d9>cQg+bfnjhxWC2t%0j zO$k;3bR42w7UzzOF&WD^R&aU_-Gm4`(f6^jk)uP(?%l;iDG_PGdKXNEAZ zQZ3!lqxS|6YmH}uhhs-JM3ff+;ZTlvfyk(5QeDO^DDYbI>cSEq!}S(jFH??bwULP^ zWaU7_?1&BTL#(YkV{a5@a)_wIGGBzYEfaJK%H^PA8)wFQqb^gJVL^JQ6(FVpsQhJ& znrjvAiD}@J*t*{^?P*?Cb#(K_C#2syxp)q{ELX+*c)dGJes3ft8neh_?c0{c@q2#R zlssNxNx~mLp(Q!U(TMm;L5CT5<1=wfddAeUT&8T-@f!#&;~|Wp;Gy(YQ_GUiupbew z_Q3&@ZG#~CuO*bQ14DKwoZi8>mLc$Bt*@>${wZ=|;nWX#<5MO=OD!-l6%2X>!zhLc z&g8b9)4aem#%4Ic*zE6pmFCk4NfG-QH9UWhKAt&2w`CdU?pyWz_$-lD;IZ~B5eIV~~;dOlX*5D-Mn$^Jw)?1zr1@aq@+1%+ESNB^E4ZuhB179@=m(`bSr%^-;!mMQH^CET1J*|ZaSvhj?^7q4BgU>sXu zZm2OsWB;wjJfa{=d?M#aa(DBE)y3#B{DD)R7RwbHE%8OY8r8)R<2T>)^qBWolF=d# zzGld?#q$0$IWq$*bQ=sB&j$5wd6PB&ZO?lS+}*w7#Wx_>;fNitaE&*d*>duZ(<7T( z-7>N8;;pVGwz|$fGUj?q7YlN&f4MH!=~U?vN8R$EG zs8oCt{Ne3>BgzjB-n;5qWeArm^ayH*BMR(c!kJs3@;4I5N9~1m73|2RJ4TbTklduC!1k$I@@+b3=lvUV096pE?^h+~4cX;n)W(1XG z&%vBb$Ig#83T}ZdR)E~SCk?$_T}iOKzu`1f#8+RV*?h4=NGFN_)Wq#DQcc{2Wr29z z66@DH!Qqb%)tYK8fs-?Pq|6+!`DQOxEOOyUz|!4rVHDsC_v-&|c@V0<$did;?4Aha zkDmz7^xa(F2)g?t zyJJv>SX1NF$U<8XU?-q_x8gIlcbA?hMcKYOU;GK=Q{s^m`wrY;)tvr*@qHD}2x4W( zh7aDbo2if&pMoCFQ%S^+QT|b=j<_-i-ZF+Dqy~3y)UxBJq6{=SUb_s$Z#*%bI>noO znOSCI^4{CpM^t0aRX=vdpQ)J!zedxD88CeZm&@MkBoBj z;_K79@Q76i6@Ldiqry9-TZI?d5fdSAChsIp5qbT6^DYBBlXr7Z-uTCin#BiB25J^R zo6-L)eihgm75A}(S%bd-O=fiXruOKV!svhMz&O>d<3^S+b-c}}X@)+nN5!#>{!&GX zJ1a(<0tCc8@bDxAqte=Q2j#Vk-W;oh!|)ziITr9CMsby7Q~?ovT5hoOoD0&vF9-=E zJ?XUkGHW%(uwJ@bBmG#pegefP?H{GDt=~v9IJf6-KNsy#2Ucn13P}R zOMI(g@@=t3B$(fQ;lSl~J~&h833L)154byV3T=rEghVF}rY*51U;|Xa4V#>18MmYM znhS8wI0%XOmdVW10s^gFgti>aD7W@8KyXAl1dj%b-zge;D2V90xaF}N@u8n)Zh0^S zKyVn+M08}?@@hRouPu{5*2=ob7>-AJ-fwcHh3O@~DNmjYBl8-vJp&J=Sx8Hg#- zN;qM_HVUI<#$h&Pk{D|c6h<1(mlJ29Q8DSXv0<1C)x_P%ZLCL{qi2dqp+$I#>1`w) zc|MY+r}Iy*l7F0@9&vgVpWO8f%6xz*F0JrJhXV?KM|ycJhO$0Bp= zIDm*QFGdHI_#O867A_(R?G7!k!5Kd|GkxP36@$h=%)q-Yb|Hwp;gH^$))s3*Lj0Gu z?wW;H)A;SFEG$0Vv!RveD_?r({L1vO`TeBl((~t6!XfxO3)p6VK0Cc`et+@452iGo zo*8r- zK@JT2zmj7-a)eFo{^WJ>M>6U$KmCd@t2bq#_PvZKCXW9i8a`1L-`ZztF~j@=0!K5a zo6IJb#O&%fDxfYbNGy&_3ZM5DBecW!_jo}$RaEJoUoBcxX`C#+ZI{LO>qaFj9c-$R zm5#*->98u+IvS=nU3BTiT)tRn`Hy*;y&0DCge1E5MaUp0aDHhqN}#F($Bv*Gnr9mP zK{-?6#f;cQ?uVj9_^)nQY7*j;eKUV8e^)Cfm~TvgJEsc~Gj}qhY#{RDO@&upetD=V z3Hs*Yvy6$5pE(_CEG|mpts-7HXh2w*C3-t91Rt;LbM)TN*Hs z^{H7Y_O#fh72{L~3c~sA$D_Q9yUFfG;1z+57ID1cCtib=z$%ivb^Jl#y)WU3E`pEp zk>XD^vt{C)ep$TBFDF(A&XoeL6mV7g-UWGf;{=qtPxGak)9)`R7$X|KyX@{K8h3-p z@;g9dHa9Ld8W!GUh@besIX-&d+k`mY+YBZ-lQ}H$Yx#M8^Ib;sJ;^NA(p>|0ot8K@WtfsDmSv^J9 znnMep1@-W{&FX$ai8wnv%I5CG`8{Ed?tym)CPP!leOyG+40(hxO&1~00*H83_1Df7 z;m(ZLzr|o^eo}P>SHk>Gia+1YM_fmo@h#w*qghxpPK0(RKDW!HEuYhqChHydvH|`M z*2?iXQ(z*(IHga72~wOV)WEnIJ;s$BX~36DY`myOgG2TS9Ww48eeKV|d3d`975`(p z|HA5FhXxQ;bP~-*pP1bO{GK;t?_XG*R13^)hf14s5A{>&TLEwIEUwC? zkO9l+U!M2!RC+IWTCqy!2xtg6TEJ%o+~VQX1s>L*dk++-bbAfMOFax%@-E_c|X8;AA>fP`pbD%J00*d#}#Ba%*}8d^e62! z66)@yQ(>K*4m%ir%`+zrswLV$cZUck6_e1Oj|=Fd`<+}^fx;%fn#TpaAnLtR%Co98 z#?79X=wx$^&>3Ns-VyvZC*wJ}i>p-H29BLRM1!bF3c@=4Er~)_cNpWForWk3&lUB! zqm=9ViDxTnRwc|@hmqSuL(9I;R_Q)bvo~N|jdTLMSR>^NU!G9LGWS-nq2~t~T0;zf z%3;_9?|SH*oI;;U$%$wim98v2P*5XnL@3zlkZ_b8vx$pF7~fdzG)Fk|1ObO3;_Tu( zV>lDhWT$qRn3Oc(*mH`QbA>SdOXyLl77b^o`NFK{;cz?Ego*O$y@KzvZiFsS{37AEIaJb(;FCY?lFxb}~WxG8N;GO@EC7r6v&Sxj1gcI;yLP(M5Ebh3&C z1?MX&eO$q?U)lMJot{S%*y&wS*Pjp{cA5c6JN;EO-xg8J_e2GDG~L9+Y#Ho@3YHk`vA^1M@W8;z_F77 zAE0ZMOe?mNP59|fG@?oeL{C}R#Q2|~!A?o!Qt2^-q@AvZC(!Bwe-t?4A4Y+7g`ey9 zw)1?v2R*ZTfX_oi&=4M)FW|f?EuFCIJZuLi@$4)1q-+QQ`i18^% zg>UWq+%~pH;N89UbN*h zNUF3Hp72mTf~%O$6+T-Dd6i-!hKeyV*3!ia=gon(t7+zFUUk!{Vm$hn=r%q$*-o1S z40mBBu+z(EAhew5Y_G!HT9biD+*3~ubCzLwaXR`s8*^rcN(pLQsVUhdsMdU@7SKvT^%If{XqBKoE#b6tXpNwz)S6UU zP&Ijbv+=$8dGtF$P6Nr*Mtn4sL(gKM!1WYeCn#?}le%6|`IsO%?FK<@$VhGy)Mpv$ zMnN4$H)6?~XgPF#jqqgZW>P@;2vic}WeMPHaKb%BzR=W#pH$3RptwLJgZeE?BA!-a;GRhMt9aW4 z`38FBL|RAN`(#{C4~dMJw~Hhl_yV>Qd1+mG=r#w)%iI>-1E zIOCyVYHElp`JFsDb&j9mA8Q%z74QJy)Knz+>MVE>- zBd_>;^q~D`z(Hjee-nLP!}h)};5f|&&c3i0@CTz1@O$umR9nI7uCp2bsi{rEh=Iji z%oz?gafRS~1z1nZ@}iKr5LNZjk{VT+nv%g!HqnfM%}^H-Fc)xYDq&+4Z4qAfwXN@TE#8 zm#9irlHM6G9?9II-S)0^u!?hGL=*j?=47PKE>ht9him4*h-v*BEj}8ivivIH>c;~t zKUOrvc|PV3bTce(VYns0a9AP3{sj!5$zynr!Z3NRlOI263=ar+FHG^#4Wb@5iTZ7< zITuE}G>`*rLiQ4P>x!!7Fy(AS1_u%6{Xx_$1-GlTsdBX+v$=z7Y2xuFRgq}F`%ZMi z)PPs?Zhk6>3=++jy}Cp@t@s`IKU8l5{3(2^UsbPC zxOjj0&j_wP8pq8x_uVk7x?~$<*4vKJuvtL$RJt3!Q7Kx)kOEI4bznZjh3+I5&=6#} zIKc34Xf2iA2yu~*3HYgi51_6pJqc(Q(_MpuqTXD~Ci+Q!mK%sz^^&|sEI6(ep18C) z%cfGZ_E#tNHnnvyi{r*eU%FpNLi7e9^ftPaN-qoenShT8)gKG9CL4Vn__AN3@i1jl zDTW5RJg_~a!i&>;D4x#G64ZJsZ`uQC7Z#aBYXjef_Tpl7j7cFa$>bJ6uBQ=I?}54$ zOB{$&lkFqFLe46t*3(;o&tU4D40V@w$gj~|8R}5ckA54uFh_J3;i6*%wVwJFIRh>l zm7#9ZoPlhbl%Y;+&P@h#XltL09(q5MSl(0+@X*`XOmgveII049bQYFBY}!8t?1iIW z#Hx)c@Ns=MT^-4ChSU>TC=I>BkJUR~rm!4fYM3)?^zUNEXtu^@0?x zDW*w+T2Hx669dKcdWI@*+UqZ+pZiFbk^{>uHjQgoN@E4JmYN+?17*~ip(-4w1}bP> zhT79`Rv<(=<_IqS=EkXkeo1;TLw?y94^-1%GSqvG7YAx6fF&f0Hh6Ob5jvEiw&mpp zYH7?sGp#De8K|Q#OiEOup8h4M=k=%R24ML8K0`gw$kb0JMbrA>k2q2?57Q^n^Ymo# zN+cF$sPa;#Dl?SFdpSf0VU5o9z1p4*G|-w1^_Pb00|RLa)~lQrtLv~dQCv`FSPr6P znY0u8@AVI&H#1ai$<2X5l*1n@amGj8cLiF=JJ_UJqFVxkX?lhll(W}=485PBDx8l5 zj-eq#Ov!x>&jyClvJ5r7d0uuaeVL&e%U;1}-`@^3C0lKK1H)<5Fq0Y_+!tu0=Y}Os za-!$+z(`u%YEmENd=nT&TQbxmIfnzs(xD7>R!|9!p(}=)l1rNQ2FB69dF_Hq*c;|$ zkEbmoOsclU6&z1vMw-;0-Fd+Yba0eOonreuFp+LP4y!w~uV}U7>CrKq_!mjli-O0K zcdRM8T&)bAKyL`jbm?SzKa=*gHZ?Gr`j0au{f?U8Ni2w1ql+Q!Nq~J_aCYXukP1A$3X@H>C(%(ww22Z6)8S3r)xxv$@-$a%) z&7MPp1jRk(tl%87;4swGnFubR7bo>foN}~9$D=rJ3L*Hf+|6TE( z|6Ce$qAAL8aULz4(yJy$O9aIQUKNayKGl@`#=S1Mh|bDT+tDf8>A4K`V$d15fWFL7 zMFq~lV%j&2^Cit%Tu5IEl6`SQ@IqQLofDs@M}oHoFQPj$RFk^QwuD~EP#<_Nw_Qx1 zXQ)cgDqDio8D>63y~)-=Mus}3-`%z(J({6bH@<62(Lq67o}|+Us&qM>HIp-5PP(9Q z5hJMEafEg`-7w3f)(grxo2m8m$$)!;m(#*iOzMidZNU{}IhCpB>FmJeww3hU9Hz{e zSw;HLGTIUR;DRqXKc2}h{ zu#R4v&y=b3T6$kl>nU4(BX})MIn$IZRNoD*r<}7)YLD;Z;079$p_-DmFM}J&x1d+e zbyO)RZi;^dL7i=8Wau%q?`NphRm=0Are``#$@8uA zvY)1pGE{EU)kwRd(@guT<9GSVowSU{piCR?qAh~rNVqwF7cESgqPb0XAw6w(4-#fkpBgmk)d*%e)R9A`8{d(<-bbpJ=7up>$I$oAQ4XkEjG{s-X5uU2dFf)AS6r6qD+Ebk3!$biXZk zz$j4dCM8{8%aRvo(oPm>mk7!%{ykci6y$RHir$jnqr%I2ZF`?8kD?++QH_G)d@tv} zPh&FFLh0rF59pRYlKbesOxhEu;69Qs=Mt9FF{t2&l#THRKW4CfNChI%wCzKx$cWCt zy7xose^grYQB>P8=YTo5y{^J5A`iMG3qUqrMl*&--;QeIz zEgQPu_H6x|`TNOfQo_OeDL0eG4&G0NnY6~xJCHmnL;W^13u!pxqLCJcUtyhvRk0QI zm+9X@e2+p=H?vOjc0-vaVWB9|o-CHRCCoCMYQch?a0+IoGA;>@31!;sXU?rQ&UHgJ z=Q1T#C-Wy)F@G9TC7NSJ{Uz$am4Qq~4U4iVl7KQ{B?a76^rgtKNfgFVrj&zI|1bFQ zO0PWQ-MQk>kGC^T6-=18M1xURneHfI&Z~CD^F^u&Kf;Tzctb|`<_inUnDF;PW;R}V zlgY%lS8(1OgJm>SPoia_dPPF#X{?6I)owOvZw@2ftW7IO+Du=LhNME57O`aVRvX)UP_#X_Q#Wpk9%=4Y*WJeJMZ12Dwp6gK z{p56!Ydol=o0-YiJaXIoFNCMoC(`?8gu>tvt;TIC&NQ!z4!=W3d{6{GvePuoj$I?DW!bo zyZ{j^(S$-4`XI!$d>&AuHKKt`+$_ed)9L*8`-#c`RQoD*1sE@h_9f zGNGx|>{S1WbIrP)$u;Y4>8pe@&lkaH6CVAu2wt6#U)ZarpITX%-0yZ_hONh?UOjz+-~G5C zw&V9J{Nj`bJRWmx#3Q&HP{qOi_K+QaW^{Wf2l5PC1Z)#?t}(JL%+>PXV{%kJm1;EE@E8@SXM_A=9NP(njjmZ_p6|YMz(nn=qOJ&x(qTeFdK{$4@WUIfHcEHJ- za0dTenJm{^w^rB75ptv82pVp@+$b7rfuvWTDi0w?vP{KC7Hgf0tj$cN~jnmR7?;m7D2_e@)UAF!wQjih4eJ?u8_6^P7xXwNgv=$bAr&b zmGW!vlDE>#?3L7JRVsJMYo%vulP}17=q~ptxcc%SLw6a&1(COqtgCOyZtEfMe)$&Z z2oxQ*aEKkYL~t&7*s>Cb=VPs}Mi0w}ExT|Kj3!V>Ic#~Ml<{yQDa!QNl_hGy6Y z0xq%-0ZiFP0B+6aR(uBUq%5_TxyLFSCDF#xZtE)BI0KvngEKO0z|rwOOyTU8yA7tef3$$@7F8-SX(l^~yZB?j~i0Rn56wam)Yq zKcWPcrtBvbo4nb|@LzS$DI2W|3;(DrgrX0XGWolLPatV6|3SIix~ovK+-*&`bKvA% zQI&47yjkG01m*me0f>n`&Bd0j)@utYEW7EqI6#$>7AEEii!Kmtd;u*l7;V{V`Mh8y z?X>uggjd#q$N48cdTl(!%{ECfXVV>?n^DJ zgmLR=Z~0TwWVx>7cFPTdbDQ8?Dk^**B{_Vy3*rd@zp*}={dY^7^&;&%%MR*S{e$H> zVbE^++&Tb%uVSOuX}y#_^xmXgN~;R;tj`Hkp2$Ep{R#YyaS1v(=5g5s&UV2$Y<;nC zwDn~eA<-gvclB)R6Eq-+IDc8h>dT^Q?WWl^r(55#coAHScmu6M#k0U4VuyhnC6?_io_ZLmvaaSNXlQOa9vODfkB~C3U+fWvT3q z+SH|Tg;%0Bd0j&iAtQI@RH;>kpAG%& zv$sTq?WYa?SxJm~d$no-pH~@wS$#r8!*&5L74R(q?-Q^L#Ul>X`sO#(GWCo6x7B+5 zf!)v49n!((e}l8EMAml8gR33d`=SXpidR41nkxV|q3h02U&FD3Te%Y*ct%p) z>>EHWQhyW^RB{_vYjf2NMQQwDt<}EkwcRw#qbfFKqN<`#&j&n6H@JVVRVzFYRV!!U zx@Qsm@u9LnJ+ow|)}mD9T}$=K^X{LtE_qm~tna4v`Pq7xdTJpqU=Tw=eJ2&?lmZ^x z90Dilbw>3zrMRd?$3Rlv3b?g=B;acN!K}&Z3j@ahzsW$bC>IqSug_3Uhs+G66EZWD zkibU?`L8Oc=#!O~>@xu!p*etgq4|Ix6*7MDK!#rxGUvAg=R@a@mFMbR^7bSq$}dG^ zekoe(OVMGz6deX5_8@lb!kRnLa`xJ5P@C1oJjsqJ-hdjsWp4%N^`e{g73#6gw}Z0) z{N2=5{DA(YX!XgGHSbw{f$-J><;Pl8S)jrL4S9^v~q0Et+kSa&LG5Em9r~XW8l{qY2lY(#b6hrvYwMPjGl_Yt>gut8BNZ z!yQewF69x+Xq#J}-Z;*-LRs59$+lJfTpd6=)Da~o+iddA(wR0MA5XLGQE$yzn6#}` z_|$Q&!l#XE6+UI$uU2~21Lrfwddsba18A+nCyZ;A1IpvJA1TZEI&eN^3`+Acaj#Xb z2>-*@X1zFi*tUb743m9@`okdI{uv^}WpA_2jTYK163?h@*5ji6f%EV+S-mto+Mb-O z<`<2&*P~~TvrkrTt6L1XwJrhpeIeuaBF5JZWc;>)3HyHG%+CPV0`G`yuz#j}fXm)* zz_}5em61E_YZX49v`9PxS|lC;+pKG&2T(ANjE5olrQIo(Zab2+z2A=@cxm9p`mPnN zYv5vgCr!gb$}84@79qM;6kI0VgR8!+mM#88N}2QodPJLa`k*?;T4jrh^&@$T@1#PB z2Wbhdi)%8=7#Ja0rUDj9JoxO9k8hfWZ*^BSpXQJ(Nh5N$;~TZHBJL8#dxT_#x+HOE;g z+NlyPmuKaXvB7zZ6zuM*YNMtIlr+!k7+C@zu1pQ zmsd;HJ6kMsHC1V`6!*X0*`jSmIJZeJ1(G*A-O|&Q11Kn6i+f17bdJV&I()aYP1_T` zAE`@mg9|>E(t9wqJm!=vw--DM6$fyAK3V;?VYJ;XtruKdQ>@# z*q#s!X3f>QnpNd)@YhtZMM zC<3ri1mFV8U$MY%lg{OVTsll)4PNfT1dWk#smvqeJYn3zr1=mSRb;fk&i=0f$KM z01lS|P&!JIy-pe1Q&pvXz{Brf1A$>l`_q-MbLr8$5XNXr42NcRISlRg1V zN#%Jix>Py|@CxaMBp$1zcL3KÉ>Yck;PqH&j-*Y1;|2dD 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 AssI20 diff --git a/README.md b/README.md index 582b7dd..b372b1a 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ *English version below — scroll past the Russian half.* -**Версия 1.2.0** — для 7 Days to Die 3.2. Автор: Alex Cube. +**Версия 1.3.0** — для 7 Days to Die 3.2. Автор: Alex Cube. - Страница мода: https://www.alexcube.ru/7-days-to-die-moi-mody/kniga-nekromanta-necromancer-s-tome/ - Nexus Mods: https://www.nexusmods.com/7daystodie/mods/12547 @@ -26,18 +26,25 @@ Отдельный скилл **"Некромантия"** растёт не от опыта, а от счётчика упокоенных зомби — свой счётчик, своя механика. Засчитывается любое убийство, за которое игра начисляет вам опыт: добитые ловушкой, сгоревшие, умершие от наложенного вами кровотечения, и зомби-звери наравне с -человекоподобными. Пять тиров, каждый открывает часть арсенала: +человекоподобными. -| Тир | Порог | Что открывается | -|---|---|---| -| Адепт | сразу | Камень духов, Нож некроманта, Синий портальный камень, Пирамида духов, Кровавая сфера | -| Адепт (доп.) | 20 зомби | Пространственный браслет | -| Адепт (доп.) | 30 / 60 / 100 / 300 зомби | Моды ножа: Слёзы мертвеца, Пир падальщика, Могильный покой, Тёмное чутьё | -| Подмастерье | 500 зомби | Свиток девиации | -| Подмастерье (доп.) | 1400 / 1700 зомби | Моды ножа: Хватка мертвеца, Мёртвая буря | -| Ученик | 2000 зомби | Призыв зомбособаки, Жуки Властелина, Призыв зомбогрифа, Кровавый камень | -| Некромант | 3000 зомби | Призыв зомбомедведя, Призыв зомбоволка, Свиток банши | -| Мастер | 5000 зомби | Чёрный портальный камень | +**Двадцать упокоенных зомби — один уровень Некромантии**, максимум 250-й уровень (5000 зомби). В +HUD за этим следят два индикатора: череп в статус-баре показывает текущий уровень, а фиолетовая +шкала рядом с полосой опыта — сколько зомби набрано внутри уровня; заполнилась — уровень вырос, и +шкала обнулилась. + +Пять тиров, каждый открывает часть арсенала (в таблице и порог в зомби, и уровень скилла): + +| Тир | Порог | Уровень | Что открывается | +|---|---|---|---| +| Адепт | сразу | 0 | Камень духов, Нож некроманта, Синий портальный камень, Пирамида духов | +| Адепт (доп.) | 20 зомби | 1 | Пространственный браслет, Кровавая сфера, мод ножа «Слёзы мертвеца» | +| Адепт (доп.) | 60 / 100 / 300 зомби | 3 / 5 / 15 | Моды ножа: Пир падальщика, Могильный покой, Тёмное чутьё | +| Подмастерье | 500 зомби | 25 | Свиток девиации | +| Подмастерье (доп.) | 1400 / 1700 зомби | 70 / 85 | Моды ножа: Хватка мертвеца, Мёртвая буря | +| Ученик | 2000 зомби | 100 | Призыв зомбособаки, Жуки Властелина, Призыв зомбогрифа, Кровавый камень | +| Некромант | 3000 зомби | 150 | Призыв зомбомедведя, Призыв зомбоволка, Свиток банши | +| Мастер | 5000 зомби | 250 | Чёрный портальный камень | ## Арсенал @@ -75,7 +82,7 @@ единицу; опустевшая сфера рассыпается. Доступна с самого начала и делается без верстака, по две за раз, из крови некроманта и праха зомби. - **Кровавый камень** — тот же слот, но не тратится вовсе: эндгейм-замена сфере. Открывается на - 2000 упокоенных и варится на химической станции из праха зомби, костей, обычной крови и крови + 2000 упокоенных (уровень 100) и варится на химической станции из праха зомби, костей, обычной крови и крови некроманта. - **Консервные банки** (пустая / с речной водой / с кипячёной) — расходный цикл вместо одноразовых банок: наполняются водой, кипятятся прямо на костре без кастрюли, выпиваются, банка @@ -139,6 +146,25 @@ ## Статус +Версия 1.3.0 — **шкала Некромантии переведена на 20 упокоенных зомби за уровень** (максимум 250-й +уровень, те же 5000 зомби). Это не косметика, а починка: игра хранит уровень любого навыка одним +байтом, поэтому старая шкала «одно убийство — один уровень» при каждом сохранении откатывала +уровень назад на 256. Внешне это выглядело как самопроизвольно закрывающиеся рецепты — на панели +скилла снова появлялся замок на том, что уже было открыто, — а тиры 500 / 2000 / 3000 / 5000 были +недостижимы вовсе. Число упокоенных зомби никогда не портилось, и уровень теперь считается из него, +в том числе при загрузке: **старые сейвы чинятся сами**, без команд и без новой игры. + +Заодно в HUD появились два индикатора: череп в статус-баре показывает уровень Некромантии (раньше +он показывал общее число убийств), а новая фиолетовая шкала рядом с полосой опыта — продвижение +внутри уровня, от 0 до 20. Мод ножа на воду (Слёзы мертвеца) переехал с 30 упокоенных на 20 — на +новой шкале 30 не выражается, и порог опущен, а не поднят. + +И третья правка этой версии: **подчинённые зомби больше не дерутся между собой**. Раньше зомби под +девиацией получал приказ «бей зомби» и видел законную цель в таком же подчинённом — чем больше вы +подчиняли, тем чаще ваша свита выясняла отношения вместо того, чтобы драться за вас. Теперь +подчинённый не считает подчинённого целью и выбирает следующего, настоящего врага; это же правило +гасит и месть, если драка началась до подчинения. + Версия 1.2.0 — у Пространственного браслета появился расходник. Забор блоков теперь питается зарядом в слоте модификаций: **Кровавая сфера** тратит единицу прочности за секунду поглощения и, опустев, рассыпается; **Кровавый камень** с третьего грейда занимает тот же слот и не тратится @@ -166,10 +192,13 @@ торговцев, крик при создании Крови некроманта. > **Эта сборка проверена не полностью.** Вкладка испытаний, оба первых испытания и счёт убийств -> в игре подтверждены. Ещё не проверены: **Кровавый камень** (нужен уровень Некромантии 2000 и -> химстанция), **новый порог Кровавой сферы** (переехала с уровня 1 на 20, туда же, где открывается -> Пространственный браслет), а также **награды испытаний и два новых испытания** — на Камень духов -> и Синий портальный камень. Если что-то поведёт себя не так, это ожидаемые места для сюрприза. Из запланированного не +> в игре подтверждены. Ещё не проверены: **новая шкала уровней и оба индикатора** (череп с уровнем +> и фиолетовая шкала прогресса), **починка старых сейвов на загрузке**, **мир между подчинёнными +> зомби**, **Кровавый камень** (нужен +> уровень Некромантии 100, он же 2000 упокоенных, и химстанция), **новый порог Кровавой сферы** +> (переехала на уровень 1, туда же, где открывается Пространственный браслет), а также **награды +> испытаний и два новых испытания** — на Камень духов и Синий портальный камень. Если что-то +> поведёт себя не так, это ожидаемые места для сюрприза. Из запланированного не сделана только часть фирменных звуков. Текст описания для сайта (RU + EN) — в `SITE_DESCRIPTION.html` (разметка блоков WordPress). Полная техническая история разработки и текст финала лежат рядом с модом в `BACKLOG.md` и `FINAL_TEXT.md` — в репозиторий они не входят (спойлеры и внутренняя кухня). @@ -178,7 +207,7 @@ # Necromancer's Tome (English) -**Version 1.2.0** - for 7 Days to Die 3.2. By Alex Cube. +**Version 1.3.0** - for 7 Days to Die 3.2. By Alex Cube. - Mod page: https://www.alexcube.ru/7-days-to-die-moi-mody/kniga-nekromanta-necromancer-s-tome/ - Nexus Mods: https://www.nexusmods.com/7daystodie/mods/12547 @@ -201,18 +230,25 @@ survival in spite of death, but power over it. A dedicated **"Necromancy"** skill grows not from experience but from a count of zombies put to rest - its own counter, its own mechanic. Anything the game gives you XP for counts: kills finished -by a trap, by fire, by a bleed you applied, and zombie animals alongside the humanoids. Five tiers, each opening part of the arsenal: +by a trap, by fire, by a bleed you applied, and zombie animals alongside the humanoids. -| Tier | Threshold | What unlocks | -|---|---|---| -| Adept | from the start | Spirit Stone, Necromancer's Knife, Blue Portal Stone, Pyramid of Spirits, Blood Sphere | -| Adept (extra) | 20 zombies | Spatial Bracelet | -| Adept (extra) | 30 / 60 / 100 / 300 zombies | Knife mods: Tears of the Dead, Scavenger's Feast, Grave's Repose, Dark Sense | -| Journeyman | 500 zombies | Scroll of Deviation | -| Journeyman (extra) | 1400 / 1700 zombies | Knife mods: Dead Man's Grip, Dead Storm | -| Apprentice | 2000 zombies | Summon Zombie Dog, Beetles of the Lord, Summon Zombie Griffin, Blood Stone | -| Necromancer | 3000 zombies | Summon Zombie Bear, Summon Zombie Wolf, Banshee's Scroll | -| Master | 5000 zombies | Black Portal Stone | +**Twenty zombies put to rest make one Necromancy level**, up to level 250 (5000 zombies). Two +indicators track it on the HUD: the skull in the status bar shows the current level, and the purple +bar next to the experience bar shows how many zombies you have gathered inside the level - it fills, +the level goes up, the bar resets. + +Five tiers, each opening part of the arsenal (the table gives both the zombie count and the level): + +| Tier | Threshold | Level | What unlocks | +|---|---|---|---| +| Adept | from the start | 0 | Spirit Stone, Necromancer's Knife, Blue Portal Stone, Pyramid of Spirits | +| Adept (extra) | 20 zombies | 1 | Spatial Bracelet, Blood Sphere, the Tears of the Dead knife mod | +| Adept (extra) | 60 / 100 / 300 zombies | 3 / 5 / 15 | Knife mods: Scavenger's Feast, Grave's Repose, Dark Sense | +| Journeyman | 500 zombies | 25 | Scroll of Deviation | +| Journeyman (extra) | 1400 / 1700 zombies | 70 / 85 | Knife mods: Dead Man's Grip, Dead Storm | +| Apprentice | 2000 zombies | 100 | Summon Zombie Dog, Beetles of the Lord, Summon Zombie Griffin, Blood Stone | +| Necromancer | 3000 zombies | 150 | Summon Zombie Bear, Summon Zombie Wolf, Banshee's Scroll | +| Master | 5000 zombies | 250 | Black Portal Stone | ## Arsenal @@ -250,7 +286,7 @@ by a trap, by fire, by a bleed you applied, and zombie animals alongside the hum pull; emptied, the sphere crumbles. Available from the very start and hand-crafted without a workbench, two at a time, from Necromancer's Blood and Zombie Ash. - **Blood Stone** - the same slot, but never spent at all: the endgame replacement for the sphere. - Opens at 2000 zombies put to rest and is brewed at a chemistry station from zombie ash, bones, + Opens at 2000 zombies put to rest (level 100) and is brewed at a chemistry station from zombie ash, bones, ordinary blood and Necromancer's Blood. - **Tin cans** (empty / with river water / with boiled water) - a reusable cycle instead of single-use jars: fill them with water, boil it right on a campfire without a pot, drink, and the @@ -315,6 +351,27 @@ story scenes play without stopping time. ## Status +Version 1.3.0 - **Necromancy now scales at 20 zombies put to rest per level** (up to level 250, +the same 5000 zombies). This is a fix, not a facelift: the game stores any skill's level in a +single byte, so the old "one kill, one level" scale rolled the level back by 256 on every save. +From the outside it looked like recipes closing on their own - the skill panel would put the lock +back on something already unlocked - and the 500 / 2000 / 3000 / 5000 tiers were unreachable +altogether. The count of zombies put to rest was never damaged, and the level is now derived from +it, including on load: **old saves repair themselves**, with no commands and no new game. + +Two HUD indicators come with it: the skull in the status bar now shows the Necromancy level (it +used to show the total kill count), and a new purple bar next to the experience bar shows the +progress inside the level, from 0 to 20. The water knife mod (Tears of the Dead) moved from 30 +zombies to 20 - 30 does not land on the new scale, and the threshold was lowered rather than +raised. + +A third fix ships with this version: **charmed zombies no longer fight each other**. A zombie under +deviation used to be told "attack zombies" and saw a perfectly valid target in another charmed one - +the more of them you charmed, the more of your retinue settled scores among themselves instead of +fighting for you. Now a charmed zombie does not count another charmed zombie as a target and picks +the next, real enemy instead; the same rule cancels revenge if the fight started before the +charming. + Version 1.2.0 - the Spatial Bracelet now runs on a charge. Pulling blocks draws on whatever sits in its mod slot: the **Blood Sphere** spends a point of durability per second of the pull and crumbles once empty, while the **Blood Stone** from the third grade takes the same slot and is never @@ -343,10 +400,12 @@ charge and the Blood Sphere's spending, Necromancy's kill count (zombie animals, included), the traders' ghostly look, and the cry when Necromancer's Blood is made. > **This build has not been fully tested.** The challenges tab, its first two challenges and the -> kill count are confirmed in game. Not yet checked: the **Blood Stone** (it needs Necromancy level -> 2000 and a chemistry station), the **Blood Sphere's new threshold** (it moved from level 1 to 20, -> where the Spatial Bracelet itself unlocks), and the **challenge rewards plus two new challenges** -> for the Spirit Stone and the Blue Portal Stone. If anything misbehaves, that is where to look. Of what was planned, only part of the mod's own sound effects is missing. The description text for the website +> kill count are confirmed in game. Not yet checked: the **new level scale and both indicators** +> (the skull showing the level and the purple progress bar), the **self-repair of old saves on +> load**, the **truce between charmed zombies**, the **Blood Stone** (it needs Necromancy level 100, i.e. 2000 zombies put to rest, and a +> chemistry station), the **Blood Sphere's new threshold** (it moved to level 1, where the Spatial +> Bracelet itself unlocks), and the **challenge rewards plus two new challenges** for the Spirit +> Stone and the Blue Portal Stone. If anything misbehaves, that is where to look. Of what was planned, only part of the mod's own sound effects is missing. The description text for the website (RU + EN) is in `SITE_DESCRIPTION.html` (WordPress block markup). The full technical history of development and the text of the finale sit next to the mod in `BACKLOG.md` and `FINAL_TEXT.md` - they are not part of the repository (spoilers and back-of-house). diff --git a/SITE_DESCRIPTION.html b/SITE_DESCRIPTION.html index 7001f89..5450e6b 100644 --- a/SITE_DESCRIPTION.html +++ b/SITE_DESCRIPTION.html @@ -6,9 +6,9 @@

Прогрессия, которая растёт от убийств

-Отдельный навык «Некромантия» качается не за очки перков и не за книги, а по счётчику упокоенных зомби. Пять тиров, 5000 убийств до вершины, каждый порог открывает часть арсенала: +Отдельный навык «Некромантия» качается не за очки перков и не за книги, а по счётчику упокоенных зомби: двадцать упокоенных — один уровень, до 250-го (5000 зомби). Уровень показывает череп в статус-баре, а фиолетовая шкала рядом с полосой опыта — сколько набрано внутри уровня. Пять тиров, каждый порог открывает часть арсенала (в таблице — зомби, в скобках уровень): -
ТирПорогЧто открывается
АдептсразуКамень духов, Нож некроманта, Синий портальный камень, Пирамида духов, Кровавая сфера
Адепт20 / 30 / 60 / 100 / 300Пространственный браслет, затем моды ножа: Слёзы мертвеца, Пир падальщика, Могильный покой, Тёмное чутьё
Подмастерье500 / 1400 / 1700Свиток девиации, моды ножа Хватка мертвеца и Мёртвая буря
Ученик2000Призыв зомбособаки, Жуки Властелина, Призыв зомбогрифа, Кровавый камень
Некромант3000Призыв зомбомедведя, Призыв зомбоволка, Свиток банши
Мастер5000Чёрный портальный камень
+
ТирПорогЧто открывается
Адептсразу (0)Камень духов, Нож некроманта, Синий портальный камень, Пирамида духов
Адепт20 (1)Пространственный браслет, Кровавая сфера, мод ножа «Слёзы мертвеца»
Адепт60 / 100 / 300 (3 / 5 / 15)Моды ножа: Пир падальщика, Могильный покой, Тёмное чутьё
Подмастерье500 / 1400 / 1700 (25 / 70 / 85)Свиток девиации, моды ножа Хватка мертвеца и Мёртвая буря
Ученик2000 (100)Призыв зомбособаки, Жуки Властелина, Призыв зомбогрифа, Кровавый камень
Некромант3000 (150)Призыв зомбомедведя, Призыв зомбоволка, Свиток банши
Мастер5000 (250)Чёрный портальный камень

Арсенал

@@ -84,9 +84,9 @@ Necromancy here is an answer to a curse, not a side branch of crafting. Instead

Progression driven by kills

-A dedicated Necromancy skill levels not from perk points and not from books, but from your zombie kill count. Five tiers, 5000 kills to the top, each threshold opening part of the arsenal: +A dedicated Necromancy skill levels not from perk points and not from books, but from your zombie kill count: twenty zombies put to rest make one level, up to level 250 (5000 zombies). The skull in the status bar shows the level, and the purple bar beside the experience bar shows how far you are into it. Five tiers, each threshold opening part of the arsenal (the table gives zombies, with the level in brackets): -
TierThresholdWhat unlocks
Adeptfrom the startSpirit Stone, Necromancer's Knife, Blue Portal Stone, Pyramid of Spirits, Blood Sphere
Adept20 / 30 / 60 / 100 / 300Spatial Bracelet, then the knife mods: Tears of the Dead, Scavenger's Feast, Grave's Repose, Dark Sense
Journeyman500 / 1400 / 1700Scroll of Deviation, knife mods Dead Man's Grip and Dead Storm
Apprentice2000Summon Zombie Dog, Beetles of the Lord, Summon Zombie Griffin, Blood Stone
Necromancer3000Summon Zombie Bear, Summon Zombie Wolf, Banshee's Scroll
Master5000Black Portal Stone
+
TierThresholdWhat unlocks
Adeptfrom the start (0)Spirit Stone, Necromancer's Knife, Blue Portal Stone, Pyramid of Spirits
Adept20 (1)Spatial Bracelet, Blood Sphere, the Tears of the Dead knife mod
Adept60 / 100 / 300 (3 / 5 / 15)Knife mods: Scavenger's Feast, Grave's Repose, Dark Sense
Journeyman500 / 1400 / 1700 (25 / 70 / 85)Scroll of Deviation, knife mods Dead Man's Grip and Dead Storm
Apprentice2000 (100)Summon Zombie Dog, Beetles of the Lord, Summon Zombie Griffin, Blood Stone
Necromancer3000 (150)Summon Zombie Bear, Summon Zombie Wolf, Banshee's Scroll
Master5000 (250)Black Portal Stone

Arsenal