Exemple #1
0
    private double EstimateUnitDamage(Unit attacker, Unit defender)
    {
        Combat.TurnPhase phase   = Combat.TurnPhase.MAGIC;
        double           epsilon = 0.05;

        while (phase < Combat.TurnPhase.CLEANUP)
        {
            UnitStack attackerStack  = new UnitStack(new Unit(attacker.GetUnitType(), 1), null);
            UnitStack defenderStack  = new UnitStack(new Unit(defender.GetUnitType(), 1), null);
            double    attackerDamage = EstimateStackAttacksDamage(attackerStack, defenderStack, phase);
            attackerStack = new UnitStack(new Unit(attacker.GetUnitType(), 1), null);
            defenderStack = new UnitStack(new Unit(defender.GetUnitType(), 1), null);
            double defenderDamage = EstimateStackAttacksDamage(defenderStack, attackerStack, phase);
            phase++;
            // read as "attacker deals significantly less damage than defender
            // during this phase"
            if (attackerDamage + epsilon < defenderDamage)
            {
                return(0);
            }
            // "defender deals significantly less damage than attacker
            // during this phase"
            if (attackerDamage > defenderDamage + epsilon)
            {
                return(attackerDamage);
            }
        }
        return(0);
    }
 /// <summary>
 /// Select a target for the spell from a list of candidates and cast the spell on it
 /// </summary>
 /// <param name="potentialTargets">The list of potential targets</param>
 public override void CastOn(List <UnitStack> potentialTargets)
 {
     if (potentialTargets.Count > 0)
     {
         // note: the spell doesn't work on holy units
         UnitStack toTarget = potentialTargets[0];
         int       qty      = toTarget.GetTotalQty();
         int       candidateQty;
         for (int i = 1; i < potentialTargets.Count; i++)
         {
             candidateQty = potentialTargets[i].GetTotalQty();
             if (toTarget.IsAffectedBy(this) ||
                 toTarget.GetUnitType().IsHoly() ||
                 (candidateQty > qty &&
                  !potentialTargets[i].IsAffectedBy(this) &&
                  !potentialTargets[i].GetUnitType().IsHoly()))
             {
                 toTarget = potentialTargets[i];
                 qty      = candidateQty;
             }
         }
         if (!toTarget.IsAffectedBy(this) && !toTarget.GetUnitType().IsHoly())
         {
             toTarget.AffectBySpell(this);
         }
     }
 }
Exemple #3
0
    /// <summary>
    /// Select a unit stack from a list of existing ones and make an illusory clone of it
    /// </summary>
    /// <param name="existing">The list of existing unit stacks</param>
    public override UnitStack Create(List <UnitStack> existing)
    {
        if (existing.Count > 0)
        {
            UnitStack toClone = existing[0];
            int       qty     = toClone.GetTotalQty();
            int       candidateQty;
            for (int i = 1; i < existing.Count; i++)
            {
                candidateQty = existing[i].GetTotalQty();
                if (candidateQty > qty)
                {
                    toClone = existing[i];
                    qty     = candidateQty;
                }
            }

            UnitType illusion = new UnitType(toClone.GetUnitType());
            illusion.SetShield(0);
            illusion.SetArmor(0);
            illusion.SetHitPoints(1);
            illusion.AddAttackQuality(AttackData.Quality.ILLUSORY);

            Unit      mirrorImage = new Unit(illusion, toClone.GetTotalQty());
            UnitStack stack       = new UnitStack(mirrorImage, toClone.GetProvinceToRetreat());
            stack.AffectBySpell(this);

            return(stack);
        }
        return(null);
    }
Exemple #4
0
    /// <summary>
    /// Calculate mathematical expectation of the weapon damage value
    /// </summary>
    /// <param name="attackRollResult">Result of the attack roll</param>
    /// <param name="defender">Defending unit stack</param>
    /// <param name="totalDefense">Defender's total defense against the attack</param>
    /// <param name="armor">Defender's armor value against the attack</param>
    /// <param name="maxValue">Max value the damage can reach</param>
    /// <returns>Mathematical expectation of the weapon damage value</returns>
    public double EstimateWeaponDamage(AttackRollResult attackRollResult, UnitStack defender, int totalDefense, int armor, int maxValue)
    {
        double result = 0;

        if ((IsUsingCriticals() && attackRollResult.IsCritical) || (attackRollResult.AttackRoll + attackRollResult.AttackSkill > totalDefense))
        {
            result = 0.5 * (attackRollResult.Attack.GetMinDamage() + attackRollResult.Attack.GetMaxDamage());
            if (IsUsingCriticals() && attackRollResult.IsCritical)
            {
                result *= 2;
            }
            if (armor > 0)
            {
                result -= armor;
            }
            if (result < 0)
            {
                result = 0;
            }
            if (result > maxValue)
            {
                result = maxValue;
            }
        }
        return(result);
    }
Exemple #5
0
    private void CreateUnitStackViewsForSide(GameObject[] spawnPoints)
    {
        bool             areProcessingAttackers = spawnPoints == _attackersSpawnPoints;
        List <UnitStack> stacks = _model.GetUnitStacks(areProcessingAttackers);
        Dictionary <UnitStack, UnitStackView> stackViews = areProcessingAttackers ? _attackerStackViews : _defenderStackViews;
        int offset = areProcessingAttackers ? _attackerStackViewsOffset : _defenderStackViewsOffset;

        int count = Mathf.Min(stacks.Count - offset, spawnPoints.Length);

        for (int i = 0; i < count; i++)
        {
            UnitStack currentStack = stacks[i + offset];

            UnitStackView view = (UnitStackView)Instantiate(_unitStackViewPrefab, spawnPoints[i].transform.position, Quaternion.identity);
            view.transform.parent = spawnPoints[i].transform;
            view.SetModel(currentStack);
            if (currentStack.GetProvinceToRetreat().GetOwnersFaction().IsPC())
            {
                view.StackSelected += OnPlayerSelectedDefendingUnitStack;
            }
            view.ExplosionAnimationCompleted += OnExplosionAnimationCompleted;
            view.StackInspected       += OnStackInspected;
            view.StackInspectionEnded += OnUnitTypeInspectionEnded;
            stackViews[currentStack]   = view;
        }
    }
Exemple #6
0
    /// <summary>
    /// Create a new unit stack with one of the chaos spawn version
    /// </summary>
    /// <param name="summoners">List of unit stacks capable of summoning chaos spawns</param>
    /// <returns>Unit stack created by the spell</returns>
    public override UnitStack Create(List <UnitStack> summoners)
    {
        if (_totalWeight == 0)
        {
            return(null);
        }
        int      randomNumber = Dice.RollDie(_totalWeight) - 1;
        UnitType unitType     = null;

        for (int i = 0; i < _convertedOutcomes.Count; i++)
        {
            if (randomNumber <= _convertedOutcomes[i].Value)
            {
                unitType = _convertedOutcomes[i].Key;
                break;
            }
            else
            {
                randomNumber -= _convertedOutcomes[i].Value;
            }
        }
        if (unitType != null)
        {
            UnitStack stack = new UnitStack(new Unit(unitType, 1), null);
            stack.AffectBySpell(this);

            FileLogger.Trace("SPAWN", unitType.GetName() + " is spawned.");

            return(stack);
        }
        return(null);
    }
Exemple #7
0
    /// <summary>
    /// Calculate defender's armor value against the attack
    /// </summary>
    /// <param name="attack">Attack under consideration</param>
    /// <param name="defender">Defending unit stack</param>
    /// <param name="isCritical">Whether the attack was a critical success</param>
    /// <returns>Defender's armor value modified by attack's qualities</returns>
    public int CalculateArmorValue(Attack attack, UnitStack defender, bool isCritical)
    {
        // AP (armor piercing), GUNPOWDER and LIGHTNING attacks halve armor rating
        // FIRE attacks ignore armor
        // Critical hits ignore armor
        // STONE SKIN spell adds 2 to the armor value after the above rules were applied
        // ILLUSORY attacks ignore armor and ignore effects of STONE SKIN spell
        int result = defender.GetUnitType().GetArmor();

        if (attack.IsArmorPiercing() || attack.IsGunpowderAttack() || attack.HasQuality(AttackData.Quality.LIGHTNING))
        {
            result /= 2;
        }
        if (isCritical && IsUsingCriticals())
        {
            result = 0;
        }
        if (attack.IsFireAttack())
        {
            result = 0;
        }
        if (defender.IsAffectedBy("Stone Skin"))
        {
            result += 2;
        }
        if (attack.HasQuality(AttackData.Quality.ILLUSORY))
        {
            result = 0;
        }

        return(result);
    }
Exemple #8
0
    private double GetEstimatedDamage(UnitStack attacker, UnitStack defender, Combat.TurnPhase phase)
    {
        int intPhase = (int)phase;

        if (attacker.GetAffectingSpells().Count == 0 && defender.GetAffectingSpells().Count == 0)
        {
            int attackerTypeId = attacker.GetUnitType().GetId();
            if (_expectedDamage.ContainsKey(attackerTypeId))
            {
                Dictionary <int, Dictionary <int, double> > attackerRecords = _expectedDamage[attackerTypeId];
                int defenderTypeId = defender.GetUnitType().GetId();
                if (attackerRecords.ContainsKey(defenderTypeId))
                {
                    Dictionary <int, double> defenderRecords = attackerRecords[defenderTypeId];
                    if (defenderRecords.ContainsKey(intPhase))
                    {
                        return(defenderRecords[intPhase]);
                    }
                }
            }
        }

        // "not found"
        return(-1);
    }
Exemple #9
0
 public BattleUnitStack(UnitStack stack)
 {
     Unit         = stack.Unit;
     LastStackHp  = stack.Unit.HitPoints;
     Number       = stack.Number;
     Effects      = new List <Effect>();
     _startNumber = stack.Number;
 }
Exemple #10
0
        public void UnitStack_ValidArgs_Creates()
        {
            var unit  = new Unit("Test", 100, 10, 5, (7, 13), 1.0);
            var stack = new UnitStack(unit, 100);

            Assert.IsNotNull(stack);
            Assert.IsInstanceOfType(stack, typeof(UnitStack));
        }
Exemple #11
0
        public void UnitStack_ValidArgs_Values()
        {
            var unit  = new Unit("Test", 100, 10, 5, (7, 13), 1.0);
            var stack = new UnitStack(unit, 100);

            Assert.AreEqual(stack.Type, unit);
            Assert.AreEqual(stack.Count, (uint)100);
        }
Exemple #12
0
    //battle stuff

    public BattleUnitStack(UnitStack CrusadeStack)
    {
        BasicAmount     = CrusadeStack.Amount; // max possible amount of minions
        this.minion     = CrusadeStack.minion;
        curHitPoints    = CrusadeStack.minion.HitPoints * CrusadeStack.Amount;
        curAttack       = CrusadeStack.minion.Attack;
        curDefence      = CrusadeStack.minion.Defence;
        curInitiative   = CrusadeStack.minion.Initiative;
        queueInitiative = curInitiative;
    }
Exemple #13
0
 /// <summary>
 /// Copy constructor
 /// </summary>
 /// <param name="stack">The unit stack to clone</param>
 public UnitStack(UnitStack stack)
 {
     _baseUnit              = new Unit(stack.GetBaseUnit());
     _provinceToRetreat     = stack.GetProvinceToRetreat();
     _hitPointsDistribution = new int[_baseUnit.GetUnitType().GetHitPoints()];
     for (int i = 0; i < _hitPointsDistribution.Length; i++)
     {
         _hitPointsDistribution[i] = stack._hitPointsDistribution[i];
     }
     _affectingSpells = new List <Spell>();
 }
Exemple #14
0
        private static (UnitSpecification specification, UnitStack stack) SetUp(uint count)
        {
            var unitSpecification  = new SlaveSpecification();
            var stackSpecification = new UnitStackSpecification(unitSpecification, count);
            var stack     = new UnitStack(stackSpecification);
            var resources = count * unitSpecification.HireCost;

            stack.Consume(resources);

            return(unitSpecification, stack);
        }
Exemple #15
0
 public void SetModel(UnitStack unitStack)
 {
     _model = unitStack;
     _model.WoundCheckMade                += OnWoundCheckMade;
     _unitImage.material.mainTexture       = SpriteCollectionManager.GetTextureByName(_model.GetUnitType().GetName());
     _mouseListener.MouseClickDetected    += OnStackSelected;
     _mouseOverListener.MouseOverDetected += OnStackInspected;
     _mouseOverListener.MouseExitDetected += OnStackInspectionEnd;
     _explosion.gameObject.SetActive(false);
     _healing.gameObject.SetActive(false);
     UpdateView();
 }
Exemple #16
0
    private void DestroyUnitStackView(UnitStack stack)
    {
        FileLogger.Trace("VIEW", "Destroying " + stack.GetUnitType().GetName() + "'s stack view");
        bool isAttackerStackDestroyed = _attackerStackViews.ContainsKey(stack);
        Dictionary <UnitStack, UnitStackView> stackViews = isAttackerStackDestroyed ? _attackerStackViews : _defenderStackViews;

        stackViews[stack].ExplosionAnimationCompleted -= OnExplosionAnimationCompleted;
        stackViews[stack].StackSelected        -= OnPlayerSelectedDefendingUnitStack;
        stackViews[stack].StackInspected       -= OnStackInspected;
        stackViews[stack].StackInspectionEnded -= OnUnitTypeInspectionEnded;
        Destroy(stackViews[stack].gameObject);
        stackViews.Remove(stack);
    }
 /// <summary>
 /// Add another attack roll result to the collection
 /// </summary>
 /// <param name="result">Attack roll result to add</param>
 /// <returns>Whether the operation was successful</returns>
 public bool AddAttackRollResult(AttackRollResult result)
 {
     if (_model.Count > 0 && result.UnitStack != _unitStack)
     {
         return(false);
     }
     _model.Add(result);
     _unitStack = result.UnitStack;
     if (Updated != null)
     {
         Updated(this, EventArgs.Empty);
     }
     return(true);
 }
Exemple #18
0
    /// <summary>
    /// Calculate damage inflicted by an attack
    /// </summary>
    /// <param name="attackRollResult">Attack roll result</param>
    /// <param name="defender">Defending unit stack</param>
    /// <param name="totalDefense">Defender's total defense value</param>
    /// <param name="armor">Defender's armor value</param>
    /// <returns>Damage inflicted by the attack to the defender</returns>
    public int CalculateDamage(AttackRollResult attackRollResult, UnitStack defender, int totalDefense, int armor)
    {
        int result = 0;

        if ((IsUsingCriticals() && attackRollResult.IsCritical) || (attackRollResult.AttackRoll + attackRollResult.AttackSkill > totalDefense))
        {
            result = attackRollResult.FullDamage;
            if (armor > 0)
            {
                result = Mathf.Max(0, result - armor);
            }
        }
        return(result);
    }
Exemple #19
0
    /// <summary>
    /// Select the unit stack which is going to soak enemy's attacks
    /// </summary>
    /// <param name="stacks">Available unit stacks</param>
    /// <param name="attacker">Attacking enemy unit stack</param>
    /// <param name="phase">Turn phase of the combat</param>
    /// <returns>Unit stack selected</returns>
    public UnitStack SelectDefendingUnitStack(List <UnitStack> stacks, UnitStack attacker, Combat.TurnPhase phase)
    {
        switch (_level)
        {
        case 1:
            // general-level AI takes into account successful defense odds
            // and selects the stack that has the lowest exectated replacement cost
            return(SelectMinReplacementCostUnit(stacks, attacker, phase));

        default:
            // captain-level AI selects the cheapest unit stack
            return(SelectCheapestUnit(stacks));
        }
    }
Exemple #20
0
 /// <summary>
 /// Class constructor
 /// </summary>
 /// <param name="attack">Attack roll result</param>
 /// <param name="target">Target unit defending against the attack</param>
 /// <param name="defensePositiveDieRoll">Value of the defense's positive roll</param>
 /// <param name="defenseNegativeDieRoll">Value of the defense's negative roll</param>
 /// <param name="defenseSkill">Value of the skill used in defense</param>
 /// <param name="shield">Shield value used in the defense roll</param>
 public AttackResolutionEvent(AttackRollResult attack,
                              UnitStack target,
                              int defensePositiveDieRoll,
                              int defenseNegativeDieRoll,
                              int defenseSkill,
                              int shield)
 {
     _attack = attack;
     _target = target;
     _defensePositiveDieRoll = defensePositiveDieRoll;
     _defenseNegativeDieRoll = defenseNegativeDieRoll;
     _defenseSkill           = defenseSkill;
     _shield = shield;
 }
Exemple #21
0
    /// <summary>
    /// Handles defender selection and related animations.
    /// </summary>
    private void ProcessPhaseWithAttacks()
    {
        FileLogger.Trace("COMBAT VIEW", "ProcessPhaseWithAttacks");
        // unit stacks could be created or destroyed - update the stack views
        UpdateUnitStackViews();
        if (!_model.AreThereUnresolvedAttacks())
        {
            _skipPhase = false;
            ProcessCombatTurn();
        }
        else
        {
            // show all attacks
            UpdateAttackViews();

            AttackRollResultsCollection currentAttackBatch = _model.SelectAttackRollResultsCollection();
            if (currentAttackBatch != null)
            {
                FileLogger.Trace("COMBAT", "Selected attacks by " + currentAttackBatch.GetUnitStack().GetUnitType().GetName());
                if (currentAttackBatch.GetUnitStack() != _currentAttacker)
                {
                    SetNewStackForCurrentAttackView(currentAttackBatch.GetUnitStack());
                    // a new defender will be selected against a new attack
                    _currentDefender = null;
                    _skipStack       = false;
                    FileLogger.Trace("COMBAT VIEW", "ProcessPhaseWithAttacks: Setting skip stack to false");
                }

                if (!_model.IsPlayerTurn())
                {
                    SelectAnNPCStackAsTarget();
                }
                else
                {
                    // if it's the player's turn
                    // and he already selected a defending stack, resolve the attack
                    if (_currentDefender != null && _currentDefender.GetTotalQty() > 0)
                    {
                        FileLogger.Trace("COMBAT", "Resolving an attack against " + _currentDefender.GetUnitType().GetName());
                        _model.ResolveCurrentAttack(false);
                    }
                    // else wait until the player will click on a stack view
                }
            }
            // else panic - there should be no case when there are unresolved attacks
            // but the model can't return an attack collection
        }
    }
Exemple #22
0
 /// <summary>
 /// Stops "object selected" animation and probably destroys the current attacks view.
 /// Starts "object selected" animation on the new one.
 /// </summary>
 private void SetNewStackForCurrentAttackView(UnitStack stack)
 {
     // handle the attacks view related to the current attacker
     if (_currentAttacker != null && _attackViews.ContainsKey(_currentAttacker))
     {
         // stop blinking
         _attackViews[_currentAttacker].GetComponent <Selectable>().IsSelected = false;
         // most likely, we exhausted attacks in this bunch - delete the view
         if (_attackViews[_currentAttacker].GetModel().Count == 0)
         {
             Destroy(_attackViews[_currentAttacker].gameObject);
         }
     }
     _currentAttacker = stack;
     // start blinking
     _attackViews[_currentAttacker].GetComponent <Selectable>().IsSelected = true;
 }
Exemple #23
0
    /// <summary>
    /// Generate an attack roll result
    /// </summary>
    /// <param name="attacker">Unit stack representing the attacker</param>
    /// <param name="attack">Attack object for roll result generation</param>
    /// <param name="plusDie">Value of the positive die's roll (pass zero to actually roll)</param>
    /// <param name="minusDie">Value of the negative die's roll (pass zero to actually roll)</param>
    /// <returns>Whether the die roll represents a critical success</returns>
    public AttackRollResult CreateAnAttackRollResult(UnitStack attacker, Attack attack, int plusDie = 0, int minusDie = 0)
    {
        bool isCritical      = false;
        int  positiveDieRoll = plusDie == 0 ? Dice.RollDie(_diceSides) : plusDie;
        int  negativeDieRoll = minusDie == 0 ? Dice.RollDie(_diceSides) : minusDie;
        int  dieRoll         = positiveDieRoll - negativeDieRoll;
        int  bonusDamage     = 0;

        if (IsCritical(dieRoll))
        {
            isCritical  = true;
            bonusDamage = attack.RollDamage();
        }
        AttackRollResult result = new AttackRollResult(attacker, attack, positiveDieRoll, negativeDieRoll, attack.GetSkill(), attack.RollDamage(), bonusDamage, isCritical);

        return(result);
    }
 /// <summary>
 /// Class constructor
 /// </summary>
 /// <param name="unitStack">Attacking unit stack</param>
 /// <param name="attack">Attack object</param>
 /// <param name="positiveDieRoll">Value of the attack's positive roll</param>
 /// <param name="negativeDieRoll">Value of the attack's negative roll</param>
 /// <param name="attackSkill">Attack skill value</param>
 /// <param name="baseDamage">Based damage value</param>
 /// <param name="bonusDamage">Bonus damage value</param>
 /// <param name="isCritical">Whether the attack is a critical hit</param>
 public AttackRollResult(UnitStack unitStack,
                         Attack attack,
                         int positiveDieRoll,
                         int negativeDieRoll,
                         int attackSkill,
                         int baseDamage,
                         int bonusDamage,
                         bool isCritical)
 {
     UnitStack       = unitStack;
     Attack          = attack;
     PositiveDieRoll = positiveDieRoll;
     NegativeDieRoll = negativeDieRoll;
     AttackSkill     = attackSkill;
     BaseDamage      = baseDamage;
     BonusDamage     = bonusDamage;
     IsCritical      = isCritical;
 }
Exemple #25
0
    /// <summary>
    /// Estimate results of a unit stack attacking another during a specified turn phase
    /// </summary>
    /// <param name="attacker">Attacking unit stack</param>
    /// <param name="defender">Defending unit stack</param>
    /// <param name="phase">Turn phase</param>
    /// <returns>Mathematical expectation of the attack damage value</returns>
    public double EstimateStackAttacksDamage(UnitStack attacker, UnitStack defender, Combat.TurnPhase phase)
    {
        double result = GetEstimatedDamage(attacker, defender, phase);

        if (result >= 0)
        {
            return(result);
        }
        result = 0;
        int           maxHP   = defender.GetUnitType().GetHitPoints();
        List <Attack> attacks = attacker.GetUnitType().GetAttacksForPhase(phase);

        for (int i = 0; i < attacks.Count; i++)
        {
            int numberOfAttacks = attacks[i].GetNumberOfAttacks();
            for (int attackerPlusDie = 0; attackerPlusDie < _diceSides; attackerPlusDie++)
            {
                for (int attackerMinusDie = 0; attackerMinusDie < _diceSides; attackerMinusDie++)
                {
                    AttackRollResult attackRollResult = CreateAnAttackRollResult(attacker, attacks[i],
                                                                                 attackerPlusDie + 1, attackerMinusDie + 1);

                    int defensiveSkill = CalculateDefensiveSkill(attackRollResult.Attack, defender);
                    int shield         = CalculateShieldValue(attackRollResult.Attack, defender);
                    int armor          = CalculateArmorValue(attackRollResult.Attack, defender, attackRollResult.IsCritical);

                    for (int defenderPlusDie = 0; defenderPlusDie < _diceSides; defenderPlusDie++)
                    {
                        for (int defenderMinusDie = 0; defenderMinusDie < _diceSides; defenderMinusDie++)
                        {
                            // both defenderPlusDie and defenderMinusDie would add +1 to them,
                            // so the +1s would cancel each other
                            int defenseRoll  = defenderPlusDie - defenderMinusDie;
                            int totalDefense = defenseRoll + defensiveSkill + shield;
                            result += numberOfAttacks * EstimateWeaponDamage(attackRollResult, defender, totalDefense, armor, maxHP);
                        }
                    }
                }
            }
        }
        result *= _damageScale;
        SetEstimatedDamage(attacker, defender, phase, result);
        return(result);
    }
Exemple #26
0
 /// <summary>
 /// Cleans up results of resolution
 /// </summary>
 private void ProcessAttackResolutionResults()
 {
     FileLogger.Trace("COMBAT VIEW", "ProcessAttackResolutionResults");
     if (_attackViews[_currentAttacker].GetModel().Count == 0)
     {
         FileLogger.Trace("COMBAT VIEW", "Destroying " + _currentAttacker.GetUnitType().GetName() + "'s attacks view");
         Destroy(_attackViews[_currentAttacker].gameObject);
         _attackViews.Remove(_currentAttacker);
         _currentAttacker = null;
     }
     else
     {
         FileLogger.Trace("COMBAT VIEW", "Updating " + _currentAttacker.GetUnitType().GetName() + "'s attacks view");
         _attackViews[_currentAttacker].UpdateView();
     }
     if (_currentDefender.GetTotalQty() == 0)
     {
         DestroyUnitStackView(_currentDefender);
         UpdateUnitStackViews();
         _currentDefender = null;
     }
     else
     {
         FileLogger.Trace("COMBAT VIEW", "Updating " + _currentDefender.GetUnitType().GetName() + "'s stack view");
         Dictionary <UnitStack, UnitStackView> stackViews = _attackerStackViews.ContainsKey(_currentDefender) ? _attackerStackViews : _defenderStackViews;
         stackViews[_currentDefender].UpdateView();
     }
     // if the attacker is reset, reset the defender, too
     // because a different defender will likely to be selected
     // against a new attack
     if (_currentAttacker == null)
     {
         _currentDefender = null;
     }
     if (_attackResolutionView.gameObject.activeSelf)
     {
         _attackResolutionView.gameObject.SetActive(false);
     }
     _model.PerformEndOfCombatCheck();
     if (!_model.IsCombatOver())
     {
         ProcessCombatTurn();
     }
 }
Exemple #27
0
    /// <summary>
    /// Calculate defender's skill value against the attack
    /// </summary>
    /// <param name="attack">Attack under consideration</param>
    /// <param name="defender">Defending unit stack</param>
    /// <returns>Defensive skill modified by attack's qualities</returns>
    public int CalculateDefensiveSkill(Attack attack, UnitStack defender)
    {
        // RANGED attacks ignore defense skill
        // SKIRMISH or MAGIC attacks halve it
        int result = defender.GetUnitType().GetDefense();

        if (attack.IsRangedAttack())
        {
            result = 0;
        }
        else
        {
            if (attack.IsSkirmishAttack() || attack.HasQuality(AttackData.Quality.MAGIC))
            {
                result /= 2;
            }
        }
        return(result);
    }
Exemple #28
0
 /// <summary>
 /// Select a target for the spell from a list of candidates and cast the spell on it
 /// </summary>
 /// <param name="potentialTargets">The list of potential targets</param>
 public override void CastOn(List <UnitStack> potentialTargets)
 {
     if (potentialTargets.Count > 0)
     {
         UnitStack toTarget = potentialTargets[0];
         int       qty      = toTarget.GetTotalQty();
         int       candidateQty;
         for (int i = 1; i < potentialTargets.Count; i++)
         {
             candidateQty = potentialTargets[i].GetTotalQty();
             if (toTarget.IsAffectedBy(this) || (candidateQty > qty && !potentialTargets[i].IsAffectedBy(this)))
             {
                 toTarget = potentialTargets[i];
                 qty      = candidateQty;
             }
         }
         toTarget.AffectBySpell(this);
     }
 }
Exemple #29
0
 private void OnPlayerSelectedDefendingUnitStack(object sender, EventArgs args)
 {
     if (_model.IsPlayerTurn())
     {
         UnitStack stack = ((UnitStackView)sender).GetModel();
         if (_attackViews.Count > 0)
         {
             _currentDefender = stack;
             _model.SetDefendingStack(stack);
             FileLogger.Trace("COMBAT VIEW", "Player selected " + _currentDefender.GetUnitType().GetName() + " as a defender");
             Dictionary <UnitStack, UnitStackView> stackViews = _attackerStackViews.ContainsKey(_currentDefender) ? _attackerStackViews : _defenderStackViews;
             stackViews[_currentDefender].PlayExplosionAnimation();
         }
         else
         {
             FileLogger.Error("COMBAT", "A defending unit stack is chosen, but there are no attacks to resolve.");
         }
     }
 }
Exemple #30
0
    /// <summary>
    /// Calculate mathematical expectation of the attack damage value
    /// </summary>
    /// <param name="attackRollResult">Attack roll result object representing the attack</param>
    /// <param name="defender">Defending unit stack</param>
    /// <returns>Mathematical expectation of the attack damage value</returns>
    public int EstimateAttackDamage(AttackRollResult attackRoll, UnitStack defender)
    {
        int    result      = 0;
        double totalDamage = 0;
        int    maxHP       = defender.GetUnitType().GetHitPoints();

        for (int attackerPlusDie = 0; attackerPlusDie < _diceSides; attackerPlusDie++)
        {
            for (int attackerMinusDie = 0; attackerMinusDie < _diceSides; attackerMinusDie++)
            {
                AttackRollResult attackRollResult = CreateAnAttackRollResult(attackRoll.UnitStack, attackRoll.Attack,
                                                                             attackerPlusDie + 1, attackerMinusDie + 1);

                int defensiveSkill = CalculateDefensiveSkill(attackRollResult.Attack, defender);
                int shield         = CalculateShieldValue(attackRollResult.Attack, defender);
                int armor          = CalculateArmorValue(attackRollResult.Attack, defender, attackRollResult.IsCritical);

                for (int defenderPlusDie = 0; defenderPlusDie < _diceSides; defenderPlusDie++)
                {
                    for (int defenderMinusDie = 0; defenderMinusDie < _diceSides; defenderMinusDie++)
                    {
                        // both defenderPlusDie and defenderMinusDie would add +1 to them,
                        // so the +1s would cancel each other
                        int defenseRoll  = defenderPlusDie - defenderMinusDie;
                        int totalDefense = defenseRoll + defensiveSkill + shield;
                        totalDamage += EstimateWeaponDamage(attackRollResult, defender, totalDefense, armor, maxHP);
                    }
                }
            }
        }

        totalDamage *= _damageScale;
        result       = Convert.ToInt32(Math.Floor(totalDamage));
        totalDamage -= result;

        System.Random rando = new System.Random();
        if (totalDamage > rando.NextDouble())
        {
            result++;
        }
        return(result);
    }