package com.pkrandom.pokemon;
/*----------------------------------------------------------------------------*/
/*-- MoveSynergy.java - synergies between moves, or between --*/
/*-- abilities/stats and moves --*/
/*-- --*/
/*-- Part of "Universal Pokemon Randomizer ZX" by the UPR-ZX team --*/
/*-- 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 . --*/
/*----------------------------------------------------------------------------*/
import com.pkrandom.constants.Abilities;
import com.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 getSoftAbilityMoveSynergy(int ability, List moveList, Type pkType1, Type pkType2) {
List 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 getSoftAbilityMoveAntiSynergy(int ability, List moveList) {
List 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 getHardAbilityMoveSynergy(int ability, Type pkType1, Type pkType2, List moveList,
int generation, int perfectAccuracy) {
List 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 getHardAbilityMoveAntiSynergy(int ability, List moveList) {
List 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 getStatMoveSynergy(Pokemon pk, List moveList) {
List 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 getStatMoveAntiSynergy(Pokemon pk, List moveList) {
List 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 getMoveSynergy(Move mv1, List moveList, int generation) {
List 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:
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:
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.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.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 getSoftMoveSynergy(Move mv1, List moveList, int generation,
boolean effectivenessUpdated) {
List synergisticMoves = new ArrayList<>();
if (mv1.category != MoveCategory.STATUS) {
List notVeryEffective = Effectiveness.notVeryEffective(mv1.type, generation, effectivenessUpdated);
for (Type nveType: notVeryEffective) {
List 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 getHardMoveAntiSynergy(Move mv1, List moveList) {
List 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;
case Moves.leechSeed:
case Moves.perishSong:
antiSynergisticMoves.add(Moves.whirlwind);
antiSynergisticMoves.add(Moves.roar);
antiSynergisticMoves.add(Moves.circleThrow);
antiSynergisticMoves.add(Moves.dragonTail);
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 getSoftMoveAntiSynergy(Move mv1, List moveList) {
List 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 requiresOtherMove(Move mv1, List moveList) {
List 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());
}
}