private void UseAct(IActor actor, ActTargetInfo target, ITacticalAct act, ISectorMap map) { bool isInDistance; if ((act.Stats.Targets & TacticalActTargets.Self) > 0 && actor == target) { isInDistance = true; } else { isInDistance = IsInDistance(actor, target.TargetNode, act, map); } if (!isInDistance) { // Это может произойти, если цель, в процессе применения действия // успела выйти из радиуса применения. // TODO Лучше сделать, чтобы этот метод возвращал объект с результатом выполнения действия. // А внешний код пусть либо считает исход допустимым, либо выбрасывает исключения типа UsageOutOfDistanceException return; } var targetNode = target.TargetNode; var targetIsOnLine = map.TargetIsOnLine( actor.Node, targetNode); if (targetIsOnLine) { actor.UseAct(targetNode, act); var tacticalActRoll = GetActEfficient(act); var actHandler = _actUsageHandlerSelector.GetHandler(target.TargetObject); actHandler.ProcessActUsage(actor, target.TargetObject, tacticalActRoll); UseActResources(actor, act); } else { // Ситация, когда цель за стеной может произойти по следующим причинам: // 1. В момент начала применения действия цель была доступна. К моменту выполнения дейтвия цель скрылась. // В этом случае изымаем патроны и начинаем КД по действию, так как фактически ресурсы на него потрачены. Но на цель не воздействуем. // 2. Ошибка во внешнем коде, когда не провели предварительную проверку. Это проверяется сравнением ячейки в которую целились // на момент начала действия и текущую ячейку цели. if (target.TargetNode == target.TargetObject.Node) { throw new UsageThroughtWallException(); } UseActResources(actor, act); } }
public void UseOn(IActor actor, ActTargetInfo target, UsedTacticalActs usedActs, ISector sector) { if (actor is null) { throw new ArgumentNullException(nameof(actor)); } if (target is null) { throw new ArgumentNullException(nameof(target)); } if (usedActs is null) { throw new ArgumentNullException(nameof(usedActs)); } if (sector is null) { throw new ArgumentNullException(nameof(sector)); } Debug.Assert(SectorHasCurrentActor(sector, actor), "Current actor must be in sector"); Debug.Assert(SectorHasAttackTarget(sector, target.TargetObject), "Target must be in sector"); foreach (var act in usedActs.Primary) { if (!act.Stats.Targets.HasFlag(TacticalActTargets.Self) && actor == target) { throw new ArgumentException("Актёр не может атаковать сам себя", nameof(target)); } UseAct(actor, target, act, sector.Map); } // Использование дополнительных действий. // Используются с некоторой вероятностью. foreach (var act in usedActs.Secondary) { var useSuccessRoll = GetUseSuccessRoll(); var useFactRoll = GetUseFactRoll(); if (useFactRoll < useSuccessRoll) { continue; } UseAct(actor, target, act, sector.Map); } }