Files
necromants-tome-7d2d-3-2/HarmonySrc/CinerariumLogist.cs
T
AlexCubeandClaude Opus 5.5 ce4752a04e Питомец дальше 100 блоков после одержимости - сразу отозван (#35); диагностика R у логиста (#77)
PetFarRecall: при выходе из одержимости питомцем - отзыв как книгой, если до тела хозяина дальше
порога; ближе - идёт своим ходом. Консоль: necropetfar <блоки>|off.
Логист: строки LogistForm в логе на нажатие R и на сборку меню блока - временно, до причины #77.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-23 12:39:19 +03:00

149 lines
7.3 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
using System.Collections.Generic;
using GUI_2;
using HarmonyLib;
using UnityEngine;
using UnityEngine.Scripting;
namespace NecromancerTome
{
/// <summary>
/// Урна логиста - латунное кадило (18.10.2026, BACKLOG «Урна логиста - своя модель: кадило»): два вида - на подставке по
/// центру клетки (necroCinerariumLogist) и на кронштейне у стены (necroCinerariumLogistWall). Пользователь: «Должна быть
/// возможность крепить её и к стене, и по центру какого-нибудь столба... как мы делали с черепом. Только череп у нас изначально
/// не блок, а тут должно получиться попроще». Вид выбирается, как у черепа-декора: урна в руке, R - меню блока игры, к нему
/// добавлен второй вид; выбор превращает стопку в ячейке пояса в другой блок (тот же счёт). Пустая урна и урна с черепом -
/// каждая в свой вид того же рода.
/// </summary>
public static class CinerariumLogistForm
{
/// <summary>Номера наших пунктов в меню блока - вне занятых игрой (-2..10) и черепом (40..42).</summary>
public const int MenuCenter = 43, MenuWall = 44;
static readonly Dictionary<string, (string center, string wall)> Pairs = new Dictionary<string, (string, string)>
{
{ 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);
}
}
/// <summary>Меню блока с урной логиста в руке: к пунктам игры - второй вид (подставка / у стены).</summary>
[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());
}
}
/// <summary>Диагностика #77 (23.10.2026: «зажимаю R - меню не открывается, только поворот»): на нажатие R с урной-логистом в
/// руке - что видит игра (блок ли в руке, не считает ли предмет оружием). Убрать, когда причина найдена.</summary>
[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));
}
}
/// <summary>Мигание урны логиста, когда класть некуда (18.10: «При застревании должно мигать»): свечение модели
/// (MaterialPropertyBlock, как у TEFeatureCinerarium.SyncGlow) пульсирует от тёмного до обычного. Выключено - обычное свечение.</summary>
[Preserve]
public class CinerariumBlink : MonoBehaviour
{
public List<Renderer> Renderers = new List<Renderer>();
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);
}
}
}
}