Files
necromants-tome-7d2d-3-2/HarmonySrc/HeldTweak.cs
T

188 lines
7.2 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 System.Globalization;
using UnityEngine;
using UnityEngine.Scripting;
namespace NecromancerTome
{
/// <summary>
/// Подбор посадки модели предмета в руке прямо в игре (10.10.2026, череп): как necropose для жестов. Сдвиг, поворот
/// и масштаб применяются к дочерним узлам модели в руке (корень модели держит игра) каждый кадр - переживают смену
/// слота. Итог - строкой в лог, затем переносится в настройку модели (NecroSkullSetup и т.п.) и бандл пересобирается
/// при закрытой игре.
/// </summary>
public static class HeldTweak
{
public static bool Enabled;
public static Vector3 Pos; // метры, в осях модели
public static Vector3 Rot; // градусы, добавка к исходному повороту
public static float Scale = 1f;
/// <summary>Предмет, для которого подбирается посадка (тот, что был в руке при первой команде). Другие предметы
/// не трогаются: 10.10 без этого поворот черепа применился и к книге, взятой следом.</summary>
public static string Item;
/// <summary>Исходные локальные значения детей модели (по экземпляру узла).</summary>
static readonly Dictionary<int, (Vector3 p, Quaternion r, Vector3 s)> _base = new Dictionary<int, (Vector3, Quaternion, Vector3)>();
public static Transform Model()
{
EntityPlayerLocal pl = GameManager.Instance?.World?.GetPrimaryPlayer();
return pl?.inventory?.GetHoldingItemTransform();
}
public static string HeldName()
{
EntityPlayerLocal pl = GameManager.Instance?.World?.GetPrimaryPlayer();
return pl?.inventory?.holdingItem?.Name;
}
public static void Apply()
{
Transform m = Model();
if (m == null || (Enabled && HeldName() != Item))
{
return;
}
for (int i = 0; i < m.childCount; i++)
{
Transform c = m.GetChild(i);
int id = c.GetInstanceID();
if (!_base.TryGetValue(id, out var b))
{
if (!Enabled)
{
continue;
}
b = (c.localPosition, c.localRotation, c.localScale);
_base[id] = b;
}
if (Enabled)
{
c.localPosition = Scale * b.p + Pos;
c.localRotation = Quaternion.Euler(Rot) * b.r;
c.localScale = b.s * Scale;
}
else
{
c.localPosition = b.p;
c.localRotation = b.r;
c.localScale = b.s;
_base.Remove(id);
}
}
}
/// <summary>Сменить хват (HoldType) предмета в руке и пересобрать его в руке, как BloodTide (16.10: «давай попробуем в
/// режиме нитей разные хваты. Ты будешь перебирать их по моей просьбе»). Меняется класс предмета - до перезапуска
/// игры или следующей команды; итог переносится в items.xml.</summary>
public static string SetHold(int _hold)
{
EntityPlayerLocal pl = GameManager.Instance?.World?.GetPrimaryPlayer();
Inventory inv = pl?.inventory;
ItemInventoryData held = inv?.holdingItemData;
if (held?.item == null)
{
return "в руке ничего";
}
if (pl.Hand != null && pl.Hand.isSwitching || inv.IsHoldingItemActionRunning())
{
return "рука занята - повторите";
}
int was = held.item.HoldType.Value;
held.item.HoldType.Value = _hold;
ItemValue pv = (held.physicalItemValue ?? held.itemValue).Clone();
pv.Seed = (ushort)(pv.Seed + 1); // «собранный» предмет устарел - соберётся заново (NeedsRebuild)
held.physicalItemValue = pv;
inv.SetHoldingItemIdx(inv.holdingItemIdx);
return held.item.Name + ": хват " + was + " -> " + _hold;
}
public static string F(float _v) => _v.ToString("0.###", CultureInfo.InvariantCulture);
public static string F(Vector3 _v) => F(_v.x) + " " + F(_v.y) + " " + F(_v.z);
}
/// <summary>
/// necroheld - посадка модели в руке:
/// pos x y z (см) | add x y z (см) | rot x y z (градусы) | scale s | hold N (хват, HoldType) | off | show
/// </summary>
[Preserve]
public class ConsoleCmdNecroHeld : ConsoleCmdAbstract
{
public override string[] getCommands() => new[] { "necroheld" };
public override string getDescription() => "NecromancerTome: посадка модели в руке - pos x y z (см)|add x y z (см)|rot x y z|scale s|hold N|off|show";
static bool Num(List<string> _p, int _i, out float _v)
{
_v = 0f;
return _p.Count > _i && float.TryParse(_p[_i].Replace(',', '.'), NumberStyles.Float, CultureInfo.InvariantCulture, out _v);
}
static bool Vec(List<string> _p, out Vector3 _v)
{
bool ok = Num(_p, 1, out float x) & Num(_p, 2, out float y) & Num(_p, 3, out float z);
_v = new Vector3(x, y, z);
return ok;
}
public override void Execute(List<string> _params, CommandSenderInfo _senderInfo)
{
string cmd = _params.Count > 0 ? _params[0] : "show";
Vector3 v;
switch (cmd)
{
case "pos" when Vec(_params, out v):
HeldTweak.Pos = v / 100f;
break;
case "add" when Vec(_params, out v):
HeldTweak.Pos += v / 100f;
break;
case "rot" when Vec(_params, out v):
HeldTweak.Rot = v;
break;
case "scale" when Num(_params, 1, out float s) && s > 0f:
HeldTweak.Scale = s;
break;
case "tphold" when Num(_params, 1, out float th):
ThreadKnifeBody.TpHold = (int)th;
Out("хват тела для ножа-для-нитей: " + ThreadKnifeBody.TpHold + (ThreadKnifeBody.TpHold > 0 ? "" : " (выкл - как у рук)") + "; место в руке - при следующем доставании");
return;
case "hold" when Num(_params, 1, out float h):
Out(HeldTweak.SetHold((int)h));
return;
case "hold":
Out("хват предмета в руке: " + (GameManager.Instance?.World?.GetPrimaryPlayer()?.inventory?.holdingItem?.HoldType.Value.ToString() ?? "нет"));
return;
case "off":
HeldTweak.Enabled = false;
HeldTweak.Pos = Vector3.zero;
HeldTweak.Rot = Vector3.zero;
HeldTweak.Scale = 1f;
Out("посадка сброшена");
return;
case "show":
break;
default:
Out(getDescription());
return;
}
if (cmd != "show")
{
if (!HeldTweak.Enabled)
{
HeldTweak.Item = HeldTweak.HeldName();
}
HeldTweak.Enabled = true;
}
Transform m = HeldTweak.Model();
Out("предмет " + HeldTweak.Item + ", модель " + (m != null ? m.name : "нет") + ": сдвиг (см) " + HeldTweak.F(HeldTweak.Pos * 100f) + ", поворот " +
HeldTweak.F(HeldTweak.Rot) + ", масштаб " + HeldTweak.F(HeldTweak.Scale) + (HeldTweak.Enabled ? "" : " (выключено)"));
}
static void Out(string _s)
{
SdtdConsole.Instance.Output(_s);
Debug.Log("[NecromancerTome] necroheld: " + _s);
}
}
}