{ "version": 3, "sources": ["../../../data/cg-teams.ts"], "sourcesContent": ["/**\r\n * Computer-Generated Teams\r\n *\r\n * Generates teams based on heuristics, most of which carry over across generations.\r\n * Teams generated will not always be competitively great, but they will have variety\r\n * and be fun to play (i.e., tries to avoid awful sets).\r\n *\r\n * The [Gen 9] Computer-Generated Teams format is personally maintained by Annika,\r\n * and is not part of any official Smogon or PS format selection. If you enjoy playing\r\n * with teams you didn't make yourself, you may want to check out Random Battles, Battle Factory,\r\n * and/or the sample teams for usage-based formats like OU.\r\n *\r\n * The core of the generator is the weightedRandomPick function, which chooses from an array\r\n * of options based on a weight associated with each option. This way, better/stronger/more useful options\r\n * are more likely to be chosen, but there's still an opportunity for weaker, more situational,\r\n * or higher-risk/higher-reward options to be chosen. However, for moves, the 'worst' moves are excluded\r\n * altogether, both to reduce the likelihood of a bad moveset and improve generator performance.\r\n *\r\n * Certain less-relevant aspects of the set are not randomized at all, such as:\r\n * - IVs (all 31s, with 0 Attack IV if the Pok\u00E9mon has no Physical moves in case of Confusion)\r\n * - EVs (84 per stat, for +21 to each)\r\n * - Nature (always Quirky, which has no effect)\r\n * - Happiness (there are no Happiness-based moves in Gen IX)\r\n *\r\n * Currently, leveling is based on a Pok\u00E9mon's position within Smogon's usage-based tiers,\r\n * but an automatic leveling system is planned for the future. This would involve storing win and loss\r\n * data by Pok\u00E9mon species in a database, and increasing and decreasing the levels of Pok\u00E9mon species\r\n * each day based on their win/loss ratio. For example, if 60% of matches with a Pok\u00E9mon species are wins,\r\n * the species is probably overleveled!\r\n *\r\n * Other aspects of the team generator that may be worth implementing in the future include:\r\n * - Explicit support for weather-oriented teams (boosting moves and typings that synergize with that weather)\r\n * - Tracking type coverage to make it more likely that a moveset can hit every type\r\n */\r\n\r\nimport {Dex, PRNG, SQL} from '../sim';\r\nimport {\r\n\tABILITY_MOVE_BONUSES,\r\n\tABILITY_MOVE_TYPE_BONUSES,\r\n\tHARDCODED_MOVE_WEIGHTS,\r\n\tMOVE_PAIRINGS,\r\n\tSPEED_BASED_MOVES,\r\n\tWEIGHT_BASED_MOVES,\r\n} from './cg-team-data';\r\n\r\ninterface TeamStats {\r\n\thazardSetters: {[moveid: string]: number};\r\n\ttypeWeaknesses: {[type: string]: number};\r\n}\r\n\r\n// We put a limit on the number of Pok\u00E9mon on a team that can be weak to a given type.\r\nconst MAX_WEAK_TO_SAME_TYPE = 3;\r\n\r\nconst levelOverride: {[speciesID: string]: number} = {};\r\nexport let levelUpdateInterval: NodeJS.Timeout | null = null;\r\n\r\nasync function updateLevels(database: SQL.DatabaseManager) {\r\n\tconst updateSpecies = await database.prepare(\r\n\t\t'UPDATE gen9computergeneratedteams SET wins = 0, losses = 0, level = ? WHERE species_id = ?'\r\n\t);\r\n\tconst updateHistory = await database.prepare(\r\n\t\t`INSERT INTO gen9_historical_levels (level, species_id, timestamp) VALUES (?, ?, ${Date.now()})`\r\n\t);\r\n\tconst data = await database.all('SELECT species_id, wins, losses, level FROM gen9computergeneratedteams');\r\n\tfor (let {species_id, wins, losses, level} of data) {\r\n\t\tconst total = wins + losses;\r\n\r\n\t\tif (total > 10) {\r\n\t\t\tif (wins / total >= 0.55) level--;\r\n\t\t\tif (wins / total <= 0.45) level++;\r\n\t\t\tlevel = Math.max(1, Math.min(100, level));\r\n\t\t\tawait updateSpecies?.run([level, species_id]);\r\n\t\t\tawait updateHistory?.run([level, species_id]);\r\n\t\t}\r\n\r\n\t\tlevelOverride[species_id] = level;\r\n\t}\r\n}\r\n\r\nif (global.Config && Config.usesqlite && Config.usesqliteleveling) {\r\n\tconst database = SQL(module, {file: './databases/battlestats.db'});\r\n\r\n\t// update every 2 hours\r\n\tvoid updateLevels(database);\r\n\tlevelUpdateInterval = setInterval(() => void updateLevels(database), 1000 * 60 * 60 * 2);\r\n}\r\n\r\nexport default class TeamGenerator {\r\n\tdex: ModdedDex;\r\n\tformat: Format;\r\n\tteamSize: number;\r\n\tforceLevel?: number;\r\n\tprng: PRNG;\r\n\titemPool: Item[];\r\n\r\n\tconstructor(format: Format | string, seed: PRNG | PRNGSeed | null) {\r\n\t\tthis.dex = Dex.forFormat(format);\r\n\t\tthis.format = Dex.formats.get(format);\r\n\t\tthis.teamSize = this.format.ruleTable?.maxTeamSize || 6;\r\n\t\tthis.prng = seed instanceof PRNG ? seed : new PRNG(seed);\r\n\t\tthis.itemPool = this.dex.items.all().filter(i => i.exists && i.isNonstandard !== 'Past' && !i.isPokeball);\r\n\r\n\t\tconst rules = Dex.formats.getRuleTable(this.format);\r\n\t\tif (rules.adjustLevel) this.forceLevel = rules.adjustLevel;\r\n\t}\r\n\r\n\tgetTeam(): PokemonSet[] {\r\n\t\tlet speciesPool = this.dex.species.all().filter(s => {\r\n\t\t\tif (!s.exists) return false;\r\n\t\t\tif (s.isNonstandard || s.isNonstandard === 'Unobtainable') return false;\r\n\t\t\tif (s.nfe) return false;\r\n\t\t\tif (s.battleOnly && !s.requiredItems?.length) return false;\r\n\r\n\t\t\treturn true;\r\n\t\t});\r\n\t\tconst teamStats: TeamStats = {\r\n\t\t\thazardSetters: {},\r\n\t\t\ttypeWeaknesses: {},\r\n\t\t};\r\n\r\n\t\tconst team: PokemonSet[] = [];\r\n\t\twhile (team.length < this.teamSize && speciesPool.length) {\r\n\t\t\tconst species = this.prng.sample(speciesPool);\r\n\r\n\t\t\tconst haveRoomToReject = speciesPool.length >= (this.teamSize - team.length);\r\n\t\t\tconst isGoodFit = this.speciesIsGoodFit(species, teamStats);\r\n\t\t\tif (haveRoomToReject && !isGoodFit) continue;\r\n\r\n\t\t\tspeciesPool = speciesPool.filter(s => s.baseSpecies !== species.baseSpecies);\r\n\t\t\tteam.push(this.makeSet(species, teamStats));\r\n\t\t}\r\n\r\n\t\treturn team;\r\n\t}\r\n\r\n\tprotected makeSet(species: Species, teamStats: TeamStats): PokemonSet {\r\n\t\tconst abilityPool = Object.values(species.abilities);\r\n\t\tconst abilityWeights = abilityPool.map(a => this.getAbilityWeight(this.dex.abilities.get(a)));\r\n\t\tconst ability = this.weightedRandomPick(abilityPool, abilityWeights);\r\n\r\n\t\tconst moves: Move[] = [];\r\n\r\n\t\tlet learnset = this.dex.species.getLearnset(species.id);\r\n\t\tlet movePool: string[] = [];\r\n\t\tlet learnsetSpecies = species;\r\n\t\tif (!learnset || species.id === 'gastrodoneast') {\r\n\t\t\tlearnsetSpecies = this.dex.species.get(species.baseSpecies);\r\n\t\t\tlearnset = this.dex.species.getLearnset(learnsetSpecies.id);\r\n\t\t}\r\n\t\tif (learnset) {\r\n\t\t\tmovePool = Object.keys(learnset).filter(\r\n\t\t\t\tmoveid => learnset![moveid].find(learned => learned.startsWith('9'))\r\n\t\t\t);\r\n\t\t}\r\n\t\tif (learnset && learnsetSpecies === species && species.changesFrom) {\r\n\t\t\tconst changesFrom = this.dex.species.get(species.changesFrom);\r\n\t\t\tlearnset = this.dex.species.getLearnset(changesFrom.id);\r\n\t\t\tfor (const moveid in learnset) {\r\n\t\t\t\tif (!movePool.includes(moveid) && learnset[moveid].some(source => source.startsWith('9'))) {\r\n\t\t\t\t\tmovePool.push(moveid);\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t}\r\n\t\tconst evoRegion = learnsetSpecies.evoRegion;\r\n\t\twhile (learnsetSpecies.prevo) {\r\n\t\t\tlearnsetSpecies = this.dex.species.get(learnsetSpecies.prevo);\r\n\t\t\tfor (const moveid in learnset) {\r\n\t\t\t\tif (!movePool.includes(moveid) &&\r\n\t\t\t\t\tlearnset[moveid].some(source => source.startsWith('9') && !evoRegion)) {\r\n\t\t\t\t\tmovePool.push(moveid);\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t}\r\n\t\tif (!movePool.length) throw new Error(`No moves for ${species.id}`);\r\n\r\n\t\t// Consider either the top 15 moves or top 30% of moves, whichever is greater.\r\n\t\tconst numberOfMovesToConsider = Math.min(movePool.length, Math.max(15, Math.trunc(movePool.length * 0.3)));\r\n\t\tlet movePoolIsTrimmed = false;\r\n\t\twhile (moves.length < 4 && movePool.length) {\r\n\t\t\tlet weights;\r\n\t\t\tif (!movePoolIsTrimmed) {\r\n\t\t\t\tconst interimMovePool = [];\r\n\t\t\t\tfor (const move of movePool) {\r\n\t\t\t\t\tconst weight = this.getMoveWeight(this.dex.moves.get(move), teamStats, species, moves, ability);\r\n\t\t\t\t\tinterimMovePool.push({move, weight});\r\n\t\t\t\t}\r\n\r\n\t\t\t\tinterimMovePool.sort((a, b) => b.weight - a.weight);\r\n\r\n\t\t\t\tmovePool = [];\r\n\t\t\t\tweights = [];\r\n\r\n\t\t\t\tfor (let i = 0; i < numberOfMovesToConsider; i++) {\r\n\t\t\t\t\tmovePool.push(interimMovePool[i].move);\r\n\t\t\t\t\tweights.push(interimMovePool[i].weight);\r\n\t\t\t\t}\r\n\t\t\t\tmovePoolIsTrimmed = true;\r\n\t\t\t} else {\r\n\t\t\t\tweights = movePool.map(m => this.getMoveWeight(this.dex.moves.get(m), teamStats, species, moves, ability));\r\n\t\t\t}\r\n\r\n\t\t\tconst moveID = this.weightedRandomPick(movePool, weights, {remove: true});\r\n\r\n\t\t\t// add paired moves, like RestTalk\r\n\t\t\tconst pairedMove = MOVE_PAIRINGS[moveID];\r\n\t\t\tconst alreadyHavePairedMove = moves.some(m => m.id === pairedMove);\r\n\t\t\tif (\r\n\t\t\t\tmoves.length < 3 &&\r\n\t\t\t\tpairedMove &&\r\n\t\t\t\t!alreadyHavePairedMove &&\r\n\t\t\t\t// We don't check movePool because sometimes paired moves are bad.\r\n\t\t\t\tthis.dex.species.getLearnset(species.id)?.[pairedMove]\r\n\t\t\t) {\r\n\t\t\t\tmoves.push(this.dex.moves.get(pairedMove));\r\n\t\t\t\tmovePool.splice(movePool.indexOf(pairedMove), 1);\r\n\t\t\t}\r\n\r\n\t\t\tmoves.push(this.dex.moves.get(moveID));\r\n\t\t}\r\n\r\n\t\tlet item = '';\r\n\t\tif (species.requiredItem) {\r\n\t\t\titem = species.requiredItem;\r\n\t\t} else if (species.requiredItems) {\r\n\t\t\titem = this.prng.sample(species.requiredItems.filter(i => !this.dex.items.get(i).isNonstandard));\r\n\t\t} else if (moves.every(m => m.id !== 'acrobatics')) { // Don't assign an item if the set includes Acrobatics...\r\n\t\t\tconst weights = [];\r\n\t\t\tconst items = [];\r\n\t\t\tfor (const i of this.itemPool) {\r\n\t\t\t\t// If the species has a special item, we should use it.\r\n\t\t\t\tif (i.itemUser?.includes(species.name)) {\r\n\t\t\t\t\titem = i.name;\r\n\t\t\t\t\tbreak;\r\n\t\t\t\t}\r\n\r\n\t\t\t\tconst weight = this.getItemWeight(i, teamStats, species, moves, ability);\r\n\t\t\t\tif (weight !== 0) {\r\n\t\t\t\t\tweights.push(weight);\r\n\t\t\t\t\titems.push(i.name);\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t\tif (!item) item = this.weightedRandomPick(items, weights);\r\n\t\t} else if (['Quark Drive', 'Protosynthesis'].includes(ability)) {\r\n\t\t\t// ...unless the Pokemon can use Booster Energy\r\n\t\t\titem = 'Booster Energy';\r\n\t\t}\r\n\r\n\t\tconst ivs: PokemonSet['ivs'] = {\r\n\t\t\thp: 31,\r\n\t\t\tatk: moves.some(move => this.dex.moves.get(move).category === 'Physical') ? 31 : 0,\r\n\t\t\tdef: 31,\r\n\t\t\tspa: 31,\r\n\t\t\tspd: 31,\r\n\t\t\tspe: 31,\r\n\t\t};\r\n\r\n\t\tconst level = this.forceLevel || TeamGenerator.getLevel(species);\r\n\r\n\t\t// For Tera Type, we just pick a random type if it's got Tera Blast or no attacking moves,\r\n\t\t// and the type of one of its attacking moves otherwise (so it can take advantage of the boosts).\r\n\t\tlet teraType;\r\n\t\tconst nonStatusMoves = moves.filter(move => this.dex.moves.get(move).category !== 'Status');\r\n\t\tif (!moves.some(m => m.id === 'terablast') && nonStatusMoves.length) {\r\n\t\t\tteraType = this.prng.sample(nonStatusMoves.map(move => this.dex.moves.get(move).type));\r\n\t\t} else {\r\n\t\t\tteraType = this.prng.sample([...this.dex.types.all()]).name;\r\n\t\t}\r\n\r\n\t\treturn {\r\n\t\t\tname: species.name,\r\n\t\t\tspecies: species.name,\r\n\t\t\titem,\r\n\t\t\tability,\r\n\t\t\tmoves: moves.map(m => m.name),\r\n\t\t\tnature: 'Quirky',\r\n\t\t\tgender: species.gender,\r\n\t\t\tevs: {hp: 84, atk: 84, def: 84, spa: 84, spd: 84, spe: 84},\r\n\t\t\tivs,\r\n\t\t\tlevel,\r\n\t\t\tteraType,\r\n\t\t\tshiny: this.prng.randomChance(1, 1024),\r\n\t\t\thappiness: 255,\r\n\t\t};\r\n\t}\r\n\r\n\t/**\r\n\t * @returns true if the Pok\u00E9mon is a good fit for the team so far, and no otherwise\r\n\t */\r\n\tprotected speciesIsGoodFit(species: Species, stats: TeamStats): boolean {\r\n\t\t// type check\r\n\t\tfor (const type of this.dex.types.all()) {\r\n\t\t\tconst effectiveness = this.dex.getEffectiveness(type.name, species.types);\r\n\t\t\tif (effectiveness === 1) { // WEAKNESS!\r\n\t\t\t\tif (stats.typeWeaknesses[type.name] === undefined) {\r\n\t\t\t\t\tstats.typeWeaknesses[type.name] = 0;\r\n\t\t\t\t}\r\n\t\t\t\tif (stats.typeWeaknesses[type.name] >= MAX_WEAK_TO_SAME_TYPE) {\r\n\t\t\t\t\t// too many weaknesses to this type\r\n\t\t\t\t\treturn false;\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t}\r\n\t\t// species passes; increment counters\r\n\t\tfor (const type of this.dex.types.all()) {\r\n\t\t\tconst effectiveness = this.dex.getEffectiveness(type.name, species.types);\r\n\t\t\tif (effectiveness === 1) {\r\n\t\t\t\tstats.typeWeaknesses[type.name]++;\r\n\t\t\t}\r\n\t\t}\r\n\t\treturn true;\r\n\t}\r\n\r\n\t/**\r\n\t * @returns A weighting for the Pok\u00E9mon's ability.\r\n\t */\r\n\tprotected getAbilityWeight(ability: Ability): number {\r\n\t\treturn ability.rating + 1; // Some ability ratings are -1\r\n\t}\r\n\r\n\t/**\r\n\t * @returns A weight for a given move on a given Pok\u00E9mon.\r\n\t */\r\n\tprotected getMoveWeight(\r\n\t\tmove: Move,\r\n\t\tteamStats: TeamStats,\r\n\t\tspecies: Species,\r\n\t\tmovesSoFar: Move[],\r\n\t\tability: string\r\n\t): number {\r\n\t\tif (!move.exists) return 0;\r\n\t\t// this is NOT doubles, so there will be no adjacent ally\r\n\t\tif (move.target === 'adjacentAlly') return 0;\r\n\r\n\t\tif (move.category === 'Status') {\r\n\t\t\t// The initial value of this weight determines how valuable status moves are vs. attacking moves.\r\n\t\t\t// You can raise it to make random status moves more valuable or lower it and increase multipliers\r\n\t\t\t// to make only CERTAIN status moves valuable.\r\n\t\t\tlet weight = 2500;\r\n\r\n\t\t\t// inflicts status\r\n\t\t\tif (move.status) weight *= TeamGenerator.statusWeight(move.status) * 2;\r\n\r\n\t\t\t// hazard setters: very important, but we don't need 2 pokemon to set the same hazard on a team\r\n\t\t\tconst isHazard = (m: Move) => m.sideCondition && m.target === 'foeSide';\r\n\t\t\tif (isHazard(move) && (teamStats.hazardSetters[move.id] || 0) < 1) {\r\n\t\t\t\tweight *= move.id === 'spikes' ? 12 : 16;\r\n\r\n\t\t\t\t// if we are ALREADY setting hazards, setting MORE is really good\r\n\t\t\t\tif (movesSoFar.some(m => isHazard(m))) weight *= 2;\r\n\t\t\t\tteamStats.hazardSetters[move.id]++;\r\n\t\t\t}\r\n\r\n\t\t\t// boosts\r\n\t\t\tweight *= this.boostWeight(move, movesSoFar, species) * 2;\r\n\t\t\tweight *= this.opponentDebuffWeight(move) * 2;\r\n\r\n\t\t\t// protection moves - useful for bulky/stally pokemon\r\n\t\t\tif (species.baseStats.def >= 100 || species.baseStats.spd >= 100 || species.baseStats.hp >= 100) {\r\n\t\t\t\tswitch (move.volatileStatus) {\r\n\t\t\t\tcase 'endure':\r\n\t\t\t\t\tweight *= 3;\r\n\t\t\t\t\tbreak;\r\n\t\t\t\tcase 'protect': case 'kingsshield': case 'silktrap':\r\n\t\t\t\t\tweight *= 4;\r\n\t\t\t\t\tbreak;\r\n\t\t\t\tcase 'banefulbunker': case 'spikyshield':\r\n\t\t\t\t\tweight *= 5;\r\n\t\t\t\t\tbreak;\r\n\t\t\t\tdefault:\r\n\t\t\t\t\tbreak;\r\n\t\t\t\t}\r\n\t\t\t}\r\n\r\n\t\t\t// Hardcoded boosts\r\n\t\t\tif (move.id in HARDCODED_MOVE_WEIGHTS) weight *= HARDCODED_MOVE_WEIGHTS[move.id];\r\n\r\n\t\t\t// Pok\u00E9mon with high Attack and Special Attack stats shouldn't have too many status moves,\r\n\t\t\t// but on bulkier Pok\u00E9mon it's more likely to be worth it.\r\n\t\t\tconst goodAttacker = species.baseStats.atk > 80 || species.baseStats.spa > 80;\r\n\t\t\tif (goodAttacker && movesSoFar.filter(m => m.category !== 'Status').length < 2) {\r\n\t\t\t\tweight *= 0.3;\r\n\t\t\t}\r\n\r\n\t\t\treturn weight;\r\n\t\t}\r\n\r\n\t\t// For Grass Knot and friends, let's just assume they average out to around 60 base power.\r\n\t\tconst isWeirdPowerMove = WEIGHT_BASED_MOVES.includes(move.id);\r\n\t\tlet basePower = isWeirdPowerMove ? 60 : move.basePower;\r\n\t\t// not how this calc works but it should be close enough\r\n\t\tif (SPEED_BASED_MOVES.includes(move.id)) basePower = species.baseStats.spe / 2;\r\n\r\n\t\tconst baseStat = move.category === 'Physical' ? species.baseStats.atk : species.baseStats.spa;\r\n\t\t// 10% bonus for never-miss moves\r\n\t\tconst accuracy = move.accuracy === true ? 1.1 : move.accuracy / 100;\r\n\r\n\t\tlet powerEstimate = basePower * baseStat * accuracy;\r\n\t\t// STAB\r\n\t\tif (species.types.includes(move.type)) powerEstimate *= ability === 'Adaptability' ? 2 : 1.5;\r\n\t\tif (ability === 'Technician' && move.basePower <= 60) powerEstimate *= 1.5;\r\n\t\tif (ability === 'Steely Spirit' && move.type === 'Steel') powerEstimate *= 1.5;\r\n\t\tif (move.multihit) {\r\n\t\t\tconst numberOfHits = Array.isArray(move.multihit) ?\r\n\t\t\t\t(ability === 'Skill Link' ? move.multihit[1] : (move.multihit[0] + move.multihit[1]) / 2) :\r\n\t\t\t\tmove.multihit;\r\n\r\n\t\t\tpowerEstimate *= numberOfHits;\r\n\t\t}\r\n\r\n\t\t// If it uses the attacking stat that we don't boost, it's less useful!\r\n\t\tconst hasSpecialSetup = movesSoFar.some(m => m.boosts?.spa || m.self?.boosts?.spa || m.selfBoost?.boosts?.spa);\r\n\t\tconst hasPhysicalSetup = movesSoFar.some(m => m.boosts?.atk || m.self?.boosts?.atk || m.selfBoost?.boosts?.atk);\r\n\t\tif (move.category === 'Physical' && hasSpecialSetup) powerEstimate *= 0.7;\r\n\t\tif (move.category === 'Special' && hasPhysicalSetup) powerEstimate *= 0.7;\r\n\r\n\t\tconst abilityBonus = (\r\n\t\t\t((ABILITY_MOVE_BONUSES[ability] || {})[move.id] || 1) *\r\n\t\t\t((ABILITY_MOVE_TYPE_BONUSES[ability] || {})[move.type] || 1)\r\n\t\t);\r\n\r\n\t\tlet weight = powerEstimate * abilityBonus;\r\n\t\tif (move.id in HARDCODED_MOVE_WEIGHTS) weight *= HARDCODED_MOVE_WEIGHTS[move.id];\r\n\r\n\t\t// priority is more useful when you're slower\r\n\t\tif (move.priority > 0) weight *= (Math.max(130 - species.baseStats.spe, 0) / 130) * 0.5 + 1;\r\n\t\tif (move.priority < 0) weight *= Math.min((1 / species.baseStats.spe) * 30, 1);\r\n\r\n\t\t// flags\r\n\t\tif (move.flags.charge || (move.flags.recharge && ability !== 'Truant')) weight *= 0.5;\r\n\t\tif (move.flags.contact) {\r\n\t\t\tif (ability === 'Tough Claws') weight *= 1.3;\r\n\t\t\tif (ability === 'Unseen Fist') weight *= 1.1;\r\n\t\t}\r\n\t\tif (move.flags.bite && ability === 'Strong Jaw') weight *= 1.5;\r\n\t\t// 10% boost for ability to break subs\r\n\t\tif (move.flags.bypasssub) weight *= 1.1;\r\n\t\tif (move.flags.pulse && ability === 'Mega Launcher') weight *= 1.5;\r\n\t\tif (move.flags.punch && ability === 'Iron Fist') weight *= 1.2;\r\n\t\tif (!move.flags.protect) weight *= 1.1;\r\n\t\tif (move.flags.slicing && ability === 'Sharpness') weight *= 1.5;\r\n\r\n\t\t// boosts/secondaries\r\n\t\t// TODO: consider more possible secondaries\r\n\t\tweight *= this.boostWeight(move, movesSoFar, species);\r\n\t\tif (move.secondary?.status) {\r\n\t\t\tweight *= TeamGenerator.statusWeight(move.secondary.status, (move.secondary.chance || 100) / 100);\r\n\t\t}\r\n\r\n\t\t// self-inflicted confusion or locking yourself in\r\n\t\tif (move.self?.volatileStatus) weight *= 0.8;\r\n\r\n\t\t// downweight moves if we already have an attacking move of the same type\r\n\t\tif (movesSoFar.some(m => m.category !== 'Status' && m.type === move.type && m.basePower >= 60)) weight *= 0.3;\r\n\r\n\t\tif (move.selfdestruct) weight *= 0.3;\r\n\t\tif (move.recoil) weight *= 1 - (move.recoil[0] / move.recoil[1]);\r\n\t\tif (move.mindBlownRecoil) weight *= 0.25;\r\n\t\tif (move.flags['futuremove']) weight *= 0.3;\r\n\t\t// TODO: account for normal higher-crit-chance moves\r\n\t\tif (move.willCrit) weight *= 1.45;\r\n\r\n\t\tif (move.drain) {\r\n\t\t\tconst drainedFraction = move.drain[0] / move.drain[1];\r\n\t\t\tweight *= 1 + (drainedFraction * 0.5);\r\n\t\t}\r\n\r\n\t\t// don't need 2 healing moves\r\n\t\tif (move.heal && movesSoFar.some(m => m.heal)) weight *= 0.5;\r\n\r\n\t\treturn weight;\r\n\t}\r\n\r\n\t/**\r\n\t * @returns A multiplier to a move weighting based on the status it inflicts.\r\n\t */\r\n\tprotected static statusWeight(status: string, chance = 1): number {\r\n\t\tif (chance !== 1) return 1 + (TeamGenerator.statusWeight(status) - 1) * chance;\r\n\r\n\t\tswitch (status) {\r\n\t\tcase 'brn': return 1.5;\r\n\t\tcase 'frz': return 5;\r\n\t\tcase 'par': return 1.5;\r\n\t\tcase 'psn': return 1.5;\r\n\t\tcase 'tox': return 4;\r\n\t\tcase 'slp': return 4;\r\n\t\t}\r\n\t\treturn 1;\r\n\t}\r\n\r\n\t/**\r\n\t * @returns A multiplier to a move weighting based on the boosts it produces for the user.\r\n\t */\r\n\tprotected boostWeight(move: Move, movesSoFar: Move[], species: Species): number {\r\n\t\tconst physicalIsRelevant = (\r\n\t\t\tmove.category === 'Physical' ||\r\n\t\t\tmovesSoFar.some(m => m.category === 'Physical')\r\n\t\t);\r\n\t\tconst specialIsRelevant = (\r\n\t\t\tmove.category === 'Special' ||\r\n\t\t\tmovesSoFar.some(m => m.category === 'Special')\r\n\t\t);\r\n\r\n\t\tlet weight = 1;\r\n\t\tfor (const {chance, boosts} of [\r\n\t\t\t{chance: 1, boosts: move.boosts},\r\n\t\t\t{chance: 1, boosts: move.self?.boosts},\r\n\t\t\t{chance: 1, boosts: move.selfBoost?.boosts},\r\n\t\t\t{\r\n\t\t\t\tchance: move.secondary ? ((move.secondary.chance || 100) / 100) : 0,\r\n\t\t\t\tboosts: move.target === 'self' ? move.secondary?.boosts : move.secondary?.self?.boosts,\r\n\t\t\t},\r\n\t\t]) {\r\n\t\t\tif (!boosts || chance === 0) continue;\r\n\r\n\t\t\tif (boosts.atk && physicalIsRelevant) weight += (chance || 1) * 0.5 * boosts.atk;\r\n\t\t\tif (boosts.spa && specialIsRelevant) weight += (chance || 1) * 0.5 * boosts.spa;\r\n\r\n\t\t\t// TODO: should these scale by base stat magnitude instead of using ternaries?\r\n\t\t\t// defense/special defense boost is less useful if we have some bulk to start with\r\n\t\t\tif (boosts.def) weight += (chance || 1) * 0.5 * boosts.def * (species.baseStats.def > 75 ? 1 : 0.5);\r\n\t\t\tif (boosts.spd) weight += (chance || 1) * 0.5 * boosts.spd * (species.baseStats.spd > 75 ? 1 : 0.5);\r\n\r\n\t\t\t// speed boost is less useful for fast pokemon\r\n\t\t\tif (boosts.spe) weight += (chance || 1) * 0.5 * boosts.spe * (species.baseStats.spe > 120 ? 0.5 : 1);\r\n\t\t}\r\n\r\n\t\treturn weight;\r\n\t}\r\n\r\n\t/**\r\n\t * @returns A weight for a move based on how much it will reduce the opponent's stats.\r\n\t */\r\n\tprotected opponentDebuffWeight(move: Move): number {\r\n\t\tif (!['allAdjacentFoes', 'allAdjacent', 'foeSide', 'normal'].includes(move.target)) return 1;\r\n\r\n\t\tlet averageNumberOfDebuffs = 0;\r\n\t\tfor (const {chance, boosts} of [\r\n\t\t\t{chance: 1, boosts: move.boosts},\r\n\t\t\t{\r\n\t\t\t\tchance: move.secondary ? ((move.secondary.chance || 100) / 100) : 0,\r\n\t\t\t\tboosts: move.secondary?.boosts,\r\n\t\t\t},\r\n\t\t]) {\r\n\t\t\tif (!boosts || chance === 0) continue;\r\n\r\n\t\t\tconst numBoosts = Object.values(boosts).filter(x => x < 0).length;\r\n\t\t\taverageNumberOfDebuffs += chance * numBoosts;\r\n\t\t}\r\n\r\n\t\treturn 1 + (0.25 * averageNumberOfDebuffs);\r\n\t}\r\n\r\n\t/**\r\n\t * @returns A weight for an item.\r\n\t */\r\n\tprotected getItemWeight(item: Item, teamStats: TeamStats, species: Species, moves: Move[], ability: string): number {\r\n\t\tlet weight;\r\n\t\tswitch (item.id) {\r\n\t\t// Choice Items\r\n\t\tcase 'choiceband':\r\n\t\t\treturn moves.every(x => x.category === 'Physical') ? 50 : 0;\r\n\t\tcase 'choicespecs':\r\n\t\t\treturn moves.every(x => x.category === 'Special') ? 50 : 0;\r\n\t\tcase 'choicescarf':\r\n\t\t\tif (moves.some(x => x.category === 'Status')) return 0;\r\n\t\t\tif (species.baseStats.spe > 65 && species.baseStats.spe < 120) return 50;\r\n\t\t\treturn 10;\r\n\r\n\t\t// Generally Decent Items\r\n\t\tcase 'lifeorb':\r\n\t\t\treturn moves.filter(x => x.category !== 'Status').length * 8;\r\n\t\tcase 'focussash':\r\n\t\t\tif (ability === 'Sturdy') return 0;\r\n\t\t\t// frail\r\n\t\t\tif (species.baseStats.hp < 80 && species.baseStats.def < 80 && species.baseStats.spd < 80) return 35;\r\n\t\t\treturn 10;\r\n\t\tcase 'heavydutyboots':\r\n\t\t\tswitch (this.dex.getEffectiveness('Rock', species)) {\r\n\t\t\tcase 1: return 30; // super effective\r\n\t\t\tcase 0: return 10; // neutral\r\n\t\t\t}\r\n\t\t\treturn 5; // not very effective/other\r\n\t\tcase 'assaultvest':\r\n\t\t\tif (moves.some(x => x.category === 'Status')) return 0;\r\n\t\t\treturn 30;\r\n\r\n\t\t// status\r\n\t\tcase 'flameorb':\r\n\t\t\tweight = ability === 'Guts' && !species.types.includes('Fire') ? 30 : 0;\r\n\t\t\tif (moves.some(m => m.id === 'facade')) weight *= 2;\r\n\t\t\treturn weight;\r\n\t\tcase 'toxicorb':\r\n\t\t\tif (species.types.includes('Poison')) return 0;\r\n\r\n\t\t\tweight = 0;\r\n\t\t\tif (ability === 'Poison Heal') weight += 25;\r\n\t\t\tif (moves.some(m => m.id === 'facade')) weight += 25;\r\n\r\n\t\t\treturn weight;\r\n\r\n\t\t// Healing\r\n\t\tcase 'leftovers':\r\n\t\t\treturn 20;\r\n\t\tcase 'blacksludge':\r\n\t\t\treturn species.types.includes('Poison') ? 40 : 0;\r\n\r\n\t\t// berries\r\n\t\tcase 'sitrusberry': case 'magoberry':\r\n\t\t\treturn 20;\r\n\r\n\t\tcase 'throatspray':\r\n\t\t\tif (moves.some(m => m.flags.sound) && moves.some(m => m.category === 'Special')) return 30;\r\n\t\t\treturn 0;\r\n\r\n\t\tdefault:\r\n\t\t\t// probably not a very good item\r\n\t\t\treturn 0;\r\n\t\t}\r\n\t}\r\n\r\n\t/**\r\n\t * @returns The level a Pok\u00E9mon should be.\r\n\t */\r\n\tprotected static getLevel(species: Species): number {\r\n\t\tif (levelOverride[species.id]) return levelOverride[species.id];\r\n\r\n\t\tswitch (species.tier) {\r\n\t\tcase 'Uber': return 70;\r\n\t\tcase 'OU': case 'Unreleased': return 80;\r\n\t\tcase 'UU': return 90;\r\n\t\tcase 'LC': case 'NFE': return 100;\r\n\t\t}\r\n\r\n\t\treturn 100;\r\n\t}\r\n\r\n\t/**\r\n\t * Picks a choice from `choices` based on the weights in `weights`.\r\n\t * `weights` must be the same length as `choices`.\r\n\t */\r\n\tweightedRandomPick(\r\n\t\tchoices: T[],\r\n\t\tweights: number[],\r\n\t\toptions?: {remove?: boolean}\r\n\t) {\r\n\t\tif (!choices.length) throw new Error(`Can't pick from an empty list`);\r\n\t\tif (choices.length !== weights.length) throw new Error(`Choices and weights must be the same length`);\r\n\r\n\t\tconst totalWeight = weights.reduce((a, b) => a + b, 0);\r\n\r\n\t\tlet randomWeight = this.prng.next(0, totalWeight);\r\n\t\tfor (let i = 0; i < choices.length; i++) {\r\n\t\t\trandomWeight -= weights[i];\r\n\t\t\tif (randomWeight < 0) {\r\n\t\t\t\tconst choice = choices[i];\r\n\t\t\t\tif (options?.remove) choices.splice(i, 1);\r\n\t\t\t\treturn choice;\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tif (options?.remove && choices.length) return choices.pop()!;\r\n\t\treturn choices[choices.length - 1];\r\n\t}\r\n\r\n\tsetSeed(seed: PRNGSeed) {\r\n\t\tthis.prng.seed = seed;\r\n\t}\r\n}\r\n"], "mappings": ";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAmCA,iBAA6B;AAC7B,0BAOO;AAQP,MAAM,wBAAwB;AAE9B,MAAM,gBAA+C,CAAC;AAC/C,IAAI,sBAA6C;AAExD,eAAe,aAAa,UAA+B;AAC1D,QAAM,gBAAgB,MAAM,SAAS;AAAA,IACpC;AAAA,EACD;AACA,QAAM,gBAAgB,MAAM,SAAS;AAAA,IACpC,mFAAmF,KAAK,IAAI;AAAA,EAC7F;AACA,QAAM,OAAO,MAAM,SAAS,IAAI,wEAAwE;AACxG,WAAS,EAAC,YAAY,MAAM,QAAQ,MAAK,KAAK,MAAM;AACnD,UAAM,QAAQ,OAAO;AAErB,QAAI,QAAQ,IAAI;AACf,UAAI,OAAO,SAAS;AAAM;AAC1B,UAAI,OAAO,SAAS;AAAM;AAC1B,cAAQ,KAAK,IAAI,GAAG,KAAK,IAAI,KAAK,KAAK,CAAC;AACxC,YAAM,eAAe,IAAI,CAAC,OAAO,UAAU,CAAC;AAC5C,YAAM,eAAe,IAAI,CAAC,OAAO,UAAU,CAAC;AAAA,IAC7C;AAEA,kBAAc,UAAU,IAAI;AAAA,EAC7B;AACD;AAEA,IAAI,OAAO,UAAU,OAAO,aAAa,OAAO,mBAAmB;AAClE,QAAM,eAAW,gBAAI,QAAQ,EAAC,MAAM,6BAA4B,CAAC;AAGjE,OAAK,aAAa,QAAQ;AAC1B,wBAAsB,YAAY,MAAM,KAAK,aAAa,QAAQ,GAAG,MAAO,KAAK,KAAK,CAAC;AACxF;AAEA,MAAO,cAA4B;AAAA,EAQlC,YAAY,QAAyB,MAA8B;AAClE,SAAK,MAAM,eAAI,UAAU,MAAM;AAC/B,SAAK,SAAS,eAAI,QAAQ,IAAI,MAAM;AACpC,SAAK,WAAW,KAAK,OAAO,WAAW,eAAe;AACtD,SAAK,OAAO,gBAAgB,kBAAO,OAAO,IAAI,gBAAK,IAAI;AACvD,SAAK,WAAW,KAAK,IAAI,MAAM,IAAI,EAAE,OAAO,OAAK,EAAE,UAAU,EAAE,kBAAkB,UAAU,CAAC,EAAE,UAAU;AAExG,UAAM,QAAQ,eAAI,QAAQ,aAAa,KAAK,MAAM;AAClD,QAAI,MAAM;AAAa,WAAK,aAAa,MAAM;AAAA,EAChD;AAAA,EAEA,UAAwB;AACvB,QAAI,cAAc,KAAK,IAAI,QAAQ,IAAI,EAAE,OAAO,OAAK;AACpD,UAAI,CAAC,EAAE;AAAQ,eAAO;AACtB,UAAI,EAAE,iBAAiB,EAAE,kBAAkB;AAAgB,eAAO;AAClE,UAAI,EAAE;AAAK,eAAO;AAClB,UAAI,EAAE,cAAc,CAAC,EAAE,eAAe;AAAQ,eAAO;AAErD,aAAO;AAAA,IACR,CAAC;AACD,UAAM,YAAuB;AAAA,MAC5B,eAAe,CAAC;AAAA,MAChB,gBAAgB,CAAC;AAAA,IAClB;AAEA,UAAM,OAAqB,CAAC;AAC5B,WAAO,KAAK,SAAS,KAAK,YAAY,YAAY,QAAQ;AACzD,YAAM,UAAU,KAAK,KAAK,OAAO,WAAW;AAE5C,YAAM,mBAAmB,YAAY,UAAW,KAAK,WAAW,KAAK;AACrE,YAAM,YAAY,KAAK,iBAAiB,SAAS,SAAS;AAC1D,UAAI,oBAAoB,CAAC;AAAW;AAEpC,oBAAc,YAAY,OAAO,OAAK,EAAE,gBAAgB,QAAQ,WAAW;AAC3E,WAAK,KAAK,KAAK,QAAQ,SAAS,SAAS,CAAC;AAAA,IAC3C;AAEA,WAAO;AAAA,EACR;AAAA,EAEU,QAAQ,SAAkB,WAAkC;AACrE,UAAM,cAAc,OAAO,OAAO,QAAQ,SAAS;AACnD,UAAM,iBAAiB,YAAY,IAAI,OAAK,KAAK,iBAAiB,KAAK,IAAI,UAAU,IAAI,CAAC,CAAC,CAAC;AAC5F,UAAM,UAAU,KAAK,mBAAmB,aAAa,cAAc;AAEnE,UAAM,QAAgB,CAAC;AAEvB,QAAI,WAAW,KAAK,IAAI,QAAQ,YAAY,QAAQ,EAAE;AACtD,QAAI,WAAqB,CAAC;AAC1B,QAAI,kBAAkB;AACtB,QAAI,CAAC,YAAY,QAAQ,OAAO,iBAAiB;AAChD,wBAAkB,KAAK,IAAI,QAAQ,IAAI,QAAQ,WAAW;AAC1D,iBAAW,KAAK,IAAI,QAAQ,YAAY,gBAAgB,EAAE;AAAA,IAC3D;AACA,QAAI,UAAU;AACb,iBAAW,OAAO,KAAK,QAAQ,EAAE;AAAA,QAChC,YAAU,SAAU,MAAM,EAAE,KAAK,aAAW,QAAQ,WAAW,GAAG,CAAC;AAAA,MACpE;AAAA,IACD;AACA,QAAI,YAAY,oBAAoB,WAAW,QAAQ,aAAa;AACnE,YAAM,cAAc,KAAK,IAAI,QAAQ,IAAI,QAAQ,WAAW;AAC5D,iBAAW,KAAK,IAAI,QAAQ,YAAY,YAAY,EAAE;AACtD,iBAAW,UAAU,UAAU;AAC9B,YAAI,CAAC,SAAS,SAAS,MAAM,KAAK,SAAS,MAAM,EAAE,KAAK,YAAU,OAAO,WAAW,GAAG,CAAC,GAAG;AAC1F,mBAAS,KAAK,MAAM;AAAA,QACrB;AAAA,MACD;AAAA,IACD;AACA,UAAM,YAAY,gBAAgB;AAClC,WAAO,gBAAgB,OAAO;AAC7B,wBAAkB,KAAK,IAAI,QAAQ,IAAI,gBAAgB,KAAK;AAC5D,iBAAW,UAAU,UAAU;AAC9B,YAAI,CAAC,SAAS,SAAS,MAAM,KAC5B,SAAS,MAAM,EAAE,KAAK,YAAU,OAAO,WAAW,GAAG,KAAK,CAAC,SAAS,GAAG;AACvE,mBAAS,KAAK,MAAM;AAAA,QACrB;AAAA,MACD;AAAA,IACD;AACA,QAAI,CAAC,SAAS;AAAQ,YAAM,IAAI,MAAM,gBAAgB,QAAQ,IAAI;AAGlE,UAAM,0BAA0B,KAAK,IAAI,SAAS,QAAQ,KAAK,IAAI,IAAI,KAAK,MAAM,SAAS,SAAS,GAAG,CAAC,CAAC;AACzG,QAAI,oBAAoB;AACxB,WAAO,MAAM,SAAS,KAAK,SAAS,QAAQ;AAC3C,UAAI;AACJ,UAAI,CAAC,mBAAmB;AACvB,cAAM,kBAAkB,CAAC;AACzB,mBAAW,QAAQ,UAAU;AAC5B,gBAAM,SAAS,KAAK,cAAc,KAAK,IAAI,MAAM,IAAI,IAAI,GAAG,WAAW,SAAS,OAAO,OAAO;AAC9F,0BAAgB,KAAK,EAAC,MAAM,OAAM,CAAC;AAAA,QACpC;AAEA,wBAAgB,KAAK,CAAC,GAAG,MAAM,EAAE,SAAS,EAAE,MAAM;AAElD,mBAAW,CAAC;AACZ,kBAAU,CAAC;AAEX,iBAAS,IAAI,GAAG,IAAI,yBAAyB,KAAK;AACjD,mBAAS,KAAK,gBAAgB,CAAC,EAAE,IAAI;AACrC,kBAAQ,KAAK,gBAAgB,CAAC,EAAE,MAAM;AAAA,QACvC;AACA,4BAAoB;AAAA,MACrB,OAAO;AACN,kBAAU,SAAS,IAAI,OAAK,KAAK,cAAc,KAAK,IAAI,MAAM,IAAI,CAAC,GAAG,WAAW,SAAS,OAAO,OAAO,CAAC;AAAA,MAC1G;AAEA,YAAM,SAAS,KAAK,mBAAmB,UAAU,SAAS,EAAC,QAAQ,KAAI,CAAC;AAGxE,YAAM,aAAa,kCAAc,MAAM;AACvC,YAAM,wBAAwB,MAAM,KAAK,OAAK,EAAE,OAAO,UAAU;AACjE,UACC,MAAM,SAAS,KACf,cACA,CAAC;AAAA,MAED,KAAK,IAAI,QAAQ,YAAY,QAAQ,EAAE,IAAI,UAAU,GACpD;AACD,cAAM,KAAK,KAAK,IAAI,MAAM,IAAI,UAAU,CAAC;AACzC,iBAAS,OAAO,SAAS,QAAQ,UAAU,GAAG,CAAC;AAAA,MAChD;AAEA,YAAM,KAAK,KAAK,IAAI,MAAM,IAAI,MAAM,CAAC;AAAA,IACtC;AAEA,QAAI,OAAO;AACX,QAAI,QAAQ,cAAc;AACzB,aAAO,QAAQ;AAAA,IAChB,WAAW,QAAQ,eAAe;AACjC,aAAO,KAAK,KAAK,OAAO,QAAQ,cAAc,OAAO,OAAK,CAAC,KAAK,IAAI,MAAM,IAAI,CAAC,EAAE,aAAa,CAAC;AAAA,IAChG,WAAW,MAAM,MAAM,OAAK,EAAE,OAAO,YAAY,GAAG;AACnD,YAAM,UAAU,CAAC;AACjB,YAAM,QAAQ,CAAC;AACf,iBAAW,KAAK,KAAK,UAAU;AAE9B,YAAI,EAAE,UAAU,SAAS,QAAQ,IAAI,GAAG;AACvC,iBAAO,EAAE;AACT;AAAA,QACD;AAEA,cAAM,SAAS,KAAK,cAAc,GAAG,WAAW,SAAS,OAAO,OAAO;AACvE,YAAI,WAAW,GAAG;AACjB,kBAAQ,KAAK,MAAM;AACnB,gBAAM,KAAK,EAAE,IAAI;AAAA,QAClB;AAAA,MACD;AACA,UAAI,CAAC;AAAM,eAAO,KAAK,mBAAmB,OAAO,OAAO;AAAA,IACzD,WAAW,CAAC,eAAe,gBAAgB,EAAE,SAAS,OAAO,GAAG;AAE/D,aAAO;AAAA,IACR;AAEA,UAAM,MAAyB;AAAA,MAC9B,IAAI;AAAA,MACJ,KAAK,MAAM,KAAK,UAAQ,KAAK,IAAI,MAAM,IAAI,IAAI,EAAE,aAAa,UAAU,IAAI,KAAK;AAAA,MACjF,KAAK;AAAA,MACL,KAAK;AAAA,MACL,KAAK;AAAA,MACL,KAAK;AAAA,IACN;AAEA,UAAM,QAAQ,KAAK,cAAc,cAAc,SAAS,OAAO;AAI/D,QAAI;AACJ,UAAM,iBAAiB,MAAM,OAAO,UAAQ,KAAK,IAAI,MAAM,IAAI,IAAI,EAAE,aAAa,QAAQ;AAC1F,QAAI,CAAC,MAAM,KAAK,OAAK,EAAE,OAAO,WAAW,KAAK,eAAe,QAAQ;AACpE,iBAAW,KAAK,KAAK,OAAO,eAAe,IAAI,UAAQ,KAAK,IAAI,MAAM,IAAI,IAAI,EAAE,IAAI,CAAC;AAAA,IACtF,OAAO;AACN,iBAAW,KAAK,KAAK,OAAO,CAAC,GAAG,KAAK,IAAI,MAAM,IAAI,CAAC,CAAC,EAAE;AAAA,IACxD;AAEA,WAAO;AAAA,MACN,MAAM,QAAQ;AAAA,MACd,SAAS,QAAQ;AAAA,MACjB;AAAA,MACA;AAAA,MACA,OAAO,MAAM,IAAI,OAAK,EAAE,IAAI;AAAA,MAC5B,QAAQ;AAAA,MACR,QAAQ,QAAQ;AAAA,MAChB,KAAK,EAAC,IAAI,IAAI,KAAK,IAAI,KAAK,IAAI,KAAK,IAAI,KAAK,IAAI,KAAK,GAAE;AAAA,MACzD;AAAA,MACA;AAAA,MACA;AAAA,MACA,OAAO,KAAK,KAAK,aAAa,GAAG,IAAI;AAAA,MACrC,WAAW;AAAA,IACZ;AAAA,EACD;AAAA;AAAA;AAAA;AAAA,EAKU,iBAAiB,SAAkB,OAA2B;AAEvE,eAAW,QAAQ,KAAK,IAAI,MAAM,IAAI,GAAG;AACxC,YAAM,gBAAgB,KAAK,IAAI,iBAAiB,KAAK,MAAM,QAAQ,KAAK;AACxE,UAAI,kBAAkB,GAAG;AACxB,YAAI,MAAM,eAAe,KAAK,IAAI,MAAM,QAAW;AAClD,gBAAM,eAAe,KAAK,IAAI,IAAI;AAAA,QACnC;AACA,YAAI,MAAM,eAAe,KAAK,IAAI,KAAK,uBAAuB;AAE7D,iBAAO;AAAA,QACR;AAAA,MACD;AAAA,IACD;AAEA,eAAW,QAAQ,KAAK,IAAI,MAAM,IAAI,GAAG;AACxC,YAAM,gBAAgB,KAAK,IAAI,iBAAiB,KAAK,MAAM,QAAQ,KAAK;AACxE,UAAI,kBAAkB,GAAG;AACxB,cAAM,eAAe,KAAK,IAAI;AAAA,MAC/B;AAAA,IACD;AACA,WAAO;AAAA,EACR;AAAA;AAAA;AAAA;AAAA,EAKU,iBAAiB,SAA0B;AACpD,WAAO,QAAQ,SAAS;AAAA,EACzB;AAAA;AAAA;AAAA;AAAA,EAKU,cACT,MACA,WACA,SACA,YACA,SACS;AACT,QAAI,CAAC,KAAK;AAAQ,aAAO;AAEzB,QAAI,KAAK,WAAW;AAAgB,aAAO;AAE3C,QAAI,KAAK,aAAa,UAAU;AAI/B,UAAIA,UAAS;AAGb,UAAI,KAAK;AAAQ,QAAAA,WAAU,cAAc,aAAa,KAAK,MAAM,IAAI;AAGrE,YAAM,WAAW,CAAC,MAAY,EAAE,iBAAiB,EAAE,WAAW;AAC9D,UAAI,SAAS,IAAI,MAAM,UAAU,cAAc,KAAK,EAAE,KAAK,KAAK,GAAG;AAClE,QAAAA,WAAU,KAAK,OAAO,WAAW,KAAK;AAGtC,YAAI,WAAW,KAAK,OAAK,SAAS,CAAC,CAAC;AAAG,UAAAA,WAAU;AACjD,kBAAU,cAAc,KAAK,EAAE;AAAA,MAChC;AAGA,MAAAA,WAAU,KAAK,YAAY,MAAM,YAAY,OAAO,IAAI;AACxD,MAAAA,WAAU,KAAK,qBAAqB,IAAI,IAAI;AAG5C,UAAI,QAAQ,UAAU,OAAO,OAAO,QAAQ,UAAU,OAAO,OAAO,QAAQ,UAAU,MAAM,KAAK;AAChG,gBAAQ,KAAK,gBAAgB;AAAA,UAC7B,KAAK;AACJ,YAAAA,WAAU;AACV;AAAA,UACD,KAAK;AAAA,UAAW,KAAK;AAAA,UAAe,KAAK;AACxC,YAAAA,WAAU;AACV;AAAA,UACD,KAAK;AAAA,UAAiB,KAAK;AAC1B,YAAAA,WAAU;AACV;AAAA,UACD;AACC;AAAA,QACD;AAAA,MACD;AAGA,UAAI,KAAK,MAAM;AAAwB,QAAAA,WAAU,2CAAuB,KAAK,EAAE;AAI/E,YAAM,eAAe,QAAQ,UAAU,MAAM,MAAM,QAAQ,UAAU,MAAM;AAC3E,UAAI,gBAAgB,WAAW,OAAO,OAAK,EAAE,aAAa,QAAQ,EAAE,SAAS,GAAG;AAC/E,QAAAA,WAAU;AAAA,MACX;AAEA,aAAOA;AAAA,IACR;AAGA,UAAM,mBAAmB,uCAAmB,SAAS,KAAK,EAAE;AAC5D,QAAI,YAAY,mBAAmB,KAAK,KAAK;AAE7C,QAAI,sCAAkB,SAAS,KAAK,EAAE;AAAG,kBAAY,QAAQ,UAAU,MAAM;AAE7E,UAAM,WAAW,KAAK,aAAa,aAAa,QAAQ,UAAU,MAAM,QAAQ,UAAU;AAE1F,UAAM,WAAW,KAAK,aAAa,OAAO,MAAM,KAAK,WAAW;AAEhE,QAAI,gBAAgB,YAAY,WAAW;AAE3C,QAAI,QAAQ,MAAM,SAAS,KAAK,IAAI;AAAG,uBAAiB,YAAY,iBAAiB,IAAI;AACzF,QAAI,YAAY,gBAAgB,KAAK,aAAa;AAAI,uBAAiB;AACvE,QAAI,YAAY,mBAAmB,KAAK,SAAS;AAAS,uBAAiB;AAC3E,QAAI,KAAK,UAAU;AAClB,YAAM,eAAe,MAAM,QAAQ,KAAK,QAAQ,IAC9C,YAAY,eAAe,KAAK,SAAS,CAAC,KAAK,KAAK,SAAS,CAAC,IAAI,KAAK,SAAS,CAAC,KAAK,IACvF,KAAK;AAEN,uBAAiB;AAAA,IAClB;AAGA,UAAM,kBAAkB,WAAW,KAAK,OAAK,EAAE,QAAQ,OAAO,EAAE,MAAM,QAAQ,OAAO,EAAE,WAAW,QAAQ,GAAG;AAC7G,UAAM,mBAAmB,WAAW,KAAK,OAAK,EAAE,QAAQ,OAAO,EAAE,MAAM,QAAQ,OAAO,EAAE,WAAW,QAAQ,GAAG;AAC9G,QAAI,KAAK,aAAa,cAAc;AAAiB,uBAAiB;AACtE,QAAI,KAAK,aAAa,aAAa;AAAkB,uBAAiB;AAEtE,UAAM,iBACH,yCAAqB,OAAO,KAAK,CAAC,GAAG,KAAK,EAAE,KAAK,OACjD,8CAA0B,OAAO,KAAK,CAAC,GAAG,KAAK,IAAI,KAAK;AAG3D,QAAI,SAAS,gBAAgB;AAC7B,QAAI,KAAK,MAAM;AAAwB,gBAAU,2CAAuB,KAAK,EAAE;AAG/E,QAAI,KAAK,WAAW;AAAG,gBAAW,KAAK,IAAI,MAAM,QAAQ,UAAU,KAAK,CAAC,IAAI,MAAO,MAAM;AAC1F,QAAI,KAAK,WAAW;AAAG,gBAAU,KAAK,IAAK,IAAI,QAAQ,UAAU,MAAO,IAAI,CAAC;AAG7E,QAAI,KAAK,MAAM,UAAW,KAAK,MAAM,YAAY,YAAY;AAAW,gBAAU;AAClF,QAAI,KAAK,MAAM,SAAS;AACvB,UAAI,YAAY;AAAe,kBAAU;AACzC,UAAI,YAAY;AAAe,kBAAU;AAAA,IAC1C;AACA,QAAI,KAAK,MAAM,QAAQ,YAAY;AAAc,gBAAU;AAE3D,QAAI,KAAK,MAAM;AAAW,gBAAU;AACpC,QAAI,KAAK,MAAM,SAAS,YAAY;AAAiB,gBAAU;AAC/D,QAAI,KAAK,MAAM,SAAS,YAAY;AAAa,gBAAU;AAC3D,QAAI,CAAC,KAAK,MAAM;AAAS,gBAAU;AACnC,QAAI,KAAK,MAAM,WAAW,YAAY;AAAa,gBAAU;AAI7D,cAAU,KAAK,YAAY,MAAM,YAAY,OAAO;AACpD,QAAI,KAAK,WAAW,QAAQ;AAC3B,gBAAU,cAAc,aAAa,KAAK,UAAU,SAAS,KAAK,UAAU,UAAU,OAAO,GAAG;AAAA,IACjG;AAGA,QAAI,KAAK,MAAM;AAAgB,gBAAU;AAGzC,QAAI,WAAW,KAAK,OAAK,EAAE,aAAa,YAAY,EAAE,SAAS,KAAK,QAAQ,EAAE,aAAa,EAAE;AAAG,gBAAU;AAE1G,QAAI,KAAK;AAAc,gBAAU;AACjC,QAAI,KAAK;AAAQ,gBAAU,IAAK,KAAK,OAAO,CAAC,IAAI,KAAK,OAAO,CAAC;AAC9D,QAAI,KAAK;AAAiB,gBAAU;AACpC,QAAI,KAAK,MAAM,YAAY;AAAG,gBAAU;AAExC,QAAI,KAAK;AAAU,gBAAU;AAE7B,QAAI,KAAK,OAAO;AACf,YAAM,kBAAkB,KAAK,MAAM,CAAC,IAAI,KAAK,MAAM,CAAC;AACpD,gBAAU,IAAK,kBAAkB;AAAA,IAClC;AAGA,QAAI,KAAK,QAAQ,WAAW,KAAK,OAAK,EAAE,IAAI;AAAG,gBAAU;AAEzD,WAAO;AAAA,EACR;AAAA;AAAA;AAAA;AAAA,EAKA,OAAiB,aAAa,QAAgB,SAAS,GAAW;AACjE,QAAI,WAAW;AAAG,aAAO,KAAK,cAAc,aAAa,MAAM,IAAI,KAAK;AAExE,YAAQ,QAAQ;AAAA,MAChB,KAAK;AAAO,eAAO;AAAA,MACnB,KAAK;AAAO,eAAO;AAAA,MACnB,KAAK;AAAO,eAAO;AAAA,MACnB,KAAK;AAAO,eAAO;AAAA,MACnB,KAAK;AAAO,eAAO;AAAA,MACnB,KAAK;AAAO,eAAO;AAAA,IACnB;AACA,WAAO;AAAA,EACR;AAAA;AAAA;AAAA;AAAA,EAKU,YAAY,MAAY,YAAoB,SAA0B;AAC/E,UAAM,qBACL,KAAK,aAAa,cAClB,WAAW,KAAK,OAAK,EAAE,aAAa,UAAU;AAE/C,UAAM,oBACL,KAAK,aAAa,aAClB,WAAW,KAAK,OAAK,EAAE,aAAa,SAAS;AAG9C,QAAI,SAAS;AACb,eAAW,EAAC,QAAQ,OAAM,KAAK;AAAA,MAC9B,EAAC,QAAQ,GAAG,QAAQ,KAAK,OAAM;AAAA,MAC/B,EAAC,QAAQ,GAAG,QAAQ,KAAK,MAAM,OAAM;AAAA,MACrC,EAAC,QAAQ,GAAG,QAAQ,KAAK,WAAW,OAAM;AAAA,MAC1C;AAAA,QACC,QAAQ,KAAK,aAAc,KAAK,UAAU,UAAU,OAAO,MAAO;AAAA,QAClE,QAAQ,KAAK,WAAW,SAAS,KAAK,WAAW,SAAS,KAAK,WAAW,MAAM;AAAA,MACjF;AAAA,IACD,GAAG;AACF,UAAI,CAAC,UAAU,WAAW;AAAG;AAE7B,UAAI,OAAO,OAAO;AAAoB,mBAAW,UAAU,KAAK,MAAM,OAAO;AAC7E,UAAI,OAAO,OAAO;AAAmB,mBAAW,UAAU,KAAK,MAAM,OAAO;AAI5E,UAAI,OAAO;AAAK,mBAAW,UAAU,KAAK,MAAM,OAAO,OAAO,QAAQ,UAAU,MAAM,KAAK,IAAI;AAC/F,UAAI,OAAO;AAAK,mBAAW,UAAU,KAAK,MAAM,OAAO,OAAO,QAAQ,UAAU,MAAM,KAAK,IAAI;AAG/F,UAAI,OAAO;AAAK,mBAAW,UAAU,KAAK,MAAM,OAAO,OAAO,QAAQ,UAAU,MAAM,MAAM,MAAM;AAAA,IACnG;AAEA,WAAO;AAAA,EACR;AAAA;AAAA;AAAA;AAAA,EAKU,qBAAqB,MAAoB;AAClD,QAAI,CAAC,CAAC,mBAAmB,eAAe,WAAW,QAAQ,EAAE,SAAS,KAAK,MAAM;AAAG,aAAO;AAE3F,QAAI,yBAAyB;AAC7B,eAAW,EAAC,QAAQ,OAAM,KAAK;AAAA,MAC9B,EAAC,QAAQ,GAAG,QAAQ,KAAK,OAAM;AAAA,MAC/B;AAAA,QACC,QAAQ,KAAK,aAAc,KAAK,UAAU,UAAU,OAAO,MAAO;AAAA,QAClE,QAAQ,KAAK,WAAW;AAAA,MACzB;AAAA,IACD,GAAG;AACF,UAAI,CAAC,UAAU,WAAW;AAAG;AAE7B,YAAM,YAAY,OAAO,OAAO,MAAM,EAAE,OAAO,OAAK,IAAI,CAAC,EAAE;AAC3D,gCAA0B,SAAS;AAAA,IACpC;AAEA,WAAO,IAAK,OAAO;AAAA,EACpB;AAAA;AAAA;AAAA;AAAA,EAKU,cAAc,MAAY,WAAsB,SAAkB,OAAe,SAAyB;AACnH,QAAI;AACJ,YAAQ,KAAK,IAAI;AAAA,MAEjB,KAAK;AACJ,eAAO,MAAM,MAAM,OAAK,EAAE,aAAa,UAAU,IAAI,KAAK;AAAA,MAC3D,KAAK;AACJ,eAAO,MAAM,MAAM,OAAK,EAAE,aAAa,SAAS,IAAI,KAAK;AAAA,MAC1D,KAAK;AACJ,YAAI,MAAM,KAAK,OAAK,EAAE,aAAa,QAAQ;AAAG,iBAAO;AACrD,YAAI,QAAQ,UAAU,MAAM,MAAM,QAAQ,UAAU,MAAM;AAAK,iBAAO;AACtE,eAAO;AAAA,MAGR,KAAK;AACJ,eAAO,MAAM,OAAO,OAAK,EAAE,aAAa,QAAQ,EAAE,SAAS;AAAA,MAC5D,KAAK;AACJ,YAAI,YAAY;AAAU,iBAAO;AAEjC,YAAI,QAAQ,UAAU,KAAK,MAAM,QAAQ,UAAU,MAAM,MAAM,QAAQ,UAAU,MAAM;AAAI,iBAAO;AAClG,eAAO;AAAA,MACR,KAAK;AACJ,gBAAQ,KAAK,IAAI,iBAAiB,QAAQ,OAAO,GAAG;AAAA,UACpD,KAAK;AAAG,mBAAO;AAAA,UACf,KAAK;AAAG,mBAAO;AAAA,QACf;AACA,eAAO;AAAA,MACR,KAAK;AACJ,YAAI,MAAM,KAAK,OAAK,EAAE,aAAa,QAAQ;AAAG,iBAAO;AACrD,eAAO;AAAA,MAGR,KAAK;AACJ,iBAAS,YAAY,UAAU,CAAC,QAAQ,MAAM,SAAS,MAAM,IAAI,KAAK;AACtE,YAAI,MAAM,KAAK,OAAK,EAAE,OAAO,QAAQ;AAAG,oBAAU;AAClD,eAAO;AAAA,MACR,KAAK;AACJ,YAAI,QAAQ,MAAM,SAAS,QAAQ;AAAG,iBAAO;AAE7C,iBAAS;AACT,YAAI,YAAY;AAAe,oBAAU;AACzC,YAAI,MAAM,KAAK,OAAK,EAAE,OAAO,QAAQ;AAAG,oBAAU;AAElD,eAAO;AAAA,MAGR,KAAK;AACJ,eAAO;AAAA,MACR,KAAK;AACJ,eAAO,QAAQ,MAAM,SAAS,QAAQ,IAAI,KAAK;AAAA,MAGhD,KAAK;AAAA,MAAe,KAAK;AACxB,eAAO;AAAA,MAER,KAAK;AACJ,YAAI,MAAM,KAAK,OAAK,EAAE,MAAM,KAAK,KAAK,MAAM,KAAK,OAAK,EAAE,aAAa,SAAS;AAAG,iBAAO;AACxF,eAAO;AAAA,MAER;AAEC,eAAO;AAAA,IACR;AAAA,EACD;AAAA;AAAA;AAAA;AAAA,EAKA,OAAiB,SAAS,SAA0B;AACnD,QAAI,cAAc,QAAQ,EAAE;AAAG,aAAO,cAAc,QAAQ,EAAE;AAE9D,YAAQ,QAAQ,MAAM;AAAA,MACtB,KAAK;AAAQ,eAAO;AAAA,MACpB,KAAK;AAAA,MAAM,KAAK;AAAc,eAAO;AAAA,MACrC,KAAK;AAAM,eAAO;AAAA,MAClB,KAAK;AAAA,MAAM,KAAK;AAAO,eAAO;AAAA,IAC9B;AAEA,WAAO;AAAA,EACR;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,mBACC,SACA,SACA,SACC;AACD,QAAI,CAAC,QAAQ;AAAQ,YAAM,IAAI,MAAM,+BAA+B;AACpE,QAAI,QAAQ,WAAW,QAAQ;AAAQ,YAAM,IAAI,MAAM,6CAA6C;AAEpG,UAAM,cAAc,QAAQ,OAAO,CAAC,GAAG,MAAM,IAAI,GAAG,CAAC;AAErD,QAAI,eAAe,KAAK,KAAK,KAAK,GAAG,WAAW;AAChD,aAAS,IAAI,GAAG,IAAI,QAAQ,QAAQ,KAAK;AACxC,sBAAgB,QAAQ,CAAC;AACzB,UAAI,eAAe,GAAG;AACrB,cAAM,SAAS,QAAQ,CAAC;AACxB,YAAI,SAAS;AAAQ,kBAAQ,OAAO,GAAG,CAAC;AACxC,eAAO;AAAA,MACR;AAAA,IACD;AAEA,QAAI,SAAS,UAAU,QAAQ;AAAQ,aAAO,QAAQ,IAAI;AAC1D,WAAO,QAAQ,QAAQ,SAAS,CAAC;AAAA,EAClC;AAAA,EAEA,QAAQ,MAAgB;AACvB,SAAK,KAAK,OAAO;AAAA,EAClB;AACD;", "names": ["weight"] }