private void ValidateTutorialMatchup(ScenarioPokemon attackingScenarioPokemon, ScenarioPokemon targetScenarioPokemon, bool oichisPokemon = false) { Pokemon attackingPokemon = _pokemonService.Retrieve((int)attackingScenarioPokemon.Pokemon); Pokemon targetPokemon = _pokemonService.Retrieve((int)targetScenarioPokemon.Pokemon); Move move = _moveService.Retrieve((int)attackingPokemon.Move); // moves always hit during the tutorial, so this isn't necessary //if (move.Accuracy != 100) //{ // ReportProbable($"The move {attackingPokemon.Move} used by {attackingScenarioPokemon.Pokemon} does not have 100% accuracy (it has {move.Accuracy}%). If it misses it will softlock the tutorial."); //} if (move.Power < 30) { ReportProbable($"The move used by {attackingScenarioPokemon.Pokemon} is weak ({move.Power}), thus there's a risk it doesn't one shot the opponent in the tutorial"); } if (move.Power < 60 && targetPokemon.Resists(move.Type)) { ReportProbable($"The defending pokemon {targetScenarioPokemon.Pokemon} resists move {attackingPokemon.Move} used by {attackingScenarioPokemon.Pokemon}, thus there's a risk it doesn't one shot the opponent in the tutorial"); } if (!_moveRangeService.Retrieve((int)move.Range).GetInRange(1)) { ReportGuaranteed($"The move {attackingPokemon.Move} used by pokemon {attackingScenarioPokemon.Pokemon} has range {move.Range} which does not hit the square immediately ahead of the user. This causes a tutorial softlock."); } if (oichisPokemon && _moveRangeService.Retrieve((int)move.Range).GetInRange(24)) { ReportProbable($"The move {attackingPokemon.Move} used by pokemon {attackingScenarioPokemon.Pokemon} has range {move.Range} thus may take out Koroku, skipping the player's turn. This causes the 'Back' button to be not work in battles."); } if (invalidEffects.Contains(move.Effect1)) { ReportGuaranteed($"The move {attackingPokemon.Move} used by pokemon {attackingScenarioPokemon.Pokemon} has effect {move.Effect1} which is multi-turn. This causes a tutorial softlock."); } if (invalidEffects.Contains(move.Effect2)) { ReportGuaranteed($"The move {attackingPokemon.Move} used by pokemon {attackingScenarioPokemon.Pokemon} has effect {move.Effect2} which is multi-turn. This causes a tutorial softlock."); } if (targetPokemon.IsImmuneTo(move.Type)) { ReportGuaranteed($"The defending pokemon {targetScenarioPokemon.Pokemon} is immune to move {attackingPokemon.Move} used by {attackingScenarioPokemon.Pokemon}."); } if (targetScenarioPokemon.Ability == AbilityId.Sturdy) { ReportGuaranteed($"The defending pokemon {targetScenarioPokemon.Pokemon} has the ability Sturdy, which means it can not be one shot in the tutorial"); } if (!MoldBreakerAbilitys.Contains(attackingScenarioPokemon.Ability)) { void reportAbilityTypeImmunity(AbilityId abilityId, TypeId type) => ReportGuaranteed($"The defending pokemon {targetScenarioPokemon.Pokemon} has the ability {abilityId}, which means it is immune to the {type} type move {attackingPokemon.Move} used by {attackingScenarioPokemon.Pokemon}"); switch (targetScenarioPokemon.Ability) { case AbilityId.Levitate: if (move.Type == TypeId.Ground) { reportAbilityTypeImmunity(AbilityId.Levitate, TypeId.Ground); } break; case AbilityId.WaterAbsorb: if (move.Type == TypeId.Water) { reportAbilityTypeImmunity(AbilityId.WaterAbsorb, TypeId.Water); } break; case AbilityId.FlashFire: if (move.Type == TypeId.Fire) { reportAbilityTypeImmunity(AbilityId.FlashFire, TypeId.Fire); } break; case AbilityId.VoltAbsorb: if (move.Type == TypeId.Electric) { reportAbilityTypeImmunity(AbilityId.VoltAbsorb, TypeId.Electric); } break; case AbilityId.Lightningrod: if (move.Type == TypeId.Electric) { reportAbilityTypeImmunity(AbilityId.Lightningrod, TypeId.Electric); } break; case AbilityId.MotorDrive: if (move.Type == TypeId.Electric) { reportAbilityTypeImmunity(AbilityId.MotorDrive, TypeId.Electric); } break; } } }