예제 #1
0
        /// <summary>
        /// Returns true if the provided CombatEntity has enough resources to use an Ability.
        /// </summary>
        /// <param name="attacker">The attacking CombatEntity.</param>
        /// <param name="ability">The ability being used by the CombatEntity.</param>
        /// <returns></returns>
        private bool HasEnoughResources(CombatEntity attacker, Ability ability, out string failureReason)
        {
            failureReason = "";

            int actionPointCost = ResourceCalculator.GetTotalActionPointCost(attacker, ability);
            int manaCost        = ResourceCalculator.GetTotalManaCost(attacker, ability);
            int healthCost      = ResourceCalculator.GetTotalHealthCost(attacker, ability);

            if (attacker.Resources.CurrentActionPoints < actionPointCost)
            {
                failureReason = BattleErrorWriter.WriteInsufficientActionPoints(attacker, ability);
                return(false);
            }

            if (attacker.Resources.CurrentMana < manaCost)
            {
                failureReason = BattleErrorWriter.WriteInsufficientMana(attacker, ability);
                return(false);
            }

            if (attacker.Resources.CurrentHealth < healthCost)
            {
                failureReason = BattleErrorWriter.WriteInsufficientHealth(attacker, ability);
                return(false);
            }

            return(true);
        }
예제 #2
0
        /// <summary>
        /// Performs an ability on a target location, applying damage, healing, and status effects to any targets.
        /// </summary>
        /// <param name="attacker">The attacker performing the ability.</param>
        /// <param name="ability">The ability used to attack the enemy.</param>
        /// <param name="targetPosition">The position to target with the ability being used.</param>
        /// <param name="targetFormation">The Formation that the CombatEntity is targeting with its action.</param>
        /// <returns></returns>
        public AbilityResult PerformAbility(CombatEntity attacker,
                                            Ability ability,
                                            int targetPosition,
                                            Formation targetFormation)
        {
            var result = new AbilityResult();

            // Target position is out of bounds
            if (!ability.IsPointBlank && !ability.IsPositionStatic &&
                (targetPosition > 9 || targetPosition < 1))
            {
                result.FailureReason = BattleErrorWriter.WriteTargetPositionOutOfBounds();
                return(result);
            }

            if (!HasEnoughResources(attacker, ability, out string failureReason))
            {
                result.FailureReason = failureReason;
                return(result);
            }

            if (ability.IsPointBlank)
            {
                targetPosition = GetTargetPosition(attacker, targetFormation);
            }
            var targets = FormationTargeter.GetTargets(ability, targetPosition, targetFormation).ToList();

            if (targets == null || targets.Count == 0)
            {
                result.FailureReason = BattleErrorWriter.WriteNoTargets();
                return(result);
            }

            // Filter out all dead targets
            targets = targets.Where(entity => entity != null && entity.Resources.CurrentHealth > 0).ToList();
            // Will be an invalid Ability usage if all targets are dead (later on will add ability to revive)
            if (targets.Count == 0)
            {
                result.FailureReason = BattleErrorWriter.WriteAllTargetsAreDead();
                return(result);
            }

            ConsumeResources(attacker, ability);
            ApplyEffects(attacker, ability, targets);

            targets.Add(attacker);

            result.AffectedEntities = targets;
            return(result);
        }
예제 #3
0
        /// <summary>
        /// Creates an instance of a DelayedAbility.
        /// </summary>
        /// <param name="attacker">The CombatEntity starting the effect of a DelayedAbility.</param>
        /// <param name="ability">The Ability to convert into a DelayedAbility.</param>
        /// <param name="action">The object containing details about the action being performed.</param>
        /// <param name="targetFormation">The Formation that the CombatEntity is targeting with its action.</param>
        /// <returns></returns>
        public DelayedAbilityResult CreateDelayedAbility(CombatEntity attacker,
                                                         Ability ability,
                                                         BattleAction action,
                                                         Formation targetFormation)
        {
            var result = new DelayedAbilityResult();

            // Target out of bounds
            if (!ability.IsPointBlank && !ability.IsPositionStatic &&
                (action.TargetPosition > 9 || action.TargetPosition < 1))
            {
                result.FailureReason = BattleErrorWriter.WriteTargetPositionOutOfBounds();
                return(result);
            }

            if (!HasEnoughResources(attacker, ability, out string failureReason))
            {
                result.FailureReason = failureReason;
                return(result);
            }

            int targetPosition = action.TargetPosition;

            if (ability.IsPointBlank)
            {
                targetPosition = GetTargetPosition(attacker, targetFormation);
            }

            ConsumeResources(attacker, ability);
            bool isCrit = IsCritical(attacker, ability);

            result.DelayedAbility = new DelayedAbility
            {
                Actor           = attacker,
                BaseAbility     = ability,
                StoredDamage    = DamageCalculator.GetDamage(attacker, ability, isCrit),
                StoredHealing   = DamageCalculator.GetHeal(attacker, ability, isCrit),
                TargetFormation = targetFormation,
                TargetPosition  = action.TargetPosition,
                IsCrit          = isCrit,
                TurnsLeft       = ability.DelayedTurns
            };

            return(result);
        }
예제 #4
0
        /// <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);
        }
예제 #5
0
        /// <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);
        }