Урна: «Содержимое» - родное окно хранилища игры с ячейкой на один череп

Своё окно с ячейкой коллектора не принимало череп ни перетаскиванием,
ни Shift+кликом. Теперь - XUiC_BagStorageWindowGroup (как сумка
транспорта и волка) с сумкой 1x1: перенос - кодом игры; после каждого
изменения в ячейке остаётся один череп, лишнее и чужое - в рюкзак.
Своё окно и группа из XUi удалены.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
AlexCube
2026-10-16 18:34:31 +03:00
co-authored by Claude Opus 5.5
parent e590fab082
commit 3ba6572bef
5 changed files with 90 additions and 80 deletions
-17
View File
@@ -208,21 +208,4 @@
<sprite depth="9" pos="0,20" height="8" color="[black]" sprite="menu_empty2px" globalopacitymod="0" type="sliced" fillcenter="false" />
<sprite depth="4" pos="0,20" height="8" width="750" color="150,60,220,200" globalopacitymod="0" type="filled" fill="{% cvar('necroNecromancyProgressCVar') / 20 }" />
</append>
<!-- «Багажник» урны-цинерария (1.7.0, 16.10, HarmonySrc/CinerariumTrunk.cs): одна ячейка под череп - та же
ячейка игры для обязательного предмета, что в панели модификаций коллектора росы (windowDewCollectorMods),
не больше одного черепа (override_stack_count). -->
<append xpath="/windows">
<window name="windowNecroCinerariumTrunk" width="228" height="121" panel="Right" cursor_area="true">
<rect style="header.panel">
<headerbg />
<sprite style="header.icon" sprite="ui_game_symbol_skull"/>
<label style="header.name.shrink" text_key="necroCinerariumTrunk" />
</rect>
<rect name="content" depth="0" pos="0,-46" height="75" disablefallthrough="true">
<grid name="inventory" rows="1" cols="1" pos="3,-3" depth="1" cell_width="75" cell_height="75" controller="NecromancerTome.XUiC_NecroCinerariumSkullGrid, NecromancerHarmony" repeat_content="true">
<item_stack controller="RequiredItemStack" name="0" override_stack_count="1"/>
</grid>
</rect>
</window>
</append>
</windows>
-6
View File
@@ -59,10 +59,4 @@
<window name="windowNonPagingHeader" />
</window_group>
</append>
<!-- «Багажник» урны-цинерария (1.7.0): ячейка черепа и рюкзак рядом, как у транспорта. -->
<append xpath="/xui">
<window_group name="necroCinerariumTrunk" open_backpack_on_open="true" close_compass_on_open="true">
<window name="windowNecroCinerariumTrunk" />
</window_group>
</append>
</xui>
+3 -3
View File
@@ -70,7 +70,7 @@ namespace NecromancerTome
base.OnRemove(_world);
RemoveBounds();
RemoveGenie(false);
XUiC_NecroCinerariumSkullGrid.CloseIfShowing(this);
CinerariumContents.CloseIfShowing(this);
if (!ConnectionManager.Instance.IsServer)
{
return;
@@ -96,7 +96,7 @@ namespace NecromancerTome
base.OnUnload(_world);
RemoveBounds();
RemoveGenie(false);
XUiC_NecroCinerariumSkullGrid.CloseIfShowing(this);
CinerariumContents.CloseIfShowing(this);
}
public override void Write(PooledBinaryWriter _bw, StreamModeWrite _eStreamMode)
@@ -602,7 +602,7 @@ namespace NecromancerTome
}
if (skull)
{
XUiC_NecroCinerariumSkullGrid.Open(_player, urn);
CinerariumContents.Open(_player, urn);
}
else if (repair)
{
+99 -66
View File
@@ -3,83 +3,116 @@ using UnityEngine;
namespace NecromancerTome
{
/// <summary>
/// «Багажник» урны-цинерария (решение 16.10: «урна как транспорт» - на E круговое меню, как у велосипеда:
/// багажник с ячейкой черепа и сумка духа). Окно necroCinerariumTrunk (Config/XUi_InGame) - панель с одной
/// ячейкой игры для обязательного предмета (XUiC_RequiredItemStack, как в панели модификаций коллектора
/// росы), рядом рюкзак (open_backpack_on_open). Ячейка принимает только череп и не больше одного
/// (override_stack_count="1" в XML). Череп - обычный предмет (ItemClass): в сейвах он уже есть, менять ему
/// класс на модификацию нельзя (см. память про сейвы), поэтому ячейка, а не сборка как у робомолота.
/// «Содержимое» урны-цинерария - ячейка черепа (решение 16.10: «урна как транспорт»; переименовано из «Багажника»).
/// Окно - родное окно хранилища игры (XUiC_BagStorageWindowGroup, как сумка транспорта и сумка волка) с сумкой на одну
/// ячейку: перетаскивание, Shift+клик и правый клик - кодом игры (16.10: «Сумки, ящики в игре есть» - своё окно с
/// ячейкой коллектора не принимало череп ни перетаскиванием, ни Shift+кликом). Своё здесь одно: после каждого изменения
/// в ячейке остаётся один череп, всё остальное (лишние черепа, чужие предметы) - назад в рюкзак, и урна узнаёт, есть ли
/// в ней череп. Череп - обычный предмет (ItemClass): он уже в сейвах, менять ему класс на модификацию нельзя.
/// </summary>
public class XUiC_NecroCinerariumSkullGrid : XUiC_ItemStackGrid
public static class CinerariumContents
{
public const string WindowGroup = "necroCinerariumTrunk";
public const string LootTemplate = "roboticDrone"; // звуки и время открытия, как у сумки волка
/// <summary>Урна, чей багажник открыт (ставится перед открытием окна).</summary>
public static TEFeatureCinerarium Urn;
static TEFeatureCinerarium _urn;
static Bag _bag;
static EntityPlayerLocal _player;
public static void Open(EntityPlayerLocal _player, TEFeatureCinerarium _urn)
public static void Open(EntityPlayerLocal _p, TEFeatureCinerarium _u)
{
LocalPlayerUI ui = _player?.PlayerUI;
if (ui == null || _urn == null)
{
return;
}
Urn = _urn;
ui.windowManager.Open(WindowGroup, true);
}
public override void OnOpen()
{
base.OnOpen();
LocalPlayerUI ui = _p != null ? LocalPlayerUI.GetUIForPlayer(_p) : null;
ItemValue skull = ItemClass.GetItem(TEFeatureCinerarium.SkullItemName);
for (int i = 0; i < itemControllers.Length; i++)
{
if (itemControllers[i] is XUiC_RequiredItemStack slot)
{
slot.SetAllowedItemClassSingle(TEFeatureCinerarium.SkullItemName);
slot.RequiredItemOnly = true;
slot.StackLocation = XUiC_ItemStack.StackLocationTypes.Workstation;
}
}
ItemStack[] stacks = new ItemStack[itemControllers.Length];
for (int i = 0; i < stacks.Length; i++)
{
stacks[i] = ItemStack.Empty.Clone();
}
if (stacks.Length > 0 && Urn != null && Urn.HasSkull && skull != null && skull.type > 0)
{
stacks[0] = new ItemStack(skull, 1);
}
SetStacks(stacks);
}
public override void OnClose()
{
base.OnClose();
Urn = null;
}
public override void UpdateBackend(ItemStack[] stackList)
{
base.UpdateBackend(stackList);
bool has = stackList != null && stackList.Length > 0 && stackList[0] != null && !stackList[0].IsEmpty();
Urn?.SetSkull(has);
}
/// <summary>Урна убрана или выгружена, пока открыт её багажник, - закрыть окно (иначе череп в ячейке
/// уже ни к чему не привязан).</summary>
public static void CloseIfShowing(TEFeatureCinerarium _urn)
{
if (Urn == null || Urn != _urn)
if (ui == null || _u == null)
{
return;
}
LocalPlayerUI ui = GameManager.Instance?.World?.GetPrimaryPlayer()?.PlayerUI;
if (ui != null && ui.windowManager.IsWindowOpen(WindowGroup))
_urn = _u;
_player = _p;
_bag = new Bag(new Vector2i(1, 1), XUiC_ItemStack.StackLocationTypes.LootContainer, null);
if (_u.HasSkull && skull != null && skull.type > 0)
{
ui.windowManager.Close(WindowGroup);
_bag.SetSlot(0, new ItemStack(skull, 1));
}
XUiC_BagStorageWindowGroup.Open(ui.xui, _p, _bag, LootContainer.GetLootContainer(LootTemplate),
Localization.Get("necroCinerariumTrunk"), Check, () =>
{
Check();
_urn = null;
_bag = null;
_player = null;
});
Debug.Log("[NecromancerTome] Cinerarium: «Содержимое» урны " + _u.ToWorldPos() + " открыто, череп " + (_u.HasSkull ? "есть" : "нет"));
}
/// <summary>Оставить в ячейке один череп, остальное - игроку; отметить в урне.</summary>
static void Check()
{
if (_bag == null || _urn == null)
{
return;
}
ItemStack s = _bag.ItemGrid.items[0];
bool has = false;
if (s != null && !s.IsEmpty())
{
ItemStack back = null;
if (s.itemValue.ItemClass?.GetItemName() != TEFeatureCinerarium.SkullItemName)
{
back = s.Clone();
_bag.SetSlot(0, ItemStack.Empty.Clone());
}
else
{
has = true;
if (s.count > 1)
{
back = s.Clone();
back.count = s.count - 1;
ItemStack one = s.Clone();
one.count = 1;
_bag.SetSlot(0, one);
}
}
if (back != null)
{
GiveBack(back);
}
}
_urn.SetSkull(has);
}
static void GiveBack(ItemStack _s)
{
if (_player == null)
{
return;
}
if (_player.bag != null && _player.bag.AddItem(_s))
{
return;
}
if (_player.inventory != null && _player.inventory.AddItem(_s))
{
return;
}
_player.world.gameManager.ItemDropServer(_s, _player.GetPosition(), Vector3.zero);
}
/// <summary>Урна убрана или выгружена, пока открыто её «Содержимое», - закрыть окно (череп из ячейки не потеряется:
/// Check успеет отметить его в урне, а урна при разрушении роняет череп).</summary>
public static void CloseIfShowing(TEFeatureCinerarium _u)
{
if (_urn == null || _urn != _u)
{
return;
}
Check();
LocalPlayerUI ui = _player != null ? LocalPlayerUI.GetUIForPlayer(_player) : null;
_urn = null;
if (ui != null && ui.windowManager.IsWindowOpen(XUiC_BagStorageWindowGroup.ID))
{
ui.windowManager.Close(XUiC_BagStorageWindowGroup.ID);
}
Urn = null;
}
}
}
Binary file not shown.