diff --git a/HarmonySrc/Possession.cs b/HarmonySrc/Possession.cs index 832b11e..b8ed5e2 100644 --- a/HarmonySrc/Possession.cs +++ b/HarmonySrc/Possession.cs @@ -662,6 +662,14 @@ namespace NecromancerTome } if (IsPet && WolfControl.Is(z)) { + // Tab в волке - окно его сумки, а не рюкзак персонажа (тест 10.10: «в волке Tab - вижу сумку игрока»). + GUIWindowManager wm = LocalPlayerUI.GetUIForPlayer(_player)?.windowManager; + if (wm != null && wm.IsWindowOpen("windowpaging") && !WolfBag.WindowOpen && !RatLoot.Viewing) + { + wm.CloseAllOpenModalWindows(); + wm.Close("windowpaging"); + WolfBag.OpenWindow(_player, z); + } // ПКМ - бросок на цель, след крови раненых (решено 09.10). WolfControl.Tick(world, _player, z, ranged, ref _bodyYaw); // E: на контейнер или мешок с зомби - лутать в сумку (3 ячейки); у тела - выгрузить сумку в рюкзак; diff --git a/HarmonySrc/RatLoot.cs b/HarmonySrc/RatLoot.cs index 2f22183..0723ba3 100644 --- a/HarmonySrc/RatLoot.cs +++ b/HarmonySrc/RatLoot.cs @@ -462,6 +462,27 @@ namespace NecromancerTome { return; } + // Ячейка сумки волка (окно рюкзака при обыске) - в ящик или мешок (указание 10.10). + XUiC_Backpack bp = __instance.GetParentByType(); + if (bp != null) + { + CursorControllerAbs c = __instance.xui.playerUI.CursorController; + if (WolfBagBackpack.On && (c.GetMouseButtonDown(UICamera.MouseButton.LeftButton) || c.GetMouseButtonDown(UICamera.MouseButton.RightButton))) + { + int bi = bp.itemControllers != null ? System.Array.IndexOf(bp.itemControllers, __instance) : -1; + XUiC_LootWindow lw = __instance.xui.GetChildByType(); + TEFeatureStorage dst = lw != null && lw.ViewComponent.IsVisible ? lw.te : null; + if (bi >= 0 && dst != null) + { + WolfBag.PutTo(dst, bi); + } + else if (bi >= 0 && _viewBag != null) + { + WolfBag.PutTo(_viewBag, bi); + } + } + return; + } // Ячейка контейнера-блока (XUiC_LootContainer) или мешка (XUiC_BagContainer), не рюкзака. XUiC_ItemStackGrid grid = (XUiC_ItemStackGrid)__instance.GetParentByType() ?? __instance.GetParentByType(); if (grid == null) diff --git a/HarmonySrc/WolfBag.cs b/HarmonySrc/WolfBag.cs index 06eecd8..aa01bed 100644 --- a/HarmonySrc/WolfBag.cs +++ b/HarmonySrc/WolfBag.cs @@ -19,8 +19,9 @@ namespace NecromancerTome /// - мешки с зомби волк лутает так же, как ящики (RatLoot, TakeFrom(EntityLootContainer)); /// - тест 10.10: «волк - это ещё одно пространственное хранилище: берёт игрок, но положить может только в эти /// 3 ячейки» - при обыске рядом с ящиком окно рюкзака показывает сумку волка (WolfBagBackpack: первые 3 - /// ячейки, остальные скрыты, ячейки заперты - перекладка щелчком по ящику), а E на предмет на земле - /// кладёт его в сумку (TryPickup). + /// ячейки, остальные скрыты, ячейки заперты - перекладка щелчком: по ящику - в сумку, по сумке - в ящик, + /// PutTo), E на предмет на земле кладёт его в сумку (TryPickup), Tab в волке - окно сумки, не рюкзак + /// персонажа (Possession: windowpaging закрывается). /// /// ХРАНЕНИЕ. Сумку сущности игра не сохраняет (Entity.bag нет в Entity.Write), поэтому она своя. /// Упаковка - та же, что у пространственного хранилища (SpatialVaultPersistence.BuildPayload/ParsePayload, @@ -191,6 +192,89 @@ namespace NecromancerTome return rest.count > 0 ? rest : ItemStack.Empty.Clone(); } + /// Ячейку сумки - в ящик (щелчок по сумке в окне рюкзака при обыске, тест 10.10: «выложить в ящик не + /// получается - это неправильно»). Сперва в неполные стопки, остаток - в пустые ячейки; что не влезло - + /// остаётся в сумке. + public static bool PutTo(TEFeatureStorage _te, int _idx) + { + ItemStack[] g = _te.ItemGrid.items; + List changed = new List(); + if (!Give(_idx, g, changed)) + { + return false; + } + foreach (int i in changed) + { + _te.UpdateSlot(i, g[i].Clone()); + } + _te.SetModified(); + _te.Parent?.NotifyListeners(); + return true; + } + + /// То же в мешок с зомби. + public static bool PutTo(EntityLootContainer _dst, int _idx) + { + ItemStack[] g = _dst.bag.ItemGrid.items; + List changed = new List(); + if (!Give(_idx, g, changed)) + { + return false; + } + foreach (int i in changed) + { + _dst.bag.SetSlot(i, g[i].Clone()); + } + _dst.OnBagModified(); + return true; + } + + /// Переложить ячейку сумки в массив ячеек контейнера (сами ячейки меняются, номера - в _changed). + static bool Give(int _idx, ItemStack[] _g, List _changed) + { + Bag b = Get(); + ItemStack src = _idx < b.SlotCount ? b.ItemGrid.items[_idx] : null; + if (src == null || src.IsEmpty()) + { + return false; + } + int left = src.count; + int max = src.itemValue.ItemClass?.Stacknumber.Value ?? 1; + for (int i = 0; i < _g.Length && left > 0 && max > 1; i++) + { + if (_g[i] != null && !_g[i].IsEmpty() && _g[i].itemValue.type == src.itemValue.type && _g[i].count < max) + { + int n = Mathf.Min(left, max - _g[i].count); + _g[i] = _g[i].Clone(); + _g[i].count += n; + left -= n; + _changed.Add(i); + } + } + for (int i = 0; i < _g.Length && left > 0; i++) + { + if (_g[i] == null || _g[i].IsEmpty()) + { + _g[i] = new ItemStack(src.itemValue.Clone(), left); + left = 0; + _changed.Add(i); + } + } + int moved = src.count - left; + if (moved <= 0) + { + Audio.Manager.PlayInsidePlayerHead("ui_denied"); + return false; + } + ItemStack rest = src.Clone(); + rest.count = left; + b.SetSlot(_idx, left > 0 ? rest : ItemStack.Empty.Clone()); + Save(); + Audio.Manager.PlayInsidePlayerHead("UseActions/takeall1"); + Debug.Log("[NecromancerTome] WolfBag: из сумки в контейнер " + src.itemValue.ItemClass.GetItemName() + " x" + moved + " - " + Describe()); + return true; + } + /// E на предмет, лежащий на земле, - в сумку (как игрок подбирает: что не влезло, остаётся лежать). /// True - предмет перед волком был (взят или «сумка полна»). public static bool TryPickup(World _world, EntityPlayerLocal _player, EntityAlive _wolf) diff --git a/NecromancerHarmony.dll b/NecromancerHarmony.dll index ff13edc..eeeaf9f 100644 Binary files a/NecromancerHarmony.dll and b/NecromancerHarmony.dll differ