Череп: три режима как у мебели - предмет / декор по центру / декор у стены
R с черепом-предметом - меню; выбор декора превращает стопку в ячейке в блок (превью, повороты блока). С декором в руке R - обычное меню блока плюс «Просто череп» и второй вид. Действие PlaceAsBlock у предмета убрано (ПКМ из предмета больше не ставит). Стопка блоков 50, как у черепа. Описания черепа и декора (13 языков) - под новую схему. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5.5
parent
4cc244a98a
commit
99c2f183ad
@@ -5,60 +5,77 @@ 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, без точки - пишется в сейв).
|
||||
/// Череп - предмет или декор (15.10.2026, вторая версия). Указание после теста: «Посмотри как ставится мебель. Например,
|
||||
/// горшки с цветами... Три режима. Предмет, и два декора. Если выбран декор, хват меняется на тот который при установке
|
||||
/// строительных блоков или мебели, и я начинаю видеть типа превью того как блок будет стоять»; поворот - как у блоков.
|
||||
/// Череп-предмет в руке, удержание R - меню: «Просто череп» / «Череп: по центру» / «Череп: у стены». Выбор декора
|
||||
/// превращает всю стопку в ячейке пояса в блок этого вида: в руке настоящий блок - превью, повороты блока.
|
||||
/// Блок-декор в руке, R - обычное меню блока (короткое нажатие - поворот), к нему добавлены «Просто череп» (стопка
|
||||
/// обратно в черепа) и второй вид декора.
|
||||
/// Поднятый (E) и разрушенный декор - снова череп-предмет (blocks.xml: CanPickup param1 / drop).
|
||||
/// Предмет necroSkull не меняется (ItemClass, без действий) - сейвы с черепом целы; блоки-декор - отдельные блоки.
|
||||
/// R для предмета игра не обрабатывает (PlayerMoveController открывает меню только оружию, ближнему бою и блокам) -
|
||||
/// нажатие ловится постфиксом к PlayerMoveController.Update.
|
||||
/// </summary>
|
||||
public static class SkullDecorPlace
|
||||
{
|
||||
public const string ModeCVar = "necroSkullDecorMode";
|
||||
public const int Off = 0, Center = 1, Back = 2;
|
||||
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);
|
||||
|
||||
public static int Mode(EntityAlive _e)
|
||||
/// <summary>Стопка в руке превращается в _name (тот же счёт).</summary>
|
||||
public static void Convert(EntityPlayerLocal _pl, string _name)
|
||||
{
|
||||
if (_e == null) return Off;
|
||||
int m = Mathf.RoundToInt(_e.GetCVar(ModeCVar));
|
||||
return m >= Off && m <= Back ? m : Off;
|
||||
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 OnRadialCommand(XUiC_Radial _sender, int _commandIndex, XUiC_Radial.RadialContextAbs _context)
|
||||
public static void OnItemMenu(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);
|
||||
}
|
||||
if (_commandIndex == CenterIdx) Convert(pl, CenterBlock);
|
||||
else if (_commandIndex == BackIdx) Convert(pl, BackBlock);
|
||||
}
|
||||
|
||||
public static void OpenMenu(PlayerMoveController _pmc, EntityPlayerLocal _pl)
|
||||
public static void OpenItemMenu(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,
|
||||
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>
|
||||
/// <summary>R с черепом-предметом в руке - меню «предмет / два декора».</summary>
|
||||
[HarmonyPatch(typeof(PlayerMoveController), nameof(PlayerMoveController.Update))]
|
||||
public static class Patch_PlayerMoveController_Update_SkullDecor
|
||||
{
|
||||
@@ -78,39 +95,29 @@ namespace NecromancerTome
|
||||
{
|
||||
return;
|
||||
}
|
||||
SkullDecorPlace.OpenMenu(__instance, pl);
|
||||
SkullDecorPlace.OpenItemMenu(__instance, pl);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>ПКМ с черепом: ставит выбранный вид; в «Просто череп» не ставит (и подсказывает про R).</summary>
|
||||
[HarmonyPatch(typeof(ItemActionPlaceAsBlock), nameof(ItemActionPlaceAsBlock.ExecuteAction))]
|
||||
public static class Patch_ItemActionPlaceAsBlock_ExecuteAction_SkullDecor
|
||||
/// <summary>Меню блока с черепом-декором в руке: к пунктам игры - «Просто череп» и второй вид.</summary>
|
||||
[HarmonyPatch(typeof(XUiC_Radial), nameof(XUiC_Radial.SetupBlockShapeData))]
|
||||
public static class Patch_XUiC_Radial_SetupBlockShapeData_SkullDecor
|
||||
{
|
||||
static float _hintAt;
|
||||
|
||||
public static bool Prefix(ItemActionPlaceAsBlock __instance, ItemActionData _actionData, bool _bReleased)
|
||||
public static void Postfix(XUiC_Radial __instance)
|
||||
{
|
||||
if (!SkullDecorPlace.IsSkull(__instance.item))
|
||||
EntityPlayerLocal pl = __instance.xui?.playerUI?.entityPlayer;
|
||||
ItemClass held = pl?.inventory?.holdingItem;
|
||||
if (!SkullDecorPlace.IsDecor(held))
|
||||
{
|
||||
return true;
|
||||
return;
|
||||
}
|
||||
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;
|
||||
__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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user