Кровавый камень: бесконечный заряд браслета
Эндгейм-версия расходника Пространственного браслета: то же место в слоте, что у
Кровавой сферы, но не тратится вовсе. Кода менять не пришлось - только конфиги.
ЗАОДНО ЭТО ПОЧИНКА УЖЕ ОТГРУЖЕННОГО ТЕКСТА. Сообщение о пустом слоте
(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:
co-authored by
Claude Opus 5
parent
896501dcd8
commit
5a512260cc
File diff suppressed because one or more lines are too long
@@ -423,4 +423,98 @@
|
||||
<property name="SellableToTrader" value="false"/>
|
||||
</item_modifier>
|
||||
</append>
|
||||
|
||||
<!-- КРОВАВЫЙ КАМЕНЬ (Blood Stone), продиктовано 2026-09-15, сделано 2026-09-16: «По сути это
|
||||
будет тот же флакон, но с бесконечной прочностью и иконкой камня с алым тинтом.»
|
||||
Эндгейм-версия расходника браслета: то же, что Кровавая сфера, только не тратится.
|
||||
|
||||
ПОЧЕМУ ЭТО БЫЛО СРОЧНО, А НЕ «ФИЧА ИЗ СПИСКА». Сообщение о пустом слоте
|
||||
(braceletSpatialVaultNoMod) и описание браслета с 15.09 обещают игроку «кровавую сферу
|
||||
ИЛИ кровавый камень» на всех 13 языках. Пока камня не было, отгруженный текст отправлял
|
||||
за предметом, которого в игре нет. Так что эта правка - ещё и починка текста.
|
||||
|
||||
ПОЧЕМУ ЭТО БЕЗОПАСНО ДЛЯ СЕЙВОВ, и это здесь главный вопрос, а не побочный.
|
||||
15.09 перенос Крови некроманта из items.xml сюда уничтожил персонажа в сейве: ItemValue
|
||||
гейтит блок модификаций одним условием на чтении (Read, ~1094) и на записи (Write, ~1228)
|
||||
- "!(itemClass is ItemClassModifier)", то есть КЛАСС ПРЕДМЕТА ОПРЕДЕЛЯЕТ БАЙТОВУЮ
|
||||
РАСКЛАДКУ КАЖДОГО ЕГО СТАКА В СЕЙВЕ. Обычный предмет пишет байт "сколько модификаций",
|
||||
ItemClassModifier не пишет ничего; после переезда читатель этот байт пропустил, поток
|
||||
съехал, ближайший ReadString() упал, и .ttp с .ttp.bak умерли оба.
|
||||
resourceBloodStone - НОВОЕ имя. В сейвах, записанных до этой правки, нет ни одного его
|
||||
стака, значит нет и ни одной записи, которую пришлось бы читать по другой раскладке.
|
||||
Именно поэтому камень заведён новым предметом, а не переводом уже существующего - тем же
|
||||
решением, что и Кровавая сфера. Правило целиком: раздел про аварию в BACKLOG.md.
|
||||
|
||||
Атрибуты - по образцу сферы:
|
||||
- installable_tags="necroBracelet" - обязательно. У CanSwap есть короткое замыкание
|
||||
"InstallableTags.IsEmpty || ...", то есть модификация БЕЗ этого атрибута лезет в любой
|
||||
предмет игры.
|
||||
- modifier_tags СВОЙ (necroBraceletStone, не ...Sphere). Мод с совпадающим modifier_tags
|
||||
считается против ItemClass.MaxModsAllowed - разбор в шапке этого файла. Слот у
|
||||
браслета сейчас один, так что практической разницы нет, но правило "свой тег на
|
||||
каждую модификацию" в моде записано, и ломать его незачем.
|
||||
- blocked_tags НЕ задаётся: у браслета в тегах noMods, отрицательную половину он
|
||||
обеспечивает сам.
|
||||
-->
|
||||
<append xpath="/item_modifiers">
|
||||
<item_modifier name="resourceBloodStone" installable_tags="necroBracelet" modifier_tags="necroBraceletStone" type="attachment">
|
||||
<!-- Та же база, что у сферы и у шести модов ножа: Group "Mods", звуки
|
||||
mod_grab/mod_place, Stacknumber 1, CreativeMode None. param1="CustomIcon"
|
||||
исключает наследование родительского missingIcon.
|
||||
НЕ наследовать resourceRockSmall ради вида камня: вместе с видом приедут
|
||||
Action0 Class="ThrowAway", ThrowableDecoy="true" и DistractionTags, то есть
|
||||
камень можно будет метать как отвлекающий. Меш берётся строками ниже. На сфере
|
||||
эта ошибка уже была и была исправлена 15.09. -->
|
||||
<property name="Extends" value="modGeneralMaster" param1="CustomIcon"/>
|
||||
<property name="DescriptionKey" value="resourceBloodStoneDesc"/>
|
||||
|
||||
<!-- В РУКЕ - КАМЕНЬ С АЛЫМ ТИНТОМ (указание 2026-09-15: «в руке и сфера и кровавый
|
||||
камень пусть будут как камень с алым тинтом»). Набор скопирован со сферы, а та -
|
||||
с трёх камней мода (Камень духов, Синий и Чёрный порталы), которые на этом же
|
||||
меше с этим же тинтом в игре видны зелёным, синим и чёрным.
|
||||
|
||||
Три меша, а не один, потому что это три разные ситуации: Meshfile общий,
|
||||
HandMeshfile в руке, DropMeshfile лежащим на земле.
|
||||
|
||||
TintColor - ТРИПЛЕТ "R, G, B", а не hex; hex берёт CustomIconTint, и это другая
|
||||
ручка (Color32 через запятые против ParseHexColor). Перепутать легко, на модах
|
||||
ножа это уже стоило круга. -->
|
||||
<property name="HoldType" value="40"/>
|
||||
<property name="Meshfile" value="@:Other/Items/Crafting/rock_smallPrefab.prefab"/>
|
||||
<property name="HandMeshfile" value="@:Other/Items/Crafting/rock_smallPrefab.prefab"/>
|
||||
<property name="DropMeshfile" value="@:Other/Items/Crafting/rock_smallPrefab.prefab"/>
|
||||
<property name="TintColor" value="220, 30, 45"/>
|
||||
|
||||
<!-- Своя рисованная иконка, лежит с 15.09 в обеих папках атласа
|
||||
(UIAtlases/ItemIconAtlas/BloodStone.png + ItemIconAtlasGreyscale/BloodStone.png).
|
||||
Серая копия обязательна: заблокированная запись в панели скилла рисуется из
|
||||
greyscale-атласа, без неё у записи не было бы картинки вообще.
|
||||
CustomIconTint НЕ ЗАДАЁТСЯ - тинт нужен заимствованным ванильным спрайтам, на
|
||||
готовой работе он бы её просто затемнил. Тот же принцип, что у сферы. -->
|
||||
<property name="CustomIcon" value="BloodStone"/>
|
||||
|
||||
<!-- БЕСКОНЕЧНАЯ ПРОЧНОСТЬ СДЕЛАНА ОТСУТСТВИЕМ СТРОК, А НЕ БОЛЬШИМ ЧИСЛОМ.
|
||||
Здесь СОЗНАТЕЛЬНО нет ни ShowQuality, ни DegradationBreaksAfter, ни effect_group
|
||||
с DegradationMax - сравнить со сферой выше, у которой все три есть.
|
||||
|
||||
Почему этого достаточно: SpendCharge (HarmonySrc/SpatialVaultPickupPatch.cs)
|
||||
списывает прочность ТОЛЬКО у модификации, чьё имя совпадает с ChargeItemName
|
||||
("resourceBloodSphere"). Камень под это условие не попадает по определению -
|
||||
цикл делает continue, UseTimes камня не трогает никто и никогда. Кода менять не
|
||||
пришлось вообще; комментарий в SpendCharge это заранее и обещает («a mod that is
|
||||
not the charge pays nothing, is not emptied, and the pull still happens»).
|
||||
|
||||
Почему НЕ выставлять огромный DegradationMax: полоска прочности, которая никогда
|
||||
не двигается, хуже её отсутствия. Плюс ловушка, уже разобранная на флаконе крови:
|
||||
при MaxUseTimes == 0 полоска рисуется ПОЛНОЙ, то есть забытая пассивка выглядит
|
||||
как "всё работает".
|
||||
|
||||
Тег necroBloodFlask здесь тоже не нужен, но уже по другой причине, чем было
|
||||
записано в спеке: после полного отката Крови некроманта (15.09) этого тега в моде
|
||||
не осталось совсем - он существовал только чтобы гейтить пассивку прочности
|
||||
флакона. Пункт снят сам собой. -->
|
||||
<property name="EconomicValue" value="0"/>
|
||||
<property name="SellableToTrader" value="false"/>
|
||||
</item_modifier>
|
||||
</append>
|
||||
</config>
|
||||
|
||||
+12
-1
@@ -163,7 +163,18 @@
|
||||
<unlock_entry item="necroModKnifeDeadStorm" unlock_tier="3"/>
|
||||
</display_entry>
|
||||
<display_entry icon="SummonZombieDog" name_key="craftingNecroNecromancyTier3Name" has_quality="false" unlock_level="2000">
|
||||
<unlock_entry item="bookSummonZombieDog,bookSummonInsectSwarm,bookSummonZombieGriffin" unlock_tier="1"/>
|
||||
<!-- resourceBloodStone добавлен 2026-09-16 (указание «доступен на третьем грейде
|
||||
некромантии, в самом его начале»). Тир 3 - это и есть третий грейд, группа
|
||||
«Ученик», а его единственный unlock_level равен 2000, то есть unlock_tier="1"
|
||||
здесь и означает «в самом начале грейда, без своего смещения».
|
||||
|
||||
ЭТА СТРОКА - ТОЛЬКО ОТОБРАЖЕНИЕ. Открытие рецепта делает тег
|
||||
necroNecromancyApprentice в recipes.xml вместе с RecipeTagUnlocked
|
||||
level="2000,5000" ниже; display_entry о тегах не знает и рисует замок сам по
|
||||
себе, по unlock_tier. Поэтому 2000 здесь и 2000 там ОБЯЗАНЫ совпадать -
|
||||
иначе замок на панели разойдётся с реальной доступностью рецепта. Совпадают:
|
||||
один порог, одно значение. -->
|
||||
<unlock_entry item="bookSummonZombieDog,bookSummonInsectSwarm,bookSummonZombieGriffin,resourceBloodStone" unlock_tier="1"/>
|
||||
</display_entry>
|
||||
<display_entry icon="SummonZombieBear" name_key="craftingNecroNecromancyTier4Name" has_quality="false" unlock_level="3000">
|
||||
<unlock_entry item="bookSummonZombieBear,bookSummonZombieWolf,bookBanshee" unlock_tier="1"/>
|
||||
|
||||
@@ -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>
|
||||
|
||||
Reference in New Issue
Block a user