Отзыв питомца: E с книгой отзывает и ничейного питомца того же вида

Стервятник 14620 из старого сейва летал у игрока, но в списке владения не был, и отзыв его не видел. Если своего питомца нет - отзывается ближайший ничейный того же вида в 60 м.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
AlexCube
2026-10-13 14:12:54 +03:00
co-authored by Claude Opus 5.5
parent 2b39efd024
commit 533e6711d1
+59
View File
@@ -467,16 +467,75 @@ namespace NecromancerTome
return; return;
} }
List<OwnedEntityData> owned = holdingEntity.GetOwnedEntities(petClassId); List<OwnedEntityData> owned = holdingEntity.GetOwnedEntities(petClassId);
EntityAlive orphan;
if (owned.Count > 0) if (owned.Count > 0)
{ {
RecallPet(holdingEntity, owned[0].Id, tooltips.RecalledKey, tooltips.ConsumesBook ? tooltips.SummonItemName : null); RecallPet(holdingEntity, owned[0].Id, tooltips.RecalledKey, tooltips.ConsumesBook ? tooltips.SummonItemName : null);
} }
else if ((orphan = NearestOrphan(holdingEntity, petClassId)) != null)
{
// Питомец без хозяина (13.10: «летает могильный стервятник, которого я не могу отозвать» - 14620 из
// старого сейва, за игроком не записан): отзываем ближайшего ничейного того же вида.
Debug.Log("[NecromancerTome] SummonPatch: отзыв ничейного " + orphan.EntityName + " (" + orphan.entityId + "), " +
(orphan.position - holdingEntity.position).magnitude.ToString("F0") + " м");
RecallPet(holdingEntity, orphan.entityId, tooltips.RecalledKey, null);
}
else if (holdingEntity.world != null) else if (holdingEntity.world != null)
{ {
GameManager.ShowTooltip(GameManager.Instance.World.GetPrimaryPlayer(), tooltips.NothingToRecallKey); GameManager.ShowTooltip(GameManager.Instance.World.GetPrimaryPlayer(), tooltips.NothingToRecallKey);
} }
} }
public const float OrphanRecallRange = 60f;
/// <summary>Ближайший живой питомец этого вида не дальше OrphanRecallRange, которого нет в списке владения
/// ни у одного игрока.</summary>
static EntityAlive NearestOrphan(EntityAlive _holder, int _classId)
{
World world = _holder.world;
if (world == null)
{
return null;
}
EntityAlive best = null;
float bestSq = OrphanRecallRange * OrphanRecallRange;
for (int i = 0; i < world.EntityAlives.Count; i++)
{
EntityAlive e = world.EntityAlives[i];
if (e == null || e.entityClass != _classId || e.IsDead())
{
continue;
}
float sq = (e.position - _holder.position).sqrMagnitude;
if (sq > bestSq || OwnedByAnyPlayer(world, e.entityId, _classId))
{
continue;
}
best = e;
bestSq = sq;
}
return best;
}
static bool OwnedByAnyPlayer(World _world, int _entityId, int _classId)
{
foreach (EntityPlayer p in _world.Players.list)
{
if (p == null)
{
continue;
}
foreach (OwnedEntityData d in p.GetOwnedEntities(_classId))
{
if (d.Id == _entityId)
{
return true;
}
}
}
return false;
}
public static void RecallPet(EntityAlive owner, int petEntityId, string recalledTooltipKey, string summonItemName) public static void RecallPet(EntityAlive owner, int petEntityId, string recalledTooltipKey, string summonItemName)
{ {
if (Possession.Active && Possession.Zombie != null && Possession.Zombie.entityId == petEntityId) if (Possession.Active && Possession.Zombie != null && Possession.Zombie.entityId == petEntityId)