Урна-логист: фильтр по 22 группам предметов в «Содержимом» (вместо образца); дух засыпает, когда игрок дальше 40 м
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5.5
parent
d8e7c8c66a
commit
0290a73477
+26
-1
File diff suppressed because one or more lines are too long
@@ -208,4 +208,60 @@
|
||||
<sprite depth="9" pos="0,20" height="8" color="[black]" sprite="menu_empty2px" globalopacitymod="0" type="sliced" fillcenter="false" />
|
||||
<sprite depth="4" pos="0,20" height="8" width="750" color="150,60,220,200" globalopacitymod="0" type="filled" fill="{% cvar('necroNecromancyProgressCVar') / 20 }" />
|
||||
</append>
|
||||
<!-- Фильтр урны-логиста (16.10.2026, HarmonySrc/CinerariumFilterWindow.cs, CinerariumGroups.cs): значки групп предметов
|
||||
в окне «Содержимое» рядом с ячейкой черепа. Окно в группе bagStorage (xui.xml) - контроллер прячет его, если окно
|
||||
открыто не урной-логистом (сумки транспорта и волка). f0..f21 - рамки, g0..g21 - значки (иконки ставит контроллер). -->
|
||||
<append xpath="/windows">
|
||||
<window name="necroUrnFilter" width="348" height="279" depth="5" panel="Left" backgroundcolor="[black]" cursor_area="true" controller="NecromancerTome.NecroUrnFilter, NecromancerHarmony">
|
||||
<rect name="header" height="43" depth="0">
|
||||
<sprite depth="1" name="headerbackground" sprite="ui_game_panel_header" width="348" height="43" />
|
||||
<sprite depth="3" name="windowIcon" style="icon32px" pivot="center" pos="21,-21" sprite="ui_game_symbol_sort" />
|
||||
<label depth="2" name="title" pos="39,-6" width="303" height="32" text_key="necroUrnFilterTitle" font_size="28" />
|
||||
</rect>
|
||||
<sprite depth="2" name="f0" pos="6,-49" width="52" height="52" sprite="menu_empty2px" type="sliced" fillcenter="false" />
|
||||
<sprite depth="3" name="g0" pos="8,-51" width="48" height="48" atlas="ItemIconAtlas" sprite="oldCash" on_press="true" sound="[paging_click]" foregroundlayer="true" />
|
||||
<sprite depth="2" name="f1" pos="62,-49" width="52" height="52" sprite="menu_empty2px" type="sliced" fillcenter="false" />
|
||||
<sprite depth="3" name="g1" pos="64,-51" width="48" height="48" atlas="ItemIconAtlas" sprite="oldCash" on_press="true" sound="[paging_click]" foregroundlayer="true" />
|
||||
<sprite depth="2" name="f2" pos="118,-49" width="52" height="52" sprite="menu_empty2px" type="sliced" fillcenter="false" />
|
||||
<sprite depth="3" name="g2" pos="120,-51" width="48" height="48" atlas="ItemIconAtlas" sprite="oldCash" on_press="true" sound="[paging_click]" foregroundlayer="true" />
|
||||
<sprite depth="2" name="f3" pos="174,-49" width="52" height="52" sprite="menu_empty2px" type="sliced" fillcenter="false" />
|
||||
<sprite depth="3" name="g3" pos="176,-51" width="48" height="48" atlas="ItemIconAtlas" sprite="oldCash" on_press="true" sound="[paging_click]" foregroundlayer="true" />
|
||||
<sprite depth="2" name="f4" pos="230,-49" width="52" height="52" sprite="menu_empty2px" type="sliced" fillcenter="false" />
|
||||
<sprite depth="3" name="g4" pos="232,-51" width="48" height="48" atlas="ItemIconAtlas" sprite="oldCash" on_press="true" sound="[paging_click]" foregroundlayer="true" />
|
||||
<sprite depth="2" name="f5" pos="286,-49" width="52" height="52" sprite="menu_empty2px" type="sliced" fillcenter="false" />
|
||||
<sprite depth="3" name="g5" pos="288,-51" width="48" height="48" atlas="ItemIconAtlas" sprite="oldCash" on_press="true" sound="[paging_click]" foregroundlayer="true" />
|
||||
<sprite depth="2" name="f6" pos="6,-105" width="52" height="52" sprite="menu_empty2px" type="sliced" fillcenter="false" />
|
||||
<sprite depth="3" name="g6" pos="8,-107" width="48" height="48" atlas="ItemIconAtlas" sprite="oldCash" on_press="true" sound="[paging_click]" foregroundlayer="true" />
|
||||
<sprite depth="2" name="f7" pos="62,-105" width="52" height="52" sprite="menu_empty2px" type="sliced" fillcenter="false" />
|
||||
<sprite depth="3" name="g7" pos="64,-107" width="48" height="48" atlas="ItemIconAtlas" sprite="oldCash" on_press="true" sound="[paging_click]" foregroundlayer="true" />
|
||||
<sprite depth="2" name="f8" pos="118,-105" width="52" height="52" sprite="menu_empty2px" type="sliced" fillcenter="false" />
|
||||
<sprite depth="3" name="g8" pos="120,-107" width="48" height="48" atlas="ItemIconAtlas" sprite="oldCash" on_press="true" sound="[paging_click]" foregroundlayer="true" />
|
||||
<sprite depth="2" name="f9" pos="174,-105" width="52" height="52" sprite="menu_empty2px" type="sliced" fillcenter="false" />
|
||||
<sprite depth="3" name="g9" pos="176,-107" width="48" height="48" atlas="ItemIconAtlas" sprite="oldCash" on_press="true" sound="[paging_click]" foregroundlayer="true" />
|
||||
<sprite depth="2" name="f10" pos="230,-105" width="52" height="52" sprite="menu_empty2px" type="sliced" fillcenter="false" />
|
||||
<sprite depth="3" name="g10" pos="232,-107" width="48" height="48" atlas="ItemIconAtlas" sprite="oldCash" on_press="true" sound="[paging_click]" foregroundlayer="true" />
|
||||
<sprite depth="2" name="f11" pos="286,-105" width="52" height="52" sprite="menu_empty2px" type="sliced" fillcenter="false" />
|
||||
<sprite depth="3" name="g11" pos="288,-107" width="48" height="48" atlas="ItemIconAtlas" sprite="oldCash" on_press="true" sound="[paging_click]" foregroundlayer="true" />
|
||||
<sprite depth="2" name="f12" pos="6,-161" width="52" height="52" sprite="menu_empty2px" type="sliced" fillcenter="false" />
|
||||
<sprite depth="3" name="g12" pos="8,-163" width="48" height="48" atlas="ItemIconAtlas" sprite="oldCash" on_press="true" sound="[paging_click]" foregroundlayer="true" />
|
||||
<sprite depth="2" name="f13" pos="62,-161" width="52" height="52" sprite="menu_empty2px" type="sliced" fillcenter="false" />
|
||||
<sprite depth="3" name="g13" pos="64,-163" width="48" height="48" atlas="ItemIconAtlas" sprite="oldCash" on_press="true" sound="[paging_click]" foregroundlayer="true" />
|
||||
<sprite depth="2" name="f14" pos="118,-161" width="52" height="52" sprite="menu_empty2px" type="sliced" fillcenter="false" />
|
||||
<sprite depth="3" name="g14" pos="120,-163" width="48" height="48" atlas="ItemIconAtlas" sprite="oldCash" on_press="true" sound="[paging_click]" foregroundlayer="true" />
|
||||
<sprite depth="2" name="f15" pos="174,-161" width="52" height="52" sprite="menu_empty2px" type="sliced" fillcenter="false" />
|
||||
<sprite depth="3" name="g15" pos="176,-163" width="48" height="48" atlas="ItemIconAtlas" sprite="oldCash" on_press="true" sound="[paging_click]" foregroundlayer="true" />
|
||||
<sprite depth="2" name="f16" pos="230,-161" width="52" height="52" sprite="menu_empty2px" type="sliced" fillcenter="false" />
|
||||
<sprite depth="3" name="g16" pos="232,-163" width="48" height="48" atlas="ItemIconAtlas" sprite="oldCash" on_press="true" sound="[paging_click]" foregroundlayer="true" />
|
||||
<sprite depth="2" name="f17" pos="286,-161" width="52" height="52" sprite="menu_empty2px" type="sliced" fillcenter="false" />
|
||||
<sprite depth="3" name="g17" pos="288,-163" width="48" height="48" atlas="ItemIconAtlas" sprite="oldCash" on_press="true" sound="[paging_click]" foregroundlayer="true" />
|
||||
<sprite depth="2" name="f18" pos="6,-217" width="52" height="52" sprite="menu_empty2px" type="sliced" fillcenter="false" />
|
||||
<sprite depth="3" name="g18" pos="8,-219" width="48" height="48" atlas="ItemIconAtlas" sprite="oldCash" on_press="true" sound="[paging_click]" foregroundlayer="true" />
|
||||
<sprite depth="2" name="f19" pos="62,-217" width="52" height="52" sprite="menu_empty2px" type="sliced" fillcenter="false" />
|
||||
<sprite depth="3" name="g19" pos="64,-219" width="48" height="48" atlas="ItemIconAtlas" sprite="oldCash" on_press="true" sound="[paging_click]" foregroundlayer="true" />
|
||||
<sprite depth="2" name="f20" pos="118,-217" width="52" height="52" sprite="menu_empty2px" type="sliced" fillcenter="false" />
|
||||
<sprite depth="3" name="g20" pos="120,-219" width="48" height="48" atlas="ItemIconAtlas" sprite="oldCash" on_press="true" sound="[paging_click]" foregroundlayer="true" />
|
||||
<sprite depth="2" name="f21" pos="174,-217" width="52" height="52" sprite="menu_empty2px" type="sliced" fillcenter="false" />
|
||||
<sprite depth="3" name="g21" pos="176,-219" width="48" height="48" atlas="ItemIconAtlas" sprite="oldCash" on_press="true" sound="[paging_click]" foregroundlayer="true" />
|
||||
</window>
|
||||
</append>
|
||||
</windows>
|
||||
|
||||
@@ -59,4 +59,8 @@
|
||||
<window name="windowNonPagingHeader" />
|
||||
</window_group>
|
||||
</append>
|
||||
<!-- Фильтр урны-логиста - в окне хранилища игры (bagStorage), рядом с ячейкой «Содержимого» (windows.xml). -->
|
||||
<append xpath="/xui/window_group[@name='bagStorage']">
|
||||
<window name="necroUrnFilter" />
|
||||
</append>
|
||||
</xui>
|
||||
|
||||
@@ -36,7 +36,7 @@ namespace NecromancerTome
|
||||
public const int Below = 1;
|
||||
public const int Above = 4;
|
||||
public const float KillsPerUrn = 500f;
|
||||
const byte SaveVersion = 2; // 2 - нити (16.10)
|
||||
const byte SaveVersion = 3; // 2 - нити, 3 - фильтр логиста (16.10)
|
||||
|
||||
public bool HasSkull;
|
||||
public bool ZoneShown;
|
||||
@@ -45,6 +45,17 @@ namespace NecromancerTome
|
||||
public bool HasThreadTo;
|
||||
public Vector3i ThreadTo;
|
||||
public bool IsLogist => HasThreadTo || ThreadFrom.Count > 0;
|
||||
/// <summary>Фильтр логиста: бит на группу CinerariumGroups; по умолчанию все включены.</summary>
|
||||
public uint GroupMask = CinerariumGroups.All;
|
||||
|
||||
public bool GroupOn(int _g) => (GroupMask & (1u << _g)) != 0;
|
||||
|
||||
public void ToggleGroup(int _g)
|
||||
{
|
||||
GroupMask ^= 1u << _g;
|
||||
SetModified();
|
||||
Debug.Log("[NecromancerTome] Cinerarium: фильтр урны " + ToWorldPos() + " - группа " + _g + (GroupOn(_g) ? " включена" : " выключена"));
|
||||
}
|
||||
|
||||
public override void CopyFromInternal(TileEntityComposite _other)
|
||||
{
|
||||
@@ -56,6 +67,7 @@ namespace NecromancerTome
|
||||
ThreadFrom.AddRange(other.ThreadFrom);
|
||||
HasThreadTo = other.HasThreadTo;
|
||||
ThreadTo = other.ThreadTo;
|
||||
GroupMask = other.GroupMask;
|
||||
_threadsDirty = true;
|
||||
}
|
||||
}
|
||||
@@ -124,6 +136,7 @@ namespace NecromancerTome
|
||||
t.Add(HasThreadTo ? 1 : 0);
|
||||
t.Add(ThreadTo.x); t.Add(ThreadTo.y); t.Add(ThreadTo.z);
|
||||
CinerariumWriteHelper.WriteInts(_bw, t.ToArray());
|
||||
CinerariumWriteHelper.WriteInts(_bw, new[] { unchecked((int)GroupMask) });
|
||||
}
|
||||
|
||||
public override void Read(PooledBinaryReader _br, StreamModeRead _eStreamMode)
|
||||
@@ -154,6 +167,19 @@ namespace NecromancerTome
|
||||
ThreadTo = new Vector3i(v[k + 1], v[k + 2], v[k + 3]);
|
||||
}
|
||||
}
|
||||
GroupMask = CinerariumGroups.All;
|
||||
if (version >= 3)
|
||||
{
|
||||
int n = _br.ReadInt32();
|
||||
for (int i = 0; i < n; i++)
|
||||
{
|
||||
int v = _br.ReadInt32();
|
||||
if (i == 0)
|
||||
{
|
||||
GroupMask = unchecked((uint)v);
|
||||
}
|
||||
}
|
||||
}
|
||||
_threadsDirty = true;
|
||||
if (version > SaveVersion)
|
||||
{
|
||||
|
||||
@@ -0,0 +1,84 @@
|
||||
using UnityEngine;
|
||||
using UnityEngine.Scripting;
|
||||
|
||||
namespace NecromancerTome
|
||||
{
|
||||
/// <summary>
|
||||
/// Фильтр урны-логиста (16.10.2026): панель значков групп (CinerariumGroups) в окне «Содержимое» - окно necroUrnFilter
|
||||
/// добавлено в группу окон игры bagStorage рядом с ячейкой черепа (Config/XUi_InGame). Видна только у урны с нитями;
|
||||
/// у сумок транспорта и волка (та же группа окон) скрыта. Щелчок по значку включает/выключает группу; по умолчанию все
|
||||
/// включены. Выключенный значок - тёмный.
|
||||
/// </summary>
|
||||
[Preserve]
|
||||
public class XUiC_NecroUrnFilter : XUiController
|
||||
{
|
||||
readonly XUiController[] _icons = new XUiController[CinerariumGroups.Count];
|
||||
readonly XUiController[] _frames = new XUiController[CinerariumGroups.Count];
|
||||
static readonly Color On = Color.white;
|
||||
static readonly Color Off = new Color(0.25f, 0.25f, 0.25f, 0.6f);
|
||||
static readonly Color FrameOn = new Color(0.45f, 0.85f, 0.55f, 1f);
|
||||
static readonly Color FrameOff = new Color(0.2f, 0.2f, 0.2f, 1f);
|
||||
|
||||
public override void Init()
|
||||
{
|
||||
base.Init();
|
||||
for (int i = 0; i < CinerariumGroups.Count; i++)
|
||||
{
|
||||
int g = i;
|
||||
_icons[i] = GetChildById("g" + i);
|
||||
_frames[i] = GetChildById("f" + i);
|
||||
if (_icons[i] == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
_icons[i].OnPress += (_s, _m) => Toggle(g);
|
||||
if (_icons[i].ViewComponent is XUiV_Sprite sp)
|
||||
{
|
||||
sp.UIAtlas = "ItemIconAtlas";
|
||||
sp.SpriteName = CinerariumGroups.Icons[g];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override void OnOpen()
|
||||
{
|
||||
base.OnOpen();
|
||||
Refresh();
|
||||
}
|
||||
|
||||
void Toggle(int _g)
|
||||
{
|
||||
TEFeatureCinerarium urn = CinerariumContents.Urn;
|
||||
if (urn == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
urn.ToggleGroup(_g);
|
||||
Refresh();
|
||||
}
|
||||
|
||||
void Refresh()
|
||||
{
|
||||
TEFeatureCinerarium urn = CinerariumContents.Urn;
|
||||
bool show = urn != null && urn.IsLogist;
|
||||
ViewComponent.IsVisible = show;
|
||||
if (!show)
|
||||
{
|
||||
return;
|
||||
}
|
||||
for (int i = 0; i < CinerariumGroups.Count; i++)
|
||||
{
|
||||
bool on = urn.GroupOn(i);
|
||||
if (_icons[i]?.ViewComponent is XUiV_Sprite sp)
|
||||
{
|
||||
sp.Color = on ? On : Off;
|
||||
sp.ToolTip = Localization.Get(CinerariumGroups.NameKey(i)) + " - " + Localization.Get(on ? "necroGroupOn" : "necroGroupOff");
|
||||
}
|
||||
if (_frames[i]?.ViewComponent is XUiV_Sprite fr)
|
||||
{
|
||||
fr.Color = on ? FrameOn : FrameOff;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -35,6 +35,20 @@ namespace NecromancerTome
|
||||
public static float BobHeight = 0.04f;
|
||||
public static float BobPeriod = 4f;
|
||||
public static float Alpha = 0.3f;
|
||||
/// <summary>Засыпание (16.10): игрок дальше SleepDistance - дух замирает дома, огоньки нитей стоят. Работа идёт.</summary>
|
||||
public static float SleepDistance = 40f;
|
||||
public static bool Hidden;
|
||||
|
||||
/// <summary>Далеко ли игрок от точки сцены (без Origin). Для засыпания духа и нитей.</summary>
|
||||
public static bool PlayerFar(Vector3 _scenePos)
|
||||
{
|
||||
EntityPlayerLocal pl = GameManager.Instance?.World?.GetPrimaryPlayer();
|
||||
if (pl == null)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
return (pl.GetPosition() - Origin.position - _scenePos).sqrMagnitude > SleepDistance * SleepDistance;
|
||||
}
|
||||
/// <summary>Руки (16.10: «Т-поза бесит»): плечо от вертикали вбок и вперёд, локоть согнут вперёд, градусы.
|
||||
/// Модель в позе покоя, аниматора нет - кости ставятся один раз при появлении.</summary>
|
||||
public static float ArmOut = 12f;
|
||||
@@ -72,7 +86,7 @@ namespace NecromancerTome
|
||||
r.receiveShadows = false;
|
||||
if (r is SkinnedMeshRenderer smr)
|
||||
{
|
||||
smr.updateWhenOffscreen = true; // скелет свой и неподвижный - границы не пересчитываются, не пропадать с краю экрана
|
||||
smr.updateWhenOffscreen = false; // 16.10: вне экрана скелет не считать (экономия); границы - от сетки
|
||||
}
|
||||
if (r.name.Contains("eye"))
|
||||
{
|
||||
@@ -421,9 +435,28 @@ namespace NecromancerTome
|
||||
CinerariumGenie.Live.Remove(this);
|
||||
}
|
||||
|
||||
float _nextSleepCheck;
|
||||
bool _asleep;
|
||||
|
||||
void Update()
|
||||
{
|
||||
if (_stuck)
|
||||
if (Time.time >= _nextSleepCheck)
|
||||
{
|
||||
_nextSleepCheck = Time.time + 0.5f;
|
||||
bool asleep = CinerariumGenie.PlayerFar(transform.position);
|
||||
if (asleep && !_asleep)
|
||||
{
|
||||
_t = -1f; // полёт прерван - дело всё равно выполнится
|
||||
Gesture(0f);
|
||||
transform.localPosition = Home();
|
||||
}
|
||||
_asleep = asleep;
|
||||
foreach (Renderer r in GetComponentsInChildren<Renderer>(true))
|
||||
{
|
||||
r.enabled = !CinerariumGenie.Hidden;
|
||||
}
|
||||
}
|
||||
if (_stuck || _asleep)
|
||||
{
|
||||
return; // замер как был
|
||||
}
|
||||
@@ -505,12 +538,18 @@ namespace NecromancerTome
|
||||
"necrogenie alpha <0-1> - body brightness (the body adds light, it is not alpha-blended)\n" +
|
||||
"necrogenie glow <0-1> - body's own glow (visible at night)\n" +
|
||||
"necrogenie tint <r> <g> <b> - body colour\n" +
|
||||
"necrogenie arms <out> <fwd> <elbow> - arm pose, degrees: upper arm from vertical sideways and forward, elbow bend";
|
||||
"necrogenie arms <out> <fwd> <elbow> - arm pose, degrees: upper arm from vertical sideways and forward, elbow bend\n" +
|
||||
"necrogenie sleep <m> - spirits and threads freeze when the player is farther (work goes on)\n" +
|
||||
"necrogenie hide|show - hide all spirits (weak PCs, video), work goes on";
|
||||
}
|
||||
|
||||
public override void Execute(List<string> _params, CommandSenderInfo _senderInfo)
|
||||
{
|
||||
SdtdConsole con = SingletonMonoBehaviour<SdtdConsole>.Instance;
|
||||
if (_params.Count == 1 && (_params[0] == "hide" || _params[0] == "show"))
|
||||
{
|
||||
CinerariumGenie.Hidden = _params[0] == "hide";
|
||||
}
|
||||
if (_params.Count >= 2 && float.TryParse(_params[1], System.Globalization.NumberStyles.Float, System.Globalization.CultureInfo.InvariantCulture, out float v))
|
||||
{
|
||||
switch (_params[0].ToLowerInvariant())
|
||||
@@ -539,6 +578,9 @@ namespace NecromancerTome
|
||||
CinerariumGenie.Glow = Mathf.Clamp01(v);
|
||||
CinerariumGenie.ApplyAlpha();
|
||||
break;
|
||||
case "sleep":
|
||||
CinerariumGenie.SleepDistance = Mathf.Max(5f, v);
|
||||
break;
|
||||
case "arms":
|
||||
CinerariumGenie.ArmOut = v;
|
||||
if (_params.Count >= 3 && float.TryParse(_params[2], System.Globalization.NumberStyles.Float, System.Globalization.CultureInfo.InvariantCulture, out float af))
|
||||
@@ -572,7 +614,7 @@ namespace NecromancerTome
|
||||
", bob " + CinerariumGenie.BobHeight.ToString("F2") + " / " + CinerariumGenie.BobPeriod.ToString("F1") + " s, alpha " +
|
||||
CinerariumGenie.Alpha.ToString("F2") + ", glow " + CinerariumGenie.Glow.ToString("F2") + ", tint " +
|
||||
CinerariumGenie.Tint.r.ToString("F2") + " " + CinerariumGenie.Tint.g.ToString("F2") + " " + CinerariumGenie.Tint.b.ToString("F2") + ", arms " + CinerariumGenie.ArmOut.ToString("F0") + " " +
|
||||
CinerariumGenie.ArmFwd.ToString("F0") + " " + CinerariumGenie.Elbow.ToString("F0") + "; spirits on screen: " + CinerariumGenie.Live.Count);
|
||||
CinerariumGenie.ArmFwd.ToString("F0") + " " + CinerariumGenie.Elbow.ToString("F0") + ", sleep " + CinerariumGenie.SleepDistance.ToString("F0") + " m" + (CinerariumGenie.Hidden ? ", HIDDEN" : "") + "; spirits on screen: " + CinerariumGenie.Live.Count);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,175 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace NecromancerTome
|
||||
{
|
||||
/// <summary>
|
||||
/// Группы предметов для фильтра урны-логиста (16.10.2026): «пиктограммы, которые по умолчанию выбраны и активны...
|
||||
/// изображения предмета, символизирующего группу предметов... Дух-логист будет переносить только те предметы, которые
|
||||
/// активированы в его урне. Это же прямой путь к автоматизации сортировки». Деление игры (свойство Group) грубое -
|
||||
/// «Ресурсы» смешивают руду, слитки, детали и кур, - поэтому группы свои, а предмет относится к группе по классу, тегам и
|
||||
/// имени. Предметы других модов разойдутся по тем же правилам; что не подошло никуда - «Прочее».
|
||||
/// Номер группы = номер бита в TEFeatureCinerarium.GroupMask - порядок НЕ менять (сейвы), новые - только в конец.
|
||||
/// </summary>
|
||||
public static class CinerariumGroups
|
||||
{
|
||||
public const int Cooked = 0, Canned = 1, Raw = 2, Harvest = 3, Flowers = 4, Seeds = 5, Drinks = 6, Medicine = 7, Ore = 8,
|
||||
Ingots = 9, Parts = 10, Materials = 11, Chemicals = 12, Tools = 13, Weapons = 14, Ammo = 15, Armor = 16, Mods = 17,
|
||||
Books = 18, Blocks = 19, Necro = 20, Other = 21;
|
||||
public const int Count = 22;
|
||||
public const uint All = (1u << Count) - 1;
|
||||
|
||||
/// <summary>Значок группы - иконка типичного предмета (ItemIconAtlas).</summary>
|
||||
public static readonly string[] Icons =
|
||||
{
|
||||
"foodMeatStew", "foodCanChili", "foodRawMeat", "foodCropCorn", "plantedChrysanthemum3Harvest", "plantedCorn1",
|
||||
"drinkJarBoiledWater", "medicalFirstAidKit", "resourceRockSmall", "resourceForgedSteel", "resourceMechanicalParts",
|
||||
"resourceWood", "resourceGunPowder", "meleeToolPickT1IronPickaxe", "gunHandgunT1Pistol", "ammo9mmBulletBall",
|
||||
"armorMinerHelmet", "modGunLaserSight", "bookArtOfMiningLuckyStrike", "cobblestoneMaster", "necroSkull", "oldCash"
|
||||
};
|
||||
|
||||
/// <summary>Ключ названия группы в Localization.csv: necroGroup0..necroGroup21.</summary>
|
||||
public static string NameKey(int _g) => "necroGroup" + _g;
|
||||
|
||||
static readonly HashSet<string> OreNames = new HashSet<string>
|
||||
{
|
||||
"resourceRockSmall", "resourceRockSmallBundle", "resourceScrapIron", "resourceScrapIronBundle", "resourceScrapLead",
|
||||
"resourceLeadBundle", "resourceCoal", "resourceCoalBundle", "resourcePotassiumNitratePowder",
|
||||
"resourcePotassiumNitratePowderBundle", "resourceOilShale", "resourceOilShaleBundle", "resourceClayLump",
|
||||
"resourceCrushedSand", "resourceCobblestones", "resourceGoldNugget", "resourceSilverNugget", "resourceRawDiamond",
|
||||
"resourceSnowBall"
|
||||
};
|
||||
static readonly HashSet<string> IngotNames = new HashSet<string> { "resourceForgedIron", "resourceForgedSteel" };
|
||||
static readonly HashSet<string> ChemNames = new HashSet<string>
|
||||
{
|
||||
"resourceGunPowder", "resourceGunPowderBundle", "resourceOil", "ammoGasCan", "ammoGasCanBundle", "resourceAcid",
|
||||
"resourceGlue", "resourcePaint", "resourceTestosteroneExtract"
|
||||
};
|
||||
static readonly HashSet<string> MaterialNames = new HashSet<string>
|
||||
{
|
||||
"resourceWood", "resourceWoodBundle", "resourceCloth", "resourceLeather", "resourceBone", "resourceFeather",
|
||||
"resourceYuccaFibers", "resourcePaper", "resourceCement", "resourceConcreteMix", "resourceBeeswax", "resourceCandleStick"
|
||||
};
|
||||
static readonly HashSet<string> AmmoParts = new HashSet<string>
|
||||
{
|
||||
"resourceArrowHeadIron", "resourceArrowHeadSteelAP", "resourceBuckshot", "resourceBulletCasing", "resourceBulletTip",
|
||||
"resourceRocketCasing", "resourceRocketTip"
|
||||
};
|
||||
static readonly HashSet<string> RawNames = new HashSet<string>
|
||||
{
|
||||
"foodRawMeat", "foodRawMeatBundle", "foodEgg", "foodHoney", "foodRottingFlesh"
|
||||
};
|
||||
|
||||
static readonly Dictionary<int, int> _cache = new Dictionary<int, int>();
|
||||
|
||||
public static int Of(ItemValue _iv)
|
||||
{
|
||||
ItemClass ic = _iv?.ItemClass;
|
||||
if (ic == null)
|
||||
{
|
||||
return Other;
|
||||
}
|
||||
if (!_cache.TryGetValue(ic.Id, out int g))
|
||||
{
|
||||
g = Classify(ic, _iv);
|
||||
_cache[ic.Id] = g;
|
||||
}
|
||||
return g;
|
||||
}
|
||||
|
||||
static bool Tag(ItemClass _ic, string _t)
|
||||
{
|
||||
return _ic.ItemTags.Test_AnySet(FastTags<TagGroup.Global>.Parse(_t));
|
||||
}
|
||||
|
||||
static int Classify(ItemClass _ic, ItemValue _iv)
|
||||
{
|
||||
string n = _ic.GetItemName() ?? "";
|
||||
if (n.IndexOf("necro", StringComparison.OrdinalIgnoreCase) >= 0)
|
||||
{
|
||||
return Necro;
|
||||
}
|
||||
if (_ic is ItemClassModifier)
|
||||
{
|
||||
return Mods;
|
||||
}
|
||||
if (_ic.IsBlock())
|
||||
{
|
||||
return new ItemValue(_ic.Id).ToBlockValue().Block is BlockPlantGrowing ? Seeds : Blocks;
|
||||
}
|
||||
if (_ic is ItemClassArmor || n.StartsWith("armor") || n.StartsWith("clothing"))
|
||||
{
|
||||
return Armor;
|
||||
}
|
||||
if (n.StartsWith("book") || n.Contains("Schematic") || n.Contains("Magazine") || Tag(_ic, "books"))
|
||||
{
|
||||
return Books;
|
||||
}
|
||||
if (OreNames.Contains(n))
|
||||
{
|
||||
return Ore;
|
||||
}
|
||||
if (IngotNames.Contains(n) || n.StartsWith("unit_"))
|
||||
{
|
||||
return Ingots;
|
||||
}
|
||||
if (ChemNames.Contains(n))
|
||||
{
|
||||
return Chemicals;
|
||||
}
|
||||
if (MaterialNames.Contains(n))
|
||||
{
|
||||
return Materials;
|
||||
}
|
||||
if (AmmoParts.Contains(n) || n.StartsWith("ammo") || n.StartsWith("thrown") || Tag(_ic, "ammo"))
|
||||
{
|
||||
return Ammo;
|
||||
}
|
||||
if (n.EndsWith("Parts") || n == "partsMaster" || n.StartsWith("vehicle") && !n.EndsWith("Placeable"))
|
||||
{
|
||||
return Parts;
|
||||
}
|
||||
if (n.StartsWith("gun") || n.StartsWith("meleeWpn") || Tag(_ic, "weapon"))
|
||||
{
|
||||
return Weapons;
|
||||
}
|
||||
if (n.StartsWith("meleeTool") || n.StartsWith("tool") || n.StartsWith("bucket") || Tag(_ic, "tool"))
|
||||
{
|
||||
return Tools;
|
||||
}
|
||||
if (n.StartsWith("foodCan"))
|
||||
{
|
||||
return Canned;
|
||||
}
|
||||
if (n.StartsWith("foodCrop"))
|
||||
{
|
||||
return Harvest;
|
||||
}
|
||||
if (n.StartsWith("resourceCrop"))
|
||||
{
|
||||
return Flowers;
|
||||
}
|
||||
if (RawNames.Contains(n) || n.StartsWith("foodRaw"))
|
||||
{
|
||||
return Raw;
|
||||
}
|
||||
if (n.StartsWith("drink"))
|
||||
{
|
||||
return Drinks;
|
||||
}
|
||||
if (n.StartsWith("medical") || n.StartsWith("drug") || Tag(_ic, "medical"))
|
||||
{
|
||||
return Medicine;
|
||||
}
|
||||
if (n.StartsWith("food") || Tag(_ic, "food"))
|
||||
{
|
||||
return Cooked;
|
||||
}
|
||||
if (n.StartsWith("resource") || n == "carBattery" || n == "smallEngine" || n == "solarCell")
|
||||
{
|
||||
return Parts;
|
||||
}
|
||||
return Other;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -329,8 +329,20 @@ namespace NecromancerTome
|
||||
}
|
||||
}
|
||||
|
||||
float _nextSleepCheck;
|
||||
bool _asleep;
|
||||
|
||||
void Update()
|
||||
{
|
||||
if (Time.time >= _nextSleepCheck)
|
||||
{
|
||||
_nextSleepCheck = Time.time + 0.5f;
|
||||
_asleep = CinerariumGenie.PlayerFar(transform.position); // засыпание (16.10): огоньки стоят
|
||||
}
|
||||
if (_asleep)
|
||||
{
|
||||
return;
|
||||
}
|
||||
foreach (Thread th in _threads)
|
||||
{
|
||||
float len = Mathf.Max(0.5f, Vector3.Distance(th.A, th.B));
|
||||
|
||||
@@ -15,6 +15,8 @@ namespace NecromancerTome
|
||||
public const string LootTemplate = "roboticDrone"; // звуки и время открытия, как у сумки волка
|
||||
|
||||
static TEFeatureCinerarium _urn;
|
||||
/// <summary>Урна, чьё «Содержимое» сейчас открыто (окно фильтра логиста), или null.</summary>
|
||||
public static TEFeatureCinerarium Urn => _urn;
|
||||
static Bag _bag;
|
||||
static EntityPlayerLocal _player;
|
||||
|
||||
|
||||
@@ -131,8 +131,8 @@ namespace NecromancerTome
|
||||
return null;
|
||||
}
|
||||
|
||||
/// <summary>Перевозка по нитям: одна стопка из ящика «откуда» в ящик «куда». По образцу - только то, что в «куда» уже
|
||||
/// есть (пустой «куда» - что угодно); «куда» полон - ждём (дух не чернеет). Открытые у игрока ящики и закреплённые
|
||||
/// <summary>Перевозка по нитям: одна стопка из ящика «откуда» в ящик «куда». Только предметы включённых в урне групп
|
||||
/// (фильтр логиста, CinerariumGroups; 16.10 заменил прежнее правило «по образцу»); «куда» полон - ждём (дух не чернеет). Открытые у игрока ящики и закреплённые
|
||||
/// ячейки не трогаются. Возвращает ящик «куда», LastFrom - откуда взято.</summary>
|
||||
static Vector3i? Ferry(World _world, TEFeatureCinerarium _urn)
|
||||
{
|
||||
@@ -145,7 +145,6 @@ namespace NecromancerTome
|
||||
{
|
||||
return null;
|
||||
}
|
||||
bool any = dst.IsEmpty();
|
||||
foreach (Vector3i f in _urn.ThreadFrom)
|
||||
{
|
||||
if (f == _urn.ThreadTo)
|
||||
@@ -160,7 +159,7 @@ namespace NecromancerTome
|
||||
for (int k = 0; k < src.ItemGrid.Length; k++)
|
||||
{
|
||||
ItemStack s = src.ItemGrid[k];
|
||||
if (s == null || s.IsEmpty() || Locked(src, k) || (!any && !Holds(dst, s.itemValue.type)) || !Fits(dst, s))
|
||||
if (s == null || s.IsEmpty() || Locked(src, k) || !_urn.GroupOn(CinerariumGroups.Of(s.itemValue)) || !Fits(dst, s))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
@@ -192,19 +191,6 @@ namespace NecromancerTome
|
||||
c.TryGetSelfOrFeature<TEFeatureStorage>(out TEFeatureStorage s) ? s : null;
|
||||
}
|
||||
|
||||
static bool Holds(TEFeatureStorage _t, int _type)
|
||||
{
|
||||
for (int i = 0; i < _t.ItemGrid.Length; i++)
|
||||
{
|
||||
ItemStack x = _t.ItemGrid[i];
|
||||
if (x != null && !x.IsEmpty() && x.itemValue.type == _type)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool IsRipe(Block _b)
|
||||
{
|
||||
return _b != null && !(_b is BlockPlantGrowing) && _b.HasAnyFastTags(CropTag) &&
|
||||
|
||||
Binary file not shown.
Reference in New Issue
Block a user