Ремонтник и лутер: свои модели (фляга со звонками, мешок), проверка добычи

- Модели (BlenderWork/necroCinerariumRepair, necroCinerariumLoot): ремонтник - квадратная
  фляга, лутер - глазурованный мешок с верёвкой; на обоих - четыре латунных звонка с
  черепом-кнопкой (деталь *_button - подсветка состояния) и руны кровью футарком
  («RIPARU ĜIS LA LASTA BRIKO», «KOLEKTU ĜIS LA LASTA PECETO»), светятся по черепу.
- Лутер: цели, из которых за проход нечего взять, второй раз не обыскиваются (не зацикливается).
- Разработка: necroclear (убрать только растения), necrobag с сумкой по списку добычи.

Проверено в игре: мешок с зомби и красный труп (прах, кожа жертвы) - в ящик, проход
заканчивается сам.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
AlexCube
2026-10-18 15:20:31 +03:00
co-authored by Claude Opus 5.5
parent a352a408a4
commit 51db24fd2f
7 changed files with 52 additions and 4 deletions
+4 -2
View File
@@ -621,7 +621,8 @@
<property name="Extends" value="necroCinerarium"/> <property name="Extends" value="necroCinerarium"/>
<property name="CreativeMode" value="Player"/> <property name="CreativeMode" value="Player"/>
<property name="DescriptionKey" value="necroCinerariumRepairDesc"/> <property name="DescriptionKey" value="necroCinerariumRepairDesc"/>
<property name="CustomIcon" value="necroCinerarium"/> <!-- своя иконка - после модели --> <property name="CustomIcon" value="necroCinerarium"/> <!-- своя иконка - после рендера -->
<property name="Model" value="#@modfolder(NecromancerTome):Resources/necrocinerarium?necroCinerariumRepairPrefab.prefab"/>
</block> </block>
<block name="necroCinerariumRepairSkull"> <block name="necroCinerariumRepairSkull">
<property name="Extends" value="necroCinerariumRepair"/> <property name="Extends" value="necroCinerariumRepair"/>
@@ -632,7 +633,8 @@
<property name="Extends" value="necroCinerarium"/> <property name="Extends" value="necroCinerarium"/>
<property name="CreativeMode" value="Player"/> <property name="CreativeMode" value="Player"/>
<property name="DescriptionKey" value="necroCinerariumLootDesc"/> <property name="DescriptionKey" value="necroCinerariumLootDesc"/>
<property name="CustomIcon" value="necroCinerarium"/> <!-- своя иконка - после модели --> <property name="CustomIcon" value="necroCinerarium"/> <!-- своя иконка - после рендера -->
<property name="Model" value="#@modfolder(NecromancerTome):Resources/necrocinerarium?necroCinerariumLootPrefab.prefab"/>
</block> </block>
<block name="necroCinerariumLootSkull"> <block name="necroCinerariumLootSkull">
<property name="Extends" value="necroCinerariumLoot"/> <property name="Extends" value="necroCinerariumLoot"/>
+8 -1
View File
@@ -173,6 +173,7 @@ namespace NecromancerTome
ZoneLacking = false; ZoneLacking = false;
ZonePressedBy = _player != null ? _player.entityId : -1; ZonePressedBy = _player != null ? _player.entityId : -1;
_queue.Clear(); _queue.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);
} }
@@ -495,6 +496,8 @@ namespace NecromancerTome
// ------------------------------------------------------------------ // ------------------------------------------------------------------
static readonly List<Entity> _ents = new List<Entity>(); static readonly List<Entity> _ents = new List<Entity>();
/// <summary>Цели, уже обысканные за этот проход (пустой мешок, нечего взять) - второй раз не трогать.</summary>
readonly HashSet<int> _lootDone = new HashSet<int>();
/// <summary>Цель лутера в зоне: предмет на земле, потом мешок с зомби, потом красный труп. Ничего - проход окончен.</summary> /// <summary>Цель лутера в зоне: предмет на земле, потом мешок с зомби, потом красный труп. Ничего - проход окончен.</summary>
void LootPick(World _world, CinerariumGenieMotion _motion) void LootPick(World _world, CinerariumGenieMotion _motion)
@@ -515,7 +518,7 @@ namespace NecromancerTome
foreach (Entity e in _ents) foreach (Entity e in _ents)
{ {
int rank = LootRank(e); int rank = LootRank(e);
if (rank < bestRank && !LockManager.Instance.IsLockedServer(e, 0)) if (rank < bestRank && !_lootDone.Contains(e.entityId) && !LockManager.Instance.IsLockedServer(e, 0))
{ {
best = e; best = e;
bestRank = rank; bestRank = rank;
@@ -628,6 +631,10 @@ namespace NecromancerTome
bag.SetSlot(i, s.count > 0 ? s : ItemStack.Empty.Clone()); bag.SetSlot(i, s.count > 0 ? s : ItemStack.Empty.Clone());
} }
ZoneLacking = left; // не всё влезло - ящик полон, кнопка мигает ZoneLacking = left; // не всё влезло - ящик полон, кнопка мигает
if (!left)
{
_lootDone.Add(e.entityId); // опустошён (или был пуст) - больше не цель; пустой убирает игра
}
Debug.Log("[NecromancerTome] Cinerarium: лутер " + ToWorldPos() + " обыскал " + e.GetType().Name + " " + e.entityId + (left ? " - не всё влезло" : "")); Debug.Log("[NecromancerTome] Cinerarium: лутер " + ToWorldPos() + " обыскал " + e.GetType().Name + " " + e.entityId + (left ? " - не всё влезло" : ""));
} }
+1 -1
View File
@@ -20,7 +20,7 @@ namespace NecromancerTome
static bool Ours(string _name) static bool Ours(string _name)
{ {
return _name == "necroBookMindPrefab" || _name == "necroKnifeDecorPrefab" || _name == "necroMortarPrefab" || _name.StartsWith("necroBloodRose") || _name.StartsWith("necroPoster") || _name == "necroBookDoorPrefab" || _name.StartsWith("necroSkullDecor") || _name == "necroCinerariumPrefab" || _name == "necroCinerariumWorkerPrefab" || _name.StartsWith("necroCinerariumLogist"); return _name == "necroBookMindPrefab" || _name == "necroKnifeDecorPrefab" || _name == "necroMortarPrefab" || _name.StartsWith("necroBloodRose") || _name.StartsWith("necroPoster") || _name == "necroBookDoorPrefab" || _name.StartsWith("necroSkullDecor") || _name == "necroCinerariumPrefab" || _name == "necroCinerariumWorkerPrefab" || _name.StartsWith("necroCinerariumLogist") || _name == "necroCinerariumRepairPrefab" || _name == "necroCinerariumLootPrefab";
} }
public static void Postfix(Transform __result) public static void Postfix(Transform __result)
+39
View File
@@ -69,6 +69,11 @@ namespace NecromancerTome
// necrobag x y z - мешок с зомби (EntityLootContainer со списком cntDropBag), нетронутый // necrobag x y z - мешок с зомби (EntityLootContainer со списком cntDropBag), нетронутый
Entity bag = EntityFactory.CreateEntity(EntityClass.FromString("DroppedLootContainer"), P(_params, 0).ToVector3() + new Vector3(0.5f, 0.3f, 0.5f)); Entity bag = EntityFactory.CreateEntity(EntityClass.FromString("DroppedLootContainer"), P(_params, 0).ToVector3() + new Vector3(0.5f, 0.3f, 0.5f));
bag.lootList = "cntDropBag"; bag.lootList = "cntDropBag";
LootContainer lc = LootContainer.GetLootContainer(bag.lootList, false);
if (lc != null)
{
bag.bag = new Bag(lc.size, XUiC_ItemStack.StackLocationTypes.LootContainer, bag);
}
w.SpawnEntityInWorld(bag); w.SpawnEntityInWorld(bag);
Out("necrobag: " + bag.entityId); Out("necrobag: " + bag.entityId);
break; break;
@@ -83,6 +88,31 @@ namespace NecromancerTome
Out("necrocorpse: " + z.entityId + " " + cls); Out("necrocorpse: " + z.entityId + " " + cls);
break; break;
} }
case "necroclear":
{
// necroclear x0 z0 x1 z1 [y0 y1] - убрать только растения (трава, кусты) в прямоугольнике; землю и постройки
// не трогает (18.10: «necroplace air» по ровной высоте срезал рельеф - яма в test8).
int x0 = int.Parse(_params[0]), z0 = int.Parse(_params[1]), x1 = int.Parse(_params[2]), z1 = int.Parse(_params[3]);
int y0 = _params.Count > 5 ? int.Parse(_params[4]) : 1, y1 = _params.Count > 5 ? int.Parse(_params[5]) : 250;
int n = 0;
for (int x = Mathf.Min(x0, x1); x <= Mathf.Max(x0, x1); x++)
{
for (int z = Mathf.Min(z0, z1); z <= Mathf.Max(z0, z1); z++)
{
for (int y = y0; y <= y1; y++)
{
BlockValue cb = w.GetBlock(x, y, z);
if (!cb.isair && cb.Block != null && cb.Block.IsPlant())
{
w.SetBlockRPC(new Vector3i(x, y, z), BlockValue.Air);
n++;
}
}
}
}
Out("necroclear: растений убрано " + n);
break;
}
case "necrogod": God(pl, _params.Count == 0 || _params[0] != "off"); break; case "necrogod": God(pl, _params.Count == 0 || _params[0] != "off"); break;
case "necroclick": case "necroclick":
// necroclick 0|1 [x y z] - по блоку под прицелом или по указанной клетке (луч не всегда попадает в низкий череп). // necroclick 0|1 [x y z] - по блоку под прицелом или по указанной клетке (луч не всегда попадает в низкий череп).
@@ -425,4 +455,13 @@ namespace NecromancerTome
public override bool AllowedInMainMenu => false; public override bool AllowedInMainMenu => false;
public override void Execute(List<string> _params, CommandSenderInfo _senderInfo) => NecroDev.Run("necrocorpse", _params); public override void Execute(List<string> _params, CommandSenderInfo _senderInfo) => NecroDev.Run("necrocorpse", _params);
} }
[Preserve]
public class ConsoleCmdNecroClear : ConsoleCmdAbstract
{
public override string[] getCommands() => new[] { "necroclear" };
public override string getDescription() => "NecromancerTome (разработка): убрать растения x0 z0 x1 z1 [y0 y1]";
public override bool AllowedInMainMenu => false;
public override void Execute(List<string> _params, CommandSenderInfo _senderInfo) => NecroDev.Run("necroclear", _params);
}
} }
Binary file not shown.
Binary file not shown.
Binary file not shown.