/// <summary> /// Performs an ability using the specified parameters. /// </summary> /// <param name="action">The object containing the original battle commands.</param> /// <param name="actor">The CombatEntity performing the ability.</param> /// <param name="actorFormation">The Formation of the CombatEntity performing the Ability.</param> /// <param name="isAttacker">Set to true if the CombatEntity is on the attacking side in battle.</param> /// <param name="ability">The Ability being performed.</param> /// <param name="result">A reference to the BattleActionResult object.</param> /// <returns>Returns an IEnumerable of CombatEntities affected by the Ability.</returns> private IEnumerable <CombatEntity> PerformAbility(BattleAction action, CombatEntity actor, Formation actorFormation, bool isAttacker, Ability ability, ref BattleActionResult result) { IEnumerable <CombatEntity> affectedEntities; Item item = null; // If using an item, prepare item to have it's charges deducted later if (action.IsUsingItem) { item = actor.EquippedItems.FirstOrDefault(i => i.ConsumableAbility.Id == action.AbilityId); if (item == null) { item = actor.PlayerInventory .Items .FirstOrDefault(i => i != null && i.ConsumableAbility.Id == action.AbilityId); } if (item == null) { result.FailureReason = BattleErrorWriter.WriteItemDoesntExist(actor); result.IsSuccess = false; return(null); } ability = item.ConsumableAbility; } // Not an item, check to see if character is restricted from using Ability else { ability = actor.Abilities.FirstOrDefault(abi => abi.Id == action.AbilityId); if (ability == null) { result.FailureReason = BattleErrorWriter.WriteAbilityDoesntExist(actor); result.IsSuccess = false; return(null); } if (ability.IsSpell && actor.StatusEffects.Any(se => se.BaseStatus.IsSilenced)) { result.FailureReason = BattleErrorWriter.WriteEntityIsSilenced(actor, ability); result.IsSuccess = false; return(null); } if (!ability.IsSpell && actor.StatusEffects.Any(se => se.BaseStatus.IsRestricted)) { result.FailureReason = BattleErrorWriter.WriteEntityIsRestricted(actor, ability); result.IsSuccess = false; return(null); } } var targetFormation = GetFormation(action.TargetFormationId, out bool throwAway); // If the ability has a delay, create a DelayedAbility if (ability.DelayedTurns > 0) { var delayedAbilityResult = _abilityManager.CreateDelayedAbility(actor, ability, action, targetFormation); if (delayedAbilityResult.DelayedAbility == null) { result.FailureReason = delayedAbilityResult.FailureReason; result.IsSuccess = false; return(null); } if (isAttacker) { _battle.AttackerDelayedAbilities.Add(delayedAbilityResult.DelayedAbility); } else { _battle.DefenderDelayedAbilities.Add(delayedAbilityResult.DelayedAbility); } affectedEntities = new List <CombatEntity> { actor }; } // Not a delayed ability, try to apply effects immediately else { var abilityResult = _abilityManager.PerformAbility(actor, ability, action.TargetPosition, targetFormation); if (abilityResult.FailureReason != null) { result.FailureReason = abilityResult.FailureReason; result.IsSuccess = false; return(null); } affectedEntities = abilityResult.AffectedEntities; } CheckForDeadEntities(affectedEntities, targetFormation); // Action was successful, remove the actor from characters free to act _battle.ActionsLeftPerFormation[actorFormation].Remove(actor); // If Ability was granted by an item, reduce the charges of the item if (item != null) { _equipmentManager.ReduceCharges(actor, item); } return(affectedEntities); }
/// <summary> /// Performs an action and returns true if the action was a success. /// </summary> /// <param name="action">The action to perform, containing data about the actor and the abilities used.</param> /// <returns></returns> public async Task <BattleActionResult> PerformActionAsync(BattleAction action) { IEnumerable <CombatEntity> affectedEntities = null; CombatEntity nextActiveEntity = null; Ability ability = null; CombatEntity actor = null; var result = new BattleActionResult { IsSuccess = true }; lock (_key) { if (_battle == null) { result.FailureReason = BattleErrorWriter.WriteNotInitiated(); result.IsSuccess = false; return(result); } var actorFormation = GetFormation(action.OwnerId, out bool isAttacker); if (actorFormation == null) { result.FailureReason = BattleErrorWriter.WriteNotParticipating(); result.IsSuccess = false; return(result); } actor = actorFormation.Positions.FirstOrDefaultTwoD(entity => entity != null && entity.Id == action.ActorId); if (actor == null) { result.FailureReason = BattleErrorWriter.WriteActorNotFound(); result.IsSuccess = false; return(result); } // Not player's turn if (_battle.IsDefenderTurn != !isAttacker) { result.FailureReason = BattleErrorWriter.WriteNotPlayersTurn(); result.IsSuccess = false; return(result); } if (!_battle.ActionsLeftPerFormation.ContainsKey(actorFormation)) { result.FailureReason = BattleErrorWriter.WriteNoMoreActions(); result.IsSuccess = false; return(result); } if (!_battle.ActionsLeftPerFormation[actorFormation].Contains(actor)) { result.FailureReason = BattleErrorWriter.WriteEntityCannotAct(actor); result.IsSuccess = false; return(result); } if (actor.StatusEffects.Any(se => se.BaseStatus.IsStunned)) { result.FailureReason = BattleErrorWriter.WriteEntityIsStunned(actor); result.IsSuccess = false; return(result); } if (!action.IsDefending && !action.IsFleeing) { affectedEntities = PerformAbility(action, actor, actorFormation, isAttacker, ability, ref result); if (affectedEntities == null) { return(result); } } // Is defending or fleeing else { if (action.IsDefending) { affectedEntities = PerformDefend(actor, actorFormation, out nextActiveEntity); } else if (action.IsFleeing) { affectedEntities = PerformFlee(actor, actorFormation); } } } await Task.Run(() => SuccessfulActionEvent.Invoke(this, new SuccessfulActionEventArgs { Ability = ability, Action = action, Actor = actor, AffectedEntities = affectedEntities, ParticipantIds = _participantIds, NextActiveEntityId = nextActiveEntity != null ? nextActiveEntity.Id : -1 })); return(result); }