summaryrefslogtreecommitdiff
path: root/src/com/sneed/pkrandom/pokemon
diff options
context:
space:
mode:
authorAjarmar <axel.jarmar@gmail.com>2022-05-08 23:52:01 +0200
committerrafa_99 <raroma09@gmail.com>2022-06-12 19:28:15 +0100
commit363b24f9153f32627802089eee7900d5749e410e (patch)
treebf170e51c43828f8030e0c15e56c30de496e3495 /src/com/sneed/pkrandom/pokemon
parent76431f3f79463ecdf3e46031d596e12996d6e471 (diff)
add "better trainer movesets" setting
Diffstat (limited to 'src/com/sneed/pkrandom/pokemon')
-rw-r--r--src/com/sneed/pkrandom/pokemon/Effectiveness.java56
-rwxr-xr-xsrc/com/sneed/pkrandom/pokemon/Move.java28
-rw-r--r--src/com/sneed/pkrandom/pokemon/MoveSynergy.java1207
-rwxr-xr-xsrc/com/sneed/pkrandom/pokemon/Trainer.java8
-rwxr-xr-xsrc/com/sneed/pkrandom/pokemon/TrainerPokemon.java2
-rwxr-xr-xsrc/com/sneed/pkrandom/pokemon/Type.java15
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));
}