Пример #1
0
    // This function evaluates the game-field
    // It then creates and returns an ActionData object referring to the steps for executing the action
    public ActionData GetActionData()
    {
        // first, find the best ability in terms of significance.
        List <AbilityOption> options = myUnit.GetAbilityOptions();
        float highestSignificance    = float.NegativeInfinity;

        // for each possible action:
        for (int i = 0; i < options.Count; i++)
        {
            // evaluate the significance of this particular option
            SignifyAbility(options[i]);
            // Debug.Log("Ability: " + options[i].GetAbility() + " | Significance: " + options[i].GetSignificance());

            // check if it has the highest significance
            if (options[i].GetSignificance() >= highestSignificance)
            {
                committedAbilityIndex  = i;
                committedAbilityOption = options[i];
                highestSignificance    = options[i].GetSignificance();
            }
        }

        committedMovement = CommitMovement();
        return(new ActionData(committedMovement.Item1, committedMovement.Item2, committedAbilityIndex));
    }
Пример #2
0
 // Takes an AbilityOption object and evaluates/sets its significance
 // this function is abstract because way in which an ability is given significance is biased based on the type of EnemyAction that has been decided upon
 // for example, being Aggro will value different things when choosing an option as opposed to being Defensive
 protected abstract void SignifyAbility(AbilityOption option);
Пример #3
0
    protected override void SignifyAbility(AbilityOption option)
    {
        // start at 0.0 significance
        option.SetSignificance(0.0f);

        // get variables
        Vector2Int bestTarget = new Vector2Int(int.MaxValue, int.MaxValue);
        Dictionary <Vector2Int, MutableTuple <Unit, float> > affectableUnits = option.GetAffectableUnits();
        bool unitIsAffectable;

        foreach (EffectState effect in option.GetAbility().GetEffectState())
        {
            foreach (Vector2Int key in affectableUnits.Keys)
            {
                unitIsAffectable = false;
                // go through each type of Effect that the ability deals, adding significance each time
                switch (effect)
                {
                case EffectState.DAMAGE:
                    // we don't want to damage EnemyUnits
                    if (!(affectableUnits[key].Item1 is EnemyUnit))
                    {
                        unitIsAffectable = true;
                        // if using this ability would reduce this Unit's HP to 0 or below,
                        // definitely consider doing this.
                        if ((option.GetAbility() as Attack).LethalAttack(affectableUnits[key].Item1))
                        {
                            affectableUnits[key].Item2 = float.PositiveInfinity;
                        }
                        else
                        {
                            // the significance of this ability against this Unit is double the ratio of how much of the Unit's current health that the ability will deal, out of 10.0
                            float significance = ((float)((option.GetAbility() as Attack).GetDamage()) / (float)(affectableUnits[key].Item1.GetHealth() + affectableUnits[key].Item1.GetDamageReduction()) * 20.0f);
                            affectableUnits[key].Item2 += significance;
                        }
                    }
                    break;

                case EffectState.BUFF_DR:
                    // viable units are (friendly) EnemyUnits that are not capped out of DR (max 5)
                    if (affectableUnits[key].Item1 is EnemyUnit && affectableUnits[key].Item1.GetDamageReduction() < 5)
                    {
                        unitIsAffectable = true;
                        // the significance of using this effect is greater the less DR the Unit already has (max 2.5)
                        float significance = ((float)(affectableUnits[key].Item1.GetDamageReduction() - 5)) / -2.0f;
                        affectableUnits[key].Item2 += significance;
                    }
                    break;

                case EffectState.BUFF_DMG:
                    // viable units are (friendly) EnemyUnits that are not Buffed
                    if (affectableUnits[key].Item1 is EnemyUnit && !affectableUnits[key].Item1.attackBuffed)
                    {
                        unitIsAffectable            = true;
                        affectableUnits[key].Item2 += 2.5f;
                    }
                    break;

                case EffectState.IMMOBILIZE:
                    // viable units are (nonfriendly) non-EnemyUnits that are not stunned
                    if (!(affectableUnits[key].Item1 is EnemyUnit) && !(affectableUnits[key].Item1.GetImmobilizedDuration() > 0))
                    {
                        unitIsAffectable            = true;
                        affectableUnits[key].Item2 += 2.5f;
                    }
                    break;

                case EffectState.KNOCKBACK:
                    // viable units are (nonfriendly) non-EnemyUnits
                    if (!(affectableUnits[key].Item1 is EnemyUnit))
                    {
                        unitIsAffectable            = true;
                        affectableUnits[key].Item2 += 1.5f;
                    }
                    break;

                case EffectState.DISABLE:
                    // viable units are (nonfriendly) non-EnemyUnits
                    if (!(affectableUnits[key].Item1 is EnemyUnit) && !(affectableUnits[key].Item1.GetDisabledDuration() > 0))
                    {
                        unitIsAffectable            = true;
                        affectableUnits[key].Item2 += 3.5f;
                    }
                    break;

                default:
                    break;
                }
                // We have a new Best Target IF: its viably affectable AND: there isn't one OR this significance is bigger than the current best
                if (unitIsAffectable && ((bestTarget.x == int.MaxValue && bestTarget.y == int.MaxValue) || (affectableUnits[key].Item2 >= affectableUnits[bestTarget].Item2)))
                {
                    bestTarget = key;
                }
            }
        }

        // If this Ability cannot affect any meaningful Units: Do NOT use it
        // IF:    This ability deals some sort of effect   AND      either: there is no bestTarget NOR affectable Unit
        if (option.GetAbility().GetEffectState().Count > 0 && ((bestTarget.x == int.MaxValue && bestTarget.y == int.MaxValue) || affectableUnits.Keys.Count <= 0))
        {
            option.SetSignificance(float.NegativeInfinity);
        }
        else if (option.GetAbility() is Wait)
        {
            // wait should be zero, AKA it should only be chosen if everything else is an awful choice
            option.SetSignificance(0.0f);
            // a disabled Unit MUST wait
            if (myUnit.GetDisabledDuration() > 0)
            {
                option.SetSignificance(float.PositiveInfinity);
            }
        }
        else
        {
            option.SetSignificance(affectableUnits[bestTarget].Item2);
        }
    }