using System.Collections.Generic;
using GUI_2;
using HarmonyLib;
using UnityEngine;
using UnityEngine.Scripting;
namespace NecromancerTome
{
///
/// Урна логиста - латунное кадило (18.10.2026, BACKLOG «Урна логиста - своя модель: кадило»): два вида - на подставке по
/// центру клетки (necroCinerariumLogist) и на кронштейне у стены (necroCinerariumLogistWall). Пользователь: «Должна быть
/// возможность крепить её и к стене, и по центру какого-нибудь столба... как мы делали с черепом. Только череп у нас изначально
/// не блок, а тут должно получиться попроще». Вид выбирается, как у черепа-декора: урна в руке, R - меню блока игры, к нему
/// добавлен второй вид; выбор превращает стопку в ячейке пояса в другой блок (тот же счёт). Пустая урна и урна с черепом -
/// каждая в свой вид того же рода.
///
public static class CinerariumLogistForm
{
/// Номера наших пунктов в меню блока - вне занятых игрой (-2..10) и черепом (40..42).
public const int MenuCenter = 43, MenuWall = 44;
static readonly Dictionary Pairs = new Dictionary
{
{ TEFeatureCinerarium.LogistBlockName, (TEFeatureCinerarium.LogistBlockName, TEFeatureCinerarium.LogistWallBlockName) },
{ TEFeatureCinerarium.LogistWallBlockName, (TEFeatureCinerarium.LogistBlockName, TEFeatureCinerarium.LogistWallBlockName) },
{ TEFeatureCinerarium.LogistSkullBlockName, (TEFeatureCinerarium.LogistSkullBlockName, TEFeatureCinerarium.LogistWallSkullBlockName) },
{ TEFeatureCinerarium.LogistWallSkullBlockName, (TEFeatureCinerarium.LogistSkullBlockName, TEFeatureCinerarium.LogistWallSkullBlockName) },
};
public static bool IsLogistItem(ItemClass _item) => _item != null && Pairs.ContainsKey(_item.Name);
static void Convert(EntityPlayerLocal _pl, bool _wall)
{
ItemStack cur = _pl?.inventory?.holdingItemStack;
if (cur == null || cur.IsEmpty() || !Pairs.TryGetValue(cur.itemValue.ItemClass.Name, out var pair))
{
return;
}
string name = _wall ? pair.wall : pair.center;
if (cur.itemValue.ItemClass.Name == name)
{
return;
}
ItemValue iv = ItemClass.GetItem(name);
if (iv == null || iv.IsEmpty())
{
return;
}
_pl.inventory.SetItem(_pl.inventory.holdingItemIdx, new ItemStack(iv, cur.count));
}
public static void OnBlockMenu(XUiC_Radial _sender, int _commandIndex, XUiC_Radial.RadialContextAbs _context)
{
EntityPlayerLocal pl = _sender?.xui?.playerUI?.entityPlayer;
switch (_commandIndex)
{
case MenuCenter: Convert(pl, false); return;
case MenuWall: Convert(pl, true); return;
}
_sender.handleBlockShapeCommand(_sender, _commandIndex, _context);
}
}
/// Меню блока с урной логиста в руке: к пунктам игры - второй вид (подставка / у стены).
[HarmonyPatch(typeof(XUiC_Radial), nameof(XUiC_Radial.SetupBlockShapeData))]
public static class Patch_XUiC_Radial_SetupBlockShapeData_LogistForm
{
public static void Postfix(XUiC_Radial __instance)
{
EntityPlayerLocal pl = __instance.xui?.playerUI?.entityPlayer;
ItemClass held = pl?.inventory?.holdingItem;
if (!CinerariumLogistForm.IsLogistItem(held))
{
return;
}
bool wall = held.Name == TEFeatureCinerarium.LogistWallBlockName || held.Name == TEFeatureCinerarium.LogistWallSkullBlockName;
if (wall)
{
__instance.CreateRadialEntry(CinerariumLogistForm.MenuCenter, TEFeatureCinerarium.LogistBlockName, "ItemIconAtlas", "", Localization.Get("necroCinerariumLogistFormCenter"));
}
else
{
__instance.CreateRadialEntry(CinerariumLogistForm.MenuWall, TEFeatureCinerarium.LogistWallBlockName, "ItemIconAtlas", "", Localization.Get("necroCinerariumLogistFormWall"));
}
__instance.SetCommonData(UIUtils.GetButtonIconForAction(__instance.xui.playerUI.playerInput.Activate), CinerariumLogistForm.OnBlockMenu,
new XUiC_Radial.RadialContextHoldingSlotIndex(pl.inventory.holdingItemIdx), -1, true, XUiC_Radial.RadialValidSameHoldingSlotIndex);
Debug.Log("[NecromancerTome] LogistForm: меню блока - " + held.Name + ", пунктов " + __instance.currentEnabledEntriesCount());
}
}
/// Диагностика #77 (23.10.2026: «зажимаю R - меню не открывается, только поворот»): на нажатие R с урной-логистом в
/// руке - что видит игра (блок ли в руке, не считает ли предмет оружием). Убрать, когда причина найдена.
[HarmonyPatch(typeof(PlayerMoveController), nameof(PlayerMoveController.Update))]
public static class Patch_PlayerMoveController_Update_LogistFormDiag
{
public static void Postfix(PlayerMoveController __instance)
{
EntityPlayerLocal pl = __instance.entityPlayerLocal;
PlayerActionsLocal inp = __instance.playerInput;
if (pl?.inventory == null || inp == null || !CinerariumLogistForm.IsLogistItem(pl.inventory.holdingItem) ||
!(inp.Reload.WasPressed || inp.PermanentActions.Reload.WasPressed))
{
return;
}
XUiC_Radial r = __instance.playerUI?.xui?.RadialWindow;
Debug.Log("[NecromancerTome] LogistForm: R - " + pl.inventory.holdingItem.Name + ", блок " + (pl.inventory.GetHoldingBlock() != null) +
", оружие " + pl.inventory.IsHoldingGun() + "/" + pl.inventory.IsHoldingDynamicMelee() + ", смена руки " + pl.inventory.IsHandSwitching() +
", меню " + (r != null && r.IsOpen) + ", модальное " + (__instance.playerUI?.windowManager?.IsModalWindowOpen() ?? false));
}
}
/// Мигание урны логиста, когда класть некуда (18.10: «При застревании должно мигать»): свечение модели
/// (MaterialPropertyBlock, как у TEFeatureCinerarium.SyncGlow) пульсирует от тёмного до обычного. Выключено - обычное свечение.
[Preserve]
public class CinerariumBlink : MonoBehaviour
{
public List Renderers = new List();
public static float Period = 0.8f;
static readonly MaterialPropertyBlock _block = new MaterialPropertyBlock();
static readonly int EmissionColorId = Shader.PropertyToID("_EmissionColor");
void Update()
{
// Резкий переход - мигание, а не дыхание: половину периода горит, половину почти погасла.
float k = Mathf.Repeat(Time.time, Period) < Period * 0.5f ? 1f : 0.08f;
Set(TEFeatureCinerarium.GlowColor * k);
}
void OnDisable()
{
Set(TEFeatureCinerarium.GlowColor);
}
void Set(Color _c)
{
foreach (Renderer r in Renderers)
{
if (r == null)
{
continue;
}
r.GetPropertyBlock(_block);
_block.SetColor(EmissionColorId, _c);
r.SetPropertyBlock(_block);
}
}
}
}