From 0afec8fd35c6567aaeeac245e026bd1b0db4b8f5 Mon Sep 17 00:00:00 2001 From: Flashfyre Date: Thu, 28 Mar 2024 14:05:15 -0400 Subject: [PATCH] Rebalance trainer evolution logic --- src/data/daily-run.ts | 3 +- src/data/enums/party-member-strength.ts | 8 ++ src/data/pokemon-species.ts | 68 ++++++++---- src/data/trainer-config.ts | 136 ++++++++++++------------ src/field/arena.ts | 3 +- src/field/pokemon.ts | 4 +- src/field/trainer.ts | 44 ++++---- 7 files changed, 152 insertions(+), 114 deletions(-) create mode 100644 src/data/enums/party-member-strength.ts diff --git a/src/data/daily-run.ts b/src/data/daily-run.ts index 98d87c93d..64e6f2d93 100644 --- a/src/data/daily-run.ts +++ b/src/data/daily-run.ts @@ -5,6 +5,7 @@ import { Starter } from "../ui/starter-select-ui-handler"; import * as Utils from "../utils"; import { Species } from "./enums/species"; import { getPokemonSpecies, speciesStarters } from "./pokemon-species"; +import { PartyMemberStrength } from "./enums/party-member-strength"; export interface DailyRunConfig { seed: integer; @@ -39,7 +40,7 @@ export function getDailyRunStarters(scene: BattleScene, seed: string): Starter[] const weightSpecies = Object.keys(speciesStarters) .map(s => parseInt(s) as Species) .filter(s => speciesStarters[s] === weight); - const starterSpecies = getPokemonSpecies(getPokemonSpecies(Utils.randSeedItem(weightSpecies)).getSpeciesForLevel(startingLevel, true, true, false, true)); + const starterSpecies = getPokemonSpecies(getPokemonSpecies(Utils.randSeedItem(weightSpecies)).getTrainerSpeciesForLevel(startingLevel, true, PartyMemberStrength.STRONGER)); const pokemon = new PlayerPokemon(scene, starterSpecies, startingLevel, undefined, undefined, undefined, undefined, undefined, undefined, undefined); const starter: Starter = { species: starterSpecies, diff --git a/src/data/enums/party-member-strength.ts b/src/data/enums/party-member-strength.ts new file mode 100644 index 000000000..793796a65 --- /dev/null +++ b/src/data/enums/party-member-strength.ts @@ -0,0 +1,8 @@ +export enum PartyMemberStrength { + WEAKEST, + WEAKER, + WEAK, + AVERAGE, + STRONG, + STRONGER +} diff --git a/src/data/pokemon-species.ts b/src/data/pokemon-species.ts index 3e2bf2654..92085fe23 100644 --- a/src/data/pokemon-species.ts +++ b/src/data/pokemon-species.ts @@ -9,6 +9,8 @@ import { uncatchableSpecies } from './biomes'; import * as Utils from '../utils'; import { StarterMoveset } from '../system/game-data'; import { speciesEggMoves } from './egg-moves'; +import { PartyMemberStrength } from "./enums/party-member-strength"; +import { GameMode } from '../game-mode'; export enum Region { NORMAL, @@ -426,7 +428,32 @@ export default class PokemonSpecies extends PokemonSpeciesForm { return this.name; } - getSpeciesForLevel(level: integer, allowEvolving: boolean = false, forTrainer: boolean = false, isBoss: boolean = false, player: boolean = false): Species { + getWildSpeciesForLevel(level: integer, allowEvolving: boolean, isBoss: boolean, gameMode: GameMode): Species { + return this.getSpeciesForLevel(level, allowEvolving, false, (isBoss ? PartyMemberStrength.WEAKER : PartyMemberStrength.AVERAGE) + (gameMode?.isEndless ? 1 : 0)); + } + + getTrainerSpeciesForLevel(level: integer, allowEvolving: boolean = false, strength: PartyMemberStrength): Species { + return this.getSpeciesForLevel(level, allowEvolving, true, strength); + } + + private getStrengthLevelDiff(strength: PartyMemberStrength): integer { + switch (Math.min(strength, PartyMemberStrength.STRONGER)) { + case PartyMemberStrength.WEAKEST: + return 60; + case PartyMemberStrength.WEAKER: + return 40; + case PartyMemberStrength.WEAK: + return 20; + case PartyMemberStrength.AVERAGE: + return 10; + case PartyMemberStrength.STRONG: + return 5; + default: + return 0; + } + } + + getSpeciesForLevel(level: integer, allowEvolving: boolean = false, forTrainer: boolean = false, strength: PartyMemberStrength = PartyMemberStrength.WEAKER): Species { const prevolutionLevels = this.getPrevolutionLevels(); if (prevolutionLevels.length) { @@ -460,25 +487,28 @@ export default class PokemonSpecies extends PokemonSpeciesForm { if (!forTrainer && isRegionalEvolution) evolutionChance = 0; - else if (ev.wildDelay === SpeciesWildEvolutionDelay.NONE) { - if (player) - evolutionChance = 1; - else { - const maxLevelDiff = forTrainer || isBoss ? forTrainer && isBoss ? 10 : 20 : 40; - const minChance = forTrainer ? 0.5 : 0.75; - evolutionChance = Math.min(minChance + easeInFunc(Math.min(level - ev.level, maxLevelDiff) / maxLevelDiff) * (1 - minChance), 1); - } - } else { - let preferredMinLevel = (ev.level - 1) + ev.wildDelay * (player ? 0 : forTrainer || isBoss ? forTrainer && isBoss ? 5 : 10 : 20); - let evolutionLevel = ev.level > 1 ? ev.level : Math.floor(preferredMinLevel / 2); + else { + if (ev.wildDelay === SpeciesWildEvolutionDelay.NONE) { + if (strength === PartyMemberStrength.STRONGER) + evolutionChance = 1; + else { + const maxLevelDiff = this.getStrengthLevelDiff(strength); + const minChance: number = 0.875 - 0.125 * strength; + + evolutionChance = Math.min(minChance + easeInFunc(Math.min(level - ev.level, maxLevelDiff) / maxLevelDiff) * (1 - minChance), 1); + } + } else { + let preferredMinLevel = (ev.level - 1) + ev.wildDelay * this.getStrengthLevelDiff(strength + 1); + let evolutionLevel = ev.level > 1 ? ev.level : Math.floor(preferredMinLevel / 2); - if (ev.level <= 1 && pokemonPrevolutions.hasOwnProperty(this.speciesId)) { - const prevolutionLevel = pokemonEvolutions[pokemonPrevolutions[this.speciesId]].find(ev => ev.speciesId === this.speciesId).level; - if (prevolutionLevel > 1) - evolutionLevel = prevolutionLevel; - } + if (ev.level <= 1 && pokemonPrevolutions.hasOwnProperty(this.speciesId)) { + const prevolutionLevel = pokemonEvolutions[pokemonPrevolutions[this.speciesId]].find(ev => ev.speciesId === this.speciesId).level; + if (prevolutionLevel > 1) + evolutionLevel = prevolutionLevel; + } - evolutionChance = Math.min(0.65 * easeInFunc((Math.min(Math.max(level - evolutionLevel, 0), preferredMinLevel) / preferredMinLevel)) + 0.35 * easeOutFunc(Math.min(level - evolutionLevel, 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(level - evolutionLevel, preferredMinLevel * 2.5) / (preferredMinLevel * 2.5)), 1); + } } if (evolutionChance > 0) { @@ -501,7 +531,7 @@ export default class PokemonSpecies extends PokemonSpeciesForm { for (let weight of evolutionPool.keys()) { if (randValue < weight) - return getPokemonSpecies(evolutionPool.get(weight)).getSpeciesForLevel(level, true, forTrainer, isBoss); + return getPokemonSpecies(evolutionPool.get(weight)).getSpeciesForLevel(level, true, forTrainer, strength); } return this.speciesId; diff --git a/src/data/trainer-config.ts b/src/data/trainer-config.ts index 41bece652..f641b7680 100644 --- a/src/data/trainer-config.ts +++ b/src/data/trainer-config.ts @@ -13,6 +13,7 @@ import { Type } from "./type"; import { initTrainerTypeDialogue } from "./dialogue"; import { PersistentModifier } from "../modifier/modifier"; import { TrainerVariant } from "../field/trainer"; +import { PartyMemberStrength } from "./enums/party-member-strength"; export enum TrainerPoolTier { COMMON, @@ -26,15 +27,6 @@ export interface TrainerTierPools { [key: integer]: Species[] } -export enum TrainerPartyMemberStrength { - WEAKEST, - WEAKER, - WEAK, - AVERAGE, - STRONG, - STRONGER -} - export enum TrainerSlot { NONE, TRAINER, @@ -43,18 +35,18 @@ export enum TrainerSlot { export class TrainerPartyTemplate { public size: integer; - public strength: TrainerPartyMemberStrength; + public strength: PartyMemberStrength; public sameSpecies: boolean; public balanced: boolean; - constructor(size: integer, strength: TrainerPartyMemberStrength, sameSpecies?: boolean, balanced?: boolean) { + constructor(size: integer, strength: PartyMemberStrength, sameSpecies?: boolean, balanced?: boolean) { this.size = size; this.strength = strength; this.sameSpecies = !!sameSpecies; this.balanced = !!balanced; } - getStrength(index: integer): TrainerPartyMemberStrength { + getStrength(index: integer): PartyMemberStrength { return this.strength; } @@ -74,11 +66,11 @@ export class TrainerPartyCompoundTemplate extends TrainerPartyTemplate { super(templates.reduce((total: integer, template: TrainerPartyTemplate) => { total += template.size; return total; - }, 0), TrainerPartyMemberStrength.AVERAGE); + }, 0), PartyMemberStrength.AVERAGE); this.templates = templates; } - getStrength(index: integer): TrainerPartyMemberStrength { + getStrength(index: integer): PartyMemberStrength { let t = 0; for (let template of this.templates) { if (t + template.size > index) @@ -113,61 +105,61 @@ export class TrainerPartyCompoundTemplate extends TrainerPartyTemplate { } export const trainerPartyTemplates = { - ONE_WEAK_ONE_STRONG: new TrainerPartyCompoundTemplate(new TrainerPartyTemplate(1, TrainerPartyMemberStrength.WEAK), new TrainerPartyTemplate(1, TrainerPartyMemberStrength.STRONG)), - ONE_AVG: new TrainerPartyTemplate(1, TrainerPartyMemberStrength.AVERAGE), - ONE_AVG_ONE_STRONG: new TrainerPartyCompoundTemplate(new TrainerPartyTemplate(1, TrainerPartyMemberStrength.AVERAGE), new TrainerPartyTemplate(1, TrainerPartyMemberStrength.STRONG)), - ONE_STRONG: new TrainerPartyTemplate(1, TrainerPartyMemberStrength.STRONG), - ONE_STRONGER: new TrainerPartyTemplate(1, TrainerPartyMemberStrength.STRONGER), - TWO_WEAKER: new TrainerPartyTemplate(2, TrainerPartyMemberStrength.WEAKER), - TWO_WEAK: new TrainerPartyTemplate(2, TrainerPartyMemberStrength.WEAK), - TWO_WEAK_ONE_AVG: new TrainerPartyCompoundTemplate(new TrainerPartyTemplate(2, TrainerPartyMemberStrength.WEAK), new TrainerPartyTemplate(1, TrainerPartyMemberStrength.AVERAGE)), - TWO_WEAK_SAME_ONE_AVG: new TrainerPartyCompoundTemplate(new TrainerPartyTemplate(2, TrainerPartyMemberStrength.WEAK, true), new TrainerPartyTemplate(1, TrainerPartyMemberStrength.AVERAGE)), - TWO_WEAK_SAME_TWO_WEAK_SAME: new TrainerPartyCompoundTemplate(new TrainerPartyTemplate(2, TrainerPartyMemberStrength.WEAK, true), new TrainerPartyTemplate(2, TrainerPartyMemberStrength.WEAK, true)), - TWO_WEAK_ONE_STRONG: new TrainerPartyCompoundTemplate(new TrainerPartyTemplate(2, TrainerPartyMemberStrength.WEAK), new TrainerPartyTemplate(1, TrainerPartyMemberStrength.STRONG)), - TWO_AVG: new TrainerPartyTemplate(2, TrainerPartyMemberStrength.AVERAGE), - TWO_AVG_ONE_STRONG: new TrainerPartyCompoundTemplate(new TrainerPartyTemplate(2, TrainerPartyMemberStrength.AVERAGE), new TrainerPartyTemplate(1, TrainerPartyMemberStrength.STRONG)), - TWO_AVG_SAME_ONE_AVG: new TrainerPartyCompoundTemplate(new TrainerPartyTemplate(2, TrainerPartyMemberStrength.AVERAGE, true), new TrainerPartyTemplate(1, TrainerPartyMemberStrength.AVERAGE)), - TWO_AVG_SAME_ONE_STRONG: new TrainerPartyCompoundTemplate(new TrainerPartyTemplate(2, TrainerPartyMemberStrength.AVERAGE, true), new TrainerPartyTemplate(1, TrainerPartyMemberStrength.STRONG)), - TWO_AVG_SAME_TWO_AVG_SAME: new TrainerPartyCompoundTemplate(new TrainerPartyTemplate(2, TrainerPartyMemberStrength.AVERAGE, true), new TrainerPartyTemplate(2, TrainerPartyMemberStrength.AVERAGE, true)), - TWO_STRONG: new TrainerPartyTemplate(2, TrainerPartyMemberStrength.STRONG), - THREE_WEAK: new TrainerPartyTemplate(3, TrainerPartyMemberStrength.WEAK), - THREE_WEAK_SAME: new TrainerPartyTemplate(3, TrainerPartyMemberStrength.WEAK, true), - THREE_AVG: new TrainerPartyTemplate(3, TrainerPartyMemberStrength.AVERAGE), - THREE_AVG_SAME: new TrainerPartyTemplate(3, TrainerPartyMemberStrength.AVERAGE, true), - THREE_WEAK_BALANCED: new TrainerPartyTemplate(3, TrainerPartyMemberStrength.WEAK, false, true), - FOUR_WEAKER: new TrainerPartyTemplate(4, TrainerPartyMemberStrength.WEAKER), - FOUR_WEAKER_SAME: new TrainerPartyTemplate(4, TrainerPartyMemberStrength.WEAKER, true), - FOUR_WEAK: new TrainerPartyTemplate(4, TrainerPartyMemberStrength.WEAK), - FOUR_WEAK_SAME: new TrainerPartyTemplate(4, TrainerPartyMemberStrength.WEAK, true), - FOUR_WEAK_BALANCED: new TrainerPartyTemplate(4, TrainerPartyMemberStrength.WEAK, false, true), - FIVE_WEAKER: new TrainerPartyTemplate(5, TrainerPartyMemberStrength.WEAKER), - FIVE_WEAK: new TrainerPartyTemplate(5, TrainerPartyMemberStrength.WEAK), - FIVE_WEAK_BALANCED: new TrainerPartyTemplate(5, TrainerPartyMemberStrength.WEAK, false, true), - SIX_WEAKER: new TrainerPartyTemplate(6, TrainerPartyMemberStrength.WEAKER), - SIX_WEAKER_SAME: new TrainerPartyTemplate(6, TrainerPartyMemberStrength.WEAKER, true), - SIX_WEAK_SAME: new TrainerPartyTemplate(6, TrainerPartyMemberStrength.WEAKER, true), - SIX_WEAK_BALANCED: new TrainerPartyTemplate(6, TrainerPartyMemberStrength.WEAK, false, true), + ONE_WEAK_ONE_STRONG: new TrainerPartyCompoundTemplate(new TrainerPartyTemplate(1, PartyMemberStrength.WEAK), new TrainerPartyTemplate(1, PartyMemberStrength.STRONG)), + ONE_AVG: new TrainerPartyTemplate(1, PartyMemberStrength.AVERAGE), + ONE_AVG_ONE_STRONG: new TrainerPartyCompoundTemplate(new TrainerPartyTemplate(1, PartyMemberStrength.AVERAGE), new TrainerPartyTemplate(1, PartyMemberStrength.STRONG)), + ONE_STRONG: new TrainerPartyTemplate(1, PartyMemberStrength.STRONG), + ONE_STRONGER: new TrainerPartyTemplate(1, PartyMemberStrength.STRONGER), + TWO_WEAKER: new TrainerPartyTemplate(2, PartyMemberStrength.WEAKER), + TWO_WEAK: new TrainerPartyTemplate(2, PartyMemberStrength.WEAK), + TWO_WEAK_ONE_AVG: new TrainerPartyCompoundTemplate(new TrainerPartyTemplate(2, PartyMemberStrength.WEAK), new TrainerPartyTemplate(1, PartyMemberStrength.AVERAGE)), + TWO_WEAK_SAME_ONE_AVG: new TrainerPartyCompoundTemplate(new TrainerPartyTemplate(2, PartyMemberStrength.WEAK, true), new TrainerPartyTemplate(1, PartyMemberStrength.AVERAGE)), + TWO_WEAK_SAME_TWO_WEAK_SAME: new TrainerPartyCompoundTemplate(new TrainerPartyTemplate(2, PartyMemberStrength.WEAK, true), new TrainerPartyTemplate(2, PartyMemberStrength.WEAK, true)), + TWO_WEAK_ONE_STRONG: new TrainerPartyCompoundTemplate(new TrainerPartyTemplate(2, PartyMemberStrength.WEAK), new TrainerPartyTemplate(1, PartyMemberStrength.STRONG)), + TWO_AVG: new TrainerPartyTemplate(2, PartyMemberStrength.AVERAGE), + TWO_AVG_ONE_STRONG: new TrainerPartyCompoundTemplate(new TrainerPartyTemplate(2, PartyMemberStrength.AVERAGE), new TrainerPartyTemplate(1, PartyMemberStrength.STRONG)), + TWO_AVG_SAME_ONE_AVG: new TrainerPartyCompoundTemplate(new TrainerPartyTemplate(2, PartyMemberStrength.AVERAGE, true), new TrainerPartyTemplate(1, PartyMemberStrength.AVERAGE)), + TWO_AVG_SAME_ONE_STRONG: new TrainerPartyCompoundTemplate(new TrainerPartyTemplate(2, PartyMemberStrength.AVERAGE, true), new TrainerPartyTemplate(1, PartyMemberStrength.STRONG)), + TWO_AVG_SAME_TWO_AVG_SAME: new TrainerPartyCompoundTemplate(new TrainerPartyTemplate(2, PartyMemberStrength.AVERAGE, true), new TrainerPartyTemplate(2, PartyMemberStrength.AVERAGE, true)), + TWO_STRONG: new TrainerPartyTemplate(2, PartyMemberStrength.STRONG), + THREE_WEAK: new TrainerPartyTemplate(3, PartyMemberStrength.WEAK), + THREE_WEAK_SAME: new TrainerPartyTemplate(3, PartyMemberStrength.WEAK, true), + THREE_AVG: new TrainerPartyTemplate(3, PartyMemberStrength.AVERAGE), + THREE_AVG_SAME: new TrainerPartyTemplate(3, PartyMemberStrength.AVERAGE, true), + THREE_WEAK_BALANCED: new TrainerPartyTemplate(3, PartyMemberStrength.WEAK, false, true), + FOUR_WEAKER: new TrainerPartyTemplate(4, PartyMemberStrength.WEAKER), + FOUR_WEAKER_SAME: new TrainerPartyTemplate(4, PartyMemberStrength.WEAKER, true), + FOUR_WEAK: new TrainerPartyTemplate(4, PartyMemberStrength.WEAK), + FOUR_WEAK_SAME: new TrainerPartyTemplate(4, PartyMemberStrength.WEAK, true), + FOUR_WEAK_BALANCED: new TrainerPartyTemplate(4, PartyMemberStrength.WEAK, false, true), + FIVE_WEAKER: new TrainerPartyTemplate(5, PartyMemberStrength.WEAKER), + FIVE_WEAK: new TrainerPartyTemplate(5, PartyMemberStrength.WEAK), + FIVE_WEAK_BALANCED: new TrainerPartyTemplate(5, PartyMemberStrength.WEAK, false, true), + SIX_WEAKER: new TrainerPartyTemplate(6, PartyMemberStrength.WEAKER), + SIX_WEAKER_SAME: new TrainerPartyTemplate(6, PartyMemberStrength.WEAKER, true), + SIX_WEAK_SAME: new TrainerPartyTemplate(6, PartyMemberStrength.WEAKER, true), + SIX_WEAK_BALANCED: new TrainerPartyTemplate(6, PartyMemberStrength.WEAK, false, true), - GYM_LEADER_1: new TrainerPartyCompoundTemplate(new TrainerPartyTemplate(1, TrainerPartyMemberStrength.STRONG), new TrainerPartyTemplate(1, TrainerPartyMemberStrength.STRONGER)), - GYM_LEADER_2: new TrainerPartyCompoundTemplate(new TrainerPartyTemplate(1, TrainerPartyMemberStrength.AVERAGE), new TrainerPartyTemplate(1, TrainerPartyMemberStrength.STRONG), new TrainerPartyTemplate(1, TrainerPartyMemberStrength.STRONGER)), - GYM_LEADER_3: new TrainerPartyCompoundTemplate(new TrainerPartyTemplate(2, TrainerPartyMemberStrength.AVERAGE), new TrainerPartyTemplate(1, TrainerPartyMemberStrength.STRONG), new TrainerPartyTemplate(1, TrainerPartyMemberStrength.STRONGER)), - GYM_LEADER_4: new TrainerPartyCompoundTemplate(new TrainerPartyTemplate(3, TrainerPartyMemberStrength.AVERAGE), new TrainerPartyTemplate(1, TrainerPartyMemberStrength.STRONG), new TrainerPartyTemplate(1, TrainerPartyMemberStrength.STRONGER)), - GYM_LEADER_5: new TrainerPartyCompoundTemplate(new TrainerPartyTemplate(4, TrainerPartyMemberStrength.AVERAGE), new TrainerPartyTemplate(1, TrainerPartyMemberStrength.STRONG), new TrainerPartyTemplate(1, TrainerPartyMemberStrength.STRONGER)), + GYM_LEADER_1: new TrainerPartyCompoundTemplate(new TrainerPartyTemplate(1, PartyMemberStrength.AVERAGE), new TrainerPartyTemplate(1, PartyMemberStrength.STRONG)), + GYM_LEADER_2: new TrainerPartyCompoundTemplate(new TrainerPartyTemplate(1, PartyMemberStrength.AVERAGE), new TrainerPartyTemplate(2, PartyMemberStrength.STRONG)), + GYM_LEADER_3: new TrainerPartyCompoundTemplate(new TrainerPartyTemplate(2, PartyMemberStrength.AVERAGE), new TrainerPartyTemplate(1, PartyMemberStrength.STRONG), new TrainerPartyTemplate(1, PartyMemberStrength.STRONGER)), + GYM_LEADER_4: new TrainerPartyCompoundTemplate(new TrainerPartyTemplate(3, PartyMemberStrength.AVERAGE), new TrainerPartyTemplate(1, PartyMemberStrength.STRONG), new TrainerPartyTemplate(1, PartyMemberStrength.STRONGER)), + GYM_LEADER_5: new TrainerPartyCompoundTemplate(new TrainerPartyTemplate(4, PartyMemberStrength.AVERAGE), new TrainerPartyTemplate(1, PartyMemberStrength.STRONG), new TrainerPartyTemplate(1, PartyMemberStrength.STRONGER)), - ELITE_FOUR: new TrainerPartyCompoundTemplate(new TrainerPartyTemplate(3, TrainerPartyMemberStrength.AVERAGE), new TrainerPartyTemplate(2, TrainerPartyMemberStrength.STRONG), new TrainerPartyTemplate(1, TrainerPartyMemberStrength.STRONGER)), + ELITE_FOUR: new TrainerPartyCompoundTemplate(new TrainerPartyTemplate(3, PartyMemberStrength.AVERAGE), new TrainerPartyTemplate(2, PartyMemberStrength.STRONG), new TrainerPartyTemplate(1, PartyMemberStrength.STRONGER)), - CHAMPION: new TrainerPartyCompoundTemplate(new TrainerPartyTemplate(1, TrainerPartyMemberStrength.STRONGER), new TrainerPartyTemplate(5, TrainerPartyMemberStrength.STRONG, false, true)), + CHAMPION: new TrainerPartyCompoundTemplate(new TrainerPartyTemplate(1, PartyMemberStrength.STRONGER), new TrainerPartyTemplate(5, PartyMemberStrength.STRONG, false, true)), - RIVAL: new TrainerPartyCompoundTemplate(new TrainerPartyTemplate(1, TrainerPartyMemberStrength.STRONG), new TrainerPartyTemplate(1, TrainerPartyMemberStrength.AVERAGE)), - RIVAL_2: new TrainerPartyCompoundTemplate(new TrainerPartyTemplate(1, TrainerPartyMemberStrength.STRONG), new TrainerPartyTemplate(1, TrainerPartyMemberStrength.AVERAGE), new TrainerPartyTemplate(1, TrainerPartyMemberStrength.AVERAGE, false, true)), - RIVAL_3: new TrainerPartyCompoundTemplate(new TrainerPartyTemplate(1, TrainerPartyMemberStrength.STRONG), new TrainerPartyTemplate(1, TrainerPartyMemberStrength.AVERAGE), new TrainerPartyTemplate(2, TrainerPartyMemberStrength.AVERAGE, false, true)), - RIVAL_4: new TrainerPartyCompoundTemplate(new TrainerPartyTemplate(1, TrainerPartyMemberStrength.STRONG), new TrainerPartyTemplate(1, TrainerPartyMemberStrength.AVERAGE), new TrainerPartyTemplate(3, TrainerPartyMemberStrength.AVERAGE, false, true)), - RIVAL_5: new TrainerPartyCompoundTemplate(new TrainerPartyTemplate(1, TrainerPartyMemberStrength.STRONG), new TrainerPartyTemplate(1, TrainerPartyMemberStrength.AVERAGE), new TrainerPartyTemplate(3, TrainerPartyMemberStrength.AVERAGE, false, true), new TrainerPartyTemplate(1, TrainerPartyMemberStrength.STRONG)), - RIVAL_6: new TrainerPartyCompoundTemplate(new TrainerPartyTemplate(1, TrainerPartyMemberStrength.STRONG), new TrainerPartyTemplate(1, TrainerPartyMemberStrength.AVERAGE), new TrainerPartyTemplate(3, TrainerPartyMemberStrength.AVERAGE, false, true), new TrainerPartyTemplate(1, TrainerPartyMemberStrength.STRONGER)) + RIVAL: new TrainerPartyCompoundTemplate(new TrainerPartyTemplate(1, PartyMemberStrength.STRONG), new TrainerPartyTemplate(1, PartyMemberStrength.AVERAGE)), + RIVAL_2: new TrainerPartyCompoundTemplate(new TrainerPartyTemplate(1, PartyMemberStrength.STRONG), new TrainerPartyTemplate(1, PartyMemberStrength.AVERAGE), new TrainerPartyTemplate(1, PartyMemberStrength.AVERAGE, false, true)), + RIVAL_3: new TrainerPartyCompoundTemplate(new TrainerPartyTemplate(1, PartyMemberStrength.STRONG), new TrainerPartyTemplate(1, PartyMemberStrength.AVERAGE), new TrainerPartyTemplate(2, PartyMemberStrength.AVERAGE, false, true)), + RIVAL_4: new TrainerPartyCompoundTemplate(new TrainerPartyTemplate(1, PartyMemberStrength.STRONG), new TrainerPartyTemplate(1, PartyMemberStrength.AVERAGE), new TrainerPartyTemplate(3, PartyMemberStrength.AVERAGE, false, true)), + RIVAL_5: new TrainerPartyCompoundTemplate(new TrainerPartyTemplate(1, PartyMemberStrength.STRONG), new TrainerPartyTemplate(1, PartyMemberStrength.AVERAGE), new TrainerPartyTemplate(3, PartyMemberStrength.AVERAGE, false, true), new TrainerPartyTemplate(1, PartyMemberStrength.STRONG)), + RIVAL_6: new TrainerPartyCompoundTemplate(new TrainerPartyTemplate(1, PartyMemberStrength.STRONG), new TrainerPartyTemplate(1, PartyMemberStrength.AVERAGE), new TrainerPartyTemplate(3, PartyMemberStrength.AVERAGE, false, true), new TrainerPartyTemplate(1, PartyMemberStrength.STRONGER)) }; type PartyTemplateFunc = (scene: BattleScene) => TrainerPartyTemplate; -type PartyMemberFunc = (scene: BattleScene, level: integer) => EnemyPokemon; +type PartyMemberFunc = (scene: BattleScene, level: integer, strength: PartyMemberStrength) => EnemyPokemon; type GenModifiersFunc = (party: EnemyPokemon[]) => PersistentModifier[]; export interface PartyMemberFuncs { @@ -507,10 +499,10 @@ function getGymLeaderPartyTemplate(scene: BattleScene) { } function getRandomPartyMemberFunc(speciesPool: Species[], trainerSlot: TrainerSlot = TrainerSlot.TRAINER, ignoreEvolution: boolean = false, postProcess?: (enemyPokemon: EnemyPokemon) => void): PartyMemberFunc { - return (scene: BattleScene, level: integer) => { + return (scene: BattleScene, level: integer, strength: PartyMemberStrength) => { let species = Utils.randSeedItem(speciesPool); if (!ignoreEvolution) - species = getPokemonSpecies(species).getSpeciesForLevel(level, true, true, scene.currentBattle.trainer.config.isBoss); + species = getPokemonSpecies(species).getTrainerSpeciesForLevel(level, true, strength); return scene.addEnemyPokemon(getPokemonSpecies(species), level, trainerSlot, undefined, undefined, postProcess); }; } @@ -518,8 +510,8 @@ function getRandomPartyMemberFunc(speciesPool: Species[], trainerSlot: TrainerSl function getSpeciesFilterRandomPartyMemberFunc(speciesFilter: PokemonSpeciesFilter, trainerSlot: TrainerSlot = TrainerSlot.TRAINER, allowLegendaries?: boolean, postProcess?: (EnemyPokemon: EnemyPokemon) => void): PartyMemberFunc { const originalSpeciesFilter = speciesFilter; speciesFilter = (species: PokemonSpecies) => allowLegendaries || (!species.legendary && !species.pseudoLegendary && !species.mythical) && originalSpeciesFilter(species); - return (scene: BattleScene, level: integer) => { - const ret = scene.addEnemyPokemon(getPokemonSpecies(scene.randomSpecies(scene.currentBattle.waveIndex, level, false, speciesFilter).getSpeciesForLevel(level, true, true, scene.currentBattle.trainer.config.isBoss)), level, trainerSlot, undefined, undefined, postProcess); + 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); return ret; }; } @@ -845,12 +837,13 @@ export const trainerConfigs: TrainerConfigs = { return [ modifierTypes.TERA_SHARD().generateType(null, [ starter.species.type1 ]).withIdFromFunc(modifierTypes.TERA_SHARD).newModifier(starter) as PersistentModifier ]; }), [TrainerType.RIVAL_5]: new TrainerConfig(++t).setName('Finn').setHasGenders('Ivy').setHasCharSprite().setTitle('Rival').setBoss().setStaticParty().setMoneyMultiplier(2.25).setEncounterBgm(TrainerType.RIVAL).setBattleBgm('battle_rival_3').setPartyTemplates(trainerPartyTemplates.RIVAL_5) - .setPartyMemberFunc(0, getRandomPartyMemberFunc([ Species.VENUSAUR, Species.CHARIZARD, Species.BLASTOISE, Species.MEGANIUM, Species.TYPHLOSION, Species.FERALIGATR, Species.SCEPTILE, Species.BLAZIKEN, Species.SWAMPERT, Species.TORTERRA, Species.INFERNAPE, Species.EMPOLEON, Species.SERPERIOR, Species.EMBOAR, Species.SAMUROTT, Species.CHESNAUGHT, Species.DELPHOX, Species.GRENINJA, Species.DECIDUEYE, Species.INCINEROAR, Species.PRIMARINA, Species.RILLABOOM, Species.CINDERACE, Species.INTELEON, Species.MEOWSCARADA, Species.SKELEDIRGE, Species.QUAQUAVAL ], TrainerSlot.TRAINER, true)) + .setPartyMemberFunc(0, getRandomPartyMemberFunc([ Species.VENUSAUR, Species.CHARIZARD, Species.BLASTOISE, Species.MEGANIUM, Species.TYPHLOSION, Species.FERALIGATR, Species.SCEPTILE, Species.BLAZIKEN, Species.SWAMPERT, Species.TORTERRA, Species.INFERNAPE, Species.EMPOLEON, Species.SERPERIOR, Species.EMBOAR, Species.SAMUROTT, Species.CHESNAUGHT, Species.DELPHOX, Species.GRENINJA, Species.DECIDUEYE, Species.INCINEROAR, Species.PRIMARINA, Species.RILLABOOM, Species.CINDERACE, Species.INTELEON, Species.MEOWSCARADA, Species.SKELEDIRGE, Species.QUAQUAVAL ], TrainerSlot.TRAINER, true, + p => p.setBoss(true, 2))) .setPartyMemberFunc(1, getRandomPartyMemberFunc([ Species.PIDGEOT, Species.NOCTOWL, Species.SWELLOW, Species.STARAPTOR, Species.UNFEZANT, Species.TALONFLAME, Species.TOUCANNON, Species.CORVIKNIGHT, Species.KILOWATTREL ], TrainerSlot.TRAINER, true)) .setPartyMemberFunc(2, getSpeciesFilterRandomPartyMemberFunc((species: PokemonSpecies) => !pokemonEvolutions.hasOwnProperty(species.speciesId) && !pokemonPrevolutions.hasOwnProperty(species.speciesId) && species.baseTotal >= 450)) .setSpeciesFilter(species => species.baseTotal >= 540) .setPartyMemberFunc(5, getRandomPartyMemberFunc([ Species.RAYQUAZA ], TrainerSlot.TRAINER, true, p => { - p.setBoss(); + p.setBoss(true, 3); p.pokeball = PokeballType.MASTER_BALL; })) .setGenModifiersFunc(party => { @@ -858,8 +851,11 @@ export const trainerConfigs: TrainerConfigs = { return [ modifierTypes.TERA_SHARD().generateType(null, [ starter.species.type1 ]).withIdFromFunc(modifierTypes.TERA_SHARD).newModifier(starter) as PersistentModifier ]; }), [TrainerType.RIVAL_6]: new TrainerConfig(++t).setName('Finn').setHasGenders('Ivy').setHasCharSprite().setTitle('Rival').setBoss().setStaticParty().setMoneyMultiplier(3).setEncounterBgm('final').setBattleBgm('battle_rival_3').setPartyTemplates(trainerPartyTemplates.RIVAL_6) - .setPartyMemberFunc(0, getRandomPartyMemberFunc([ Species.VENUSAUR, Species.CHARIZARD, Species.BLASTOISE, Species.MEGANIUM, Species.TYPHLOSION, Species.FERALIGATR, Species.SCEPTILE, Species.BLAZIKEN, Species.SWAMPERT, Species.TORTERRA, Species.INFERNAPE, Species.EMPOLEON, Species.SERPERIOR, Species.EMBOAR, Species.SAMUROTT, Species.CHESNAUGHT, Species.DELPHOX, Species.GRENINJA, Species.DECIDUEYE, Species.INCINEROAR, Species.PRIMARINA, Species.RILLABOOM, Species.CINDERACE, Species.INTELEON, Species.MEOWSCARADA, Species.SKELEDIRGE, Species.QUAQUAVAL ], TrainerSlot.TRAINER, true)) - .setPartyMemberFunc(1, getRandomPartyMemberFunc([ Species.PIDGEOT, Species.NOCTOWL, Species.SWELLOW, Species.STARAPTOR, Species.UNFEZANT, Species.TALONFLAME, Species.TOUCANNON, Species.CORVIKNIGHT, Species.KILOWATTREL ], TrainerSlot.TRAINER, true)) + .setPartyMemberFunc(0, getRandomPartyMemberFunc([ Species.VENUSAUR, Species.CHARIZARD, Species.BLASTOISE, Species.MEGANIUM, Species.TYPHLOSION, Species.FERALIGATR, Species.SCEPTILE, Species.BLAZIKEN, Species.SWAMPERT, Species.TORTERRA, Species.INFERNAPE, Species.EMPOLEON, Species.SERPERIOR, Species.EMBOAR, Species.SAMUROTT, Species.CHESNAUGHT, Species.DELPHOX, Species.GRENINJA, Species.DECIDUEYE, Species.INCINEROAR, Species.PRIMARINA, Species.RILLABOOM, Species.CINDERACE, Species.INTELEON, Species.MEOWSCARADA, Species.SKELEDIRGE, Species.QUAQUAVAL ], TrainerSlot.TRAINER, true, + p => p.setBoss(true, 3)) + ) + .setPartyMemberFunc(1, getRandomPartyMemberFunc([ Species.PIDGEOT, Species.NOCTOWL, Species.SWELLOW, Species.STARAPTOR, Species.UNFEZANT, Species.TALONFLAME, Species.TOUCANNON, Species.CORVIKNIGHT, Species.KILOWATTREL ], TrainerSlot.TRAINER, true, + p => p.setBoss(true, 2))) .setPartyMemberFunc(2, getSpeciesFilterRandomPartyMemberFunc((species: PokemonSpecies) => !pokemonEvolutions.hasOwnProperty(species.speciesId) && !pokemonPrevolutions.hasOwnProperty(species.speciesId) && species.baseTotal >= 450)) .setSpeciesFilter(species => species.baseTotal >= 540) .setPartyMemberFunc(5, getRandomPartyMemberFunc([ Species.RAYQUAZA ], TrainerSlot.TRAINER, true, p => { diff --git a/src/field/arena.ts b/src/field/arena.ts index f874eeaaf..891f3f1ad 100644 --- a/src/field/arena.ts +++ b/src/field/arena.ts @@ -17,6 +17,7 @@ import { Moves } from "../data/enums/moves"; import { TimeOfDay } from "../data/enums/time-of-day"; import { Terrain, TerrainType } from "../data/terrain"; import { PostTerrainChangeAbAttr, PostWeatherChangeAbAttr, applyPostTerrainChangeAbAttrs, applyPostWeatherChangeAbAttrs } from "../data/ability"; +import { PartyMemberStrength } from "../data/enums/party-member-strength"; const WEATHER_OVERRIDE = WeatherType.NONE; @@ -118,7 +119,7 @@ export class Arena { return this.randomSpecies(waveIndex, level, (attempt || 0) + 1); } - const newSpeciesId = ret.getSpeciesForLevel(level, true, false, isBoss); + const newSpeciesId = ret.getWildSpeciesForLevel(level, true, isBoss, this.scene.gameMode); if (newSpeciesId !== ret.speciesId) { console.log('Replaced', Species[ret.speciesId], 'with', Species[newSpeciesId]); ret = getPokemonSpecies(newSpeciesId); diff --git a/src/field/pokemon.ts b/src/field/pokemon.ts index fc85418fe..dea7ebe4e 100644 --- a/src/field/pokemon.ts +++ b/src/field/pokemon.ts @@ -2254,9 +2254,9 @@ export class EnemyPokemon extends Pokemon { this.battleInfo.updateBossSegments(this); } - setBoss(boss: boolean = true): void { + setBoss(boss: boolean = true, bossSegments: integer = 0): void { if (boss) { - this.bossSegments = this.scene.getEncounterBossSegments(this.scene.currentBattle.waveIndex, this.level, this.species, true); + this.bossSegments = bossSegments || this.scene.getEncounterBossSegments(this.scene.currentBattle.waveIndex, this.level, this.species, true); this.bossSegmentIndex = this.bossSegments - 1; } else { this.bossSegments = 0; diff --git a/src/field/trainer.ts b/src/field/trainer.ts index 5cb0646b2..d680f0416 100644 --- a/src/field/trainer.ts +++ b/src/field/trainer.ts @@ -1,7 +1,8 @@ import BattleScene from "../battle-scene"; import { pokemonPrevolutions } from "../data/pokemon-evolutions"; import PokemonSpecies, { getPokemonSpecies } from "../data/pokemon-species"; -import { TrainerConfig, TrainerPartyCompoundTemplate, TrainerPartyMemberStrength, TrainerPartyTemplate, TrainerPoolTier, TrainerSlot, trainerConfigs, trainerPartyTemplates } from "../data/trainer-config"; +import { TrainerConfig, TrainerPartyCompoundTemplate, TrainerPartyTemplate, TrainerPoolTier, TrainerSlot, trainerConfigs, trainerPartyTemplates } from "../data/trainer-config"; +import { PartyMemberStrength } from "../data/enums/party-member-strength"; import { TrainerType } from "../data/enums/trainer-type"; import { EnemyPokemon } from "./pokemon"; import * as Utils from "../utils"; @@ -150,28 +151,28 @@ export default class Trainer extends Phaser.GameObjects.Container { const strength = partyTemplate.getStrength(i); switch (strength) { - case TrainerPartyMemberStrength.WEAKER: + case PartyMemberStrength.WEAKER: multiplier = 0.95; break; - case TrainerPartyMemberStrength.WEAK: + case PartyMemberStrength.WEAK: multiplier = 1.0; break; - case TrainerPartyMemberStrength.AVERAGE: + case PartyMemberStrength.AVERAGE: multiplier = 1.1; break; - case TrainerPartyMemberStrength.STRONG: + case PartyMemberStrength.STRONG: multiplier = 1.2; break; - case TrainerPartyMemberStrength.STRONGER: + case PartyMemberStrength.STRONGER: multiplier = 1.25; break; } let levelOffset = 0; - if (strength < TrainerPartyMemberStrength.STRONG) { + if (strength < PartyMemberStrength.STRONG) { multiplier = Math.min(multiplier + 0.025 * Math.floor(difficultyWaveIndex / 25), 1.2); - levelOffset = -Math.floor((difficultyWaveIndex / 50) * (TrainerPartyMemberStrength.STRONG - strength)); + levelOffset = -Math.floor((difficultyWaveIndex / 50) * (PartyMemberStrength.STRONG - strength)); } const level = Math.ceil(baseLevel * multiplier) + levelOffset; @@ -189,13 +190,14 @@ export default class Trainer extends Phaser.GameObjects.Container { this.scene.executeWithSeedOffset(() => { const template = this.getPartyTemplate(); + const strength: PartyMemberStrength = template.getStrength(index); if (this.config.partyMemberFuncs.hasOwnProperty(index)) { - ret = this.config.partyMemberFuncs[index](this.scene, level); + ret = this.config.partyMemberFuncs[index](this.scene, level, strength); return; } if (this.config.partyMemberFuncs.hasOwnProperty(index - template.size)) { - ret = this.config.partyMemberFuncs[index - template.size](this.scene, level); + ret = this.config.partyMemberFuncs[index - template.size](this.scene, level, template.getStrength(index)); return; } @@ -210,8 +212,8 @@ export default class Trainer extends Phaser.GameObjects.Container { } const species = template.isSameSpecies(index) && index > offset - ? getPokemonSpecies(battle.enemyParty[offset].species.getSpeciesForLevel(level, false, true, this.config.isBoss)) - : this.genNewPartyMemberSpecies(level); + ? getPokemonSpecies(battle.enemyParty[offset].species.getTrainerSpeciesForLevel(level, false, template.getStrength(offset))) + : this.genNewPartyMemberSpecies(level, strength); ret = this.scene.addEnemyPokemon(species, level, !this.isDouble() || !(index % 2) ? TrainerSlot.TRAINER : TrainerSlot.TRAINER_PARTNER); }, this.config.hasStaticParty ? this.config.getDerivedType() + ((index + 1) << 8) : this.scene.currentBattle.waveIndex + (this.config.getDerivedType() << 10) + (((!this.config.useSameSeedForAllMembers ? index : 0) + 1) << 8)); @@ -219,7 +221,7 @@ export default class Trainer extends Phaser.GameObjects.Container { return ret; } - genNewPartyMemberSpecies(level: integer, attempt?: integer): PokemonSpecies { + genNewPartyMemberSpecies(level: integer, strength: PartyMemberStrength, attempt?: integer): PokemonSpecies { const battle = this.scene.currentBattle; const template = this.getPartyTemplate(); @@ -237,7 +239,7 @@ export default class Trainer extends Phaser.GameObjects.Container { } else species = this.scene.randomSpecies(battle.waveIndex, level, false, this.config.speciesFilter); - let ret = getPokemonSpecies(species.getSpeciesForLevel(level, true, true, this.config.isBoss)); + let ret = getPokemonSpecies(species.getTrainerSpeciesForLevel(level, true, strength)); let retry = false; console.log(ret.getName()); @@ -255,7 +257,7 @@ export default class Trainer extends Phaser.GameObjects.Container { console.log('Attempting reroll of species evolution to fit specialty type...'); let evoAttempt = 0; while (retry && evoAttempt++ < 10) { - ret = getPokemonSpecies(species.getSpeciesForLevel(level, true, true, this.config.isBoss)); + ret = getPokemonSpecies(species.getTrainerSpeciesForLevel(level, true, strength)); console.log(ret.name); if (this.config.specialtyTypes.find(t => ret.isOfType(t))) retry = false; @@ -264,7 +266,7 @@ export default class Trainer extends Phaser.GameObjects.Container { if (retry && (attempt || 0) < 10) { console.log('Rerolling party member...') - ret = this.genNewPartyMemberSpecies(level, (attempt || 0) + 1); + ret = this.genNewPartyMemberSpecies(level, strength, (attempt || 0) + 1); } return ret; @@ -323,15 +325,15 @@ export default class Trainer extends Phaser.GameObjects.Container { getPartyMemberModifierChanceMultiplier(index: integer): number { switch (this.getPartyTemplate().getStrength(index)) { - case TrainerPartyMemberStrength.WEAKER: + case PartyMemberStrength.WEAKER: return 0.75; - case TrainerPartyMemberStrength.WEAK: + case PartyMemberStrength.WEAK: return 0.675; - case TrainerPartyMemberStrength.AVERAGE: + case PartyMemberStrength.AVERAGE: return 0.5625; - case TrainerPartyMemberStrength.STRONG: + case PartyMemberStrength.STRONG: return 0.45; - case TrainerPartyMemberStrength.STRONGER: + case PartyMemberStrength.STRONGER: return 0.375; } }