Пример #1
0
 public float heuristic(Move m, BattlePokemon p)
 {
     return heuristic(m.type, p, true);
 }
Пример #2
0
        /// <summary>
        /// Gives a specialised value of the effectiveness
        /// of a move t from pokemon p towards the defender.
        /// </summary>
        /// <param name="t">Attacking move type</param>
        /// <param name="p">Pokemon attacking</param>
        /// <returns></returns>
        public float heuristic(Type t, BattlePokemon p, bool countStab)
        {
            float eff1 = damageCalc(t, this.type1);
            float eff2 = damageCalc(t, this.type2);
            float stab = 1;
            if (countStab)
            {
                if (t == p.type1 || t == p.type2)
                    stab = 1.5f;
            }
            float immunityFromAbility = 1;
            if (immunityCheck(t, this))
                immunityFromAbility = 0;

            return (eff1 * eff2 * stab * immunityFromAbility);
        }
Пример #3
0
        /// <summary>
        /// Used to handle moves whose BP is unknown or varies.
        /// </summary>
        /// <param name="m"></param>
        /// <returns></returns>
        private float getRealBP(Move m, BattlePokemon enemy)
        {
            if (m.bp > -1)
                return m.bp;
               
            else if (m.bp == -2)
            {
                if (m.name == "Gyro Ball")
                {
                    float np = 25 * (enemy.getStat("spe") / this.getStat("spe"));
                }
            }

            return 20; //assume default
        }
Пример #4
0
 /// <summary>
 /// Gets the heuristic value of pokemon p vs. this pokemon.
 /// Returns a value between 0-8
 /// </summary>
 /// <param name="p"></param>
 /// <returns></returns>
 public float matchup(BattlePokemon p)
 {
     //All of this sucks and it needs to be rewritten to be more clear and useful.
     if (Object.ReferenceEquals(p, null))
     {
         //in a test case where volt-switch killed an opponent "p" was null
         //todo: return a more helpful indicator
         return 1;
     }
     return heuristic(p.type1, p,false) + heuristic(p.type2, p,false);
 }
Пример #5
0
 public float heuristic(Move m, BattlePokemon p)
 {
     return(heuristic(m.type, p, true));
 }
Пример #6
0
        /// <summary>
        /// Returns the damage modifier for the held item.
        /// </summary>
        /// <returns></returns>
        private float itemDamageMod(Move m, BattlePokemon enemy)
        {
            if (item == "none")
                return 1;
            if (item == "choiceband" && m.group == "physical")
                return 1.5f;
            if (item == "choicespecs" && m.group == "special")
                return 1.5f;
            if (item == "lifeorb")
                return 1.3f;
            if (item == "expertbelt" && this.isSuperEffective(m, enemy))
                return 1.2f;

            return 1;
        }
Пример #7
0
        /// <summary>
        /// 
        /// </summary>
        /// <param name="you"></param>
        /// <param name="e"></param>
        /// <param name="m"></param>
        /// <returns></returns>
        private int getStatusChance(BattlePokemon you, BattlePokemon e, Move m, List<BattlePokemon> enemyTeam)
        {
            int max = GlobalConstants.MAX_MOVE_RANK;
            if (e.status != Status.STATE_HEALTHY)
                return -max;
            if (e.mon.hasAbility("magic bounce"))
                return -max;
            if (e.mon.hasAbility("poison heal") && m.statuseffect == "tox")
                return -max;
            if (e.mon.hasAbility("limber") && m.statuseffect == "par")
                return -max;
            if (m.statuseffect == "tox" && (e.hasType(types["poison"]) || e.hasType(types["steel"])))
                return -max;
            if (m.statuseffect == "par" && (e.hasType(types["ground"]) || e.hasType(types["electric"])))
                return -max;

            int chance = 0;
            if (m.statuseffect == "brn" && e.mon.getRole().physical)
                chance += 2;
            else if (m.statuseffect == "par" && (e.getStat("spe") >= you.getStat("spe")))
                chance += 2;
            else if (m.statuseffect == "slp" && (you.getStat("spe") >= e.getStat("spe")))
            {
                foreach (BattlePokemon bp in enemyTeam)
                {
                    if (bp.status == Status.STATE_SLP)
                        return -max; //abide by sleep clause
                }
                chance += 2;
            }

            chance += (int)Math.Round(10 * e.checkKOChance(you)); //Increase chance if enemy is too strong and needs to be weakened.

            return chance;
        }
Пример #8
0
 /// <summary>
 /// Simply returns whether the move is super-effective or better (4x)
 /// </summary>
 /// <param name="m"></param>
 /// <param name="enemy"></param>
 /// <returns></returns>
 public bool isSuperEffective(Move m, BattlePokemon enemy)
 {
     float a = damageCalc(m.type, enemy.type1);
     float b = 1;
     if (enemy.type1 != enemy.type2)
         b = damageCalc(m.type, enemy.type2);
     return (a * b > 2f) ? true : false;
 }
Пример #9
0
        /// <summary>
        /// The damage formula used by the games / PS!
        /// This returns a fairly accurate representation of
        /// how much damage this pokemon will do to enemy with move m.
        /// Ignores critical chance and variance.
        /// </summary>
        /// <param name="m"></param>
        /// <param name="enemy"></param>
        /// <returns></returns>
        private int damageFormula(Move m, BattlePokemon enemy)
        {
            float first = (2f * this.level + 10f) / 250f;
            float second = 0;
            if (m.group == "physical")
            {
                second = (float)this.getStat("atk") / (float)enemy.getStat("def");
            }
            else
            {
                second = (float)this.getStat("spa") / (float)enemy.getStat("spd");
            }
            float third = getRealBP(m, enemy);
            float totaldmg = first * second * third + 2;

            //Calculate modifier.
            //We will assume no critical hit and disregard the random variance.
            float itemmod = 1;
            float stab = 1;
            float immunity = 1;

            float type = damageCalc(m.type, enemy.type1);
            if(enemy.type1 != enemy.type2)
                type = type * damageCalc(m.type, enemy.type2);

            if (m.type == this.type1 || m.type == this.type2)
            {
                stab = 1.5f;
            }
            itemmod = itemDamageMod(m, enemy);
            if (immunityCheck(m.type, enemy))
                immunity = 0;
            float multiplier = type * stab * itemmod * immunity;
            return (int)Math.Floor(totaldmg * multiplier);
        }
Пример #10
0
        /// <summary>
        /// Returns a rank from -4 to 7
        /// </summary>
        /// <param name="e"></param>
        /// <param name="lastAction"></param>
        /// <returns></returns>
        private int getRecoverChance(BattlePokemon e, LastBattleAction lastAction)
        {
            BattlePokemon you = this;
            int hpThreshold = 40; //Percent of health at which to conisder recovering.
            int chance = 0;

            if (you.getHPPercentage() <= hpThreshold) chance += 3;
            else if (you.getHPPercentage() > (100 - hpThreshold)) chance -= 2;
            if (e.checkKOChance(you) < 0.3f) chance += 2; //heal if the opponent cannot ohko us.
            if (you.status != Status.STATE_HEALTHY && lastAction != LastBattleAction.ACTION_SLEEPTALK) chance += 2;
            if (lastAction == LastBattleAction.ACTION_RECOVER) chance -= 2;

            return chance;
        }
Пример #11
0
 /// <summary>
 /// Returns how many times this pokemon will
 /// have to use move m to KO enemy.
 /// </summary>
 /// <param name="m"></param>
 /// <param name="enemy"></param>
 /// <returns></returns>
 public int hitsToKill(Move m, BattlePokemon enemy)
 {
     int totalDamage = damageFormula(m, enemy);
     //Compare the damage we will deal to the health of the enemy.
     int times = 0; //number of times it takes to use this move to KO the opponent.
     int health = enemy.getHealth();
     for (;(health > 0); times++)
     {
         if (times > GlobalConstants.MAX_HKO)
             break;
         health -= totalDamage;
     }
     return times;
 }
Пример #12
0
 /// <summary>
 /// Ranks a given move.
 /// Returns a rank >= 1
 /// </summary>
 /// <param name="m"></param>
 /// <param name="enemy"></param>
 /// <returns></returns>
 public int rankMove(Move m, BattlePokemon enemy,List<BattlePokemon> enemyTeam, LastBattleAction lba)
 {
     int DEFAULT_RANK = 11; //(15 - 4)
     int rank = DEFAULT_RANK; // rank of move m
     if (m.group != "status")
     {
         rank = hitsToKill(m, enemy);
         //discourage the use of low accuracy moves if they're overkill
         if (m.accuracy != 1 && enemy.getHPPercentage() < 20)
             ++rank;
         if (m.priority > 0)
             rank -= m.priority;
         //To rank in ascending order (ie 1 is a poor rank) subtract the rank from the max.
         if (rank > GlobalConstants.MAX_MOVE_RANK) rank = GlobalConstants.MAX_MOVE_RANK;
         rank = GlobalConstants.MAX_MOVE_RANK - rank;
        
     }
     else
     {
        if (m.heal)
         {
             rank = getRecoverChance(enemy, lba);
             rank += ((100-getHPPercentage())/10);
         }
        else if (m.status)
         {
             rank += getStatusChance(this, enemy, m, enemyTeam);
             /* add the status rank to the default rank, meaning a good
              * status move will rank around the same as a 2HKO. This
              * will prevent cases where an easy OHKO is available, but
              * a turn is wasted on status. However it may need more
              * balancing.
              */
         }
        else if (m.isBoost)
         {
             rank += getBoostChance(this, enemy, m, lba);
         }
     }
     return rank;
 }
Пример #13
0
        public void testBattle()
        {
            BattlePokemon off = new BattlePokemon(Global.lookup("magcargo"));
            BattlePokemon def = new BattlePokemon(Global.lookup("scizor"));
            List<BattlePokemon> defteam = new List<BattlePokemon>();
            defteam.Add(def);
            Move m1 = Global.moveLookup("Fire Blast");
            Move m2 = Global.moveLookup("Flamethrower");
            def.setHealth(10);
            int dmg1 = off.rankMove(m1, def,defteam, LastBattleAction.ACTION_ATTACK_SUCCESS);
            int dmg2 = off.rankMove(m2, def, defteam, LastBattleAction.ACTION_ATTACK_SUCCESS);
            cwrite(off.mon.name + "'s " + m1.name + " against " + def.mon.name+":"+dmg1, "debug", COLOR_BOT);
            cwrite(off.mon.name + "'s " + m2.name + " against " + def.mon.name + ":" + dmg2, "debug", COLOR_BOT);

        }
Пример #14
0
        /// <summary>
        /// Predicts how well the pokemon matches up against
        /// the opponent. This only takes into account the pokemon's
        /// typing as compared to it's opponent's.
        /// </summary>
        /// <param name="enemy">the opposing pokemon</param>
        /// <returns>a float in range 0-8</returns>
        public float checkTypes(BattlePokemon defender)
        {
            float val = damageCalc(this.mon.type1, defender.type1);
            if (defender.type1.value != defender.type2.value ||
                defender.type2.value != null)
                val = val * damageCalc(this.mon.type1, defender.type2);
            if (this.mon.type1 != this.mon.type2 || this.mon.type2 != null)
            {
                val = val * damageCalc(this.mon.type2, defender.type2);
                if (defender.type1.value != defender.type2.value ||
                defender.type2.value != null)
                    val = val * damageCalc(this.mon.type2, defender.type2);
            }
            return val;

        }
Пример #15
0
        private int getBoostChance(BattlePokemon you, BattlePokemon e, Move m, LastBattleAction lastAction)
        {
            int chance = 0;
            int minHP = 30;
            float enemyTolerance = 0.5f;

            List<String> boosts = m.whatBoosts();
            //lower rank if already maxed out.
            foreach (string s in boosts)
            {
                if (this.getBoostModifier(s) == 4f)
                    chance -= 1;
            }
            if (you.getHPPercentage() <= minHP) chance -= 2; //too weak, should focus efforts elsewhere

            if (e.checkKOChance(you) < enemyTolerance) chance += 2; //enemy does not threaten us
            else if (e.checkKOChance(you) - 0.2f < enemyTolerance) chance += 2; //if boosting will make us survive, do it.
            else chance -= 2; //otherwise too risky

            if (you.mon.getRole().setup) chance += 4; //if the mon is a setup sweeper, etc, 
            if (lastAction == LastBattleAction.ACTION_BOOST) chance -= 1; //Be careful not to boost forever.
            return chance;
        }
Пример #16
0
 /// <summary>
 /// Checks if a move is immune against another Pokemon based on its abilities, etc.
 /// NOTE: Type-based immunities are covered within their own typings, not here.
 /// </summary>
 /// <param name="t"></param>
 /// <param name="p"></param>
 /// <returns></returns>
 public bool immunityCheck(Type t, BattlePokemon p)
 {
     if (t.value == "ground" && p.mon.hasAbility("levitate"))
         return true;
     if (t.value == "fire" && p.mon.hasAbility("flashfire"))
         return true;
     return false;
 }
Пример #17
0
        /// <summary>
        /// Calculates the total damage a move will do to a particular pokemon,
        /// with respect to abilities, types, STAB, common items, etc.
        /// </summary>
        /// <param name="m">Move used by (this) pokemon.</param>
        /// <param name="enemy"></param>
        /// <returns></returns>
        public float damageCalcTotal(Move m, BattlePokemon enemy)
        {
            float mult = damageCalc(m.type, enemy.type1);
            mult = mult * damageCalc(m.type, enemy.type2);
            float dmg = getRealBP(m,enemy);
            float stab = 1;
            float ability = 1;
            float immunity = 1;
            if (immunityCheck(m.type, enemy))
                immunity = 0;
            if (m.type == this.type1 || m.type == this.type2)
            {
                stab = 1.5f;
            }
            //do ability calculations

            float additional = itemDamageMod(m, enemy);
            

            return (dmg * mult * stab * ability * additional * immunity);
        }
Пример #18
0
        /// <summary>
        /// Returns a number between 0,1 that determines
        /// the likelihood of this mon KOing the enemy
        /// </summary>
        /// <param name="enemy"></param>
        /// <returns></returns>
        public float checkKOChance(BattlePokemon enemy)
        {
            float chance = 0;
            //First check if we are faster.
            
            if (this.getStat("spe") > enemy.getStat("spe"))
            {
                chance += 0.1f;
            }
            //Now check if we are a suitable attacker
            Role role = mon.getRole();
            DefenseType edeftype = enemy.mon.getDefType();
            if (((role.physical) && (edeftype.special)) ||
                 ((role.special) && (edeftype.physical)) ||
                 (edeftype.any))
            {
                chance += 0.4f;
            }

            if (enemy.getHPPercentage() < 50)
                chance += 0.2f;
            else
                chance -= 0.1f;

            if (checkTypes(enemy) >= 2.5f)
                chance += 0.2f;

            //Todo: add other parameters here. Decrement chance for unsuitable matchings, etc.
            //Todo also: adjust chance scale. do some calcs to find out what produces more favorable results.
            return chance;

        }
Пример #19
0
        /// <summary>
        /// Ranks a given move.
        /// Returns a rank >= 1
        /// </summary>
        /// <param name="m"></param>
        /// <param name="enemy"></param>
        /// <returns></returns>
        public int rankMove(Move m, BattlePokemon enemy, List <BattlePokemon> enemyTeam, LastBattleAction lba, Weather weather)
        {
            int DEFAULT_RANK = 11;           //(15 - 4)
            int rank         = DEFAULT_RANK; // rank of move m

            if (m.group != "status")
            {
                rank = hitsToKill(m, enemy, weather);

                /*
                 * Set the rank to the maximum if this move is fake out, and it can be used.
                 * This is isn't always the move we want to make, so further checks need
                 * to be developed. Namely, prevent using it against ghost types and
                 * rough skin/iron barbs, etc. */
                if (m.name.Contains("Fake Out") && this.canUseFakeout)
                {
                    rank = 0; //Rank order is reversed for damaging moves, 0 = Max Rank.
                }
                //discourage the use of low accuracy moves if they're overkill
                if (m.accuracy != 1 && enemy.getHPPercentage() < 20)
                {
                    ++rank;
                }
                if (m.priority > 0)
                {
                    rank -= m.priority;
                }
                //To rank in ascending order (ie 1 is a poor rank) subtract the rank from the max.
                if (rank > GlobalConstants.MAX_MOVE_RANK)
                {
                    rank = GlobalConstants.MAX_MOVE_RANK;                                       //Prevent negative ranks.
                }
                rank = GlobalConstants.MAX_MOVE_RANK - rank;
            }
            else
            {
                if (m.heal)
                {
                    rank  = getRecoverChance(enemy, lba);
                    rank += ((100 - getHPPercentage()) / 10);
                }
                else if (m.status)
                {
                    rank += getStatusChance(this, enemy, m, enemyTeam);

                    /* add the status rank to the default rank, meaning a good
                     * status move will rank around the same as a 2HKO. This
                     * will prevent cases where an easy OHKO is available, but
                     * a turn is wasted on status. However it may need more
                     * balancing.
                     */
                }
                else if (m.isBoost)
                {
                    rank += getBoostChance(this, enemy, m, lba);
                }
                else if (m.field)
                {
                    /*
                     * If the pokemon is a lead and hasn't used a hazard,
                     * rank this highly. Otherwise give it a small boost,
                     * or have it remain default for non-lead pokemon.
                     * This needs to be refined more. */
                    if (this.mon.getRole().lead&& !this.hasUsedHazard)
                    {
                        rank = GlobalConstants.MAX_MOVE_RANK;
                    }
                    else if (this.mon.getRole().lead)
                    {
                        rank += 1;
                    }
                }
            }
            return(rank);
        }