- Блоки логиста на модели кадила: по центру на подставке (necroCinerariumLogist) и новый вид у стены на кронштейне (necroCinerariumLogistWall/+Skull); выбор вида - R с урной в руке. - Дух логиста втрое меньше, в покое сидит в кадиле, на перевозку вылетает через окно крышки (у стены - не в стену) и возвращается тем же окном. - Застрял (ящик «куда» полон) - урна мигает (CinerariumBlink) вместо почерневшего духа; прежняя зелёная подмена свечения старой модели убрана. - Команды разработки без мыши: necrospawn, necroexit [quit], necrolook, necroaim, necroplace, necrohold, necrobox, necrourn, necroclick. Проверено в игре (test8): перевозка обоими видами, вылет духа, вид у стены от стены. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
127 lines
5.8 KiB
C#
127 lines
5.8 KiB
C#
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);
|
||
}
|
||
}
|
||
|
||
/// <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);
|
||
}
|
||
}
|
||
}
|
||
}
|