Ремонтник: сначала то, на что есть материал; ячейка нехватки видна всегда

- Блоки без материалов откладываются (_lacking) и не держат очередь;
  к ним ремонтник возвращается, когда чинить больше нечего, и чинит, как
  только материал появился. Зона не останавливается, пока они есть.
- Кнопка жёлтая, только когда кроме ждущих чинить нечего; ячейка «не
  хватает» видна, пока хоть один блок ждёт.
- «Запустить» повторно отпускает старые взятые блоки (Claimed) - раньше
  они не попадали в обход заново.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
AlexCube
2026-10-24 15:47:13 +03:00
co-authored by Claude Opus 5.5
parent 3d08511e5b
commit 5ebd09dacd
4 changed files with 82 additions and 19 deletions
+3 -2
View File
@@ -8,7 +8,8 @@ namespace NecromancerTome
/// нужен в данный момент? А то не угадать», «Пусть показывает в виде ячейки с материалом», «И восклицательный знак. Чтобы /// нужен в данный момент? А то не угадать», «Пусть показывает в виде ячейки с материалом», «И восклицательный знак. Чтобы
/// было понятно что именно это требуется»). Ячейка дописана в окно игры windowBagStorage (Config/XUi_InGame/windows.xml) /// было понятно что именно это требуется»). Ячейка дописана в окно игры windowBagStorage (Config/XUi_InGame/windows.xml)
/// под блоком лимита урн: иконка материала, сколько доложить в ящики с нитями, красный «!». Только показ - не ячейка /// под блоком лимита урн: иконка материала, сколько доложить в ящики с нитями, красный «!». Только показ - не ячейка
/// сумки, взять из неё нечего. Видна у ремонтника, пока он ждёт материал (TEFeatureCinerarium.LackType/LackCount). /// сумки, взять из неё нечего. Видна у ремонтника, пока хоть один блок ждёт материал (TEFeatureCinerarium.LackType/LackCount) - и когда он чинит
/// остальное.
/// </summary> /// </summary>
[Preserve] [Preserve]
public class XUiC_NecroRepairNeed : XUiController public class XUiC_NecroRepairNeed : XUiController
@@ -44,7 +45,7 @@ namespace NecromancerTome
{ {
_nextRefresh = Time.time + 0.5f; _nextRefresh = Time.time + 0.5f;
TEFeatureCinerarium urn = CinerariumContents.Urn; TEFeatureCinerarium urn = CinerariumContents.Urn;
ItemClass ic = urn != null && urn.IsRepairer && urn.ZoneLacking && urn.LackType > 0 ? ItemClass.GetForId(urn.LackType) : null; ItemClass ic = urn != null && urn.IsRepairer && urn.LackType > 0 ? ItemClass.GetForId(urn.LackType) : null;
ViewComponent.IsVisible = ic != null; ViewComponent.IsVisible = ic != null;
if (ic == null) if (ic == null)
{ {
+79 -17
View File
@@ -89,6 +89,10 @@ namespace NecromancerTome
static readonly HashSet<Vector3i> Claimed = new HashSet<Vector3i>(); static readonly HashSet<Vector3i> Claimed = new HashSet<Vector3i>();
readonly List<Vector3i> _queue = new List<Vector3i>(); readonly List<Vector3i> _queue = new List<Vector3i>();
/// <summary>Ремонтник: блоки, на которые нет материалов (24.10, пользователь: «Если не может починить что-то для чего
/// нет ресурсов, пусть сначала чинит то, для чего они есть»). Не держат очередь обхода; к ним - когда больше нечего.</summary>
readonly List<Vector3i> _lacking = new List<Vector3i>();
const int LackingMax = 256;
float _zoneNext; float _zoneNext;
bool _zonePending; bool _zonePending;
float _zoneActAt; float _zoneActAt;
@@ -175,7 +179,7 @@ namespace NecromancerTome
ZoneCursor = 0; ZoneCursor = 0;
ZoneLacking = false; ZoneLacking = false;
ZonePressedBy = _player != null ? _player.entityId : -1; ZonePressedBy = _player != null ? _player.entityId : -1;
_queue.Clear(); ReleaseClaims();
_lootDone.Clear(); _lootDone.Clear();
Audio.Manager.BroadcastPlay(World.blockToTransformPos(ToWorldPos()), "button4"); Audio.Manager.BroadcastPlay(World.blockToTransformPos(ToWorldPos()), "button4");
Debug.Log("[NecromancerTome] Cinerarium: " + (IsLooter ? "лутер" : "ремонтник") + " " + ToWorldPos() + " запущен, зона " + ZoneSideNow); Debug.Log("[NecromancerTome] Cinerarium: " + (IsLooter ? "лутер" : "ремонтник") + " " + ToWorldPos() + " запущен, зона " + ZoneSideNow);
@@ -206,11 +210,7 @@ namespace NecromancerTome
/// <summary>Остановить проход (кнопка, урна убрана): очередь и взятые блоки отпускаются.</summary> /// <summary>Остановить проход (кнопка, урна убрана): очередь и взятые блоки отпускаются.</summary>
public void ZoneStop(bool _log) public void ZoneStop(bool _log)
{ {
foreach (Vector3i p in _queue) ReleaseClaims();
{
Claimed.Remove(p);
}
_queue.Clear();
_zonePending = false; _zonePending = false;
if (ZoneRunning && _log) if (ZoneRunning && _log)
{ {
@@ -220,6 +220,23 @@ namespace NecromancerTome
ZoneLacking = false; ZoneLacking = false;
} }
/// <summary>Очередь и отложенные блоки - отпустить (Claimed) и забыть.</summary>
void ReleaseClaims()
{
foreach (Vector3i p in _queue)
{
Claimed.Remove(p);
}
foreach (Vector3i p in _lacking)
{
Claimed.Remove(p);
}
_queue.Clear();
_lacking.Clear();
LackType = 0;
LackCount = 0;
}
void ZoneWork(World _world) void ZoneWork(World _world)
{ {
SyncButtons(); SyncButtons();
@@ -326,7 +343,7 @@ namespace NecromancerTome
} }
} }
} }
if (ZoneCursor >= total && _queue.Count == 0 && !_zonePending) if (ZoneCursor >= total && _queue.Count == 0 && _lacking.Count == 0 && !_zonePending)
{ {
Debug.Log("[NecromancerTome] Cinerarium: ремонтник " + c + " обошёл зону - ожидание"); Debug.Log("[NecromancerTome] Cinerarium: ремонтник " + c + " обошёл зону - ожидание");
ZoneStop(false); ZoneStop(false);
@@ -334,32 +351,78 @@ namespace NecromancerTome
} }
} }
/// <summary>Следующий блок: сначала из очереди обхода, на что есть материалы (на что нет - в _lacking), потом из _lacking,
/// если материал появился. Нечего чинить, кроме ждущих материала, - кнопка жёлтая. Ячейка «не хватает» в «Содержимом» -
/// первый блок из _lacking (LackType/LackCount), пока он есть.</summary>
void RepairPick(World _world, CinerariumGenieMotion _motion) void RepairPick(World _world, CinerariumGenieMotion _motion)
{ {
while (_queue.Count > 0) while (_queue.Count > 0)
{ {
Vector3i p = _queue[0]; Vector3i p = _queue[0];
_queue.RemoveAt(0);
BlockValue bv = _world.GetBlock(p); BlockValue bv = _world.GetBlock(p);
if (bv.isair || bv.damage <= 0 || bv.Block?.RepairItems == null) if (bv.isair || bv.damage <= 0 || bv.Block?.RepairItems == null)
{ {
_queue.RemoveAt(0);
Claimed.Remove(p); Claimed.Remove(p);
continue; // починили до нас или блок убран continue; // починили до нас или блок убран
} }
if (!HasMaterials(_world, bv, false)) if (!HasMaterials(_world, bv, false))
{ {
if (!ZoneLacking) if (_lacking.Count < LackingMax)
{ {
Debug.Log("[NecromancerTome] Cinerarium: ремонтнику " + ToWorldPos() + " не хватает материалов для " + bv.Block.GetBlockName() + " в " + p); _lacking.Add(p);
} }
ZoneLacking = true; else
return; // ждём: положат в ящик - продолжим с того же блока {
Claimed.Remove(p); // найдётся при следующем обходе
}
continue;
} }
ZoneLacking = false; Go(_world, _motion, p);
_zoneTarget = p;
FlyThenAct(_world, _motion, p);
return; return;
} }
int lackType = 0, lackCount = 0;
for (int i = 0; i < _lacking.Count; i++)
{
Vector3i p = _lacking[i];
BlockValue bv = _world.GetBlock(p);
if (bv.isair || bv.damage <= 0 || bv.Block?.RepairItems == null)
{
_lacking.RemoveAt(i--);
Claimed.Remove(p);
continue;
}
if (HasMaterials(_world, bv, false))
{
_lacking.RemoveAt(i);
Go(_world, _motion, p);
LackType = lackType;
LackCount = lackCount;
return;
}
if (lackType == 0)
{
lackType = LackType;
lackCount = LackCount;
}
}
LackType = lackType;
LackCount = lackCount;
bool stuck = _lacking.Count > 0;
if (stuck && !ZoneLacking)
{
ItemClass ic = ItemClass.GetForId(LackType);
Debug.Log("[NecromancerTome] Cinerarium: ремонтнику " + ToWorldPos() + " нечего чинить без материалов: ждут " + _lacking.Count +
" блок(ов), первым не хватает " + LackCount + " " + ic?.GetItemName());
}
ZoneLacking = stuck;
}
void Go(World _world, CinerariumGenieMotion _motion, Vector3i _p)
{
ZoneLacking = false;
_zoneTarget = _p;
FlyThenAct(_world, _motion, _p);
} }
void RepairNow(World _world, Vector3i _p) void RepairNow(World _world, Vector3i _p)
@@ -373,8 +436,7 @@ namespace NecromancerTome
} }
if (!HasMaterials(_world, bv, true)) if (!HasMaterials(_world, bv, true))
{ {
ZoneLacking = true; _lacking.Add(_p); // материал забрали, пока дух летел
_queue.Insert(0, _p);
Claimed.Add(_p); Claimed.Add(_p);
return; return;
} }
Binary file not shown.
Binary file not shown.