Ejemplo n.º 1
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);
         }
     }
 }
Ejemplo n.º 2
0
 public void PlayExplosionAnimation()
 {
     if (!_explosionActivated)
     {
         FileLogger.Trace("COMBAT VIEW", "Playing explosion animation on " + _model.GetUnitType().GetName());
         _explosion.gameObject.SetActive(true);
         _explosion.TimeIsUp += OnExplosionCompleted;
         _explosionActivated  = true;
         _explosion.StartTimer();
     }
 }
Ejemplo n.º 3
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
        }
    }
Ejemplo n.º 4
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);
    }
Ejemplo n.º 5
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);
    }
Ejemplo n.º 6
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);
    }
Ejemplo n.º 7
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();
     }
 }
Ejemplo n.º 8
0
 private void SetEstimatedDamage(UnitStack attacker, UnitStack defender, Combat.TurnPhase phase, double damage)
 {
     if (attacker.GetAffectingSpells().Count == 0 && defender.GetAffectingSpells().Count == 0)
     {
         int attackerTypeId = attacker.GetUnitType().GetId();
         if (!_expectedDamage.ContainsKey(attackerTypeId))
         {
             _expectedDamage[attackerTypeId] = new Dictionary <int, Dictionary <int, double> >();
         }
         int defenderTypeId = defender.GetUnitType().GetId();
         if (!_expectedDamage[attackerTypeId].ContainsKey(defenderTypeId))
         {
             _expectedDamage[attackerTypeId][defenderTypeId] = new Dictionary <int, double>();
         }
         _expectedDamage[attackerTypeId][defenderTypeId][(int)phase] = damage;
     }
     FileLogger.Trace("ESTIMATE", "Estimated damage of " + attacker.GetUnitType().GetName() +
                      " vs " + defender.GetUnitType().GetName() + " during " +
                      phase + " phase is " + damage);
 }
Ejemplo n.º 9
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);
    }
Ejemplo n.º 10
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);
    }
Ejemplo n.º 11
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.");
         }
     }
 }
Ejemplo n.º 12
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);
    }
Ejemplo n.º 13
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);
    }
Ejemplo n.º 14
0
 /// <summary>
 /// Resolve combat
 /// Used by the game to resolve NPC-to-NPC battles
 /// and by Strategos to plan invasions
 /// </summary>
 /// <param name="useEstimates">Whether estimated results will be used or honest rolls will be made</param>
 public void ResolveCombat(bool useEstimates = false)
 {
     while (!IsCombatOver())
     {
         PerformPhaseActions();
         AttackRollResultsCollection currentAttackBatch = SelectAttackRollResultsCollection();
         if (currentAttackBatch != null)
         {
             FileLogger.Trace("COMBAT", "Selected attacks by " + currentAttackBatch.GetUnitStack().GetUnitType().GetName());
             UnitStack target = SelectDefendingStack();
             if (target != null)
             {
                 FileLogger.Trace("COMBAT", "Selected " + target.GetUnitType().GetName() + " as a target");
                 ResolveCurrentAttack(useEstimates);
             }
             else
             {
                 PerformEndOfCombatCheck();
             }
         }
     }
 }
Ejemplo n.º 15
0
    /// <summary>
    /// Select the unit stack which has the lowest training cost
    /// </summary>
    /// <param name="stacks">Available unit stacks</param>
    /// <returns>Unit stack selected</returns>
    public UnitStack SelectCheapestUnit(List <UnitStack> stacks)
    {
        UnitStack result       = null;
        int       trainingCost = 0;

        for (int i = 0; i < stacks.Count; i++)
        {
            if (stacks[i].GetTotalQty() == 0)
            {
                FileLogger.Trace("TAI", stacks[i].GetUnitType().GetName() + " is empty");
                continue;
            }
            if (result == null)
            {
                result       = stacks[i];
                trainingCost = stacks[i].GetUnitType().GetTrainingCost();
                FileLogger.Trace("TAI", "Initial selection: " + stacks[i].GetUnitType().GetName() + ", training cost: " + trainingCost.ToString());
            }
            else
            {
                int alternativeTrainingCost = stacks[i].GetUnitType().GetTrainingCost();
                if (alternativeTrainingCost > 0 && alternativeTrainingCost < trainingCost)
                {
                    result       = stacks[i];
                    trainingCost = alternativeTrainingCost;
                    FileLogger.Trace("TAI", "Current selection: " + stacks[i].GetUnitType().GetName() + ", training cost: " + trainingCost.ToString());
                }
                else
                {
                    FileLogger.Trace("TAI", stacks[i].GetUnitType().GetName() + " is more expensive to train: " + alternativeTrainingCost.ToString());
                }
            }
        }
        if (result != null)
        {
            FileLogger.Trace("TAI", "Easy Level AI selected  " + result.GetUnitType().GetName() + " as a target");
        }
        return(result);
    }
Ejemplo n.º 16
0
    /// <summary>
    /// Calculate defender's shield value against the attack
    /// </summary>
    /// <param name="attack">Attack under consideration</param>
    /// <param name="defender">Defending unit stack</param>
    /// <returns>Defender's shield value modified by attack's qualities</returns>
    public int CalculateShieldValue(Attack attack, UnitStack defender)
    {
        // Shields perform at 150% against SKIRMISH attacks
        // They perform at 200% against regular RANGED attacks
        // GUNPOWDER attacks ignore shields
        // MAGIC and LIGHTNING attacks halve the shield value
        // MAGIC SHIELD spell adds 2 to the shield value after the rules above were applied
        // ILLUSORY attacks ignore shields, including those created by MAGIC SHIELD spell
        int shieldRating = defender.GetUnitType().GetShield();
        int result       = shieldRating;

        if (attack.IsSkirmishAttack())
        {
            result += shieldRating / 2;
        }

        if (attack.IsRangedAttack())
        {
            result = 2 * shieldRating;
        }

        if (attack.HasQuality(AttackData.Quality.MAGIC) || attack.HasQuality(AttackData.Quality.LIGHTNING))
        {
            result = shieldRating / 2;
        }
        if (attack.HasQuality(AttackData.Quality.GUNPOWDER))
        {
            result = 0;
        }
        if (defender.IsAffectedBy("Magic Shield"))
        {
            result += 2;
        }
        if (attack.HasQuality(AttackData.Quality.ILLUSORY))
        {
            result = 0;
        }
        return(result);
    }
Ejemplo n.º 17
0
    /// <summary>
    /// Select the unit stack which is going to be cheapest to re-train, taking into account odds of successful defense
    /// </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 SelectMinReplacementCostUnit(List <UnitStack> stacks, UnitStack attacker, Combat.TurnPhase phase)
    {
        UnitStack result          = null;
        double    replacementCost = double.MaxValue;
        double    altervative;

        for (int i = 0; i < stacks.Count; i++)
        {
            if (stacks[i].GetTotalQty() > 0)
            {
                altervative = CombatHelper.Instance.EstimateStackAttacksDamage(attacker, stacks[i], phase) * stacks[i].GetUnitType().GetTrainingCost() / stacks[i].GetUnitType().GetHitPoints();
                if (altervative < replacementCost)
                {
                    replacementCost = altervative;
                    result          = stacks[i];
                }
            }
        }
        if (result != null)
        {
            FileLogger.Trace("TAI", "Medium Level AI selected " + result.GetUnitType().GetName() + " as a target, expected replacement cost is " + replacementCost);
        }
        return(result);
    }
Ejemplo n.º 18
0
 /// <summary>
 /// Get attacker's unit type
 /// </summary>
 /// <returns>Unit type of the attacker</returns>
 public UnitType GetUnitType()
 {
     return(UnitStack.GetUnitType());
 }
Ejemplo n.º 19
0
    /// <summary>
    /// Is the unit stack a valid target for the attack?
    /// </summary>
    /// <param name="target">Unit stack which is a potential target for the attack</param>
    /// <param name="attackRollResult">Attack roll result representing the attack</param>
    /// <returns>Whether the unit stack is a valid target for the attack</returns>
    private bool IsValidAttackTarget(UnitStack target, AttackRollResult attackRollResult)
    {
        if (_attackers.Contains(target) && _attackers.Contains(attackRollResult.UnitStack))
        {
            FileLogger.Trace("COMBAT", "Both " + attackRollResult.UnitStack.GetUnitType().GetName() + " and " + target.GetUnitType().GetName() + " belong to the attacker");
            return(false);
        }

        if (_defenders.Contains(target) && _defenders.Contains(attackRollResult.UnitStack))
        {
            FileLogger.Trace("COMBAT", "Both " + attackRollResult.UnitStack.GetUnitType().GetName() + " and " + target.GetUnitType().GetName() + " belong to the defender");
            return(false);
        }

        if (target.GetTotalQty() == 0)
        {
            FileLogger.Trace("COMBAT", "No defenders left in this stack");
            return(false);
        }
        return(true);
    }
Ejemplo n.º 20
0
 /// <summary>
 /// Set the defending unit stack
 /// </summary>
 /// <param name="stack">Unit stack that will be defending against attacks</param>
 public void SetDefendingStack(UnitStack stack)
 {
     _currentTarget = stack;
     FileLogger.Trace("COMBAT", "SetDefendingStack: set " + _currentTarget.GetUnitType().GetName() + " as a target.");
 }
Ejemplo n.º 21
0
    /// <summary>
    /// Stops "object selected" animation and probably destroys the current attacks view
    /// Starts "object selected" animation on the new one
    /// </summary>
    private void SelectAnNPCStackAsTarget()
    {
        FileLogger.Trace("COMBAT VIEW", "SelectAnNPCStackAsTarget");
        UnitStack target = _model.SelectDefendingStack();

        if (target != null)
        {
            FileLogger.Trace("COMBAT", "Selected " + target.GetUnitType().GetName() + " as a target");
            if (_currentDefender != target)
            {
                _currentDefender = target;

                // cover the case when the game selects
                // an NPC defender who's offscreen
                bool             areProcessingAttackers = false;
                List <UnitStack> stacks = _model.GetUnitStacks(areProcessingAttackers);
                int index = stacks.FindIndex(a => a == _currentDefender);
                if (index == -1)
                {
                    areProcessingAttackers = true;
                    stacks = _model.GetUnitStacks(areProcessingAttackers);
                    index  = stacks.FindIndex(a => a == _currentDefender);
                }
                Dictionary <UnitStack, UnitStackView> stackViews = areProcessingAttackers ? _attackerStackViews : _defenderStackViews;

                // these variables are defined here so that they can be used in an error message below
                int offset = -1;
                int numberOfSpawnPoints = -1;

                if (!stackViews.ContainsKey(_currentDefender))
                {
                    numberOfSpawnPoints = areProcessingAttackers ? _attackersSpawnPoints.Length : _defendersSpawnPoints.Length;
                    offset = index >= numberOfSpawnPoints ? index + 1 - numberOfSpawnPoints : 0;

                    FileLogger.Trace("COMBAT VIEW", "Current defender: " + _currentDefender.GetUnitType().GetName() + ", index = " + index + ", number of spawn points: " + numberOfSpawnPoints + ", offset: " + offset + ")");

                    if (areProcessingAttackers)
                    {
                        _attackerStackViewsOffset = offset;
                    }
                    else
                    {
                        _defenderStackViewsOffset = offset;
                    }
                    UpdateUnitStackViews();
                }

                if (stackViews.ContainsKey(_currentDefender))
                {
                    // the attack will be resoved after the explosion animation plays out
                    stackViews[_currentDefender].PlayExplosionAnimation();
                }
                else
                {
                    FileLogger.Error("COMBAT", "Selected " + _currentDefender.GetUnitType().GetName() + " as a target, but it doesn't have a view! (index = " + index + ", number of spawn points: " + numberOfSpawnPoints + ", offset: " + offset + ")");
                }
            }
            else
            {
                FileLogger.Trace("COMBAT", "SelectAnNPCStackAsTarget: resolving the current attack");
                // explosion animation already played for this defender -
                // go ahead and resolve the attack
                _model.ResolveCurrentAttack(false);
            }
        }
        // else panic - if it's not the player's turn select a defender, the model should not return null
    }
Ejemplo n.º 22
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();
 }