578 lines
26 KiB
JavaScript
578 lines
26 KiB
JavaScript
"use strict";
|
|
var __create = Object.create;
|
|
var __defProp = Object.defineProperty;
|
|
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
var __getProtoOf = Object.getPrototypeOf;
|
|
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
var __export = (target, all) => {
|
|
for (var name in all)
|
|
__defProp(target, name, { get: all[name], enumerable: true });
|
|
};
|
|
var __copyProps = (to, from, except, desc) => {
|
|
if (from && typeof from === "object" || typeof from === "function") {
|
|
for (let key of __getOwnPropNames(from))
|
|
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
}
|
|
return to;
|
|
};
|
|
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
// If the importer is in node compatibility mode or this is not an ESM
|
|
// file that has been converted to a CommonJS file using a Babel-
|
|
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
mod
|
|
));
|
|
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
var random_teams_exports = {};
|
|
__export(random_teams_exports, {
|
|
RandomGen3Teams: () => RandomGen3Teams,
|
|
default: () => random_teams_default
|
|
});
|
|
module.exports = __toCommonJS(random_teams_exports);
|
|
var import_random_teams = __toESM(require("../gen4/random-teams"));
|
|
var import_lib = require("../../../lib");
|
|
class RandomGen3Teams extends import_random_teams.default {
|
|
constructor(format, prng) {
|
|
super(format, prng);
|
|
this.randomData = require("./random-data.json");
|
|
this.battleHasDitto = false;
|
|
this.battleHasWobbuffet = false;
|
|
this.moveEnforcementCheckers = {
|
|
Bug: (movePool, moves, abilities, types, counter, species) => movePool.includes("megahorn") || !species.types[1] && movePool.includes("hiddenpowerbug"),
|
|
Electric: (movePool, moves, abilities, types, counter) => !counter.get("Electric"),
|
|
Fighting: (movePool, moves, abilities, types, counter) => !counter.get("Fighting"),
|
|
Fire: (movePool, moves, abilities, types, counter) => !counter.get("Fire"),
|
|
Ground: (movePool, moves, abilities, types, counter) => !counter.get("Ground"),
|
|
Normal: (movePool, moves, abilities, types, counter, species) => {
|
|
if (species.id === "blissey" && movePool.includes("softboiled"))
|
|
return true;
|
|
return !counter.get("Normal") && counter.setupType === "Physical";
|
|
},
|
|
Psychic: (movePool, moves, abilities, types, counter, species) => types.has("Psychic") && (movePool.includes("psychic") || movePool.includes("psychoboost")) && species.baseStats.spa >= 100,
|
|
Rock: (movePool, moves, abilities, types, counter, species) => !counter.get("Rock") && species.baseStats.atk >= 100,
|
|
Water: (movePool, moves, abilities, types, counter, species) => !counter.get("Water") && counter.setupType !== "Physical" && species.baseStats.spa >= 60,
|
|
// If the Pokémon has this move, the other move will be forced
|
|
protect: (movePool) => movePool.includes("wish"),
|
|
sunnyday: (movePool) => movePool.includes("solarbeam"),
|
|
sleeptalk: (movePool) => movePool.includes("rest")
|
|
};
|
|
}
|
|
shouldCullMove(move, types, moves, abilities, counter, movePool, teamDetails, species) {
|
|
const restTalk = moves.has("rest") && moves.has("sleeptalk");
|
|
switch (move.id) {
|
|
case "bulkup":
|
|
case "curse":
|
|
case "dragondance":
|
|
case "swordsdance":
|
|
return {
|
|
cull: counter.setupType !== "Physical" || counter.get("physicalsetup") > 1 || counter.get("Physical") + counter.get("physicalpool") < 2 && !moves.has("batonpass") && !restTalk,
|
|
isSetup: true
|
|
};
|
|
case "calmmind":
|
|
return {
|
|
cull: counter.setupType !== "Special" || counter.get("Special") + counter.get("specialpool") < 2 && !moves.has("batonpass") && !moves.has("refresh") && !restTalk,
|
|
isSetup: true
|
|
};
|
|
case "agility":
|
|
return {
|
|
cull: counter.damagingMoves.size < 2 && !moves.has("batonpass") || moves.has("substitute") || restTalk,
|
|
isSetup: !counter.setupType
|
|
};
|
|
case "amnesia":
|
|
case "sleeptalk":
|
|
if (moves.has("roar") || moves.has("whirlwind"))
|
|
return { cull: true };
|
|
if (!moves.has("rest"))
|
|
return { cull: true };
|
|
if (movePool.length > 1) {
|
|
const rest = movePool.indexOf("rest");
|
|
if (rest >= 0)
|
|
this.fastPop(movePool, rest);
|
|
}
|
|
break;
|
|
case "barrier":
|
|
return { cull: !moves.has("calmmind") && !moves.has("batonpass") && !moves.has("mirrorcoat") };
|
|
case "batonpass":
|
|
return { cull: !counter.setupType && !counter.get("speedsetup") && ["meanlook", "spiderweb", "substitute", "wish"].every((m) => !moves.has(m)) };
|
|
case "endeavor":
|
|
case "flail":
|
|
case "reversal":
|
|
return { cull: restTalk || !moves.has("endure") && !moves.has("substitute") };
|
|
case "endure":
|
|
return { cull: movePool.includes("destinybond") };
|
|
case "extremespeed":
|
|
case "raindance":
|
|
case "sunnyday":
|
|
return { cull: counter.damagingMoves.size < 2 || moves.has("rest") };
|
|
case "focuspunch":
|
|
return { cull: counter.damagingMoves.size < 2 || moves.has("rest") || counter.setupType && !moves.has("spore") || !moves.has("substitute") && (counter.get("Physical") < 4 || moves.has("fakeout")) || species.id === "breloom" && (moves.has("machpunch") || moves.has("skyuppercut")) };
|
|
case "moonlight":
|
|
return { cull: moves.has("wish") || moves.has("protect") };
|
|
case "perishsong":
|
|
return { cull: !moves.has("meanlook") && !moves.has("spiderweb") };
|
|
case "protect":
|
|
return { cull: !abilities.has("Speed Boost") && ["perishsong", "toxic", "wish"].every((m) => !moves.has(m)) };
|
|
case "refresh":
|
|
return { cull: !counter.setupType };
|
|
case "rest":
|
|
return { cull: movePool.includes("sleeptalk") || !moves.has("sleeptalk") && (!!counter.get("recovery") || movePool.includes("curse")) };
|
|
case "solarbeam":
|
|
if (movePool.length > 1) {
|
|
const sunnyday = movePool.indexOf("sunnyday");
|
|
if (sunnyday >= 0)
|
|
this.fastPop(movePool, sunnyday);
|
|
}
|
|
return { cull: !moves.has("sunnyday") };
|
|
case "aromatherapy":
|
|
case "healbell":
|
|
return { cull: moves.has("rest") || !!teamDetails.statusCure };
|
|
case "confuseray":
|
|
return { cull: !!counter.setupType || restTalk };
|
|
case "counter":
|
|
case "mirrorcoat":
|
|
return { cull: !!counter.setupType || ["rest", "substitute", "toxic"].some((m) => moves.has(m)) };
|
|
case "destinybond":
|
|
return { cull: !!counter.setupType || moves.has("explosion") || moves.has("selfdestruct") };
|
|
case "doubleedge":
|
|
case "facade":
|
|
case "fakeout":
|
|
case "waterspout":
|
|
return { cull: !types.has(move.type) && counter.get("Status") >= 1 || move.id === "doubleedge" && moves.has("return") };
|
|
case "encore":
|
|
case "painsplit":
|
|
case "recover":
|
|
case "yawn":
|
|
return { cull: restTalk };
|
|
case "explosion":
|
|
case "machpunch":
|
|
case "selfdestruct":
|
|
const snorlaxCase = species.id === "snorlax" && !moves.has("return") && !moves.has("bodyslam");
|
|
return { cull: snorlaxCase || moves.has("rest") || moves.has("substitute") || !!counter.get("recovery") };
|
|
case "haze":
|
|
return { cull: !!counter.setupType || moves.has("raindance") || restTalk };
|
|
case "icywind":
|
|
case "pursuit":
|
|
case "superpower":
|
|
case "transform":
|
|
return { cull: !!counter.setupType || moves.has("rest") };
|
|
case "leechseed":
|
|
return { cull: !!counter.setupType || moves.has("explosion") };
|
|
case "stunspore":
|
|
return { cull: moves.has("sunnyday") || moves.has("toxic") };
|
|
case "lightscreen":
|
|
return { cull: !!counter.setupType || !!counter.get("speedsetup") };
|
|
case "meanlook":
|
|
case "spiderweb":
|
|
return { cull: !!counter.get("speedsetup") || !moves.has("batonpass") && !moves.has("perishsong") };
|
|
case "morningsun":
|
|
return { cull: counter.get("speedsetup") >= 1 };
|
|
case "quickattack":
|
|
return { cull: !!counter.get("speedsetup") || moves.has("substitute") || !types.has("Normal") && !!counter.get("Status") };
|
|
case "rapidspin":
|
|
return { cull: !!counter.setupType || moves.has("rest") || !!teamDetails.rapidSpin };
|
|
case "reflect":
|
|
return { cull: !!counter.setupType || !!counter.get("speedsetup") };
|
|
case "roar":
|
|
case "whirlwind":
|
|
return { cull: moves.has("sleeptalk") || moves.has("rest") };
|
|
case "seismictoss":
|
|
return { cull: !!counter.setupType || moves.has("thunderbolt") };
|
|
case "spikes":
|
|
return { cull: !!counter.setupType || moves.has("substitute") || restTalk || !!teamDetails.spikes };
|
|
case "substitute":
|
|
const restOrDD = moves.has("rest") || moves.has("dragondance") && !moves.has("bellydrum");
|
|
return { cull: restOrDD || species.id !== "entei" && !moves.has("batonpass") && movePool.includes("calmmind") };
|
|
case "thunderwave":
|
|
return { cull: !!counter.setupType || moves.has("bodyslam") || moves.has("substitute") && movePool.includes("toxic") || restTalk };
|
|
case "toxic":
|
|
return { cull: !!counter.setupType || !!counter.get("speedsetup") || ["endure", "focuspunch", "raindance", "yawn", "hypnosis"].some((m) => moves.has(m)) };
|
|
case "trick":
|
|
return { cull: counter.get("Status") > 1 };
|
|
case "willowisp":
|
|
return { cull: !!counter.setupType || moves.has("hypnosis") || moves.has("toxic") };
|
|
case "bodyslam":
|
|
return { cull: moves.has("return") && !!counter.get("Status") };
|
|
case "headbutt":
|
|
return { cull: !moves.has("bodyslam") && !moves.has("thunderwave") };
|
|
case "return":
|
|
return { cull: moves.has("endure") || moves.has("substitute") && moves.has("flail") || moves.has("bodyslam") && !counter.get("Status") };
|
|
case "fireblast":
|
|
return { cull: moves.has("flamethrower") && !!counter.get("Status") };
|
|
case "flamethrower":
|
|
return { cull: moves.has("fireblast") && !counter.get("Status") };
|
|
case "overheat":
|
|
return { cull: moves.has("flamethrower") || moves.has("substitute") };
|
|
case "hydropump":
|
|
return { cull: moves.has("surf") && !!counter.get("Status") };
|
|
case "surf":
|
|
return { cull: moves.has("hydropump") && !counter.get("Status") };
|
|
case "gigadrain":
|
|
return { cull: moves.has("morningsun") || moves.has("toxic") };
|
|
case "hiddenpower":
|
|
const stabCondition = types.has(move.type) && counter.get(move.type) > 1 && (moves.has("substitute") && !counter.setupType && !moves.has("toxic") || species.id !== "meganium" && moves.has("toxic") && !moves.has("substitute") || restTalk);
|
|
return { cull: stabCondition || move.type === "Grass" && moves.has("sunnyday") && moves.has("solarbeam") };
|
|
case "brickbreak":
|
|
case "crosschop":
|
|
case "skyuppercut":
|
|
return { cull: moves.has("substitute") && (moves.has("focuspunch") || movePool.includes("focuspunch")) };
|
|
case "earthquake":
|
|
return { cull: moves.has("bonemerang") };
|
|
}
|
|
return { cull: false };
|
|
}
|
|
getItem(ability, types, moves, counter, species) {
|
|
if (species.name === "Ditto")
|
|
return this.sample(["Metal Powder", "Quick Claw"]);
|
|
if (species.name === "Farfetch\u2019d")
|
|
return "Stick";
|
|
if (species.name === "Marowak")
|
|
return "Thick Club";
|
|
if (species.name === "Pikachu")
|
|
return "Light Ball";
|
|
if (species.name === "Shedinja")
|
|
return "Lum Berry";
|
|
if (species.name === "Unown")
|
|
return "Twisted Spoon";
|
|
if (moves.has("trick"))
|
|
return "Choice Band";
|
|
if (moves.has("rest") && !moves.has("sleeptalk") && !["Early Bird", "Natural Cure", "Shed Skin"].includes(ability)) {
|
|
return "Chesto Berry";
|
|
}
|
|
if (moves.has("dragondance") && ability !== "Natural Cure")
|
|
return "Lum Berry";
|
|
if (moves.has("bellydrum") && counter.get("Physical") - counter.get("priority") > 1 || (moves.has("swordsdance") && counter.get("Status") < 2 || moves.has("bulkup") && moves.has("substitute")) && !counter.get("priority") && species.baseStats.spe >= 60 && species.baseStats.spe <= 95) {
|
|
return "Salac Berry";
|
|
}
|
|
if (moves.has("endure") || moves.has("substitute") && ["bellydrum", "endeavor", "flail", "reversal"].some((m) => moves.has(m))) {
|
|
return species.baseStats.spe <= 100 && ability !== "Speed Boost" && !counter.get("speedsetup") && !moves.has("focuspunch") ? "Salac Berry" : "Liechi Berry";
|
|
}
|
|
if (moves.has("substitute") && counter.get("Physical") >= 3 && species.baseStats.spe >= 120)
|
|
return "Liechi Berry";
|
|
if ((moves.has("substitute") || moves.has("raindance")) && counter.get("Special") >= 3)
|
|
return "Petaya Berry";
|
|
if (counter.get("Physical") >= 4 && !moves.has("fakeout"))
|
|
return "Choice Band";
|
|
if (counter.get("Physical") >= 3 && !moves.has("rapidspin") && (["fireblast", "icebeam", "overheat"].some((m) => moves.has(m)) || Array.from(moves).some((m) => {
|
|
const moveData = this.dex.moves.get(m);
|
|
return moveData.category === "Special" && types.has(moveData.type);
|
|
}))) {
|
|
return "Choice Band";
|
|
}
|
|
if (moves.has("psychoboost"))
|
|
return "White Herb";
|
|
return "Leftovers";
|
|
}
|
|
shouldCullAbility(ability, types, moves, abilities, counter, movePool, teamDetails, species) {
|
|
switch (ability) {
|
|
case "Chlorophyll":
|
|
return !moves.has("sunnyday") && !teamDetails["sun"];
|
|
case "Compound Eyes":
|
|
return !counter.get("inaccurate");
|
|
case "Hustle":
|
|
return counter.get("Physical") < 2;
|
|
case "Lightning Rod":
|
|
return species.types.includes("Ground");
|
|
case "Overgrow":
|
|
return !counter.get("Grass");
|
|
case "Rock Head":
|
|
return !counter.get("recoil");
|
|
case "Sand Veil":
|
|
return !teamDetails["sand"];
|
|
case "Serene Grace":
|
|
return species.id === "blissey";
|
|
case "Sturdy":
|
|
return true;
|
|
case "Swift Swim":
|
|
return !moves.has("raindance") && !teamDetails["rain"];
|
|
case "Swarm":
|
|
return !counter.get("Bug");
|
|
case "Torrent":
|
|
return !counter.get("Water");
|
|
case "Water Absorb":
|
|
return abilities.has("Swift Swim");
|
|
}
|
|
return false;
|
|
}
|
|
randomSet(species, teamDetails = {}) {
|
|
species = this.dex.species.get(species);
|
|
let forme = species.name;
|
|
const data = this.randomData[species.id];
|
|
if (typeof species.battleOnly === "string")
|
|
forme = species.battleOnly;
|
|
const movePool = (data.moves || Object.keys(this.dex.species.getLearnset(species.id))).slice();
|
|
const rejectedPool = [];
|
|
const moves = /* @__PURE__ */ new Set();
|
|
let ability = "";
|
|
const evs = { hp: 85, atk: 85, def: 85, spa: 85, spd: 85, spe: 85 };
|
|
const ivs = { hp: 31, atk: 31, def: 31, spa: 31, spd: 31, spe: 31 };
|
|
let availableHP = 0;
|
|
for (const setMoveid of movePool) {
|
|
if (setMoveid.startsWith("hiddenpower"))
|
|
availableHP++;
|
|
}
|
|
const types = new Set(species.types);
|
|
const abilities = new Set(Object.values(species.abilities));
|
|
let counter;
|
|
let hasHiddenPower = false;
|
|
do {
|
|
while (moves.size < this.maxMoveCount && movePool.length) {
|
|
const moveid = this.sampleNoReplace(movePool);
|
|
if (moveid.startsWith("hiddenpower")) {
|
|
availableHP--;
|
|
if (hasHiddenPower)
|
|
continue;
|
|
hasHiddenPower = true;
|
|
}
|
|
moves.add(moveid);
|
|
}
|
|
while (moves.size < this.maxMoveCount && rejectedPool.length) {
|
|
const moveid = this.sampleNoReplace(rejectedPool);
|
|
if (moveid.startsWith("hiddenpower")) {
|
|
if (hasHiddenPower)
|
|
continue;
|
|
hasHiddenPower = true;
|
|
}
|
|
moves.add(moveid);
|
|
}
|
|
counter = this.queryMoves(moves, species.types, abilities, movePool);
|
|
for (const moveid of moves) {
|
|
const move = this.dex.moves.get(moveid);
|
|
let { cull, isSetup } = this.shouldCullMove(move, types, moves, abilities, counter, movePool, teamDetails, species);
|
|
if (counter.setupType === "Physical" && move.category === "Special" && !types.has(move.type) && move.type !== "Fire" || counter.setupType === "Special" && move.category === "Physical" && moveid !== "superpower") {
|
|
cull = true;
|
|
}
|
|
const moveIsRejectable = !move.weather && (move.category !== "Status" || !move.flags.heal) && (counter.setupType || !move.stallingMove) && // These moves cannot be rejected in favor of a forced move
|
|
!["batonpass", "sleeptalk", "solarbeam", "substitute", "sunnyday"].includes(moveid) && (move.category === "Status" || !types.has(move.type) || move.basePower && move.basePower < 40 && !move.multihit);
|
|
const requiresStab = !counter.get("stab") && !moves.has("seismictoss") && !moves.has("nightshade") && species.id !== "castform" && species.id !== "umbreon" && // If a Flying-type has Psychic, it doesn't need STAB
|
|
!(moves.has("psychic") && types.has("Flying")) && !(types.has("Ghost") && species.baseStats.spa > species.baseStats.atk) && !// With Calm Mind, Lugia and pure Normal-types are fine without STAB
|
|
(counter.setupType === "Special" && (species.id === "lugia" || types.has("Normal") && species.types.length < 2)) && !// With Swords Dance, Dark-types and pure Water-types are fine without STAB
|
|
(counter.setupType === "Physical" && (types.has("Water") && species.types.length < 2 || types.has("Dark"))) && counter.get("physicalpool") + counter.get("specialpool") > 0;
|
|
const runEnforcementChecker = (checkerName) => {
|
|
if (!this.moveEnforcementCheckers[checkerName])
|
|
return false;
|
|
return this.moveEnforcementCheckers[checkerName](
|
|
movePool,
|
|
moves,
|
|
abilities,
|
|
types,
|
|
counter,
|
|
species,
|
|
teamDetails
|
|
);
|
|
};
|
|
if (!cull && !isSetup && moveIsRejectable) {
|
|
if (requiresStab || counter.setupType && counter.get(counter.setupType) < 2 && !moves.has("refresh") || moves.has("substitute") && movePool.includes("morningsun") || ["meteormash", "spore", "recover"].some((m) => movePool.includes(m))) {
|
|
cull = true;
|
|
} else {
|
|
for (const type of types) {
|
|
if (runEnforcementChecker(type)) {
|
|
cull = true;
|
|
}
|
|
}
|
|
for (const m of moves) {
|
|
if (runEnforcementChecker(m))
|
|
cull = true;
|
|
}
|
|
}
|
|
}
|
|
if (moveid === "rest" && cull) {
|
|
const sleeptalk = movePool.indexOf("sleeptalk");
|
|
if (sleeptalk >= 0) {
|
|
if (movePool.length < 2) {
|
|
cull = false;
|
|
} else {
|
|
this.fastPop(movePool, sleeptalk);
|
|
}
|
|
}
|
|
}
|
|
const moveIsHP = moveid.startsWith("hiddenpower");
|
|
if (cull && (movePool.length - availableHP || availableHP && (moveIsHP || !hasHiddenPower))) {
|
|
if (move.category !== "Status" && !move.damage && (!moveIsHP || !availableHP)) {
|
|
rejectedPool.push(moveid);
|
|
}
|
|
if (moveIsHP)
|
|
hasHiddenPower = false;
|
|
moves.delete(moveid);
|
|
break;
|
|
}
|
|
if (cull && rejectedPool.length) {
|
|
if (moveIsHP)
|
|
hasHiddenPower = false;
|
|
moves.delete(moveid);
|
|
break;
|
|
}
|
|
}
|
|
} while (moves.size < this.maxMoveCount && (movePool.length || rejectedPool.length));
|
|
if (hasHiddenPower) {
|
|
let hpType;
|
|
for (const move of moves) {
|
|
if (move.startsWith("hiddenpower"))
|
|
hpType = move.substr(11);
|
|
}
|
|
if (!hpType)
|
|
throw new Error(`hasHiddenPower is true, but no Hidden Power move was found.`);
|
|
const HPivs = this.dex.types.get(hpType).HPivs;
|
|
let iv;
|
|
for (iv in HPivs) {
|
|
ivs[iv] = HPivs[iv];
|
|
}
|
|
}
|
|
const abilityData = Array.from(abilities).map((a) => this.dex.abilities.get(a)).filter((a) => a.gen === 3);
|
|
import_lib.Utils.sortBy(abilityData, (abil) => -abil.rating);
|
|
let ability0 = abilityData[0];
|
|
let ability1 = abilityData[1];
|
|
if (abilityData[1]) {
|
|
if (ability0.rating <= ability1.rating && this.randomChance(1, 2)) {
|
|
[ability0, ability1] = [ability1, ability0];
|
|
} else if (ability0.rating - 0.6 <= ability1.rating && this.randomChance(2, 3)) {
|
|
[ability0, ability1] = [ability1, ability0];
|
|
}
|
|
ability = ability0.name;
|
|
while (this.shouldCullAbility(ability, types, moves, abilities, counter, movePool, teamDetails, species)) {
|
|
if (ability === ability0.name && ability1.rating > 1) {
|
|
ability = ability1.name;
|
|
} else {
|
|
ability = abilityData[0].name;
|
|
break;
|
|
}
|
|
}
|
|
} else {
|
|
ability = abilityData[0].name;
|
|
}
|
|
const item = this.getItem(ability, types, moves, counter, species);
|
|
const level = this.adjustLevel || data.level || (species.nfe ? 90 : 80);
|
|
let hp = Math.floor(Math.floor(2 * species.baseStats.hp + ivs.hp + Math.floor(evs.hp / 4) + 100) * level / 100 + 10);
|
|
if (moves.has("substitute") && ["endeavor", "flail", "reversal"].some((m) => moves.has(m))) {
|
|
if (hp % 4 === 0)
|
|
evs.hp -= 4;
|
|
} else if (moves.has("substitute") && (item === "Salac Berry" || item === "Petaya Berry" || item === "Liechi Berry")) {
|
|
while (hp % 4 > 0) {
|
|
evs.hp -= 4;
|
|
hp = Math.floor(Math.floor(2 * species.baseStats.hp + ivs.hp + Math.floor(evs.hp / 4) + 100) * level / 100 + 10);
|
|
}
|
|
}
|
|
if (!counter.get("Physical") && !moves.has("transform")) {
|
|
evs.atk = 0;
|
|
ivs.atk = hasHiddenPower ? ivs.atk - 28 : 0;
|
|
}
|
|
return {
|
|
name: species.baseSpecies,
|
|
species: forme,
|
|
gender: species.gender,
|
|
moves: Array.from(moves),
|
|
ability,
|
|
evs,
|
|
ivs,
|
|
item,
|
|
level,
|
|
shiny: this.randomChance(1, 1024)
|
|
};
|
|
}
|
|
randomTeam() {
|
|
this.enforceNoDirectCustomBanlistChanges();
|
|
const seed = this.prng.seed;
|
|
const ruleTable = this.dex.formats.getRuleTable(this.format);
|
|
const pokemon = [];
|
|
const isMonotype = !!this.forceMonotype || ruleTable.has("sametypeclause");
|
|
const typePool = this.dex.types.names();
|
|
const type = this.forceMonotype || this.sample(typePool);
|
|
const baseFormes = {};
|
|
const tierCount = {};
|
|
const typeCount = {};
|
|
const typeComboCount = {};
|
|
const typeWeaknesses = {};
|
|
const teamDetails = {};
|
|
const pokemonPool = this.getPokemonPool(type, pokemon, isMonotype);
|
|
while (pokemonPool.length && pokemon.length < this.maxTeamSize) {
|
|
const species = this.dex.species.get(this.sampleNoReplace(pokemonPool));
|
|
if (!species.exists || !this.randomData[species.id]?.moves)
|
|
continue;
|
|
if (baseFormes[species.baseSpecies])
|
|
continue;
|
|
if (species.name === "Wobbuffet" && this.battleHasWobbuffet)
|
|
continue;
|
|
if (this.dex.gen < 3 && species.name === "Ditto" && this.battleHasDitto)
|
|
continue;
|
|
const tier = species.tier;
|
|
const types = species.types;
|
|
const typeCombo = types.slice().sort().join();
|
|
if (!isMonotype && !this.forceMonotype) {
|
|
const limitFactor = Math.round(this.maxTeamSize / 6) || 1;
|
|
if (tierCount[tier] >= 2 * limitFactor)
|
|
continue;
|
|
let skip = false;
|
|
for (const typeName of types) {
|
|
if (typeCount[typeName] >= 2 * limitFactor) {
|
|
skip = true;
|
|
break;
|
|
}
|
|
}
|
|
if (skip)
|
|
continue;
|
|
for (const typeName of this.dex.types.names()) {
|
|
if (this.dex.getEffectiveness(typeName, species) > 0) {
|
|
if (!typeWeaknesses[typeName])
|
|
typeWeaknesses[typeName] = 0;
|
|
if (typeWeaknesses[typeName] >= 3 * limitFactor) {
|
|
skip = true;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
if (skip)
|
|
continue;
|
|
if (!this.forceMonotype && typeComboCount[typeCombo] >= 1 * limitFactor)
|
|
continue;
|
|
}
|
|
const set = this.randomSet(species, teamDetails);
|
|
pokemon.push(set);
|
|
baseFormes[species.baseSpecies] = 1;
|
|
if (tierCount[tier]) {
|
|
tierCount[tier]++;
|
|
} else {
|
|
tierCount[tier] = 1;
|
|
}
|
|
for (const typeName of types) {
|
|
if (typeName in typeCount) {
|
|
typeCount[typeName]++;
|
|
} else {
|
|
typeCount[typeName] = 1;
|
|
}
|
|
}
|
|
if (typeCombo in typeComboCount) {
|
|
typeComboCount[typeCombo]++;
|
|
} else {
|
|
typeComboCount[typeCombo] = 1;
|
|
}
|
|
for (const typeName of this.dex.types.names()) {
|
|
if (this.dex.getEffectiveness(typeName, species) > 0) {
|
|
typeWeaknesses[typeName]++;
|
|
}
|
|
}
|
|
if (set.ability === "Drizzle" || set.moves.includes("raindance"))
|
|
teamDetails.rain = 1;
|
|
if (set.ability === "Sand Stream")
|
|
teamDetails.sand = 1;
|
|
if (set.moves.includes("spikes"))
|
|
teamDetails.spikes = 1;
|
|
if (set.moves.includes("rapidspin"))
|
|
teamDetails.rapidSpin = 1;
|
|
if (set.moves.includes("aromatherapy") || set.moves.includes("healbell"))
|
|
teamDetails.statusCure = 1;
|
|
if (set.ability === "Shadow Tag")
|
|
this.battleHasWobbuffet = true;
|
|
if (species.id === "ditto")
|
|
this.battleHasDitto = true;
|
|
}
|
|
if (pokemon.length < this.maxTeamSize && !isMonotype && !this.forceMonotype && pokemon.length < 12) {
|
|
throw new Error(`Could not build a random team for ${this.format} (seed=${seed})`);
|
|
}
|
|
return pokemon;
|
|
}
|
|
}
|
|
var random_teams_default = RandomGen3Teams;
|
|
//# sourceMappingURL=random-teams.js.map
|