R с черепом-предметом - меню; выбор декора превращает стопку в ячейке в блок (превью, повороты блока). С декором в руке R - обычное меню блока плюс «Просто череп» и второй вид. Действие PlaceAsBlock у предмета убрано (ПКМ из предмета больше не ставит). Стопка блоков 50, как у черепа. Описания черепа и декора (13 языков) - под новую схему. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
124 lines
7.1 KiB
C#
124 lines
7.1 KiB
C#
using GUI_2;
|
||
using HarmonyLib;
|
||
using UnityEngine;
|
||
|
||
namespace NecromancerTome
|
||
{
|
||
/// <summary>
|
||
/// Череп - предмет или декор (15.10.2026, вторая версия). Указание после теста: «Посмотри как ставится мебель. Например,
|
||
/// горшки с цветами... Три режима. Предмет, и два декора. Если выбран декор, хват меняется на тот который при установке
|
||
/// строительных блоков или мебели, и я начинаю видеть типа превью того как блок будет стоять»; поворот - как у блоков.
|
||
/// Череп-предмет в руке, удержание R - меню: «Просто череп» / «Череп: по центру» / «Череп: у стены». Выбор декора
|
||
/// превращает всю стопку в ячейке пояса в блок этого вида: в руке настоящий блок - превью, повороты блока.
|
||
/// Блок-декор в руке, R - обычное меню блока (короткое нажатие - поворот), к нему добавлены «Просто череп» (стопка
|
||
/// обратно в черепа) и второй вид декора.
|
||
/// Поднятый (E) и разрушенный декор - снова череп-предмет (blocks.xml: CanPickup param1 / drop).
|
||
/// Предмет necroSkull не меняется (ItemClass, без действий) - сейвы с черепом целы; блоки-декор - отдельные блоки.
|
||
/// R для предмета игра не обрабатывает (PlayerMoveController открывает меню только оружию, ближнему бою и блокам) -
|
||
/// нажатие ловится постфиксом к PlayerMoveController.Update.
|
||
/// </summary>
|
||
public static class SkullDecorPlace
|
||
{
|
||
public const int ItemIdx = 0, CenterIdx = 1, BackIdx = 2;
|
||
/// <summary>Номера наших пунктов в меню блока - вне занятых игрой (-2..10).</summary>
|
||
public const int BlockMenuItem = 40, BlockMenuCenter = 41, BlockMenuBack = 42;
|
||
public const string CenterBlock = "necroSkullDecorCenter";
|
||
public const string BackBlock = "necroSkullDecorBack";
|
||
|
||
public static bool IsSkull(ItemClass _item) => _item != null && _item.Name == NecroSkull.ItemName;
|
||
public static bool IsDecor(ItemClass _item) => _item != null && (_item.Name == CenterBlock || _item.Name == BackBlock);
|
||
|
||
/// <summary>Стопка в руке превращается в _name (тот же счёт).</summary>
|
||
public static void Convert(EntityPlayerLocal _pl, string _name)
|
||
{
|
||
if (_pl?.inventory == null) return;
|
||
ItemStack cur = _pl.inventory.holdingItemStack;
|
||
if (cur == null || cur.IsEmpty() || !(IsSkull(cur.itemValue.ItemClass) || IsDecor(cur.itemValue.ItemClass))) return;
|
||
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 OnItemMenu(XUiC_Radial _sender, int _commandIndex, XUiC_Radial.RadialContextAbs _context)
|
||
{
|
||
EntityPlayerLocal pl = _sender?.xui?.playerUI?.entityPlayer;
|
||
if (_commandIndex == CenterIdx) Convert(pl, CenterBlock);
|
||
else if (_commandIndex == BackIdx) Convert(pl, BackBlock);
|
||
}
|
||
|
||
public static void OpenItemMenu(PlayerMoveController _pmc, EntityPlayerLocal _pl)
|
||
{
|
||
XUiC_Radial r = _pmc.playerUI?.xui?.RadialWindow;
|
||
if (r == null) return;
|
||
r.Open();
|
||
r.ResetRadialEntries();
|
||
r.CreateRadialEntry(ItemIdx, "necroSkull", "ItemIconAtlas", "", Localization.Get("necroSkullModeOff"), true);
|
||
r.CreateRadialEntry(CenterIdx, "ui_game_symbol_skull", "UIAtlas", "", Localization.Get("necroSkullDecorCenter"));
|
||
r.CreateRadialEntry(BackIdx, "ui_game_symbol_skull", "UIAtlas", "", Localization.Get("necroSkullDecorBack"));
|
||
r.SetCommonData(UIUtils.GetButtonIconForAction(_pmc.playerInput.Reload), OnItemMenu,
|
||
new XUiC_Radial.RadialContextHoldingSlotIndex(_pl.inventory.holdingItemIdx), ItemIdx, false,
|
||
XUiC_Radial.RadialValidSameHoldingSlotIndex);
|
||
}
|
||
|
||
/// <summary>Меню блока с декором в руке: наши пункты - сами, остальное - игре.</summary>
|
||
public static void OnBlockMenu(XUiC_Radial _sender, int _commandIndex, XUiC_Radial.RadialContextAbs _context)
|
||
{
|
||
EntityPlayerLocal pl = _sender?.xui?.playerUI?.entityPlayer;
|
||
switch (_commandIndex)
|
||
{
|
||
case BlockMenuItem: Convert(pl, NecroSkull.ItemName); return;
|
||
case BlockMenuCenter: Convert(pl, CenterBlock); return;
|
||
case BlockMenuBack: Convert(pl, BackBlock); return;
|
||
}
|
||
_sender.handleBlockShapeCommand(_sender, _commandIndex, _context);
|
||
}
|
||
}
|
||
|
||
/// <summary>R с черепом-предметом в руке - меню «предмет / два декора».</summary>
|
||
[HarmonyPatch(typeof(PlayerMoveController), nameof(PlayerMoveController.Update))]
|
||
public static class Patch_PlayerMoveController_Update_SkullDecor
|
||
{
|
||
public static void Postfix(PlayerMoveController __instance)
|
||
{
|
||
EntityPlayerLocal pl = __instance.entityPlayerLocal;
|
||
if (pl == null || pl.inventory == null || !SkullDecorPlace.IsSkull(pl.inventory.holdingItem) || pl.IsDead())
|
||
{
|
||
return;
|
||
}
|
||
PlayerActionsLocal inp = __instance.playerInput;
|
||
if (inp == null || !(inp.Reload.WasPressed || inp.PermanentActions.Reload.WasPressed) || pl.inventory.IsHandSwitching())
|
||
{
|
||
return;
|
||
}
|
||
if (__instance.playerUI == null || __instance.playerUI.windowManager.IsModalWindowOpen())
|
||
{
|
||
return;
|
||
}
|
||
SkullDecorPlace.OpenItemMenu(__instance, pl);
|
||
}
|
||
}
|
||
|
||
/// <summary>Меню блока с черепом-декором в руке: к пунктам игры - «Просто череп» и второй вид.</summary>
|
||
[HarmonyPatch(typeof(XUiC_Radial), nameof(XUiC_Radial.SetupBlockShapeData))]
|
||
public static class Patch_XUiC_Radial_SetupBlockShapeData_SkullDecor
|
||
{
|
||
public static void Postfix(XUiC_Radial __instance)
|
||
{
|
||
EntityPlayerLocal pl = __instance.xui?.playerUI?.entityPlayer;
|
||
ItemClass held = pl?.inventory?.holdingItem;
|
||
if (!SkullDecorPlace.IsDecor(held))
|
||
{
|
||
return;
|
||
}
|
||
__instance.CreateRadialEntry(SkullDecorPlace.BlockMenuItem, "necroSkull", "ItemIconAtlas", "", Localization.Get("necroSkullModeOff"));
|
||
if (held.Name == SkullDecorPlace.CenterBlock)
|
||
__instance.CreateRadialEntry(SkullDecorPlace.BlockMenuBack, "ui_game_symbol_skull", "UIAtlas", "", Localization.Get("necroSkullDecorBack"));
|
||
else
|
||
__instance.CreateRadialEntry(SkullDecorPlace.BlockMenuCenter, "ui_game_symbol_skull", "UIAtlas", "", Localization.Get("necroSkullDecorCenter"));
|
||
__instance.SetCommonData(UIUtils.GetButtonIconForAction(__instance.xui.playerUI.playerInput.Activate), SkullDecorPlace.OnBlockMenu,
|
||
new XUiC_Radial.RadialContextHoldingSlotIndex(pl.inventory.holdingItemIdx), -1, true, XUiC_Radial.RadialValidSameHoldingSlotIndex);
|
||
}
|
||
}
|
||
}
|