[Balance] Make sure trainers are using fully evolved Pokémon by gym 3 (#3499)
* Make sure trainers are using fully evolved Pokemon by gym 3 * Expand comment info Co-authored-by: Mumble <kimjoanne@protonmail.com> * Implement suggestions * Update `getPokemonSpecies()` to throw an error if passed `undefined` --------- Co-authored-by: Mumble <kimjoanne@protonmail.com>
This commit is contained in:
parent
f5757f0a3a
commit
d234466d61
|
@ -49,7 +49,8 @@ export function getDailyRunStarters(scene: BattleScene, seed: string): Starter[]
|
||||||
const costSpecies = Object.keys(speciesStarters)
|
const costSpecies = Object.keys(speciesStarters)
|
||||||
.map(s => parseInt(s) as Species)
|
.map(s => parseInt(s) as Species)
|
||||||
.filter(s => speciesStarters[s] === cost);
|
.filter(s => speciesStarters[s] === cost);
|
||||||
const starterSpecies = getPokemonSpecies(getPokemonSpecies(Utils.randSeedItem(costSpecies)).getTrainerSpeciesForLevel(startingLevel, true, PartyMemberStrength.STRONGER));
|
const randPkmSpecies = getPokemonSpecies(Utils.randSeedItem(costSpecies));
|
||||||
|
const starterSpecies = getPokemonSpecies(randPkmSpecies.getTrainerSpeciesForLevel(startingLevel, true, PartyMemberStrength.STRONGER));
|
||||||
starters.push(getDailyRunStarter(scene, starterSpecies, startingLevel));
|
starters.push(getDailyRunStarter(scene, starterSpecies, startingLevel));
|
||||||
}
|
}
|
||||||
}, 0, seed);
|
}, 0, seed);
|
||||||
|
|
|
@ -1,24 +1,21 @@
|
||||||
|
import { Localizable } from "#app/interfaces/locales";
|
||||||
|
import { Abilities } from "#enums/abilities";
|
||||||
|
import { PartyMemberStrength } from "#enums/party-member-strength";
|
||||||
|
import { Species } from "#enums/species";
|
||||||
|
import { QuantizerCelebi, argbFromRgba, rgbaFromArgb } from "@material/material-color-utilities";
|
||||||
|
import i18next from "i18next";
|
||||||
import BattleScene, { AnySound } from "../battle-scene";
|
import BattleScene, { AnySound } from "../battle-scene";
|
||||||
import { Variant, variantColorCache } from "./variant";
|
import { GameMode } from "../game-mode";
|
||||||
import { variantData } from "./variant";
|
import { StarterMoveset } from "../system/game-data";
|
||||||
|
import * as Utils from "../utils";
|
||||||
|
import { uncatchableSpecies } from "./biomes";
|
||||||
|
import { speciesEggMoves } from "./egg-moves";
|
||||||
import { GrowthRate } from "./exp";
|
import { GrowthRate } from "./exp";
|
||||||
import { EvolutionLevel, SpeciesWildEvolutionDelay, pokemonEvolutions, pokemonPrevolutions } from "./pokemon-evolutions";
|
import { EvolutionLevel, SpeciesWildEvolutionDelay, pokemonEvolutions, pokemonPrevolutions } from "./pokemon-evolutions";
|
||||||
import { Type } from "./type";
|
import { Type } from "./type";
|
||||||
import { LevelMoves, pokemonFormLevelMoves, pokemonFormLevelMoves as pokemonSpeciesFormLevelMoves, pokemonSpeciesLevelMoves } from "./pokemon-level-moves";
|
import { LevelMoves, pokemonFormLevelMoves, pokemonFormLevelMoves as pokemonSpeciesFormLevelMoves, pokemonSpeciesLevelMoves } from "./pokemon-level-moves";
|
||||||
import { uncatchableSpecies } from "./biomes";
|
|
||||||
import * as Utils from "../utils";
|
|
||||||
import { StarterMoveset } from "../system/game-data";
|
|
||||||
import { speciesEggMoves } from "./egg-moves";
|
|
||||||
import { GameMode } from "../game-mode";
|
|
||||||
import { QuantizerCelebi, argbFromRgba, rgbaFromArgb } from "@material/material-color-utilities";
|
|
||||||
import { VariantSet } from "./variant";
|
|
||||||
import i18next from "i18next";
|
|
||||||
import { Localizable } from "#app/interfaces/locales";
|
|
||||||
import { Stat } from "./pokemon-stat";
|
import { Stat } from "./pokemon-stat";
|
||||||
import { Abilities } from "#enums/abilities";
|
import { Variant, VariantSet, variantColorCache, variantData } from "./variant";
|
||||||
import { PartyMemberStrength } from "#enums/party-member-strength";
|
|
||||||
import { Species } from "#enums/species";
|
|
||||||
|
|
||||||
export enum Region {
|
export enum Region {
|
||||||
NORMAL,
|
NORMAL,
|
||||||
|
@ -28,7 +25,15 @@ export enum Region {
|
||||||
PALDEA
|
PALDEA
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getPokemonSpecies(species: Species | Species[]): PokemonSpecies {
|
/**
|
||||||
|
* Gets the {@linkcode PokemonSpecies} object associated with the {@linkcode Species} enum given
|
||||||
|
* @param species The species to fetch
|
||||||
|
* @returns The associated {@linkcode PokemonSpecies} object
|
||||||
|
*/
|
||||||
|
export function getPokemonSpecies(species: Species | Species[] | undefined): PokemonSpecies {
|
||||||
|
if (!species) {
|
||||||
|
throw new Error("`species` must not be undefined in `getPokemonSpecies()`");
|
||||||
|
}
|
||||||
// If a special pool (named trainers) is used here it CAN happen that they have a array as species (which means choose one of those two). So we catch that with this code block
|
// If a special pool (named trainers) is used here it CAN happen that they have a array as species (which means choose one of those two). So we catch that with this code block
|
||||||
if (Array.isArray(species)) {
|
if (Array.isArray(species)) {
|
||||||
// Pick a random species from the list
|
// Pick a random species from the list
|
||||||
|
@ -648,8 +653,8 @@ export default class PokemonSpecies extends PokemonSpeciesForm implements Locali
|
||||||
return this.getSpeciesForLevel(level, allowEvolving, false, (isBoss ? PartyMemberStrength.WEAKER : PartyMemberStrength.AVERAGE) + (gameMode?.isEndless ? 1 : 0));
|
return this.getSpeciesForLevel(level, allowEvolving, false, (isBoss ? PartyMemberStrength.WEAKER : PartyMemberStrength.AVERAGE) + (gameMode?.isEndless ? 1 : 0));
|
||||||
}
|
}
|
||||||
|
|
||||||
getTrainerSpeciesForLevel(level: integer, allowEvolving: boolean = false, strength: PartyMemberStrength): Species {
|
getTrainerSpeciesForLevel(level: integer, allowEvolving: boolean = false, strength: PartyMemberStrength, currentWave: number = 0): Species {
|
||||||
return this.getSpeciesForLevel(level, allowEvolving, true, strength);
|
return this.getSpeciesForLevel(level, allowEvolving, true, strength, currentWave);
|
||||||
}
|
}
|
||||||
|
|
||||||
private getStrengthLevelDiff(strength: PartyMemberStrength): integer {
|
private getStrengthLevelDiff(strength: PartyMemberStrength): integer {
|
||||||
|
@ -669,7 +674,7 @@ export default class PokemonSpecies extends PokemonSpeciesForm implements Locali
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
getSpeciesForLevel(level: integer, allowEvolving: boolean = false, forTrainer: boolean = false, strength: PartyMemberStrength = PartyMemberStrength.WEAKER): Species {
|
getSpeciesForLevel(level: integer, allowEvolving: boolean = false, forTrainer: boolean = false, strength: PartyMemberStrength = PartyMemberStrength.WEAKER, currentWave: number = 0): Species {
|
||||||
const prevolutionLevels = this.getPrevolutionLevels();
|
const prevolutionLevels = this.getPrevolutionLevels();
|
||||||
|
|
||||||
if (prevolutionLevels.length) {
|
if (prevolutionLevels.length) {
|
||||||
|
@ -730,6 +735,11 @@ export default class PokemonSpecies extends PokemonSpeciesForm implements Locali
|
||||||
evolutionChance = Math.min(0.65 * easeInFunc(Math.min(Math.max(level - evolutionLevel, 0), preferredMinLevel) / preferredMinLevel) + 0.35 * easeOutFunc(Math.min(Math.max(level - evolutionLevel, 0), preferredMinLevel * 2.5) / (preferredMinLevel * 2.5)), 1);
|
evolutionChance = Math.min(0.65 * easeInFunc(Math.min(Math.max(level - evolutionLevel, 0), preferredMinLevel) / preferredMinLevel) + 0.35 * easeOutFunc(Math.min(Math.max(level - evolutionLevel, 0), preferredMinLevel * 2.5) / (preferredMinLevel * 2.5)), 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
/* (Most) Trainers shouldn't be using unevolved Pokemon by the third gym leader / wave 80. Exceptions to this include Breeders, whose large teams are balanced by the use of weaker pokemon */
|
||||||
|
if (currentWave >= 80 && forTrainer && strength > PartyMemberStrength.WEAKER) {
|
||||||
|
evolutionChance = 1;
|
||||||
|
noEvolutionChance = 0;
|
||||||
|
}
|
||||||
|
|
||||||
if (evolutionChance > 0) {
|
if (evolutionChance > 0) {
|
||||||
if (isRegionalEvolution) {
|
if (isRegionalEvolution) {
|
||||||
|
@ -754,7 +764,7 @@ export default class PokemonSpecies extends PokemonSpeciesForm implements Locali
|
||||||
|
|
||||||
for (const weight of evolutionPool.keys()) {
|
for (const weight of evolutionPool.keys()) {
|
||||||
if (randValue < weight) {
|
if (randValue < weight) {
|
||||||
return getPokemonSpecies(evolutionPool.get(weight)!).getSpeciesForLevel(level, true, forTrainer, strength); // TODO: is the bang correct?
|
return getPokemonSpecies(evolutionPool.get(weight)).getSpeciesForLevel(level, true, forTrainer, strength, currentWave);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -142,7 +142,7 @@ export const trainerPartyTemplates = {
|
||||||
FIVE_WEAK_BALANCED: new TrainerPartyTemplate(5, PartyMemberStrength.WEAK, false, true),
|
FIVE_WEAK_BALANCED: new TrainerPartyTemplate(5, PartyMemberStrength.WEAK, false, true),
|
||||||
SIX_WEAKER: new TrainerPartyTemplate(6, PartyMemberStrength.WEAKER),
|
SIX_WEAKER: new TrainerPartyTemplate(6, PartyMemberStrength.WEAKER),
|
||||||
SIX_WEAKER_SAME: new TrainerPartyTemplate(6, PartyMemberStrength.WEAKER, true),
|
SIX_WEAKER_SAME: new TrainerPartyTemplate(6, PartyMemberStrength.WEAKER, true),
|
||||||
SIX_WEAK_SAME: new TrainerPartyTemplate(6, PartyMemberStrength.WEAKER, true),
|
SIX_WEAK_SAME: new TrainerPartyTemplate(6, PartyMemberStrength.WEAK, true),
|
||||||
SIX_WEAK_BALANCED: new TrainerPartyTemplate(6, PartyMemberStrength.WEAK, false, true),
|
SIX_WEAK_BALANCED: new TrainerPartyTemplate(6, PartyMemberStrength.WEAK, false, true),
|
||||||
|
|
||||||
GYM_LEADER_1: new TrainerPartyCompoundTemplate(new TrainerPartyTemplate(1, PartyMemberStrength.AVERAGE), new TrainerPartyTemplate(1, PartyMemberStrength.STRONG)),
|
GYM_LEADER_1: new TrainerPartyCompoundTemplate(new TrainerPartyTemplate(1, PartyMemberStrength.AVERAGE), new TrainerPartyTemplate(1, PartyMemberStrength.STRONG)),
|
||||||
|
@ -965,7 +965,7 @@ function getRandomPartyMemberFunc(speciesPool: Species[], trainerSlot: TrainerSl
|
||||||
return (scene: BattleScene, level: integer, strength: PartyMemberStrength) => {
|
return (scene: BattleScene, level: integer, strength: PartyMemberStrength) => {
|
||||||
let species = Utils.randSeedItem(speciesPool);
|
let species = Utils.randSeedItem(speciesPool);
|
||||||
if (!ignoreEvolution) {
|
if (!ignoreEvolution) {
|
||||||
species = getPokemonSpecies(species).getTrainerSpeciesForLevel(level, true, strength);
|
species = getPokemonSpecies(species).getTrainerSpeciesForLevel(level, true, strength, scene.currentBattle.waveIndex);
|
||||||
}
|
}
|
||||||
return scene.addEnemyPokemon(getPokemonSpecies(species), level, trainerSlot, undefined, undefined, postProcess);
|
return scene.addEnemyPokemon(getPokemonSpecies(species), level, trainerSlot, undefined, undefined, postProcess);
|
||||||
};
|
};
|
||||||
|
@ -975,7 +975,7 @@ function getSpeciesFilterRandomPartyMemberFunc(speciesFilter: PokemonSpeciesFilt
|
||||||
const originalSpeciesFilter = speciesFilter;
|
const originalSpeciesFilter = speciesFilter;
|
||||||
speciesFilter = (species: PokemonSpecies) => (allowLegendaries || (!species.legendary && !species.subLegendary && !species.mythical)) && !species.isTrainerForbidden() && originalSpeciesFilter(species);
|
speciesFilter = (species: PokemonSpecies) => (allowLegendaries || (!species.legendary && !species.subLegendary && !species.mythical)) && !species.isTrainerForbidden() && originalSpeciesFilter(species);
|
||||||
return (scene: BattleScene, level: integer, strength: PartyMemberStrength) => {
|
return (scene: BattleScene, level: integer, strength: PartyMemberStrength) => {
|
||||||
const ret = scene.addEnemyPokemon(getPokemonSpecies(scene.randomSpecies(scene.currentBattle.waveIndex, level, false, speciesFilter).getTrainerSpeciesForLevel(level, true, strength)), level, trainerSlot, undefined, undefined, postProcess);
|
const ret = scene.addEnemyPokemon(getPokemonSpecies(scene.randomSpecies(scene.currentBattle.waveIndex, level, false, speciesFilter).getTrainerSpeciesForLevel(level, true, strength, scene.currentBattle.waveIndex)), level, trainerSlot, undefined, undefined, postProcess);
|
||||||
return ret;
|
return ret;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -359,12 +359,12 @@ export default class Trainer extends Phaser.GameObjects.Container {
|
||||||
let species = useNewSpeciesPool
|
let species = useNewSpeciesPool
|
||||||
? getPokemonSpecies(newSpeciesPool[Math.floor(Math.random() * newSpeciesPool.length)])
|
? getPokemonSpecies(newSpeciesPool[Math.floor(Math.random() * newSpeciesPool.length)])
|
||||||
: template.isSameSpecies(index) && index > offset
|
: template.isSameSpecies(index) && index > offset
|
||||||
? getPokemonSpecies(battle.enemyParty[offset].species.getTrainerSpeciesForLevel(level, false, template.getStrength(offset)))
|
? getPokemonSpecies(battle.enemyParty[offset].species.getTrainerSpeciesForLevel(level, false, template.getStrength(offset), this.scene.currentBattle.waveIndex))
|
||||||
: this.genNewPartyMemberSpecies(level, strength);
|
: this.genNewPartyMemberSpecies(level, strength);
|
||||||
|
|
||||||
// If the species is from newSpeciesPool, we need to adjust it based on the level and strength
|
// If the species is from newSpeciesPool, we need to adjust it based on the level and strength
|
||||||
if (newSpeciesPool) {
|
if (newSpeciesPool) {
|
||||||
species = getPokemonSpecies(species.getSpeciesForLevel(level, true, true, strength));
|
species = getPokemonSpecies(species.getSpeciesForLevel(level, true, true, strength, this.scene.currentBattle.waveIndex));
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = this.scene.addEnemyPokemon(species, level, !this.isDouble() || !(index % 2) ? TrainerSlot.TRAINER : TrainerSlot.TRAINER_PARTNER);
|
ret = this.scene.addEnemyPokemon(species, level, !this.isDouble() || !(index % 2) ? TrainerSlot.TRAINER : TrainerSlot.TRAINER_PARTNER);
|
||||||
|
@ -393,7 +393,7 @@ export default class Trainer extends Phaser.GameObjects.Container {
|
||||||
species = this.scene.randomSpecies(battle.waveIndex, level, false, this.config.speciesFilter);
|
species = this.scene.randomSpecies(battle.waveIndex, level, false, this.config.speciesFilter);
|
||||||
}
|
}
|
||||||
|
|
||||||
let ret = getPokemonSpecies(species.getTrainerSpeciesForLevel(level, true, strength));
|
let ret = getPokemonSpecies(species.getTrainerSpeciesForLevel(level, true, strength, this.scene.currentBattle.waveIndex));
|
||||||
let retry = false;
|
let retry = false;
|
||||||
|
|
||||||
console.log(ret.getName());
|
console.log(ret.getName());
|
||||||
|
@ -412,7 +412,7 @@ export default class Trainer extends Phaser.GameObjects.Container {
|
||||||
console.log("Attempting reroll of species evolution to fit specialty type...");
|
console.log("Attempting reroll of species evolution to fit specialty type...");
|
||||||
let evoAttempt = 0;
|
let evoAttempt = 0;
|
||||||
while (retry && evoAttempt++ < 10) {
|
while (retry && evoAttempt++ < 10) {
|
||||||
ret = getPokemonSpecies(species.getTrainerSpeciesForLevel(level, true, strength));
|
ret = getPokemonSpecies(species.getTrainerSpeciesForLevel(level, true, strength, this.scene.currentBattle.waveIndex));
|
||||||
console.log(ret.name);
|
console.log(ret.name);
|
||||||
if (this.config.specialtyTypes.find(t => ret.isOfType(t))) {
|
if (this.config.specialtyTypes.find(t => ret.isOfType(t))) {
|
||||||
retry = false;
|
retry = false;
|
||||||
|
|
Loading…
Reference in New Issue