Волк: щелчок по сумке кладёт в ящик/мешок; Tab в волке открывает его сумку

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
AlexCube
2026-10-11 00:04:17 +03:00
co-authored by Claude Opus 5.5
parent 3aeeae04ae
commit d845fa1108
4 changed files with 115 additions and 2 deletions
+8
View File
@@ -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 ячейки); у тела - выгрузить сумку в рюкзак;
+21
View File
@@ -462,6 +462,27 @@ namespace NecromancerTome
{
return;
}
// Ячейка сумки волка (окно рюкзака при обыске) - в ящик или мешок (указание 10.10).
XUiC_Backpack bp = __instance.GetParentByType<XUiC_Backpack>();
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<XUiC_LootWindow>();
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<XUiC_LootContainer>() ?? __instance.GetParentByType<XUiC_BagContainer>();
if (grid == null)
+86 -2
View File
@@ -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();
}
/// <summary>Ячейку сумки - в ящик (щелчок по сумке в окне рюкзака при обыске, тест 10.10: «выложить в ящик не
/// получается - это неправильно»). Сперва в неполные стопки, остаток - в пустые ячейки; что не влезло -
/// остаётся в сумке.</summary>
public static bool PutTo(TEFeatureStorage _te, int _idx)
{
ItemStack[] g = _te.ItemGrid.items;
List<int> changed = new List<int>();
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;
}
/// <summary>То же в мешок с зомби.</summary>
public static bool PutTo(EntityLootContainer _dst, int _idx)
{
ItemStack[] g = _dst.bag.ItemGrid.items;
List<int> changed = new List<int>();
if (!Give(_idx, g, changed))
{
return false;
}
foreach (int i in changed)
{
_dst.bag.SetSlot(i, g[i].Clone());
}
_dst.OnBagModified();
return true;
}
/// <summary>Переложить ячейку сумки в массив ячеек контейнера (сами ячейки меняются, номера - в _changed).</summary>
static bool Give(int _idx, ItemStack[] _g, List<int> _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;
}
/// <summary>E на предмет, лежащий на земле, - в сумку (как игрок подбирает: что не влезло, остаётся лежать).
/// True - предмет перед волком был (взят или «сумка полна»).</summary>
public static bool TryPickup(World _world, EntityPlayerLocal _player, EntityAlive _wolf)
Binary file not shown.