Кровавый камень: бесконечный заряд браслета

Эндгейм-версия расходника Пространственного браслета: то же место в слоте, что у
Кровавой сферы, но не тратится вовсе. Кода менять не пришлось - только конфиги.

ЗАОДНО ЭТО ПОЧИНКА УЖЕ ОТГРУЖЕННОГО ТЕКСТА. Сообщение о пустом слоте
(braceletSpatialVaultNoMod) и описание браслета обещают игроку "кровавую сферу
ИЛИ кровавый камень" на всех 13 языках с 15.09. Пока камня не было, оба текста
отправляли за предметом, которого в игре не существует.

СОВМЕСТИМОСТЬ СЕЙВОВ - ПЕРВОЕ, ЧТО ПРОВЕРЕНО. resourceBloodStone - НОВОЕ имя, в
существующих сейвах его нет, значит нет и ни одного стака, который читался бы по
другой байтовой раскладке. Это ровно то условие, нарушение которого в e362c62
убило персонажа: ItemValue.Read/Write гейтят блок модификаций одним условием
!(itemClass is ItemClassModifier), и класс предмета определяет раскладку каждого
стака в сейве. Камень заведён новым предметом, а не переводом существующего -
тем же решением, что и Кровавая сфера. Добавление нового <item_modifier>
раскладку уже записанных стаков не меняет: айди новых предметов дописываются в
name->id мэппинг сейва, байты старых стаков остаются как были.

БЕСКОНЕЧНАЯ ПРОЧНОСТЬ СДЕЛАНА ОТСУТСТВИЕМ СТРОК, А НЕ БОЛЬШИМ ЧИСЛОМ. У камня
сознательно нет ни ShowQuality, ни DegradationBreaksAfter, ни effect_group с
DegradationMax - сравнить со сферой, у которой все три есть. SpendCharge
(SpatialVaultPickupPatch.cs) списывает прочность только у модификации, чьё имя
равно ChargeItemName ("resourceBloodSphere"); камень под условие не попадает,
цикл делает continue, его UseTimes не трогает никто. Большой DegradationMax был
бы хуже: неподвижная полоска прочности бесполезна, а при MaxUseTimes == 0 она
рисуется ПОЛНОЙ, то есть забытая пассивка выглядела бы как "всё работает".

Три места в коде сверены на то, что камень пройдёт весь путь:

  1. Гейт пустого слота в Begin - это !_bracelet.HasMods(), то есть "в слоте
     что-нибудь есть", а НЕ "есть сфера по имени". Камень гейт проходит. Это был
     главный риск правки: искал бы гейт сферу по имени, камень не работал бы.
  2. SpendCharge вызывается ПОСЛЕ SetBlockRPC(..., Air) и bag.AddItem, а его
     результат только логируется - ветки "не заплатил -> откажи" нет. Блок с
     камнем уходит в хранилище, в логе "took ... into the vault for 0 of charge".
  3. Ветка max <= 0 в SpendCharge камня не касается: до неё доходят только
     предметы, прошедшие проверку имени.

ФАЙЛЫ

Config/item_modifiers.xml - новый item_modifier resourceBloodStone,
installable_tags="necroBracelet", свой modifier_tags="necroBraceletStone".
Extends="modGeneralMaster" param1="CustomIcon" - НЕ resourceRockSmall: с ним
приехали бы Action0 ThrowAway и ThrowableDecoy, и камень можно было бы метать
как отвлекающий (на сфере эта ошибка уже была и была исправлена). Вид в руке -
HoldType 40 плюс все три меша rock_smallPrefab плюс TintColor "220, 30, 45", как
у сферы и трёх камней мода. CustomIcon="BloodStone", без CustomIconTint:
иконка своя, рисованная, лежит в обеих папках атласа с 15.09.

Config/recipes.xml - рецепт на химстанции, craft_area="chemistryStation",
tags="learnable,chemStationCrafting,necroNecromancyApprentice": 50 праха зомби,
20 костей, 4 обычной крови, 1 кровь некроманта. Все четыре имени проверены по
файлам. Цена выше, чем читается по списку: крафт самой крови некроманта снимает
90% текущего ХП.

Config/progression.xml - камень добавлен в unlock_entry третьего display_entry
(unlock_level="2000", unlock_tier="1"). Это только строка в панели скилла;
открытие рецепта делает тег. 2000 здесь и 2000 у RecipeTagUnlocked обязаны
совпадать, иначе замок на панели разойдётся с доступностью рецепта.

Config/Localization.csv - два ключа, resourceBloodStone и
resourceBloodStoneDesc, 13 языков; ключей стало 135. Названия камня взяты из уже
переведённого braceletSpatialVaultNoMod, так что сообщение об отказе и имя в
инвентаре совпадают слово в слово. braceletSpatialVaultDesc дополнено на всех 13
языках: камень не тратится. Файл переписан через csv-модуль, round-trip без
правок даёт побайтово тот же файл - кавычки и CRLF остальных строк не поехали.

ОПИСАНИЯ. README.md, SITE_DESCRIPTION.html и NEXUS_DESCRIPTION.bbcode доведены
до текущего состояния мода: сфера и камень добавлены в таблицы тиров и в список
арсенала, у браслета сказано, что забор блоков питается зарядом в слоте,
счётчик ключей 130 -> 135. Заодно снято утверждение "весь контент проходит тесты
в игре" - оно перестало быть верным: расход сферы в игре подтверждён, камень в
игру ещё не грузился.

НЕ ПРОВЕРЕНО В ИГРЕ: камень целиком. Всё выше - сверка по файлам и по
декомпиляции. Сценарий проверки в BACKLOG.md; главное, на что смотреть, -
отсутствие полоски прочности у камня в слоте и "for 0 of charge" в логе.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
AlexCube
2026-09-16 20:24:22 +03:00
co-authored by Claude Opus 5
parent 896501dcd8
commit 5a512260cc
7 changed files with 206 additions and 25 deletions
+49
View File
@@ -399,4 +399,53 @@
<ingredient name="resourceZombieAsh" count="5"/>
</recipe>
</append>
<!-- Кровавый камень, продиктовано 2026-09-15: «Рецепт: 50 праха зомби, 20 костей, 4 флакона
обычной крови, 1 кровь некроманта. Рецепт будет доступен на третьем грейде некромантии
(в самом его начале)... Рабочее место - химическая станция.»
Все четыре имени проверены по файлам, а не по памяти:
resourceZombieAsh - свой предмет мода (Config/items.xml)
resourceBone - ванильный (Data/Config/items.xml:23781)
medicalBloodBag - ванильный (Data/Config/items.xml:19196)
resourceNecromancerBlood - свой предмет мода (Config/items.xml:1321). После отката
15.09 он снова обычный <item> в items.xml, а не модификация.
ЦЕНА ВЫШЕ, ЧЕМ ЧИТАЕТСЯ ПО СПИСКУ: одна кровь некроманта стоит ещё и 90% текущего ХП на
её собственный крафт (NecromancerBloodPatch.cs).
«ТРЕТИЙ ГРЕЙД, В САМОМ ЕГО НАЧАЛЕ» = ровно порог группы 3 «Ученик», без собственного
смещения, то есть тег necroNecromancyApprentice и уровень 2000 (progression.xml,
RecipeTagUnlocked level="2000,5000"). Тег уже заведён и уже работает - свой
necroNecromancyLvl*-тег здесь не нужен, такие одноразовые уровни в моде заведены ровно
один раз (necroNecromancyLvl20 для браслета) и считаются исключением, а не приёмом.
В progression.xml камень добавлен в display_entry третьего тира (unlock_level="2000")
строкой скилл-панели - это чисто отображение, механику открытия делает тег.
ДВА ИМЕНИ, КОТОРЫЕ ЛЕГКО ПЕРЕПУТАТЬ, выписаны проверенными по ванили (образцы ammoGasCan,
carBattery в Data/Config/recipes.xml): craft_area="chemistryStation" - ПОЛНОЕ слово, а
тег - chemStationCrafting, СОКРАЩЁННОЕ "chem", не "chemistry".
Тег learnable - как у остальных гейтованных рецептов мода, чтобы рецепт не светился в
меню до открытия группы.
ПОБОЧНОЕ СЛЕДСТВИЕ, замеченное заранее: химстанция добавляет камню ВТОРОЙ порог поверх
уровня 2000 - она открывается своим путём (перк/схема), с Некромантией не связанным.
Практически к 2000 уровню она у игрока почти наверняка есть, но формально «третий грейд»
перестаёт быть единственным условием. Ручка одна: убрать craft_area и вернуть личный
крафт.
БАЛАНСОВАЯ ЗАМЕТКА: слот у браслета один, значит камень с бесконечной прочностью не
дополняет Кровавую сферу, а ВЫТЕСНЯЕТ её в тот момент, когда игрок его получает. Судя по
формулировке («тот же флакон, но с бесконечной прочностью») это и задумано - камень это
эндгейм-версия расходника, уровень 2000 как раз про это. Записано, чтобы потом не
удивляться, что сфера перестала расходоваться. -->
<append xpath="/recipes">
<recipe name="resourceBloodStone" count="1" craft_area="chemistryStation" tags="learnable,chemStationCrafting,necroNecromancyApprentice">
<ingredient name="resourceZombieAsh" count="50"/>
<ingredient name="resourceBone" count="20"/>
<ingredient name="medicalBloodBag" count="4"/>
<ingredient name="resourceNecromancerBlood" count="1"/>
</recipe>
</append>
</config>