diff --git a/HarmonySrc/PetFollowPatch.cs b/HarmonySrc/PetFollowPatch.cs index ba36c48..eb8139a 100644 --- a/HarmonySrc/PetFollowPatch.cs +++ b/HarmonySrc/PetFollowPatch.cs @@ -460,7 +460,6 @@ namespace NecromancerTome // ВЫШЕ проверки на пустой список питомцев намеренно: трупы помечает Нож некроманта, // и к тому, есть ли у игрока сейчас призванный питомец, они отношения не имеют. CorpseLoot.RetryPendingTints(world); - Patch_ItemActionSpawnEntity_Spawn_PetLimit.RemoveOrphans(world); if (TrackedPets.Count == 0) { diff --git a/HarmonySrc/SummonPatch.cs b/HarmonySrc/SummonPatch.cs index b94df85..4f25013 100644 --- a/HarmonySrc/SummonPatch.cs +++ b/HarmonySrc/SummonPatch.cs @@ -467,18 +467,14 @@ namespace NecromancerTome return; } List owned = holdingEntity.GetOwnedEntities(petClassId); - EntityAlive orphan; if (owned.Count > 0) { RecallPet(holdingEntity, owned[0].Id, tooltips.RecalledKey, tooltips.ConsumesBook ? tooltips.SummonItemName : null); } - else if ((orphan = NearestOrphan(holdingEntity, petClassId)) != null) + else if (holdingEntity.world != null && RemoveOrphans(holdingEntity.world) > 0) { - // Питомец без хозяина (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); + // Своего нет, но ничейные были и убраны (13.10: стервятник 14620 из старого сейва) - для игрока это отзыв. + GameManager.ShowTooltip(GameManager.Instance.World.GetPrimaryPlayer(), tooltips.RecalledKey); } else if (holdingEntity.world != null) { @@ -486,58 +482,17 @@ namespace NecromancerTome } } - public const float OrphanRecallRange = 60f; - - /// Ближайший живой питомец этого вида не дальше OrphanRecallRange, которого нет в списке владения - /// ни у одного игрока. - static EntityAlive NearestOrphan(EntityAlive _holder, int _classId) + /// Ничейных питомцев - убрать (указание 13.10: «при призыве нового питомца и при отзыве старого пусть + /// проверяются все остальные питомцы и вычищаются»; стервятник 14620 из старого сейва летал у игрока без + /// хозяина). Ничейный - питомец нашего вида, которого нет в списке владения ни у одного игрока. Зовут только + /// призыв (CreateEntity, после записи владения) и отзыв - не по таймеру. Только на сервере (в одиночной + /// игре он же). Возвращает, сколько убрано. + public static int RemoveOrphans(World _world) { - World world = _holder.world; - if (world == null) + if (_world == null || !ConnectionManager.Instance.IsServer) { - return null; + return 0; } - 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; - } - - /// Ничейных питомцев - убрать (указание 13.10: «лучше чистить таких непривязанных»; стервятник - /// 14620 из старого сейва летал у игрока без хозяина). Раз в OrphanSweepInterval, только на сервере - /// (в одиночной игре он же), и не раньше OrphanGrace после появления игрока: до того список владения - /// игрока может быть ещё не прочитан из сейва, и под удаление попали бы все свои. - public static void RemoveOrphans(World _world) - { - if (!ConnectionManager.Instance.IsServer || _world.GetPrimaryPlayer() == null && _world.Players.list.Count == 0) - { - _orphanSweepAt = 0f; - return; - } - if (_orphanSweepAt == 0f) - { - _orphanSweepAt = Time.time + OrphanGrace; - return; - } - if (Time.time < _orphanSweepAt) - { - return; - } - _orphanSweepAt = Time.time + OrphanSweepInterval; if (_orphanClassIds == null) { _orphanClassIds = new HashSet(); @@ -550,6 +505,7 @@ namespace NecromancerTome } } } + int removed = 0; for (int i = _world.EntityAlives.Count - 1; i >= 0; i--) { EntityAlive e = _world.EntityAlives[i]; @@ -561,11 +517,11 @@ namespace NecromancerTome Debug.Log("[NecromancerTome] SummonPatch: ничейный питомец " + e.EntityName + " (" + e.entityId + ") убран"); // WolfBag.DropFrom здесь нельзя: сумка одна на игрока, ничейный волк вывалил бы сумку своего. _world.RemoveEntity(e.entityId, EnumRemoveEntityReason.Killed); + removed++; } + return removed; } - public const float OrphanGrace = 20f, OrphanSweepInterval = 5f; - static float _orphanSweepAt; static HashSet _orphanClassIds; static bool OwnedByAnyPlayer(World _world, int _entityId, int _classId) @@ -601,6 +557,7 @@ namespace NecromancerTome } owner.RemoveOwnedEntity(petEntityId); PetFollowPatch.Unregister(petEntityId); + RemoveOrphans(world); if (summonItemName != null) { GiveBackSummonItem(owner, summonItemName); @@ -853,6 +810,7 @@ namespace NecromancerTome } owner.AddOwnedEntity(__result); + Patch_ItemActionSpawnEntity_Spawn_PetLimit.RemoveOrphans(world); // призыв тоже чистит ничейных (13.10) // Рой из плевка одержимого ранчера - не свиток: без !Possession.Active плевок списывал предмет, который // держит тело игрока (тест 13.10). if (petInfo.ConsumesBook && !Possession.Active && owner.inventory != null) diff --git a/NecromancerHarmony.dll b/NecromancerHarmony.dll index 4aa564e..bb2771c 100644 Binary files a/NecromancerHarmony.dll and b/NecromancerHarmony.dll differ diff --git a/NecromancerHarmony.pdb b/NecromancerHarmony.pdb index f6d7e48..00bd353 100644 Binary files a/NecromancerHarmony.pdb and b/NecromancerHarmony.pdb differ