Предмет necroSkull остаётся ItemClass, добавлено Action1 PlaceAsBlock (в ItemValue не пишется - сейвы целы). R для черепа ловится постфиксом PlayerMoveController.Update, выбор - cvar necroSkullDecorMode. Поднятый и разрушенный блок - снова череп. Помощник necroSkullDecor спрятан (CreativeMode None), рецепт «череп -> декор» убран, обратный оставлен для уже сделанных помощников. Описание черепа дополнено (13 языков), подсказка и пункт меню «Просто череп». Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
117 lines
5.4 KiB
C#
117 lines
5.4 KiB
C#
using GUI_2;
|
||
using HarmonyLib;
|
||
using UnityEngine;
|
||
|
||
namespace NecromancerTome
|
||
{
|
||
/// <summary>
|
||
/// Череп ставится декором прямо из руки (15.10.2026, указание: «Сейчас держу в руках именно череп. И он нормальный.
|
||
/// Но его нельзя поставить как декор. Может сделать возможность через R переключаться в режим декора и сразу
|
||
/// выбирать центральный или у стены?»; «А при поднятии снова делать просто черепом»).
|
||
/// Удержание R с черепом в руке - круговое меню: «Просто череп» / «Декор: по центру» / «Декор: у стены».
|
||
/// ПКМ - ставит блок выбранного вида (Action1 = PlaceAsBlock у necroSkull в items.xml); в «Просто череп» - ничего.
|
||
/// Поднятый блок (E) и разрушенный - снова череп-предмет (CanPickup param1 / drop в blocks.xml).
|
||
/// Предмет остаётся ItemClass: действие в ItemValue не пишется (ItemValue.Write: тип, износ, качество, Meta,
|
||
/// метаданные, статы, моды) - старые стаки черепа читаются как прежде.
|
||
/// R для черепа игра сама не обрабатывает (PlayerMoveController открывает меню только оружию, ближнему бою и
|
||
/// блокам) - поэтому нажатие ловится постфиксом к PlayerMoveController.Update. Выбор - cvar игрока
|
||
/// (necroSkullDecorMode, без точки - пишется в сейв).
|
||
/// </summary>
|
||
public static class SkullDecorPlace
|
||
{
|
||
public const string ModeCVar = "necroSkullDecorMode";
|
||
public const int Off = 0, Center = 1, Back = 2;
|
||
public const string CenterBlock = "necroSkullDecorCenter";
|
||
public const string BackBlock = "necroSkullDecorBack";
|
||
|
||
public static bool IsSkull(ItemClass _item) => _item != null && _item.Name == NecroSkull.ItemName;
|
||
|
||
public static int Mode(EntityAlive _e)
|
||
{
|
||
if (_e == null) return Off;
|
||
int m = Mathf.RoundToInt(_e.GetCVar(ModeCVar));
|
||
return m >= Off && m <= Back ? m : Off;
|
||
}
|
||
|
||
public static void OnRadialCommand(XUiC_Radial _sender, int _commandIndex, XUiC_Radial.RadialContextAbs _context)
|
||
{
|
||
EntityPlayerLocal pl = _sender?.xui?.playerUI?.entityPlayer;
|
||
if (pl != null && _commandIndex >= Off && _commandIndex <= Back)
|
||
{
|
||
pl.SetCVar(ModeCVar, _commandIndex);
|
||
}
|
||
}
|
||
|
||
public static void OpenMenu(PlayerMoveController _pmc, EntityPlayerLocal _pl)
|
||
{
|
||
XUiC_Radial r = _pmc.playerUI?.xui?.RadialWindow;
|
||
if (r == null) return;
|
||
int cur = Mode(_pl);
|
||
r.Open();
|
||
r.ResetRadialEntries();
|
||
r.CreateRadialEntry(Off, "ui_game_symbol_hand", "UIAtlas", "", Localization.Get("necroSkullModeOff"), cur == Off);
|
||
r.CreateRadialEntry(Center, "ui_game_symbol_skull", "UIAtlas", "", Localization.Get("necroSkullDecorCenter"), cur == Center);
|
||
r.CreateRadialEntry(Back, "ui_game_symbol_skull", "UIAtlas", "", Localization.Get("necroSkullDecorBack"), cur == Back);
|
||
r.SetCommonData(UIUtils.GetButtonIconForAction(_pmc.playerInput.Reload), OnRadialCommand,
|
||
new XUiC_Radial.RadialContextHoldingSlotIndex(_pl.inventory.holdingItemIdx), cur, false,
|
||
XUiC_Radial.RadialValidSameHoldingSlotIndex);
|
||
}
|
||
}
|
||
|
||
/// <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.OpenMenu(__instance, pl);
|
||
}
|
||
}
|
||
|
||
/// <summary>ПКМ с черепом: ставит выбранный вид; в «Просто череп» не ставит (и подсказывает про R).</summary>
|
||
[HarmonyPatch(typeof(ItemActionPlaceAsBlock), nameof(ItemActionPlaceAsBlock.ExecuteAction))]
|
||
public static class Patch_ItemActionPlaceAsBlock_ExecuteAction_SkullDecor
|
||
{
|
||
static float _hintAt;
|
||
|
||
public static bool Prefix(ItemActionPlaceAsBlock __instance, ItemActionData _actionData, bool _bReleased)
|
||
{
|
||
if (!SkullDecorPlace.IsSkull(__instance.item))
|
||
{
|
||
return true;
|
||
}
|
||
EntityAlive e = _actionData?.invData?.holdingEntity;
|
||
int mode = SkullDecorPlace.Mode(e);
|
||
if (mode == SkullDecorPlace.Off)
|
||
{
|
||
if (_bReleased && e is EntityPlayerLocal pl && Time.time - _hintAt > 2f)
|
||
{
|
||
_hintAt = Time.time;
|
||
GameManager.ShowTooltip(pl, Localization.Get("necroSkullDecorHint"));
|
||
}
|
||
return false;
|
||
}
|
||
BlockValue bv = Block.GetBlockValue(mode == SkullDecorPlace.Back ? SkullDecorPlace.BackBlock : SkullDecorPlace.CenterBlock);
|
||
if (!bv.isair)
|
||
{
|
||
__instance.blockToPlace = bv;
|
||
}
|
||
return true;
|
||
}
|
||
}
|
||
}
|