예제 #1
0
 public int[] CalcDamage(RbyPokemon attacker, RbyPokemon defender, RbyMove move, bool crit)
 {
     int[] ret = new int[39];
     for (int i = 0; i < ret.Length; i++)
     {
         ret[i] = CalcDamage(attacker, defender, move, i + 217, crit);
     }
     return(ret);
 }
예제 #2
0
    // Code ported from route one. (https://github.com/HRoll/poke-router/blob/master/src/DamageCalculator.java)
    public int CalcDamage(RbyPokemon attacker, RbyPokemon defender, RbyMove move, int damageRoll, bool crit)
    {
        damageRoll = Math.Clamp(damageRoll, 217, 255);

        if (move.Power == 0)
        {
            return(0);
        }

        bool special           = move.Type.IsSpecial();
        int  attackUnmodified  = special ? attacker.UnmodifiedSpecial : attacker.UnmodifiedAttack;
        int  attack            = special ? attacker.Special : attacker.Attack;
        int  defenseUnmodified = special ? defender.UnmodifiedSpecial : defender.UnmodifiedDefense;
        int  defense           = special ? defender.Special : defender.Defense;

        if (move.Name == "SELFDESTRUCT" || move.Name == "EXPLOSION")
        {
            defenseUnmodified = Math.Max(defenseUnmodified / 2, 1);
            defense           = Math.Max(defense / 2, 1);
        }

        bool stab = attacker.Species.Type1 == move.Type || attacker.Species.Type2 == move.Type;

        int damage = ((attacker.Level * (crit ? 2 : 1)) & 0xff) * 2 / 5 + 2;

        damage *= crit ? attackUnmodified : attack;
        damage *= move.Power;
        damage /= 50;
        damage /= crit ? defenseUnmodified : defense;
        damage += 2;
        if (stab)
        {
            damage = damage * 3 / 2;
        }
        damage = damage * move.Game.GetTypeEffectiveness(move.Type, defender.Species.Type1) / 10;
        damage = damage * move.Game.GetTypeEffectiveness(move.Type, defender.Species.Type2) / 10;

        if (damage == 0)
        {
            return(0);
        }

        damage *= damageRoll;
        damage /= 255;

        return(Math.Max(damage, 1));
    }
예제 #3
0
    private void ForceTurnInternal(RbyTurn turn)
    {
        int random          = SYM["Random"] + 0x10;
        int playerTurnDone1 = SYM["MainInBattleLoop.playerMovesFirst"] + 0x3;
        int playerTurnDone2 = SYM["MainInBattleLoop.AIActionUsedEnemyFirst"] + 0xc;
        int playerTurnDone3 = SYM["HandlePlayerMonFainted"];
        int enemyTurnDone1  = SYM["MainInBattleLoop.enemyMovesFirst"] + 0x11;
        int enemyTurnDone2  = SYM["MainInBattleLoop.playerMovesFirst"] + 0x27;
        int enemyTurnDone3  = SYM["HandleEnemyMonFainted"];

        int    ret;
        Joypad holdButton = Joypad.None;

        if ((CpuRead("wOptions") & 0x7) != 1)
        {
            holdButton = Joypad.A;
        }

        string[] sideEffects =
        {
            "FreezeBurnParalyzeEffect",
            "StatModifierDownEffect",
            "PoisonEffect",
            "ConfusionSideEffect",
            "FlinchSideEffect"
        };

        while ((ret = ClearTextUntil(holdButton, random, playerTurnDone1, playerTurnDone2, playerTurnDone3, enemyTurnDone1, enemyTurnDone2, enemyTurnDone3)) == random)
        {
            int addr = CpuReadLE <ushort>(SP);
            if (addr > 0x4000)
            {
                addr |= CpuRead("hLoadedROMBank") << 16;
            }
            string address = SYM[addr];
            RunUntil(addr);
            if (!address.StartsWith("VBlank"))
            {
                if (address.StartsWith("MoveHitTest"))  // hit/miss
                {
                    A = (turn.Flags & Miss) > 0 ? 0xff : 0x00;
                }
                else if (address.StartsWith("CriticalHitTest"))    // crit
                {
                    A = (turn.Flags & Crit) > 0 ? 0x00 : 0xff;
                }
                else if (address.StartsWith("RandomizeDamage"))    // damage roll
                {
                    int roll = turn.Flags & 0x3f;
                    if (roll < 1)
                    {
                        roll = 1;
                    }
                    if (roll > 39)
                    {
                        roll = 39;
                    }
                    roll += 216;
                    A     = (byte)((roll << 1) | (roll >> 7));     // rotate left to counter a rrca instruction
                }
                else if (address == "StatModifierDownEffect+0021") // AI's 25% chance to miss
                {
                    A = (turn.Flags & Miss) > 0 ? 0x00 : 0xff;
                }
                else if (sideEffects.Any(effect => address.StartsWith(effect)))    // various side effects
                {
                    A = (turn.Flags & SideEffect) > 0 ? 0x00 : 0xff;
                }
                else if (address.StartsWith("TrainerAI"))     // trainer ai
                {
                    if ((turn.Flags & AiItem) > 0)
                    {
                        A = 0x00; break;
                    }
                    else
                    {
                        A = 0xff;
                    }
                }
                else if (address.StartsWith("ThrashPetalDanceEffect"))     // thresh/petal dance length
                {
                    A = (turn.Flags & ThreeTurn) > 0 ? 0 : 1;
                }
                else if (address.StartsWith("CheckPlayerStatusConditions.IsConfused") || address.StartsWith("CheckEnemyStatusConditions.IsConfused"))     // confusion hit through
                {
                    A = (turn.Flags & Hitself) > 0 ? 0xff : 0x00;
                }
                else if (address.StartsWith("CheckPlayerStatusConditions.ThrashingAboutCheck"))    // confused for 2-5 turns after thrash/petal dance ends
                {
                    A = 0;
                }
                else if (address.StartsWith("ApplyAttackToPlayerPokemon.loop"))    // psywave damage
                {
                    A = turn.Flags & 0x3f;
                }
                else if (address.StartsWith("DisableEffect.pickMoveToDisable"))    // disable move
                {
                    A = FindBattleMove(turn.Target) & 0x3;
                }
                else if (address.StartsWith("DisableEffect.playerTurnNotLinkBattle"))    // disable number of turns (1-8)
                {
                    int turns = turn.Flags / Turns;
                    A = ((turns >= 1 ? turns : 8) - 1) & 0x7;
                }
                else if (address.StartsWith("BideEffect.bideEffect"))    // bide number of turns (2-3)
                {
                    int turns = turn.Flags / Turns;
                    A = ((turns >= 2 ? turns : 3) - 2) & 0x7;
                }
                else if (address == "TrappingEffect.trappingEffect+000b" || address == "TwoToFiveAttacksEffect.setNumberOfHits+000e")    // not needed
                {
                    A = 0x3;
                }
                else if (address == "TrappingEffect.trappingEffect+0014" || address == "TwoToFiveAttacksEffect.setNumberOfHits+0017")    // multi-attack number of hits (2-5)
                {
                    int turns = turn.Flags / Turns;
                    A = ((turns >= 2 ? turns : 5) - 2) & 0x3;
                }
                else if (address.StartsWith("MetronomePickMove"))
                {
                    RbyMove move = Moves[turn.Target];
                    Debug.Assert(move != null, "Unable to find the move: " + turn.Target);
                    A = move.Id;
                }
                else
                {
                    Console.WriteLine("Unhandled Random call coming from " + address);
                }
            }
        }
        RunFor(1);
    }
예제 #4
0
 public float OneShotPercentage(RbyPokemon attacker, RbyPokemon defender, RbyMove move, bool crit)
 {
     int[] damageRolls = CalcDamage(attacker, defender, move, crit);
     return((float)damageRolls.Where(dmg => dmg >= defender.HP).Count() / (float)damageRolls.Length);
 }