Одержимый зомби: оружие на поясе по ремеслу (#37), карта по M (#36)

- Пояс - нижний ряд сумки зомби; оружие ближнего боя в руку, если этот тип зомби
  им владеет (ZombieWeapons: таблица умений, утверждена 25.10). Удар как у персонажа:
  ItemActionAttack.Hit, урон предмета без перков зомби, износ, темп оружия.
  Модель на кость RightWeapon, хват WeaponHoldType; иконки и износ на поясе HUD.
  Неумелое или сломанное - кулаки и подсказка (13 языков). Выключатель
  necroarms weapon on|off; dev-команда necropossess для проверок без мыши.
- M в зомби и волке открывал сумку вместо карты (перехват windowpaging) - исправлено;
  туман карты и карта на одержимом - у любого одержимого зомби, как у стервятника.
- Глава «Одержимость» (EN/RU): пояс - оружие, M - карта.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
AlexCube
2026-10-25 14:26:55 +03:00
co-authored by Claude Opus 5.5
parent 5ebd09dacd
commit cf61d98bb7
8 changed files with 626 additions and 18 deletions
+69
View File
@@ -19,6 +19,7 @@ namespace NecromancerTome
/// necrobox x y z list|clear|add предмет число - содержимое хранилища (ящик, сумка урны)
/// necrourn x y z info|skull 0|1|from|to|out bx by bz|clear|sample предмет число|group все|нет - урна
/// necroclick 0|1 - отпущенная ЛКМ/ПКМ ножом для нитей по блоку под прицелом
/// necropossess near [класс]|fp|hit|look id / x y z|slot N|belt N предмет [качество]|info|exit - одержимость без мыши (#37, 25.10)
/// </summary>
public static class NecroDev
{
@@ -265,6 +266,7 @@ namespace NecromancerTome
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 "necropossess": Possess(w, pl, _params); break;
case "necroclick":
// necroclick 0|1 [x y z] - по блоку под прицелом или по указанной клетке (луч не всегда попадает в низкий череп).
if (_params.Count >= 4)
@@ -310,6 +312,64 @@ namespace NecromancerTome
/// <summary>Режим бога и невидимость для ИИ: пока ассистент проверяет, персонаж стоит - зомби тестового мира его не трогают
/// (18.10: «пока персонаж просто стоит, его скушают»; «Я обычно ставлю режим Бога»).</summary>
/// <summary>necropossess: вселиться в ближайшего зомби (класс - начало имени), вид от первого лица, ЛКМ, ячейка и
/// предмет пояса, состояние, выход.</summary>
static void Possess(World _w, EntityPlayerLocal _pl, List<string> _p)
{
string cmd = _p.Count > 0 ? _p[0] : "info";
EntityAlive z = Possession.Zombie;
switch (cmd)
{
case "near":
{
string cls = _p.Count > 1 ? _p[1] : "";
EntityAlive best = null;
float bestD = 40f * 40f;
foreach (EntityAlive e in _w.EntityAlives)
{
if (!Possession.CanPossess(e) || !EntityClass.list.TryGetValue(e.entityClass, out EntityClass ec) ||
!ec.entityClassName.StartsWith(cls, System.StringComparison.OrdinalIgnoreCase))
{
continue;
}
float d = (e.position - _pl.position).sqrMagnitude;
if (d < bestD)
{
bestD = d;
best = e;
}
}
Out("necropossess: " + (best == null ? "зомби рядом нет" : best.EntityName + " (" + best.entityId + ") - " + (Possession.Enter(_pl, best) ? "вселился" : "не вышло")));
return;
}
case "fp": Possession.DevView = true; break;
case "hit": Possession.DevAttack = true; break;
case "look":
{
// look id - на существо (грудь), look x y z - на точку
Vector3 at = _p.Count >= 4 ? new Vector3(F(_p[1]), F(_p[2]), F(_p[3]))
: (_w.GetEntity(int.Parse(_p[1])) as EntityAlive)?.getChestPosition() ?? Vector3.zero;
Possession.DevLookAt(at);
break;
}
case "slot": Possession.BeltSlot = Mathf.Clamp(int.Parse(_p[1]) - 1, 0, Possession.BeltSlots - 1); break;
case "belt":
{
ItemValue iv = ItemClass.GetItem(_p[2]);
if (iv == null || iv.IsEmpty())
{
Out("necropossess: нет предмета " + _p[2]);
return;
}
iv = new ItemValue(iv.type, _p.Count > 3 ? int.Parse(_p[3]) : 1, _p.Count > 3 ? int.Parse(_p[3]) : 1);
Out("necropossess: " + (ZombieBag.DevSetBelt(int.Parse(_p[1]) - 1, new ItemStack(iv, 1)) ? "положено" : "сумки нет"));
break;
}
case "exit": Possession.Exit("necropossess"); Out("necropossess: выход"); return;
}
Out("necropossess: " + (z == null ? "не в одержимости" : z.EntityName + ", от первого лица " + Possession.FirstPerson + "\n" + ZombieWeapons.Dump(z)));
}
static void God(EntityPlayerLocal _pl, bool _on)
{
_pl.IsGodMode.Value = _on;
@@ -592,6 +652,15 @@ namespace NecromancerTome
public override void Execute(List<string> _params, CommandSenderInfo _senderInfo) => NecroDev.Run("necroclick", _params);
}
[Preserve]
public class ConsoleCmdNecroPossess : ConsoleCmdAbstract
{
public override string[] getCommands() => new[] { "necropossess" };
public override string getDescription() => "NecromancerTome (разработка): одержимость без мыши - near [класс] | fp | hit | slot N | belt N предмет [качество] | info | exit";
public override bool AllowedInMainMenu => false;
public override void Execute(List<string> _params, CommandSenderInfo _senderInfo) => NecroDev.Run("necropossess", _params);
}
[Preserve]
public class ConsoleCmdNecroGod : ConsoleCmdAbstract
{