diff --git a/HarmonySrc/BloodTide.cs b/HarmonySrc/BloodTide.cs index 8ca0e20..ff55447 100644 --- a/HarmonySrc/BloodTide.cs +++ b/HarmonySrc/BloodTide.cs @@ -57,6 +57,7 @@ namespace NecromancerTome { Active = Armed = false; _swapped = false; // классы предметов игра грузит заново с миром + _recreate = false; _origHoldType = -1; Heart(false); Patch_XUiC_HUDStatBar_Update_BloodTide.Forget(); @@ -70,6 +71,7 @@ namespace NecromancerTome Debug.Log("[NecromancerTome] BloodTide: " + (tide ? "прилив начался" : "прилив схлынул")); } SwapKnife(player, Active); + TryRecreate(player); if (Time.time >= _nextBuffCheck && !player.IsDead()) { _nextBuffCheck = Time.time + 0.5f; @@ -108,20 +110,82 @@ namespace NecromancerTome knife.HoldType.Value = _tide ? TideHoldType : _origHoldType; knife.MeshFile = _tide && !string.IsNullOrEmpty(TideMeshFile) ? TideMeshFile : _origMesh; _swapped = _tide; - Inventory inv = _player.inventory; - ItemInventoryData held = inv?.holdingItemData; - if (held != null && held.item == knife) + Hand hand = _player.Hand; + // Ножи в других слотах пояса: «собранная» копия помечается устаревшей - соберутся заново (с новыми хватом и + // моделью), когда их возьмут. Нож в руке - в TryRecreate, когда рука свободна. + if (hand?.slotDatas != null) { - // NeedsRebuild - «собранный» предмет не совпадает с тем, что в слоте: сбрасываем собранный, и - // повторный выбор того же слота снимает нож и собирает его заново (Hand.SelectHoldingMode). - // Не ItemValue.None (тест 10.10: NRE в Hand.Unequip - он читает класс предмета у собранного): копия того же - // ножа с другим Seed - класс прежний, а EqualsExceptUseTimesAndMeta (по нему NeedsRebuild) уже не совпадёт. - ItemValue pv = (held.physicalItemValue ?? held.itemValue).Clone(); - pv.Seed = (ushort)(pv.Seed + 1); - held.physicalItemValue = pv; - inv.SetHoldingItemIdx(inv.holdingItemIdx); + foreach (ItemInventoryData d in hand.slotDatas) + { + if (d != null && d.item == knife && d != hand.equipped && d.physicalItemValue != null) + { + MarkStale(d); + } + } + } + _recreate = true; + Debug.Log("[NecromancerTome] BloodTide: нож - хват " + knife.HoldType.Value); + } + + /// Нож в руке ждёт пересоздания (сменились хват/модель). + static bool _recreate; + + /// «Собранный» предмет перестаёт совпадать со слотом (NeedsRebuild): копия того же ножа с другим Seed. + /// Не ItemValue.None (тест 10.10): Hand.Unequip читает класс предмета у собранного - NRE. + static void MarkStale(ItemInventoryData _d) + { + ItemValue pv = (_d.physicalItemValue ?? _d.itemValue).Clone(); + pv.Seed = (ushort)(pv.Seed + 1); + _d.physicalItemValue = pv; + } + + /// + /// Пересоздать нож в руке: повторный выбор того же слота снимает его и собирает заново (Hand.SelectHoldingMode). + /// Только когда рука свободна - не идёт смена предмета и удар; иначе ждём кадр. Тест 10.10: при сбое внутри + /// SelectHoldingMode игра оставляла Hand.isSwitching = true навсегда, и рука переставала брать что-либо до + /// перезапуска («после ошибки не получается переключиться на что-либо ещё»). Поэтому сбой перехватываем и + /// возвращаем руку в рабочее состояние. + /// + static void TryRecreate(EntityPlayerLocal _player) + { + if (!_recreate) + { + return; + } + Inventory inv = _player.inventory; + Hand hand = _player.Hand; + ItemInventoryData held = inv?.holdingItemData; + if (hand == null || held == null || !SnakeMode.IsKnife(held.item)) + { + _recreate = false; // ножа в руке нет - возьмут, тогда и соберётся (слоты помечены) + return; + } + if (hand.isSwitching || inv.IsHoldingItemActionRunning() || _player.IsDead()) + { + return; + } + _recreate = false; + ItemValue before = held.physicalItemValue; + try + { + MarkStale(held); + inv.SetHoldingItemIdx(inv.holdingItemIdx); + Debug.Log("[NecromancerTome] BloodTide: нож в руке пересоздан, хват " + held.item.HoldType.Value); + } + catch (System.Exception ex) + { + Debug.LogWarning("[NecromancerTome] BloodTide: нож не пересоздан - " + ex.Message + "; рука восстановлена"); + held.physicalItemValue = before; + hand.isSwitching = false; + try + { + hand.Reconcile(); + } + catch (System.Exception ex2) + { + Debug.LogWarning("[NecromancerTome] BloodTide: Reconcile - " + ex2.Message); + } } - Debug.Log("[NecromancerTome] BloodTide: нож - хват " + knife.HoldType.Value + (held != null && held.item == knife ? ", в руке пересоздан" : "")); } // ---------------------------------------------------------------- сердце diff --git a/NecromancerHarmony.dll b/NecromancerHarmony.dll index ff023db..6de571a 100644 Binary files a/NecromancerHarmony.dll and b/NecromancerHarmony.dll differ diff --git a/NecromancerHarmony.pdb b/NecromancerHarmony.pdb index 7863f6f..18568ce 100644 Binary files a/NecromancerHarmony.pdb and b/NecromancerHarmony.pdb differ