Нити цинерария: нож «хватом для нитей» (R), нити урна-ящик как у стриппера, урна-логист перевозит по образцу, зелёные глазницы

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
AlexCube
2026-10-16 20:29:50 +03:00
co-authored by Claude Opus 5.5
parent fad57a3756
commit d8e7c8c66a
10 changed files with 885 additions and 63 deletions
+83
View File
@@ -59,9 +59,18 @@ namespace NecromancerTome
}
}
/// <summary>У перевозки по нити - ящик «откуда» последнего шага (дух летит сначала к нему), иначе null.</summary>
public static Vector3i? LastFrom;
static Vector3i? DoStep(World _world, TEFeatureCinerarium _urn, out bool _stuck)
{
_stuck = false;
LastFrom = null;
// Урна с нитями - логист (16.10: «занимается только перетаскиванием из ящиков в ящики»).
if (_urn.IsLogist)
{
return Ferry(_world, _urn);
}
Zone z = Scan(_world, _urn);
// 1. Расходники.
foreach (TileEntityCollector c in z.Collectors)
@@ -122,6 +131,80 @@ namespace NecromancerTome
return null;
}
/// <summary>Перевозка по нитям: одна стопка из ящика «откуда» в ящик «куда». По образцу - только то, что в «куда» уже
/// есть (пустой «куда» - что угодно); «куда» полон - ждём (дух не чернеет). Открытые у игрока ящики и закреплённые
/// ячейки не трогаются. Возвращает ящик «куда», LastFrom - откуда взято.</summary>
static Vector3i? Ferry(World _world, TEFeatureCinerarium _urn)
{
if (!_urn.HasThreadTo)
{
return null;
}
TEFeatureStorage dst = BoxAt(_world, _urn.ThreadTo);
if (dst == null)
{
return null;
}
bool any = dst.IsEmpty();
foreach (Vector3i f in _urn.ThreadFrom)
{
if (f == _urn.ThreadTo)
{
continue;
}
TEFeatureStorage src = BoxAt(_world, f);
if (src == null)
{
continue;
}
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))
{
continue;
}
LastFrom = f;
if (_dry)
{
return _urn.ThreadTo;
}
ItemStack moving = s.Clone();
Place(moving, new[] { dst });
int moved = s.count - moving.count;
if (moved <= 0)
{
continue;
}
Take(src, k, moved);
dst.SetModified();
Debug.Log("[NecromancerTome] Cinerarium: дух перенёс " + moved + " " + s.itemValue.ItemClass?.GetItemName() + " из " + f + " в " + _urn.ThreadTo);
return _urn.ThreadTo;
}
}
return null;
}
static TEFeatureStorage BoxAt(World _world, Vector3i _p)
{
return _world.GetTileEntity(_p) is TileEntityComposite c && !c.IsUserAccessing() &&
!c.TryGetSelfOrFeature<TEFeatureCinerarium>(out TEFeatureCinerarium _) &&
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) &&