/* This function applies the correct formulae to detemine whether a move hits or not. * The attacking Pokemon's accuracy stage and the defending Pokemon's evasion stage are combined * The calculated stage is then sent to the PokemonInBattle.ApplyAccStage() function, which returns a percentage change of the attack hitting. * Finally, the percentage is compared to a random number between 0 and 99 to determine if the move actually hits. */ public static bool AccuracyCheck(byte moveAccuracy, sbyte attackerAccStage, sbyte defenderEvaStage) { sbyte stage = (sbyte)MathHelper.Clamp((attackerAccStage - defenderEvaStage), -6, 6); byte accuracy = (byte)MathHelper.Clamp((PokemonInBattle.ApplyAccStage(moveAccuracy, stage)), 0, 100); return(PkmnUtils.RandomInclusive(99) < accuracy); }
/* When a TurnRun is executed, the engine will work out whether the user can run away. */ public override bool Execute() { /* A byte representing the probability of a successful escape is generated using this formula. * It is then compared to a random integer between 0 and 255 to determine whether the escape can happen. */ byte escapeChance = (byte)((((user.Speed * 128) / target.Speed) + (30 * user.RunCount)) % 256); bool canRun = (PkmnUtils.RandomInclusive(255) < escapeChance); /* If the player Pokemon has tried to run away, and they have managed it, then it is written to the log. * The battle's EmptyLog flag is set to true so that the log is displayed to the screen, and the function returns true. * This means that the battle will end after this turn, since the user has run away. * However, if the player cannot run, this is also written to the log, EmptyLog is set to true and the function returns false since the battle will continue. */ if (user == battleRef.CurrentPlayer) { if (canRun) { battleRef.WriteToLog("You fled from the battle!"); battleRef.EmptyLog = true; return(true); } else { battleRef.WriteToLog("Couldn't escape!"); battleRef.EmptyLog = true; return(false); } } /* Otherwise, the opponent Pokemon is the one trying to run away. * If the run has succeeded, then it's written to the log, EmptyLog is set to true, and the function returns true. * In the other case, the run failed, and this is written to the log. EmptyLog is again set to true and false is returned. */ else { if (canRun) { battleRef.WriteToLog(target.Nickname + " fled from the battle!"); battleRef.EmptyLog = true; return(true); } else { battleRef.WriteToLog(target.Nickname + " tried to run but couldn't escape!"); battleRef.EmptyLog = true; return(false); } } }
/* The main constructor for a Pokemon takes its species (PokemonData), Gender, moveset, level, and a TrainerRank. * The TrainerRank is nullable so that null can be passed in for a wild Pokemon. */ public Pokemon(PokemonData pokemonData, Gender gender, Move[] moves, byte level, TrainerRank?rank) { /* The nickname, type and base stats for the Pokemon are copied from the PokemonData for its species. */ Nickname = pokemonData.PokemonName; pokemonID = pokemonData.ID; baseHP = pokemonData.BaseHP; baseAttack = pokemonData.BaseAttack; baseDefence = pokemonData.BaseDefence; baseSpecialAttack = pokemonData.BaseSpecialAttack; baseSpecialDefence = pokemonData.BaseSpecialDefence; baseSpeed = pokemonData.BaseSpeed; type = new List <PkmnType>(); type = pokemonData.Type; /* Gender and Level are set according to what was passed in. */ this.gender = gender; this.level = level; /* Fainted is false by default, as a Pokemon is initially conscious. */ fainted = false; /* The moveset is copied using Array.Copy(). */ Array.Copy(moves, this.moves, 4); /* The IVs for the Pokemon are randomly generated between 0 and 31. */ iv_HP = (byte)PkmnUtils.RandomInclusive(31); iv_Attack = (byte)PkmnUtils.RandomInclusive(31); iv_Defence = (byte)PkmnUtils.RandomInclusive(31); iv_SpecialAttack = (byte)PkmnUtils.RandomInclusive(31); iv_SpecialDefence = (byte)PkmnUtils.RandomInclusive(31); iv_Speed = (byte)PkmnUtils.RandomInclusive(31); /* The EVs of the Pokemon are set according to the TrainerRank passed in. * This will only happen if the Pokemon is owned by an NPC trainer. * The TrainerRank will be null for player Pokemon (since they earn EVs through battle and start at 0). * It will also be null for wild Pokemon since they have EVs of 0. */ if (rank.HasValue) { if (rank.Value == TrainerRank.Normal) { ev_HP = ev_Attack = ev_Defence = ev_SpecialAttack = ev_SpecialDefence = ev_Speed = 0; } else if (rank.Value == TrainerRank.Grunt) { ev_HP = ev_Attack = ev_Defence = ev_SpecialAttack = ev_SpecialDefence = ev_Speed = 10; } else if (rank.Value == TrainerRank.Elite) { ev_HP = ev_Attack = ev_Defence = ev_SpecialAttack = ev_SpecialDefence = ev_Speed = 20; } else if (rank.Value == TrainerRank.GymLeader) { ev_HP = ev_Attack = ev_Defence = ev_SpecialAttack = ev_SpecialDefence = ev_Speed = 40; } else if (rank.Value == TrainerRank.EliteFour) { ev_HP = ev_Attack = ev_Defence = ev_SpecialAttack = ev_SpecialDefence = ev_Speed = 60; } else if (rank.Value == TrainerRank.Champion) { ev_HP = ev_Attack = ev_Defence = ev_SpecialAttack = ev_SpecialDefence = ev_Speed = 80; } } else { /* This block executes if the TrainerRank passed in is null. * This means newly created wild Pokemon or player Pokemon have EVs of 0. */ ev_HP = ev_Attack = ev_Defence = ev_SpecialAttack = ev_SpecialDefence = ev_Speed = 0; } /* Finally, set the health of the Pokemon using the new HP stats. */ health = new AttributePair(HP); }
/* The CheckSpawn() function checks if a wild Pokemon battle will be triggered on this frame. * It is only called when the player's StepCheck bit is true, so it is only called once every step. */ private void CheckSpawn() { /* This Random object will be needed for a lot of things later. */ Random r = new Random(); /* Each MapLayer in the map needs to be checked for a Tile with its Spawn bit set to true. */ foreach (MapLayer layer in world.CurrentMap.MapLayers) { /* If tile that the player is standing on in the layer has its Spawn bit set to true, a battle may happen. */ if (layer.GetTile(player.Sprite.TileLocation.X, player.Sprite.TileLocation.Y).Spawn) { /* This condition determines whether an actual battle happens or not. * If a random double between 0 and 187.5 is less than the level's grass encounter rate, then a battle will happen. * The most likely a battle can be to happen is a VeryCommon encounter rate, which is 10.0. * With a VeryCommon encounter rate, the chance of a battle occurring is 10/187.5. * The least likely a battle can be to happen is with a VeryRare encounter rate, which has a chance of 1.25/187.5. * Note the the encounter rate is not how likely it is for a certain Pokemon to be battled - it is how likely that a battle will happen at all. */ if ((r.NextDouble() * 187.5) < World.CurrentLevel.GrassEncounterRate) { /* A new array of ProportionValue<PokemonSpawn> objects is created with the length of the GrassSpawns in the current level. * GrassSpawns is a list of PokemonSpawn objects for the level's grass, stating what Pokemon at what level can be encountered. * The spawns array is filled with ProportionValues created using the PokemonSpawn's Percentage property, and the PokemonSpawn object itself. */ ProportionValue <PokemonSpawn>[] spawns = new ProportionValue <PokemonSpawn> [World.CurrentLevel.GrassSpawns.Count]; for (int i = 0; i < spawns.Length; i++) // NOTE TO SELF: IT WOULD BE MORE EFFICIENT TO CREATE THE ARRAY IN A HIGHER SCOPE, SINCE IT IS PART OF THE LEVEL, BUT THIS WILL DO FOR NOW. { spawns[i] = ProportionValue.Create(World.CurrentLevel.GrassSpawns[i].Percentage, World.CurrentLevel.GrassSpawns[i]); } /* The encounter for the spawn is found proportionally from the array using ChooseByRandom(). * A new Pokemon object is created using the encounter data's ID, gender, and minimum/maximum levels. * The wild Pokemon's level is chosen randomly between the minimum and maximum level in the selected PokemonSpawn. * The moveset is currently just "Scratch". Although dynamic moveset generation is not part of the user requirements, * I could add it if I have time by choosing the last four moves that the species can learn before it reaches its level. */ PokemonSpawn encounter = spawns.ChooseByRandom(); Pokemon p = new Pokemon(DataManager.PokemonSpecies[encounter.ID], Pokemon.GetGender(DataManager.PokemonSpecies[encounter.ID].GenderRatio), new[] { DataManager.Moves["Scratch"], null, null, null }, (byte)PkmnUtils.RandomInclusive(encounter.MinLevel, encounter.MaxLevel), null); /* A wild battle is essentially a fight against an enemy team of one Pokemon. * The BattleScreen.InitBattle() is called, which sends the player and enemy to the screen and sets the battle background index to zero. * Finally, the BattleScreen is pushed on to the state stack. */ GameRef.BattleScreen.InitBattle(player.Team, p, 0); Change(ChangeType.Push, GameRef.BattleScreen); } } } }