Урны: прозрачные духи, понятные отказы в постановке, 50 убийств на урну

- Духи снова полупрозрачные (Solid = false) - поза принята.
- Отказ в постановке - с цифрами: пересечение зон (сколько блоков до соседнего сборщика,
  зоны 5x5); лимит - сколько стоит из скольких, сколько упокоено и сколько ещё до следующей,
  с обоснованием (сила некроманта держит духов). Логист/рабочий/ремонтник/лутер не в лимите.
- Лимит сборщиков: одна урна на 50 упокоенных (было 200); описание урны - 13 языков.
- Команда necrocanplace - текст отказа для клетки.

Проверено в игре: подсказка о пересечении (2 блока, 5x5), логист рядом - можно.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
AlexCube
2026-10-18 18:50:46 +03:00
co-authored by Claude Opus 5.5
parent eaa6b3bbb3
commit 05dca19852
6 changed files with 38 additions and 11 deletions
File diff suppressed because one or more lines are too long
+21 -7
View File
@@ -71,7 +71,7 @@ namespace NecromancerTome
public const int Above = 4;
/// <summary>Убийств на одну урну сборщика. 17.10: «лимит урн - ослабить/убрать» - нагрузку теперь держит общий бюджет
/// шагов (CinerariumLoad), лимит остался мягким игровым порогом: было 500, стало 200.</summary>
public const float KillsPerUrn = 200f;
public const float KillsPerUrn = 50f; // 18.10 вечером: «Пусть будет 50 киллов на урну» (было 200, до того 500)
const byte SaveVersion = 6; // 2 - нити, 3 - фильтр логиста (16.10), 4 - нити рабочего «куда» и образец (18.10), 5 - черепа-ретрансляторы (18.10), 6 - зона и запуск ремонтника/лутера (18.10)
public bool HasSkull;
@@ -1098,12 +1098,14 @@ namespace NecromancerTome
return Mathf.CeilToInt(kills / KillsPerUrn);
}
/// <summary>Ключ подсказки, почему урну сюда нельзя, или null.</summary>
/// <summary>Текст подсказки, почему урну сюда нельзя (с цифрами - 18.10: «Ограничения на урны нужно сделать чёткими и
/// понятными, чтобы персонаж их мог видеть»), или null.</summary>
public static string PlacementRefusal(Vector3i _pos, Block _placing)
{
if (!IsZonelessBlock(_placing) && CinerariumRegistry.Overlaps(_pos))
if (!IsZonelessBlock(_placing) && CinerariumRegistry.Overlaps(_pos, out Vector3i other))
{
return "necroCinerariumOverlap";
int d = Math.Max(Math.Abs(other.x - _pos.x), Math.Abs(other.z - _pos.z));
return string.Format(Localization.Get("necroCinerariumOverlap"), d, HalfWidth * 2 + 1);
}
if (IsZonelessBlock(_placing))
{
@@ -1115,9 +1117,16 @@ namespace NecromancerTome
if (player != null && world != null && !world.IsRemote())
{
PlatformUserIdentifierAbs me = PlatformManager.InternalLocalUserIdentifier;
if (CinerariumRegistry.CountFor(me) >= UrnLimit(player))
int have = CinerariumRegistry.CountFor(me), limit = UrnLimit(player);
if (have >= limit)
{
return "necroCinerariumLimit";
float kills = player.Buffs != null ? player.Buffs.GetCustomVar(Patch_EntityPlayer_AddKillXP_NecromancyCount.KillsCVarName) : 0f;
int next = Mathf.CeilToInt((limit + 1) * KillsPerUrn - kills);
if (kills <= 0f)
{
next = Mathf.CeilToInt(KillsPerUrn);
}
return string.Format(Localization.Get("necroCinerariumLimit"), have, limit, (int)KillsPerUrn, (int)kills, Math.Max(1, next));
}
}
return null;
@@ -1242,8 +1251,12 @@ namespace NecromancerTome
/// <summary>Пересекутся ли зоны урны в _pos и уже стоящей: по горизонтали ближе 5 блоков по обеим осям,
/// по высоте ближе 6 (зона от -1 до +4).</summary>
public static bool Overlaps(Vector3i _pos)
public static bool Overlaps(Vector3i _pos) => Overlaps(_pos, out Vector3i _);
/// <summary>То же, с урной, с которой пересечётся зона.</summary>
public static bool Overlaps(Vector3i _pos, out Vector3i _other)
{
_other = _pos;
int w = TEFeatureCinerarium.HalfWidth * 2;
int h = TEFeatureCinerarium.Below + TEFeatureCinerarium.Above;
World world = GameManager.Instance?.World;
@@ -1255,6 +1268,7 @@ namespace NecromancerTome
}
if (p != _pos && Math.Abs(p.x - _pos.x) <= w && Math.Abs(p.z - _pos.z) <= w && Math.Abs(p.y - _pos.y) <= h)
{
_other = p;
return true;
}
}
+1 -1
View File
@@ -183,7 +183,7 @@ namespace NecromancerTome
/// <summary>ВРЕМЕННО (17.10: «Временно убери им прозрачность. А то плохо видно» - пока подбирается поза рук): дух
/// непрозрачный, обычная заливка с записью глубины. Перед релизом вернуть false (BACKLOG). Консоль: necrogenie solid 0|1.</summary>
public static bool Solid = true;
public static bool Solid = false; // 18.10: прозрачность вернули («Прозрачность верни сразу»)
static void SetLook(Material _m)
{
+13
View File
@@ -236,6 +236,10 @@ namespace NecromancerTome
Out("necrosmooth: краевых клеток " + edge.Count);
break;
}
case "necrocanplace":
// necrocanplace блок x y z - подсказка, почему урну сюда нельзя (или «можно»)
Out("necrocanplace: " + (TEFeatureCinerarium.PlacementRefusal(P(_params, 1), Block.GetBlockByName(_params[0], true)) ?? "можно"));
break;
case "necrogod": God(pl, _params.Count == 0 || _params[0] != "off"); break;
case "necroclick":
// necroclick 0|1 [x y z] - по блоку под прицелом или по указанной клетке (луч не всегда попадает в низкий череп).
@@ -615,4 +619,13 @@ namespace NecromancerTome
public override bool AllowedInMainMenu => false;
public override void Execute(List<string> _params, CommandSenderInfo _senderInfo) => NecroDev.Run("necrosmooth", _params);
}
[Preserve]
public class ConsoleCmdNecroCanPlace : ConsoleCmdAbstract
{
public override string[] getCommands() => new[] { "necrocanplace" };
public override string getDescription() => "NecromancerTome (разработка): почему урну нельзя поставить: блок x y z";
public override bool AllowedInMainMenu => false;
public override void Execute(List<string> _params, CommandSenderInfo _senderInfo) => NecroDev.Run("necrocanplace", _params);
}
}
Binary file not shown.
Binary file not shown.