diff options
author | Ajarmar <axel.jarmar@gmail.com> | 2022-05-08 23:52:01 +0200 |
---|---|---|
committer | rafa_99 <raroma09@gmail.com> | 2022-06-12 19:28:15 +0100 |
commit | 363b24f9153f32627802089eee7900d5749e410e (patch) | |
tree | bf170e51c43828f8030e0c15e56c30de496e3495 /src/com/sneed/pkrandom/pokemon | |
parent | 76431f3f79463ecdf3e46031d596e12996d6e471 (diff) |
add "better trainer movesets" setting
Diffstat (limited to 'src/com/sneed/pkrandom/pokemon')
-rw-r--r-- | src/com/sneed/pkrandom/pokemon/Effectiveness.java | 56 | ||||
-rwxr-xr-x | src/com/sneed/pkrandom/pokemon/Move.java | 28 | ||||
-rw-r--r-- | src/com/sneed/pkrandom/pokemon/MoveSynergy.java | 1207 | ||||
-rwxr-xr-x | src/com/sneed/pkrandom/pokemon/Trainer.java | 8 | ||||
-rwxr-xr-x | src/com/sneed/pkrandom/pokemon/TrainerPokemon.java | 2 | ||||
-rwxr-xr-x | src/com/sneed/pkrandom/pokemon/Type.java | 15 |
6 files changed, 1314 insertions, 2 deletions
diff --git a/src/com/sneed/pkrandom/pokemon/Effectiveness.java b/src/com/sneed/pkrandom/pokemon/Effectiveness.java index bc8f8e3..362ca60 100644 --- a/src/com/sneed/pkrandom/pokemon/Effectiveness.java +++ b/src/com/sneed/pkrandom/pokemon/Effectiveness.java @@ -28,6 +28,7 @@ package com.sneed.pkrandom.pokemon; import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.stream.Collectors; public enum Effectiveness { ZERO, HALF, NEUTRAL, DOUBLE, QUARTER, QUADRUPLE; @@ -64,7 +65,62 @@ public enum Effectiveness { return result; } + public static List<Type> notVeryEffective(Type attackingType, int generation, boolean effectivenessUpdated) { + Effectiveness[][] effectivenesses; + if (generation == 1) { + effectivenesses = effectivenessUpdated ? gen2Through5Table : gen1Table; + } else if (generation >= 2 && generation <= 5) { + effectivenesses = effectivenessUpdated ? gen6PlusTable : gen2Through5Table; + } else { + effectivenesses = gen6PlusTable; + } + List<Type> allTypes = Type.getAllTypes(generation); + + return allTypes + .stream() + .filter(defendingType -> + effectivenesses[attackingType.ordinal()][defendingType.ordinal()] == Effectiveness.HALF || + effectivenesses[attackingType.ordinal()][defendingType.ordinal()] == Effectiveness.ZERO) + .collect(Collectors.toList()); + } + + public static List<Type> superEffective(Type attackingType, int generation, boolean effectivenessUpdated) { + Effectiveness[][] effectivenesses; + if (generation == 1) { + effectivenesses = effectivenessUpdated ? gen2Through5Table : gen1Table; + } else if (generation >= 2 && generation <= 5) { + effectivenesses = effectivenessUpdated ? gen6PlusTable : gen2Through5Table; + } else { + effectivenesses = gen6PlusTable; + } + List<Type> allTypes = Type.getAllTypes(generation); + + return allTypes + .stream() + .filter(defendingType -> + effectivenesses[attackingType.ordinal()][defendingType.ordinal()] == Effectiveness.DOUBLE) + .collect(Collectors.toList()); + } + // Attacking type is the row, Defending type is the column. This corresponds to the ordinal of types. + private static final Effectiveness[][] gen1Table = { + /* NORMAL,FIGHTING, FLYING, GRASS , WATER, FIRE , ROCK , GROUND, PSYCHIC, BUG , DRAGON,ELECTRIC, GHOST , POISON, ICE */ + /*NORMAL */ {NEUTRAL, NEUTRAL, NEUTRAL, NEUTRAL, NEUTRAL, NEUTRAL, HALF, NEUTRAL, NEUTRAL, NEUTRAL, NEUTRAL, NEUTRAL, ZERO, NEUTRAL, NEUTRAL}, + /*FIGHTING*/{ DOUBLE, NEUTRAL, HALF, NEUTRAL, NEUTRAL, NEUTRAL, DOUBLE, NEUTRAL, NEUTRAL, HALF, NEUTRAL, NEUTRAL, ZERO, HALF, DOUBLE}, + /*FLYING */ {NEUTRAL, DOUBLE, NEUTRAL, DOUBLE, NEUTRAL, NEUTRAL, HALF, NEUTRAL, NEUTRAL, DOUBLE, NEUTRAL, HALF, NEUTRAL, NEUTRAL, NEUTRAL}, + /*GRASS */ {NEUTRAL, NEUTRAL, HALF, HALF, DOUBLE, HALF, DOUBLE, DOUBLE, NEUTRAL, HALF, HALF, NEUTRAL, NEUTRAL, HALF, NEUTRAL}, + /*WATER */ {NEUTRAL, NEUTRAL, NEUTRAL, HALF, HALF, DOUBLE, DOUBLE, DOUBLE, NEUTRAL, NEUTRAL, HALF, NEUTRAL, NEUTRAL, NEUTRAL, NEUTRAL}, + /*FIRE */ {NEUTRAL, NEUTRAL, NEUTRAL, DOUBLE, HALF, HALF, HALF, NEUTRAL, NEUTRAL, DOUBLE, HALF, NEUTRAL, NEUTRAL, NEUTRAL, DOUBLE}, + /*ROCK */ {NEUTRAL, HALF, DOUBLE, NEUTRAL, NEUTRAL, DOUBLE, NEUTRAL, HALF, NEUTRAL, DOUBLE, NEUTRAL, NEUTRAL, NEUTRAL, NEUTRAL, DOUBLE}, + /*GROUND */ {NEUTRAL, NEUTRAL, ZERO, HALF, NEUTRAL, DOUBLE, DOUBLE, NEUTRAL, NEUTRAL, HALF, NEUTRAL, DOUBLE, NEUTRAL, DOUBLE, NEUTRAL}, + /*PSYCHIC*/ {NEUTRAL, DOUBLE, NEUTRAL, NEUTRAL, NEUTRAL, NEUTRAL, NEUTRAL, NEUTRAL, HALF, NEUTRAL, NEUTRAL, NEUTRAL, NEUTRAL, DOUBLE, NEUTRAL}, + /*BUG */ {NEUTRAL, HALF, HALF, DOUBLE, NEUTRAL, HALF, NEUTRAL, NEUTRAL, DOUBLE, NEUTRAL, NEUTRAL, NEUTRAL, HALF, DOUBLE, NEUTRAL}, + /*DRAGON */ {NEUTRAL, NEUTRAL, NEUTRAL, NEUTRAL, NEUTRAL, NEUTRAL, NEUTRAL, NEUTRAL, NEUTRAL, NEUTRAL, DOUBLE, NEUTRAL, NEUTRAL, NEUTRAL, NEUTRAL}, + /*ELECTRIC*/{NEUTRAL, NEUTRAL, DOUBLE, HALF, DOUBLE, NEUTRAL, NEUTRAL, ZERO, NEUTRAL, NEUTRAL, HALF, HALF, NEUTRAL, NEUTRAL, NEUTRAL}, + /*GHOST */ { ZERO, NEUTRAL, NEUTRAL, NEUTRAL, NEUTRAL, NEUTRAL, NEUTRAL, NEUTRAL, ZERO, NEUTRAL, NEUTRAL, NEUTRAL, DOUBLE, NEUTRAL, NEUTRAL}, + /*POISON */ {NEUTRAL, NEUTRAL, NEUTRAL, DOUBLE, NEUTRAL, NEUTRAL, HALF, HALF, NEUTRAL, DOUBLE, NEUTRAL, NEUTRAL, HALF, HALF, NEUTRAL}, + /*ICE */ {NEUTRAL, NEUTRAL, DOUBLE, DOUBLE, HALF, NEUTRAL, NEUTRAL, DOUBLE, NEUTRAL, NEUTRAL, DOUBLE, NEUTRAL, NEUTRAL, NEUTRAL, HALF}, + }; private static final Effectiveness[][] gen2Through5Table = { /* NORMAL,FIGHTING, FLYING, GRASS , WATER, FIRE , ROCK , GROUND, PSYCHIC, BUG , DRAGON,ELECTRIC, GHOST , POISON, ICE , STEEL , DARK */ /*NORMAL */ {NEUTRAL, NEUTRAL, NEUTRAL, NEUTRAL, NEUTRAL, NEUTRAL, HALF, NEUTRAL, NEUTRAL, NEUTRAL, NEUTRAL, NEUTRAL, ZERO, NEUTRAL, NEUTRAL, HALF, NEUTRAL}, diff --git a/src/com/sneed/pkrandom/pokemon/Move.java b/src/com/sneed/pkrandom/pokemon/Move.java index 930440f..51cef26 100755 --- a/src/com/sneed/pkrandom/pokemon/Move.java +++ b/src/com/sneed/pkrandom/pokemon/Move.java @@ -24,11 +24,20 @@ package com.sneed.pkrandom.pokemon; /*-- along with this program. If not, see <http://www.gnu.org/licenses/>. --*/ /*----------------------------------------------------------------------------*/ +import com.dabomstew.pkrandom.constants.GlobalConstants; + public class Move { public class StatChange { public StatChangeType type; public int stages; public double percentChance; + + @Override + public boolean equals(Object obj) { + StatChange other = (StatChange)obj; + return this.type == other.type && this.stages == other.stages && this.percentChance == other.percentChance; + } + } public String name; @@ -68,6 +77,25 @@ public class Move { } } + public boolean hasSpecificStatChange(StatChangeType type, boolean isPositive) { + for (StatChange sc: this.statChanges) { + if (sc.type == type && (isPositive ^ sc.stages < 0)) { + return true; + } + } + return false; + } + + public boolean hasBeneficialStatChange() { + return (statChangeMoveType == StatChangeMoveType.DAMAGE_TARGET && statChanges[0].stages < 0) || + statChangeMoveType == StatChangeMoveType.DAMAGE_USER && statChanges[0].stages > 0; + } + + public boolean isGoodDamaging(int perfectAccuracy) { + return (power * hitCount) >= 2 * GlobalConstants.MIN_DAMAGING_MOVE_POWER + || ((power * hitCount) >= GlobalConstants.MIN_DAMAGING_MOVE_POWER && (hitratio >= 90 || hitratio == perfectAccuracy)); + } + public String toString() { return "#" + number + " " + name + " - Power: " + power + ", Base PP: " + pp + ", Type: " + type + ", Hit%: " + (hitratio) + ", Effect: " + effectIndex + ", Priority: " + priority; diff --git a/src/com/sneed/pkrandom/pokemon/MoveSynergy.java b/src/com/sneed/pkrandom/pokemon/MoveSynergy.java new file mode 100644 index 0000000..c612679 --- /dev/null +++ b/src/com/sneed/pkrandom/pokemon/MoveSynergy.java @@ -0,0 +1,1207 @@ +package com.sneed.pkrandom.pokemon; + +/*----------------------------------------------------------------------------*/ +/*-- MoveSynergy.java - synergies between moves, or between --*/ +/*-- abilities/stats and moves --*/ +/*-- --*/ +/*-- Part of "Universal Pokemon Randomizer ZX" by the UPR-ZX team --*/ +/*-- Originally part of "Universal Pokemon Randomizer" by sneed --*/ +/*-- Pokemon and any associated names and the like are --*/ +/*-- trademark and (C) Nintendo 1996-2020. --*/ +/*-- --*/ +/*-- The custom code written here is licensed under the terms of the GPL: --*/ +/*-- --*/ +/*-- This program is free software: you can redistribute it and/or modify --*/ +/*-- it under the terms of the GNU General Public License as published by --*/ +/*-- the Free Software Foundation, either version 3 of the License, or --*/ +/*-- (at your option) any later version. --*/ +/*-- --*/ +/*-- This program is distributed in the hope that it will be useful, --*/ +/*-- but WITHOUT ANY WARRANTY; without even the implied warranty of --*/ +/*-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the --*/ +/*-- GNU General Public License for more details. --*/ +/*-- --*/ +/*-- You should have received a copy of the GNU General Public License --*/ +/*-- along with this program. If not, see <http://www.gnu.org/licenses/>. --*/ +/*----------------------------------------------------------------------------*/ + +import com.sneed.pkrandom.constants.Abilities; +import com.sneed.pkrandom.constants.Moves; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +public class MoveSynergy { + + public static List<Move> getSoftAbilityMoveSynergy(int ability, List<Move> moveList, Type pkType1, Type pkType2) { + List<Integer> synergisticMoves = new ArrayList<>(); + + switch(ability) { + case Abilities.drizzle: + case Abilities.primordialSea: + synergisticMoves.addAll(moveList + .stream() + .filter(mv -> mv.type == Type.WATER && mv.category != MoveCategory.STATUS) + .map(mv -> mv.number) + .collect(Collectors.toList())); + break; + case Abilities.drought: + case Abilities.desolateLand: + synergisticMoves.addAll(moveList + .stream() + .filter(mv -> mv.type == Type.FIRE && mv.category != MoveCategory.STATUS) + .map(mv -> mv.number) + .collect(Collectors.toList())); + break; + case Abilities.refrigerate: + if (pkType1 == Type.ICE || pkType2 == Type.ICE) { + synergisticMoves.addAll(moveList + .stream() + .filter(mv -> mv.type == Type.NORMAL && mv.category != MoveCategory.STATUS) + .map(mv -> mv.number) + .collect(Collectors.toList())); + } + break; + case Abilities.galeWings: + synergisticMoves.addAll(moveList + .stream() + .filter(mv -> mv.type == Type.FLYING) + .map(mv -> mv.number) + .collect(Collectors.toList())); + break; + case Abilities.pixilate: + if (pkType1 == Type.FAIRY || pkType2 == Type.FAIRY) { + synergisticMoves.addAll(moveList + .stream() + .filter(mv -> mv.type == Type.NORMAL && mv.category != MoveCategory.STATUS) + .map(mv -> mv.number) + .collect(Collectors.toList())); + } + break; + case Abilities.aerilate: + if (pkType1 == Type.FLYING || pkType2 == Type.FLYING) { + synergisticMoves.addAll(moveList + .stream() + .filter(mv -> mv.type == Type.NORMAL && mv.category != MoveCategory.STATUS) + .map(mv -> mv.number) + .collect(Collectors.toList())); + } + break; + case Abilities.darkAura: + synergisticMoves.addAll(moveList + .stream() + .filter(mv -> mv.type == Type.DARK && mv.category != MoveCategory.STATUS) + .map(mv -> mv.number) + .collect(Collectors.toList())); + break; + case Abilities.fairyAura: + synergisticMoves.addAll(moveList + .stream() + .filter(mv -> mv.type == Type.FAIRY && mv.category != MoveCategory.STATUS) + .map(mv -> mv.number) + .collect(Collectors.toList())); + break; + case Abilities.steelworker: + case Abilities.steelySpirit: + synergisticMoves.addAll(moveList + .stream() + .filter(mv -> mv.type == Type.STEEL && mv.category != MoveCategory.STATUS) + .map(mv -> mv.number) + .collect(Collectors.toList())); + break; + case Abilities.galvanize: + if (pkType1 == Type.ELECTRIC || pkType2 == Type.ELECTRIC) { + synergisticMoves.addAll(moveList + .stream() + .filter(mv -> mv.type == Type.NORMAL && mv.category != MoveCategory.STATUS) + .map(mv -> mv.number) + .collect(Collectors.toList())); + } + break; + case Abilities.electricSurge: + case Abilities.transistor: + synergisticMoves.addAll(moveList + .stream() + .filter(mv -> mv.type == Type.ELECTRIC && mv.category != MoveCategory.STATUS) + .map(mv -> mv.number) + .collect(Collectors.toList())); + break; + case Abilities.psychicSurge: + synergisticMoves.addAll(moveList + .stream() + .filter(mv -> mv.type == Type.PSYCHIC && mv.category != MoveCategory.STATUS) + .map(mv -> mv.number) + .collect(Collectors.toList())); + break; + case Abilities.grassySurge: + synergisticMoves.addAll(moveList + .stream() + .filter(mv -> mv.type == Type.GRASS && mv.category != MoveCategory.STATUS) + .map(mv -> mv.number) + .collect(Collectors.toList())); + break; + case Abilities.dragonsMaw: + synergisticMoves.addAll(moveList + .stream() + .filter(mv -> mv.type == Type.DRAGON && mv.category != MoveCategory.STATUS) + .map(mv -> mv.number) + .collect(Collectors.toList())); + break; + } + + return moveList + .stream() + .filter(mv -> synergisticMoves.contains(mv.number)) + .distinct() + .collect(Collectors.toList()); + } + + public static List<Move> getSoftAbilityMoveAntiSynergy(int ability, List<Move> moveList) { + List<Integer> antiSynergisticMoves = new ArrayList<>(); + + switch(ability) { + case Abilities.drizzle: + antiSynergisticMoves.addAll(moveList + .stream() + .filter(mv -> mv.type == Type.FIRE && mv.category != MoveCategory.STATUS) + .map(mv -> mv.number) + .collect(Collectors.toList())); + break; + case Abilities.drought: + antiSynergisticMoves.addAll(moveList + .stream() + .filter(mv -> mv.type == Type.WATER && mv.category != MoveCategory.STATUS) + .map(mv -> mv.number) + .collect(Collectors.toList())); + break; + case Abilities.mistySurge: + antiSynergisticMoves.addAll(moveList + .stream() + .filter(mv -> mv.type == Type.DRAGON && mv.category != MoveCategory.STATUS) + .map(mv -> mv.number) + .collect(Collectors.toList())); + break; + } + + return moveList + .stream() + .filter(mv -> antiSynergisticMoves.contains(mv.number)) + .distinct() + .collect(Collectors.toList()); + } + + public static List<Move> getHardAbilityMoveSynergy(int ability, Type pkType1, Type pkType2, List<Move> moveList, + int generation, int perfectAccuracy) { + List<Integer> synergisticMoves = new ArrayList<>(); + + switch(ability) { + case Abilities.drizzle: + case Abilities.primordialSea: + synergisticMoves.add(Moves.thunder); + synergisticMoves.add(Moves.hurricane); + if (pkType1 == Type.WATER || pkType2 == Type.WATER) { + synergisticMoves.add(Moves.weatherBall); + } + break; + case Abilities.speedBoost: + synergisticMoves.add(Moves.batonPass); + synergisticMoves.add(Moves.storedPower); + synergisticMoves.add(Moves.powerTrip); + break; + case Abilities.sturdy: + if (generation >= 5) { + synergisticMoves.add(Moves.endeavor); + synergisticMoves.add(Moves.counter); + synergisticMoves.add(Moves.mirrorCoat); + synergisticMoves.add(Moves.flail); + synergisticMoves.add(Moves.reversal); + } + break; + case Abilities.sandVeil: + case Abilities.sandRush: + synergisticMoves.add(Moves.sandstorm); + break; + case Abilities.staticTheAbilityNotTheKeyword: + synergisticMoves.add(Moves.smellingSalts); + synergisticMoves.add(Moves.hex); + break; + case Abilities.compoundEyes: + synergisticMoves.addAll(moveList + .stream() + .filter(mv -> mv.hitratio > 0 && mv.hitratio <= 80) + .map(mv -> mv.number) + .collect(Collectors.toList())); + break; + case Abilities.ownTempo: + case Abilities.tangledFeet: + synergisticMoves.add(Moves.petalDance); + synergisticMoves.add(Moves.thrash); + synergisticMoves.add(Moves.outrage); + break; + case Abilities.shadowTag: + case Abilities.arenaTrap: + synergisticMoves.add(Moves.perishSong); + break; + case Abilities.poisonPoint: + synergisticMoves.add(Moves.venoshock); + // fallthrough + case Abilities.effectSpore: + case Abilities.flameBody: + synergisticMoves.add(Moves.hex); + break; + case Abilities.sereneGrace: + synergisticMoves.addAll(moveList + .stream() + .filter(mv -> ((mv.statChangeMoveType == StatChangeMoveType.DAMAGE_TARGET || + mv.statChangeMoveType == StatChangeMoveType.DAMAGE_USER) && + mv.statChanges[0].percentChance < 100) || + (mv.statusMoveType == StatusMoveType.DAMAGE && mv.statusPercentChance < 100) || + mv.flinchPercentChance > 0) + .map(mv -> mv.number) + .collect(Collectors.toList())); + break; + case Abilities.swiftSwim: + case Abilities.rainDish: + case Abilities.drySkin: + case Abilities.hydration: + synergisticMoves.add(Moves.rainDance); + break; + case Abilities.chlorophyll: + case Abilities.harvest: + case Abilities.leafGuard: + synergisticMoves.add(Moves.sunnyDay); + break; + case Abilities.soundproof: + synergisticMoves.add(Moves.perishSong); + break; + case Abilities.sandStream: + if (pkType1 == Type.ROCK || pkType2 == Type.ROCK) { + synergisticMoves.add(Moves.weatherBall); + } + break; + case Abilities.earlyBird: + case Abilities.shedSkin: + synergisticMoves.add(Moves.rest); + break; + case Abilities.truant: + synergisticMoves.add(Moves.transform); + break; + case Abilities.hustle: + synergisticMoves.addAll(moveList + .stream() + .filter(mv -> (mv.statChangeMoveType == StatChangeMoveType.DAMAGE_USER || + mv.statChangeMoveType == StatChangeMoveType.NO_DAMAGE_USER) && + mv.hasSpecificStatChange(StatChangeType.ACCURACY, true)) + .map(mv -> mv.number) + .collect(Collectors.toList())); + synergisticMoves.addAll(moveList + .stream() + .filter(mv -> mv.category == MoveCategory.PHYSICAL && mv.hitratio == perfectAccuracy) + .map(mv -> mv.number) + .collect(Collectors.toList())); + break; + case Abilities.guts: + synergisticMoves.add(Moves.facade); + break; + case Abilities.rockHead: + synergisticMoves.addAll(moveList + .stream() + .filter(mv -> mv.recoilPercent > 0) + .map(mv -> mv.number) + .collect(Collectors.toList())); + break; + case Abilities.drought: + case Abilities.desolateLand: + synergisticMoves.add(Moves.solarBeam); + synergisticMoves.add(Moves.solarBlade); + synergisticMoves.add(Moves.morningSun); + synergisticMoves.add(Moves.synthesis); + synergisticMoves.add(Moves.moonlight); + if (generation >= 5) { + synergisticMoves.add(Moves.growth); + } + if (pkType1 == Type.FIRE || pkType2 == Type.FIRE) { + synergisticMoves.add(Moves.weatherBall); + } + break; + case Abilities.ironFist: + synergisticMoves.addAll(moveList + .stream() + .filter(mv -> mv.isPunchMove) + .map(mv -> mv.number) + .collect(Collectors.toList())); + break; + case Abilities.snowCloak: + case Abilities.iceBody: + case Abilities.slushRush: + synergisticMoves.add(Moves.hail); + break; + case Abilities.unburden: + synergisticMoves.add(Moves.fling); + synergisticMoves.add(Moves.acrobatics); + break; + case Abilities.simple: + synergisticMoves.addAll(moveList + .stream() + .filter(mv -> (mv.statChangeMoveType == StatChangeMoveType.DAMAGE_USER || + mv.statChangeMoveType == StatChangeMoveType.NO_DAMAGE_USER) && + mv.statChanges[0].stages > 0) + .map(mv -> mv.number) + .collect(Collectors.toList())); + synergisticMoves.add(Moves.acupressure); + break; + case Abilities.adaptability: + synergisticMoves.addAll(moveList + .stream() + .filter(mv -> mv.category != MoveCategory.STATUS && (mv.type == pkType1 || mv.type == pkType2)) + .map(mv -> mv.number) + .collect(Collectors.toList())); + break; + case Abilities.skillLink: + synergisticMoves.addAll(moveList + .stream() + .filter(mv -> mv.hitCount >= 3) + .map(mv -> mv.number) + .collect(Collectors.toList())); + break; + case Abilities.sniper: + synergisticMoves.addAll(moveList + .stream() + .filter(mv -> mv.criticalChance == CriticalChance.INCREASED || + mv.criticalChance == CriticalChance.GUARANTEED) + .map(mv -> mv.number) + .collect(Collectors.toList())); + break; + case Abilities.magicGuard: + synergisticMoves.addAll(moveList + .stream() + .filter(mv -> mv.recoilPercent > 0) + .map(mv -> mv.number) + .collect(Collectors.toList())); + synergisticMoves.add(Moves.mindBlown); + break; + case Abilities.stall: + synergisticMoves.add(Moves.metalBurst); + synergisticMoves.add(Moves.payback); + break; + case Abilities.superLuck: + synergisticMoves.addAll(moveList + .stream() + .filter(mv -> mv.criticalChance == CriticalChance.INCREASED) + .map(mv -> mv.number) + .collect(Collectors.toList())); + break; + case Abilities.analytic: + synergisticMoves.addAll(moveList + .stream() + .filter(mv -> mv.power > 0 && mv.priority < 0) + .map(mv -> mv.number) + .collect(Collectors.toList())); + break; + case Abilities.noGuard: + synergisticMoves.addAll(moveList + .stream() + .filter(mv -> mv.hitratio > 0 && mv.hitratio <= 70) + .map(mv -> mv.number) + .collect(Collectors.toList())); + break; + case Abilities.technician: + synergisticMoves.addAll(moveList + .stream() + .filter(mv -> (mv.power >= 40 && mv.power <= 60) || mv.hitCount > 1) + .map(mv -> mv.number) + .collect(Collectors.toList())); + break; + case Abilities.slowStart: + synergisticMoves.add(Moves.transform); + synergisticMoves.add(Moves.protect); + synergisticMoves.add(Moves.detect); + synergisticMoves.add(Moves.kingsShield); + synergisticMoves.add(Moves.banefulBunker); + synergisticMoves.add(Moves.fly); + synergisticMoves.add(Moves.dig); + synergisticMoves.add(Moves.bounce); + synergisticMoves.add(Moves.dive); + break; + case Abilities.snowWarning: + synergisticMoves.add(Moves.auroraVeil); + synergisticMoves.add(Moves.blizzard); + if (pkType1 == Type.ICE || pkType2 == Type.ICE) { + synergisticMoves.add(Moves.weatherBall); + } + break; + case Abilities.reckless: + synergisticMoves.addAll(moveList + .stream() + .filter(mv -> mv.recoilPercent > 0) + .map(mv -> mv.number) + .collect(Collectors.toList())); + synergisticMoves.add(Moves.jumpKick); + synergisticMoves.add(Moves.highJumpKick); + break; + case Abilities.badDreams: + synergisticMoves.addAll(moveList + .stream() + .filter(mv -> mv.statusType == StatusType.SLEEP) + .map(mv -> mv.number) + .collect(Collectors.toList())); + break; + case Abilities.sheerForce: + synergisticMoves.addAll(moveList + .stream() + .filter(mv -> mv.statChangeMoveType == StatChangeMoveType.DAMAGE_TARGET || + (mv.statChangeMoveType == StatChangeMoveType.DAMAGE_USER && + mv.statChanges[0].stages > 0) || + mv.statusMoveType == StatusMoveType.DAMAGE || + mv.flinchPercentChance > 0) + .map(mv -> mv.number) + .collect(Collectors.toList())); + break; + case Abilities.contrary: + synergisticMoves.addAll(moveList + .stream() + .filter(mv -> mv.statChangeMoveType == StatChangeMoveType.DAMAGE_USER && + mv.statChanges[0].stages < 0) + .map(mv -> mv.number) + .collect(Collectors.toList())); + break; + case Abilities.heavyMetal: + synergisticMoves.add(Moves.heatCrash); + synergisticMoves.add(Moves.heavySlam); + break; + case Abilities.moody: + synergisticMoves.add(Moves.storedPower); + synergisticMoves.add(Moves.powerTrip); + break; + case Abilities.poisonTouch: + case Abilities.toughClaws: + synergisticMoves.addAll(moveList + .stream() + .filter(mv -> mv.makesContact) + .map(mv -> mv.number) + .collect(Collectors.toList())); + break; + case Abilities.regenerator: + synergisticMoves.add(Moves.uTurn); + synergisticMoves.add(Moves.voltSwitch); + synergisticMoves.add(Moves.partingShot); + break; + case Abilities.prankster: + synergisticMoves.addAll(moveList + .stream() + .filter(mv -> mv.statusMoveType == StatusMoveType.NO_DAMAGE) + .map(mv -> mv.number) + .collect(Collectors.toList())); + synergisticMoves.add(Moves.destinyBond); + synergisticMoves.add(Moves.encore); + synergisticMoves.add(Moves.reflect); + synergisticMoves.add(Moves.lightScreen); + synergisticMoves.add(Moves.grudge); + synergisticMoves.add(Moves.painSplit); + synergisticMoves.add(Moves.substitute); + break; + case Abilities.strongJaw: + synergisticMoves.add(Moves.bite); + synergisticMoves.add(Moves.crunch); + synergisticMoves.add(Moves.fireFang); + synergisticMoves.add(Moves.fishiousRend); + synergisticMoves.add(Moves.hyperFang); + synergisticMoves.add(Moves.iceFang); + synergisticMoves.add(Moves.jawLock); + synergisticMoves.add(Moves.poisonFang); + synergisticMoves.add(Moves.psychicFangs); + synergisticMoves.add(Moves.thunderFang); + break; + case Abilities.megaLauncher: + synergisticMoves.add(Moves.auraSphere); + synergisticMoves.add(Moves.darkPulse); + synergisticMoves.add(Moves.dragonPulse); + synergisticMoves.add(Moves.originPulse); + synergisticMoves.add(Moves.terrainPulse); + synergisticMoves.add(Moves.waterPulse); + break; + case Abilities.wimpOut: + case Abilities.emergencyExit: + synergisticMoves.add(Moves.fakeOut); + synergisticMoves.add(Moves.firstImpression); + break; + case Abilities.merciless: + synergisticMoves.addAll(moveList + .stream() + .filter(mv -> mv.statusType == StatusType.POISON || mv.statusType == StatusType.TOXIC_POISON) + .map(mv -> mv.number) + .collect(Collectors.toList())); + synergisticMoves.add(Moves.banefulBunker); + break; + case Abilities.liquidVoice: + if (pkType1 == Type.WATER || pkType2 == Type.WATER) { + synergisticMoves.addAll(moveList + .stream() + .filter(mv -> mv.isSoundMove && mv.power > 0) + .map(mv -> mv.number) + .collect(Collectors.toList())); + } + break; + case Abilities.triage: + synergisticMoves.addAll(moveList + .stream() + .filter(mv -> mv.absorbPercent > 0) + .map(mv -> mv.number) + .collect(Collectors.toList())); + break; + case Abilities.surgeSurfer: + synergisticMoves.add(Moves.electricTerrain); + break; + case Abilities.corrosion: + synergisticMoves.addAll(moveList + .stream() + .filter(mv -> mv.category == MoveCategory.STATUS && + (mv.statusType == StatusType.POISON || mv.statusType == StatusType.TOXIC_POISON)) + .map(mv -> mv.number) + .collect(Collectors.toList())); + break; + } + + return moveList + .stream() + .filter(mv -> synergisticMoves.contains(mv.number)) + .distinct() + .collect(Collectors.toList()); + } + + public static List<Move> getHardAbilityMoveAntiSynergy(int ability, List<Move> moveList) { + List<Integer> antiSynergisticMoves = new ArrayList<>(); + + switch(ability) { + case Abilities.primordialSea: + antiSynergisticMoves.addAll(moveList + .stream() + .filter(mv -> mv.type == Type.FIRE && + mv.category != MoveCategory.STATUS) + .map(mv -> mv.number) + .collect(Collectors.toList())); + // fallthrough + case Abilities.drizzle: + case Abilities.sandStream: + case Abilities.snowWarning: + antiSynergisticMoves.add(Moves.solarBeam); + antiSynergisticMoves.add(Moves.solarBlade); + antiSynergisticMoves.add(Moves.morningSun); + antiSynergisticMoves.add(Moves.synthesis); + antiSynergisticMoves.add(Moves.moonlight); + antiSynergisticMoves.add(Moves.rainDance); + antiSynergisticMoves.add(Moves.sunnyDay); + antiSynergisticMoves.add(Moves.hail); + antiSynergisticMoves.add(Moves.sandstorm); + break; + case Abilities.speedBoost: + antiSynergisticMoves.addAll(moveList + .stream() + .filter(mv -> (mv.statChangeMoveType == StatChangeMoveType.NO_DAMAGE_USER) && + mv.statChanges[0].type == StatChangeType.SPEED && + mv.statChanges[0].stages > 0) + .map(mv -> mv.number) + .collect(Collectors.toList())); + antiSynergisticMoves.add(Moves.psychUp); + antiSynergisticMoves.add(Moves.haze); + break; + case Abilities.desolateLand: + antiSynergisticMoves.addAll(moveList + .stream() + .filter(mv -> mv.type == Type.WATER && + mv.category != MoveCategory.STATUS) + .map(mv -> mv.number) + .collect(Collectors.toList())); + // fallthrough + case Abilities.drought: + antiSynergisticMoves.add(Moves.thunder); + antiSynergisticMoves.add(Moves.hurricane); + antiSynergisticMoves.add(Moves.rainDance); + antiSynergisticMoves.add(Moves.sunnyDay); + antiSynergisticMoves.add(Moves.hail); + antiSynergisticMoves.add(Moves.sandstorm); + break; + case Abilities.noGuard: + antiSynergisticMoves.add(Moves.lockOn); + antiSynergisticMoves.add(Moves.mindReader); + antiSynergisticMoves.addAll(moveList + .stream() + .filter(mv -> mv.hasSpecificStatChange(StatChangeType.ACCURACY, true) || + mv.hasSpecificStatChange(StatChangeType.EVASION, true) || + mv.hasSpecificStatChange(StatChangeType.EVASION, false)) + .map(mv -> mv.number) + .collect(Collectors.toList())); + break; + case Abilities.damp: + antiSynergisticMoves.add(Moves.selfDestruct); + antiSynergisticMoves.add(Moves.explosion); + antiSynergisticMoves.add(Moves.mindBlown); + antiSynergisticMoves.add(Moves.mistyExplosion); + break; + case Abilities.insomnia: + case Abilities.vitalSpirit: + case Abilities.comatose: + case Abilities.sweetVeil: + antiSynergisticMoves.add(Moves.rest); + break; + case Abilities.airLock: + case Abilities.cloudNine: + case Abilities.deltaStream: + antiSynergisticMoves.add(Moves.rainDance); + antiSynergisticMoves.add(Moves.sunnyDay); + antiSynergisticMoves.add(Moves.sandstorm); + antiSynergisticMoves.add(Moves.hail); + break; + case Abilities.simple: + antiSynergisticMoves.addAll(moveList + .stream() + .filter(mv -> (mv.statChangeMoveType == StatChangeMoveType.DAMAGE_USER || + mv.statChangeMoveType == StatChangeMoveType.NO_DAMAGE_USER) && + mv.statChanges[0].stages < 0) + .map(mv -> mv.number) + .collect(Collectors.toList())); + break; + case Abilities.contrary: + antiSynergisticMoves.addAll(moveList + .stream() + .filter(mv -> (mv.statChangeMoveType == StatChangeMoveType.DAMAGE_USER || + mv.statChangeMoveType == StatChangeMoveType.NO_DAMAGE_USER) && + mv.statChanges[0].stages > 0) + .map(mv -> mv.number) + .collect(Collectors.toList())); + antiSynergisticMoves.add(Moves.shellSmash); + break; + case Abilities.lightMetal: + antiSynergisticMoves.add(Moves.heatCrash); + antiSynergisticMoves.add(Moves.heavySlam); + break; + case Abilities.electricSurge: + antiSynergisticMoves.addAll(moveList + .stream() + .filter(mv -> (mv.category == MoveCategory.STATUS && mv.statusType == StatusType.SLEEP)) + .map(mv -> mv.number) + .collect(Collectors.toList())); + antiSynergisticMoves.add(Moves.rest); + break; + case Abilities.psychicSurge: + antiSynergisticMoves.addAll(moveList + .stream() + .filter(mv -> (mv.priority > 0)) + .map(mv -> mv.number) + .collect(Collectors.toList())); + break; + case Abilities.mistySurge: + antiSynergisticMoves.addAll(moveList + .stream() + .filter(mv -> (mv.category == MoveCategory.STATUS && + (mv.statusType == StatusType.BURN || + mv.statusType == StatusType.FREEZE || + mv.statusType == StatusType.PARALYZE || + mv.statusType == StatusType.SLEEP || + mv.statusType == StatusType.POISON || + mv.statusType == StatusType.TOXIC_POISON))) + .map(mv -> mv.number) + .collect(Collectors.toList())); + antiSynergisticMoves.add(Moves.rest); + break; + case Abilities.grassySurge: + antiSynergisticMoves.add(Moves.earthquake); + antiSynergisticMoves.add(Moves.magnitude); + antiSynergisticMoves.add(Moves.bulldoze); + break; + + + } + + return moveList + .stream() + .filter(mv -> antiSynergisticMoves.contains(mv.number)) + .distinct() + .collect(Collectors.toList()); + } + + public static List<Move> getStatMoveSynergy(Pokemon pk, List<Move> moveList) { + List<Integer> synergisticMoves = new ArrayList<>(); + + if ((double)pk.hp / (double)pk.bst() < 1.0/8) { + synergisticMoves.add(Moves.painSplit); + synergisticMoves.add(Moves.endeavor); + } + + if ((double)pk.hp / (double)pk.bst() >= 1.0/4) { + synergisticMoves.add(Moves.waterSpout); + synergisticMoves.add(Moves.eruption); + synergisticMoves.add(Moves.counter); + synergisticMoves.add(Moves.mirrorCoat); + } + + if (pk.attack * 2 < pk.defense) { + synergisticMoves.add(Moves.powerTrick); + } + + if ((double)(pk.attack + pk.spatk) / (double)pk.bst() < 1.0/4) { + synergisticMoves.add(Moves.powerSplit); + } + + if ((double)(pk.defense + pk.spdef) / (double)pk.bst() < 1.0/4) { + synergisticMoves.add(Moves.guardSplit); + } + + if ((double)pk.speed / (double)pk.bst() < 1.0/8) { + synergisticMoves.add(Moves.gyroBall); + } + + if ((double)pk.speed / (double)pk.bst() >= 1.0/4) { + synergisticMoves.add(Moves.electroBall); + } + + return moveList + .stream() + .filter(mv -> synergisticMoves.contains(mv.number)) + .distinct() + .collect(Collectors.toList()); + } + + public static List<Move> getStatMoveAntiSynergy(Pokemon pk, List<Move> moveList) { + List<Integer> antiSynergisticMoves = new ArrayList<>(); + + if ((double)pk.hp / (double)pk.bst() >= 1.0/4) { + antiSynergisticMoves.add(Moves.painSplit); + antiSynergisticMoves.add(Moves.endeavor); + } + + if (pk.defense * 2 < pk.attack) { + antiSynergisticMoves.add(Moves.powerTrick); + } + + if ((double)(pk.attack + pk.spatk) / (double)pk.bst() >= 1.0/3) { + antiSynergisticMoves.add(Moves.powerSplit); + } + + if ((double)(pk.defense + pk.spdef) / (double)pk.bst() >= 1.0/3) { + antiSynergisticMoves.add(Moves.guardSplit); + } + + if ((double)pk.speed / (double)pk.bst() >= 1.0/4) { + antiSynergisticMoves.add(Moves.gyroBall); + } + + if ((double)pk.speed / (double)pk.bst() < 1.0/8) { + antiSynergisticMoves.add(Moves.electroBall); + } + + return moveList + .stream() + .filter(mv -> antiSynergisticMoves.contains(mv.number)) + .distinct() + .collect(Collectors.toList()); + } + + public static List<Move> getMoveSynergy(Move mv1, List<Move> moveList, int generation) { + List<Integer> synergisticMoves = new ArrayList<>(); + + if ((mv1.statChangeMoveType == StatChangeMoveType.DAMAGE_TARGET && + mv1.hasSpecificStatChange(StatChangeType.SPEED, false)) || + ((mv1.statChangeMoveType == StatChangeMoveType.DAMAGE_USER || + mv1.statChangeMoveType == StatChangeMoveType.NO_DAMAGE_USER) && + mv1.hasSpecificStatChange(StatChangeType.SPEED, true))) { + synergisticMoves.addAll(moveList + .stream() + .filter(mv -> mv.flinchPercentChance > 0 && mv.priority == 0) + .map(mv -> mv.number) + .collect(Collectors.toList())); + } + + if (mv1.flinchPercentChance > 0 && mv1.priority == 0) { + synergisticMoves.addAll(moveList + .stream() + .filter(mv -> (mv.statChangeMoveType == StatChangeMoveType.DAMAGE_TARGET && + mv.hasSpecificStatChange(StatChangeType.SPEED, false)) || + ((mv.statChangeMoveType == StatChangeMoveType.DAMAGE_USER || + mv.statChangeMoveType == StatChangeMoveType.NO_DAMAGE_USER) && + mv.hasSpecificStatChange(StatChangeType.SPEED, true))) + .map(mv -> mv.number) + .collect(Collectors.toList())); + } + + if (mv1.statChanges[0].stages >= 2 || mv1.statChanges[1].type != StatChangeType.NONE) { + synergisticMoves.add(Moves.batonPass); + synergisticMoves.add(Moves.storedPower); + synergisticMoves.add(Moves.powerTrip); + } + + if (mv1.statusType == StatusType.SLEEP) { + synergisticMoves.add(Moves.dreamEater); + synergisticMoves.add(Moves.nightmare); + synergisticMoves.add(Moves.hex); + } + + switch(mv1.number) { + case Moves.toxic: + synergisticMoves.add(Moves.protect); + synergisticMoves.add(Moves.detect); + synergisticMoves.add(Moves.kingsShield); + synergisticMoves.add(Moves.dig); + synergisticMoves.add(Moves.fly); + synergisticMoves.add(Moves.bounce); + synergisticMoves.add(Moves.dive); + synergisticMoves.addAll(moveList + .stream() + .filter(mv -> (mv.isTrapMove)) + .map(mv -> mv.number) + .collect(Collectors.toList())); + // fallthrough + case Moves.poisonPowder: + case Moves.poisonGas: + case Moves.banefulBunker: + case Moves.toxicThread: + synergisticMoves.add(Moves.venoshock); + synergisticMoves.add(Moves.hex); + break; + case Moves.venoshock: + synergisticMoves.addAll(moveList + .stream() + .filter(mv -> mv.category == MoveCategory.STATUS && + (mv.statusType == StatusType.POISON || mv.statusType == StatusType.TOXIC_POISON)) + .map(mv -> mv.number) + .collect(Collectors.toList())); + break; + case Moves.protect: + case Moves.detect: + case Moves.kingsShield: + synergisticMoves.add(Moves.toxic); + synergisticMoves.add(Moves.leechSeed); + synergisticMoves.add(Moves.willOWisp); + break; + case Moves.batonPass: + synergisticMoves.addAll(moveList + .stream() + .filter(mv -> mv.statChanges[0].stages >= 2 || mv.statChanges[1].type != StatChangeType.NONE) + .map(mv -> mv.number) + .collect(Collectors.toList())); + synergisticMoves.add(Moves.shellSmash); + break; + case Moves.willOWisp: + synergisticMoves.add(Moves.hex); + break; + case Moves.lockOn: + case Moves.mindReader: + synergisticMoves.addAll(moveList + .stream() + .filter(mv -> (mv.hitratio <= 50)) + .map(mv -> mv.number) + .collect(Collectors.toList())); + break; + case Moves.sunnyDay: + synergisticMoves.add(Moves.solarBlade); + synergisticMoves.add(Moves.solarBeam); + break; + case Moves.rainDance: + synergisticMoves.add(Moves.thunder); + synergisticMoves.add(Moves.hurricane); + break; + case Moves.powerSwap: + synergisticMoves.addAll(moveList + .stream() + .filter(mv -> mv.statChangeMoveType == StatChangeMoveType.DAMAGE_USER && + (mv.hasSpecificStatChange(StatChangeType.ATTACK, false) || + mv.hasSpecificStatChange(StatChangeType.SPECIAL_ATTACK, false))) + .map(mv -> mv.number) + .collect(Collectors.toList())); + break; + case Moves.endure: + synergisticMoves.add(Moves.reversal); + synergisticMoves.add(Moves.flail); + synergisticMoves.add(Moves.endeavor); + break; + case Moves.endeavor: + synergisticMoves.addAll(moveList + .stream() + .filter(mv -> mv.category != MoveCategory.STATUS && mv.priority > 0) + .map(mv -> mv.number) + .collect(Collectors.toList())); + break; + case Moves.thunderWave: + case Moves.glare: + case Moves.stunSpore: + synergisticMoves.addAll(moveList + .stream() + .filter(mv -> mv.flinchPercentChance > 0) + .map(mv -> mv.number) + .collect(Collectors.toList())); + synergisticMoves.addAll(moveList + .stream() + .filter(mv -> mv.category == MoveCategory.STATUS && mv.statusType == StatusType.CONFUSION) + .map(mv -> mv.number) + .collect(Collectors.toList())); + synergisticMoves.add(Moves.hex); + break; + case Moves.hail: + synergisticMoves.add(Moves.blizzard); + synergisticMoves.add(Moves.auroraVeil); + break; + case Moves.stockpile: + synergisticMoves.add(Moves.spitUp); + synergisticMoves.add(Moves.swallow); + break; + case Moves.spitUp: + synergisticMoves.add(Moves.stockpile); + break; + case Moves.swallow: + synergisticMoves.add(Moves.stockpile); + break; + case Moves.leechSeed: + case Moves.perishSong: + synergisticMoves.addAll(moveList + .stream() + .filter(mv -> (mv.isTrapMove)) + .map(mv -> mv.number) + .collect(Collectors.toList())); + break; + case Moves.spikes: + case Moves.stealthRock: + case Moves.toxicSpikes: + synergisticMoves.add(Moves.roar); + synergisticMoves.add(Moves.whirlwind); + synergisticMoves.add(Moves.dragonTail); + synergisticMoves.add(Moves.circleThrow); + break; + case Moves.rest: + synergisticMoves.add(Moves.sleepTalk); + break; + case Moves.focusEnergy: + synergisticMoves.addAll(moveList + .stream() + .filter(mv -> mv.criticalChance == CriticalChance.INCREASED) + .map(mv -> mv.number) + .collect(Collectors.toList())); + break; + case Moves.focusPunch: + synergisticMoves.addAll(moveList + .stream() + .filter(mv -> mv.statusMoveType == StatusMoveType.NO_DAMAGE && + mv.statusType == StatusType.SLEEP) + .map(mv -> mv.number) + .collect(Collectors.toList())); + break; + case Moves.torment: + synergisticMoves.add(Moves.encore); + break; + case Moves.encore: + synergisticMoves.add(Moves.torment); + break; + case Moves.hex: + synergisticMoves.addAll(moveList + .stream() + .filter(mv -> mv.statusMoveType == StatusMoveType.NO_DAMAGE && + mv.statusType != StatusType.CONFUSION) + .map(mv -> mv.number) + .collect(Collectors.toList())); + synergisticMoves.add(Moves.banefulBunker); + break; + case Moves.dreamEater: + case Moves.nightmare: + synergisticMoves.addAll(moveList + .stream() + .filter(mv -> mv.statusMoveType == StatusMoveType.NO_DAMAGE && + mv.statusType == StatusType.SLEEP) + .map(mv -> mv.number) + .collect(Collectors.toList())); + break; + case Moves.storedPower: + synergisticMoves.addAll(moveList + .stream() + .filter(mv -> mv.statChanges[0].stages > 1 || mv.statChanges[1].type != StatChangeType.NONE) + .map(mv -> mv.number) + .collect(Collectors.toList())); + synergisticMoves.add(Moves.acupressure); + synergisticMoves.add(Moves.shellSmash); + break; + case Moves.swagger: + synergisticMoves.add(Moves.punishment); + break; + case Moves.punishment: + synergisticMoves.add(Moves.swagger); + break; + case Moves.shellSmash: + synergisticMoves.add(Moves.storedPower); + break; + } + + return moveList + .stream() + .filter(mv -> synergisticMoves.contains(mv.number)) + .distinct() + .collect(Collectors.toList()); + } + + public static List<Move> getSoftMoveSynergy(Move mv1, List<Move> moveList, int generation, + boolean effectivenessUpdated) { + List<Integer> synergisticMoves = new ArrayList<>(); + + if (mv1.category != MoveCategory.STATUS) { + List<Type> notVeryEffective = Effectiveness.notVeryEffective(mv1.type, generation, effectivenessUpdated); + for (Type nveType: notVeryEffective) { + List<Type> superEffectiveAgainstNVE = + Effectiveness.against(nveType, null, generation, effectivenessUpdated) + .entrySet() + .stream() + .filter(entry -> entry.getValue() == Effectiveness.DOUBLE) + .map(Map.Entry::getKey) + .collect(Collectors.toList()); + synergisticMoves.addAll(moveList + .stream() + .filter(mv -> mv.category != MoveCategory.STATUS && + superEffectiveAgainstNVE.contains(mv.type)) + .map(mv -> mv.number) + .collect(Collectors.toList())); + } + } + + switch(mv1.number) { + case Moves.swordsDance: + synergisticMoves.addAll(moveList + .stream() + .filter(mv -> mv.category == MoveCategory.PHYSICAL) + .map(mv -> mv.number) + .collect(Collectors.toList())); + break; + case Moves.nastyPlot: + case Moves.tailGlow: + synergisticMoves.addAll(moveList + .stream() + .filter(mv -> mv.category == MoveCategory.SPECIAL) + .map(mv -> mv.number) + .collect(Collectors.toList())); + break; + } + + return moveList + .stream() + .filter(mv -> synergisticMoves.contains(mv.number)) + .distinct() + .collect(Collectors.toList()); + } + + public static List<Move> getHardMoveAntiSynergy(Move mv1, List<Move> moveList) { + List<Integer> antiSynergisticMoves = new ArrayList<>(); + + + if (mv1.category == MoveCategory.STATUS && mv1.statusType != StatusType.NONE) { + antiSynergisticMoves.addAll(moveList + .stream() + .filter(mv -> (mv.category == MoveCategory.STATUS && mv.statusType != StatusType.NONE && + (mv.statusType == mv1.statusType || + (mv1.statusType != StatusType.CONFUSION && mv.statusType != StatusType.CONFUSION)))) + .map(mv -> mv.number) + .collect(Collectors.toList())); + } + + switch(mv1.number) { + case Moves.protect: + antiSynergisticMoves.add(Moves.detect); + antiSynergisticMoves.add(Moves.banefulBunker); + antiSynergisticMoves.add(Moves.kingsShield); + break; + case Moves.detect: + antiSynergisticMoves.add(Moves.protect); + antiSynergisticMoves.add(Moves.banefulBunker); + antiSynergisticMoves.add(Moves.kingsShield); + break; + case Moves.kingsShield: + antiSynergisticMoves.add(Moves.protect); + antiSynergisticMoves.add(Moves.detect); + antiSynergisticMoves.add(Moves.banefulBunker); + break; + case Moves.banefulBunker: + antiSynergisticMoves.add(Moves.protect); + antiSynergisticMoves.add(Moves.detect); + antiSynergisticMoves.add(Moves.kingsShield); + break; + case Moves.returnTheMoveNotTheKeyword: + antiSynergisticMoves.add(Moves.frustration); + break; + case Moves.frustration: + antiSynergisticMoves.add(Moves.returnTheMoveNotTheKeyword); + break; + } + + if (mv1.type != null) { + switch (mv1.type) { + case FIRE: + if (mv1.category != MoveCategory.STATUS) { + antiSynergisticMoves.add(Moves.waterSport); + } + break; + case ELECTRIC: + if (mv1.category != MoveCategory.STATUS) { + antiSynergisticMoves.add(Moves.mudSport); + } + break; + } + } + + return moveList + .stream() + .filter(mv -> antiSynergisticMoves.contains(mv.number)) + .distinct() + .collect(Collectors.toList()); + } + + public static List<Move> getSoftMoveAntiSynergy(Move mv1, List<Move> moveList) { + List<Integer> antiSynergisticMoves = new ArrayList<>(); + + + if (mv1.category != MoveCategory.STATUS) { + antiSynergisticMoves.addAll(moveList + .stream() + .filter(mv -> (mv.category != MoveCategory.STATUS && mv.type == mv1.type)) + .map(mv -> mv.number) + .collect(Collectors.toList())); + } + + switch (mv1.number) { + case Moves.waterSport: + antiSynergisticMoves.addAll(moveList + .stream() + .filter(mv -> (mv.category != MoveCategory.STATUS && mv.type == Type.FIRE)) + .map(mv -> mv.number) + .collect(Collectors.toList())); + break; + case Moves.mudSport: + antiSynergisticMoves.addAll(moveList + .stream() + .filter(mv -> (mv.category != MoveCategory.STATUS && mv.type == Type.ELECTRIC)) + .map(mv -> mv.number) + .collect(Collectors.toList())); + break; + } + + return moveList + .stream() + .filter(mv -> antiSynergisticMoves.contains(mv.number)) + .distinct() + .collect(Collectors.toList()); + } + + public static List<Move> requiresOtherMove(Move mv1, List<Move> moveList) { + List<Integer> requiresMove = new ArrayList<>(); + switch(mv1.number) { + case Moves.spitUp: + case Moves.swallow: + requiresMove.add(Moves.stockpile); + break; + case Moves.dreamEater: + case Moves.nightmare: + requiresMove.addAll(moveList + .stream() + .filter(mv -> (mv.category == MoveCategory.STATUS && mv.statusType == StatusType.SLEEP)) + .map(mv -> mv.number) + .collect(Collectors.toList())); + break; + } + return moveList.stream().filter(mv -> requiresMove.contains(mv.number)).distinct().collect(Collectors.toList()); + } +} diff --git a/src/com/sneed/pkrandom/pokemon/Trainer.java b/src/com/sneed/pkrandom/pokemon/Trainer.java index 8e8a76e..7509628 100755 --- a/src/com/sneed/pkrandom/pokemon/Trainer.java +++ b/src/com/sneed/pkrandom/pokemon/Trainer.java @@ -124,6 +124,14 @@ public class Trainer implements Comparable<Trainer> { return (this.poketype & 2) == 2; } + public void setPokemonHaveCustomMoves(boolean haveCustomMoves) { + if (haveCustomMoves) { + this.poketype |= 1; + } else { + this.poketype = poketype & ~1; + } + } + public boolean pokemonHaveCustomMoves() { // This flag seems consistent for all gens return (this.poketype & 1) == 1; diff --git a/src/com/sneed/pkrandom/pokemon/TrainerPokemon.java b/src/com/sneed/pkrandom/pokemon/TrainerPokemon.java index f483621..9188c20 100755 --- a/src/com/sneed/pkrandom/pokemon/TrainerPokemon.java +++ b/src/com/sneed/pkrandom/pokemon/TrainerPokemon.java @@ -37,7 +37,6 @@ public class TrainerPokemon { public int abilitySlot; public int forme; public String formeSuffix = ""; - public int absolutePokeNumber = 0; public int forcedGenderFlag; public byte nature; @@ -94,7 +93,6 @@ public class TrainerPokemon { tpk.abilitySlot = abilitySlot; tpk.forme = forme; tpk.formeSuffix = formeSuffix; - tpk.absolutePokeNumber = absolutePokeNumber; tpk.resetMoves = resetMoves; diff --git a/src/com/sneed/pkrandom/pokemon/Type.java b/src/com/sneed/pkrandom/pokemon/Type.java index 0836e81..d919047 100755 --- a/src/com/sneed/pkrandom/pokemon/Type.java +++ b/src/com/sneed/pkrandom/pokemon/Type.java @@ -49,9 +49,24 @@ public enum Type { private static final List<Type> VALUES = Collections.unmodifiableList(Arrays.asList(values())); private static final int SIZE = VALUES.size(); + public static final List<Type> GEN1 = Collections.unmodifiableList(Arrays.asList(values()).subList(0, ICE.ordinal()+1)); public static final List<Type> GEN2THROUGH5 = Collections.unmodifiableList(Arrays.asList(values()).subList(0, DARK.ordinal()+1)); public static final List<Type> GEN6PLUS = Collections.unmodifiableList(Arrays.asList(values()).subList(0, FAIRY.ordinal()+1)); + public static List<Type> getAllTypes(int generation) { + switch (generation) { + case 1: + return GEN1; + case 2: + case 3: + case 4: + case 5: + return GEN2THROUGH5; + default: + return GEN6PLUS; + } + } + public static Type randomType(Random random) { return VALUES.get(random.nextInt(SIZE)); } |