Питомец дальше 100 блоков после одержимости - сразу отозван (#35); диагностика R у логиста (#77)

PetFarRecall: при выходе из одержимости питомцем - отзыв как книгой, если до тела хозяина дальше
порога; ближе - идёт своим ходом. Консоль: necropetfar <блоки>|off.
Логист: строки LogistForm в логе на нажатие R и на сборку меню блока - временно, до причины #77.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
AlexCube
2026-10-23 12:39:19 +03:00
co-authored by Claude Opus 5.5
parent 66ee53c05f
commit ce4752a04e
5 changed files with 102 additions and 0 deletions
+22
View File
@@ -84,6 +84,28 @@ namespace NecromancerTome
}
__instance.SetCommonData(UIUtils.GetButtonIconForAction(__instance.xui.playerUI.playerInput.Activate), CinerariumLogistForm.OnBlockMenu,
new XUiC_Radial.RadialContextHoldingSlotIndex(pl.inventory.holdingItemIdx), -1, true, XUiC_Radial.RadialValidSameHoldingSlotIndex);
Debug.Log("[NecromancerTome] LogistForm: меню блока - " + held.Name + ", пунктов " + __instance.currentEnabledEntriesCount());
}
}
/// <summary>Диагностика #77 (23.10.2026: «зажимаю R - меню не открывается, только поворот»): на нажатие R с урной-логистом в
/// руке - что видит игра (блок ли в руке, не считает ли предмет оружием). Убрать, когда причина найдена.</summary>
[HarmonyPatch(typeof(PlayerMoveController), nameof(PlayerMoveController.Update))]
public static class Patch_PlayerMoveController_Update_LogistFormDiag
{
public static void Postfix(PlayerMoveController __instance)
{
EntityPlayerLocal pl = __instance.entityPlayerLocal;
PlayerActionsLocal inp = __instance.playerInput;
if (pl?.inventory == null || inp == null || !CinerariumLogistForm.IsLogistItem(pl.inventory.holdingItem) ||
!(inp.Reload.WasPressed || inp.PermanentActions.Reload.WasPressed))
{
return;
}
XUiC_Radial r = __instance.playerUI?.xui?.RadialWindow;
Debug.Log("[NecromancerTome] LogistForm: R - " + pl.inventory.holdingItem.Name + ", блок " + (pl.inventory.GetHoldingBlock() != null) +
", оружие " + pl.inventory.IsHoldingGun() + "/" + pl.inventory.IsHoldingDynamicMelee() + ", смена руки " + pl.inventory.IsHandSwitching() +
", меню " + (r != null && r.IsOpen) + ", модальное " + (__instance.playerUI?.windowManager?.IsModalWindowOpen() ?? false));
}
}
+78
View File
@@ -0,0 +1,78 @@
using System.Collections.Generic;
using UnityEngine;
namespace NecromancerTome
{
/// <summary>
/// Дальний питомец после одержимости (указание 23.10.2026, #35: «Если питомец далеко от хозяина и хозяин вышел из режима
/// одержимости, то питомец должен сразу быть отозван. Скажем, если больше 100 блоков, то отзовём, если меньше, то
/// возвращается своим ходом»). Отзыв - тот же, что книгой (RecallPet: подсказка «… отозван», книга назад, если призыв её
/// тратит). Далеко ушедший питомец иначе остаётся в выгруженном участке, и PetFollowPatch снимает с него владение.
/// </summary>
public static class PetFarRecall
{
/// <summary>Порог в блоках; 0 - выключено (питомец всегда идёт своим ходом, как раньше).</summary>
public static float Distance = 100f;
/// <summary>true - питомец отозван (дальше ничего с ним не делать).</summary>
public static bool TryRecall(EntityPlayer _owner, EntityAlive _pet)
{
if (Distance <= 0f || _owner == null || _pet == null || _pet.IsDead())
{
return false;
}
float d = Vector3.Distance(_owner.position, _pet.position);
string cls = EntityClass.list.TryGetValue(_pet.entityClass, out EntityClass ec) ? ec.entityClassName : null;
if (d <= Distance || cls == null ||
!Patch_ItemActionSpawnEntity_Spawn_PetLimit.LimitedPets.TryGetValue(cls, out Patch_ItemActionSpawnEntity_Spawn_PetLimit.PetInfo info) ||
info.RecalledKey == null)
{
return false;
}
Debug.Log("[NecromancerTome] PetFarRecall: " + cls + " " + _pet.entityId + " в " + Mathf.RoundToInt(d) + " блоках от хозяина - отозван");
Patch_ItemActionSpawnEntity_Spawn_PetLimit.RecallPet(_owner, _pet.entityId, info.RecalledKey, info.ConsumesBook ? info.SummonItemName : null);
return true;
}
}
public class ConsoleCmdNecroPetFar : ConsoleCmdAbstract
{
public override bool IsExecuteOnClient => true;
public override bool AllowedInMainMenu => false;
public override string[] getCommands()
{
return new string[] { "necropetfar" };
}
public override string getDescription()
{
return "Necromancer's Tome: recall a far pet when leaving possession - distance.";
}
public override string getHelp()
{
return "necropetfar - status\n" +
"necropetfar <blocks> - recall the pet if it is farther than this from you\n" +
"necropetfar off - never recall, the pet always walks back";
}
public override void Execute(List<string> _params, CommandSenderInfo _senderInfo)
{
SdtdConsole con = SingletonMonoBehaviour<SdtdConsole>.Instance;
if (_params.Count >= 1)
{
if (_params[0] == "off")
{
PetFarRecall.Distance = 0f;
}
else if (float.TryParse(_params[0], System.Globalization.NumberStyles.Float, System.Globalization.CultureInfo.InvariantCulture, out float v) && v >= 0f)
{
PetFarRecall.Distance = v;
}
}
con.Output("necropetfar: " + (PetFarRecall.Distance > 0f ? "recall farther than " + PetFarRecall.Distance + " blocks" : "off - the pet always walks back"));
}
}
}
+2
View File
@@ -449,10 +449,12 @@ namespace NecromancerTome
}
}
// Питомец просто отпущен: его ИИ (следование, охрана, поводок) сам вернёт его к хозяину.
// Далеко ушедший - сразу отозван (23.10, #35: PetFarRecall).
if (pet)
{
z.SetMoveForwardWithModifiers(0f, 0f, 0f, false);
z.SetAttackTarget(null, 0);
PetFarRecall.TryRecall(player, z);
return;
}
// Сам зомби в ужасе бежит от тела игрока (решение 03.10: «пугается и убегает как при отрицании»).
Binary file not shown.
Binary file not shown.