From fac20ca97a214acbdd83d0f1795bf73d499f5186 Mon Sep 17 00:00:00 2001 From: Sirz Benjie <142067137+SirzBenjie@users.noreply.github.com> Date: Fri, 28 Mar 2025 22:24:19 -0500 Subject: [PATCH 1/2] [Ability] Fully implement Flower Gift and Victory Star (#5222) * Fully implement Flower Gift and Victory Star * Fully implement Flower Gift and Victory Star * Update src/field/pokemon.ts Co-authored-by: NightKev <34855794+DayKev@users.noreply.github.com> * Update src/field/pokemon.ts Co-authored-by: NightKev <34855794+DayKev@users.noreply.github.com> * Update src/data/ability.ts Co-authored-by: NightKev <34855794+DayKev@users.noreply.github.com> * Update src/data/ability.ts Co-authored-by: NightKev <34855794+DayKev@users.noreply.github.com> * Accept suggested change Co-authored-by: NightKev <34855794+DayKev@users.noreply.github.com> * Accept suggested change Co-authored-by: NightKev <34855794+DayKev@users.noreply.github.com> * Update src/data/ability.ts Co-authored-by: NightKev <34855794+DayKev@users.noreply.github.com> * Update src/data/ability.ts Co-authored-by: NightKev <34855794+DayKev@users.noreply.github.com> * Update src/data/ability.ts Co-authored-by: NightKev <34855794+DayKev@users.noreply.github.com> * Update src/field/pokemon.ts Co-authored-by: NightKev <34855794+DayKev@users.noreply.github.com> * Fix check for ignore_abilities move flag * Fix missing argument to getBaseDamage in getAttackDamage * Fix merge conflict due to same changed import line * Fix call to getAttackDamage that was reset after merge * Update calls to getEffectiveStat --------- Co-authored-by: NightKev <34855794+DayKev@users.noreply.github.com> --- src/data/ability.ts | 88 ++++++++++++++++++++++++- src/data/battler-tags.ts | 10 ++- src/data/moves/move.ts | 4 +- src/field/pokemon.ts | 34 +++++++++- test/abilities/flower_gift.test.ts | 95 ++++++++++++++++++++++++--- test/abilities/protosynthesis.test.ts | 48 ++++++++++++-- test/abilities/victory_star.test.ts | 60 +++++++++++++++++ 7 files changed, 317 insertions(+), 22 deletions(-) create mode 100644 test/abilities/victory_star.test.ts diff --git a/src/data/ability.ts b/src/data/ability.ts index 5bf02cabf6c..6ffdc1f5403 100644 --- a/src/data/ability.ts +++ b/src/data/ability.ts @@ -1712,6 +1712,62 @@ export class PostAttackAbAttr extends AbAttr { args: any[]): void {} } +/** + * Multiplies a Stat from an ally pokemon's ability. + * @see {@link applyAllyStatMultiplierAbAttrs} + * @see {@link applyAllyStat} + */ +export class AllyStatMultiplierAbAttr extends AbAttr { + private stat: BattleStat; + private multiplier: number; + private ignorable: boolean; + + /** + * @param stat - The stat being modified + * @param multipler - The multiplier to apply to the stat + * @param ignorable - Whether the multiplier can be ignored by mold breaker-like moves and abilities + */ + constructor(stat: BattleStat, multiplier: number, ignorable: boolean = true) { + super(false); + + this.stat = stat; + this.multiplier = multiplier; + this.ignorable = ignorable; + } + + /** + * Multiply a Pokemon's Stat due to an Ally's ability. + * @param _pokemon - The ally {@linkcode Pokemon} with the ability (unused) + * @param passive - unused + * @param _simulated - Whether the ability is being simulated (unused) + * @param _stat - The type of the checked {@linkcode Stat} (unused) + * @param statValue - {@linkcode Utils.NumberHolder} containing the value of the checked stat + * @param _checkedPokemon - The {@linkcode Pokemon} this ability is targeting (unused) + * @param _ignoreAbility - Whether the ability should be ignored if possible + * @param _args - unused + * @returns `true` if this changed the checked stat, `false` otherwise. + */ + applyAllyStat(_pokemon: Pokemon, _passive: boolean, _simulated: boolean, _stat: BattleStat, statValue: Utils.NumberHolder, _checkedPokemon: Pokemon, _ignoreAbility: boolean, _args: any[]) { + statValue.value *= this.multiplier; + } + + /** + * Check if this ability can apply to the checked stat. + * @param pokemon - The ally {@linkcode Pokemon} with the ability (unused) + * @param passive - unused + * @param simulated - Whether the ability is being simulated (unused) + * @param stat - The type of the checked {@linkcode Stat} + * @param statValue - {@linkcode Utils.NumberHolder} containing the value of the checked stat + * @param checkedPokemon - The {@linkcode Pokemon} this ability is targeting (unused) + * @param ignoreAbility - Whether the ability should be ignored if possible + * @param args - unused + * @returns `true` if this can apply to the checked stat, `false` otherwise. + */ + canApplyAllyStat(pokemon: Pokemon, _passive: boolean, simulated: boolean, stat: BattleStat, statValue: Utils.NumberHolder, checkedPokemon: Pokemon, ignoreAbility: boolean, args: any[]): boolean { + return stat === this.stat && !(ignoreAbility && this.ignorable); + } +} + /** * Ability attribute for Gorilla Tactics * @extends PostAttackAbAttr @@ -5594,6 +5650,30 @@ export function applyStatMultiplierAbAttrs( args, ); } + +/** + * Applies an ally's Stat multiplier attribute + * @param attrType - {@linkcode AllyStatMultiplierAbAttr} should always be AllyStatMultiplierAbAttr for the time being + * @param pokemon - The {@linkcode Pokemon} with the ability + * @param stat - The type of the checked {@linkcode Stat} + * @param statValue - {@linkcode Utils.NumberHolder} containing the value of the checked stat + * @param checkedPokemon - The {@linkcode Pokemon} with the checked stat + * @param ignoreAbility - Whether or not the ability should be ignored by the pokemon or its move. + * @param args - unused + */ +export function applyAllyStatMultiplierAbAttrs(attrType: Constructor, + pokemon: Pokemon, stat: BattleStat, statValue: Utils.NumberHolder, simulated: boolean = false, checkedPokemon: Pokemon, ignoreAbility: boolean, ...args: any[] +): void { + return applyAbAttrsInternal( + attrType, + pokemon, + (attr, passive) => attr.applyAllyStat(pokemon, passive, simulated, stat, statValue, checkedPokemon, ignoreAbility, args), + (attr, passive) => attr.canApplyAllyStat(pokemon, passive, simulated, stat, statValue, checkedPokemon, ignoreAbility, args), + args, + simulated, + ); +} + export function applyPostSetStatusAbAttrs( attrType: Constructor, pokemon: Pokemon, @@ -5606,7 +5686,8 @@ export function applyPostSetStatusAbAttrs( attrType, pokemon, (attr, passive) => attr.applyPostSetStatus(pokemon, sourcePokemon, passive, effect, simulated, args), - (attr, passive) => attr.canApplyPostSetStatus(pokemon, sourcePokemon, passive, effect, simulated, args), args, + (attr, passive) => attr.canApplyPostSetStatus(pokemon, sourcePokemon, passive, effect, simulated, args), + args, simulated, ); } @@ -6437,11 +6518,12 @@ export function initAbilities() { new Ability(Abilities.FLOWER_GIFT, 4) .conditionalAttr(getWeatherCondition(WeatherType.SUNNY || WeatherType.HARSH_SUN), StatMultiplierAbAttr, Stat.ATK, 1.5) .conditionalAttr(getWeatherCondition(WeatherType.SUNNY || WeatherType.HARSH_SUN), StatMultiplierAbAttr, Stat.SPDEF, 1.5) + .conditionalAttr(getWeatherCondition(WeatherType.SUNNY || WeatherType.HARSH_SUN), AllyStatMultiplierAbAttr, Stat.ATK, 1.5) + .conditionalAttr(getWeatherCondition(WeatherType.SUNNY || WeatherType.HARSH_SUN), AllyStatMultiplierAbAttr, Stat.SPDEF, 1.5) .attr(UncopiableAbilityAbAttr) .attr(NoFusionAbilityAbAttr) .attr(PostSummonFormChangeByWeatherAbAttr, Abilities.FLOWER_GIFT) .attr(PostWeatherChangeFormChangeAbAttr, Abilities.FLOWER_GIFT, [ WeatherType.NONE, WeatherType.SANDSTORM, WeatherType.STRONG_WINDS, WeatherType.FOG, WeatherType.HAIL, WeatherType.HEAVY_RAIN, WeatherType.SNOW, WeatherType.RAIN ]) - .partial() // Should also boosts stats of ally .ignorable(), new Ability(Abilities.BAD_DREAMS, 4) .attr(PostTurnHurtIfSleepingAbAttr), @@ -6577,7 +6659,7 @@ export function initAbilities() { .bypassFaint(), new Ability(Abilities.VICTORY_STAR, 5) .attr(StatMultiplierAbAttr, Stat.ACC, 1.1) - .partial(), // Does not boost ally's accuracy + .attr(AllyStatMultiplierAbAttr, Stat.ACC, 1.1, false), new Ability(Abilities.TURBOBLAZE, 5) .attr(PostSummonMessageAbAttr, (pokemon: Pokemon) => i18next.t("abilityTriggers:postSummonTurboblaze", { pokemonNameWithAffix: getPokemonNameWithAffix(pokemon) })) .attr(MoveAbilityBypassAbAttr), diff --git a/src/data/battler-tags.ts b/src/data/battler-tags.ts index c4004e9c582..8981644d885 100644 --- a/src/data/battler-tags.ts +++ b/src/data/battler-tags.ts @@ -1644,7 +1644,9 @@ export class ContactDamageProtectedTag extends ProtectedTag { if (effectPhase instanceof MoveEffectPhase && effectPhase.move.getMove().hasFlag(MoveFlags.MAKES_CONTACT)) { const attacker = effectPhase.getPokemon(); if (!attacker.hasAbilityWithAttr(BlockNonDirectDamageAbAttr)) { - attacker.damageAndUpdate(toDmgValue(attacker.getMaxHp() * (1 / this.damageRatio)), { result: HitResult.INDIRECT }); + attacker.damageAndUpdate(toDmgValue(attacker.getMaxHp() * (1 / this.damageRatio)), { + result: HitResult.INDIRECT, + }); } } } @@ -1970,7 +1972,7 @@ export class HighestStatBoostTag extends AbilityBattlerTag { let highestStat: EffectiveStat; EFFECTIVE_STATS.map(s => - pokemon.getEffectiveStat(s, undefined, undefined, undefined, undefined, undefined, undefined, true), + pokemon.getEffectiveStat(s, undefined, undefined, undefined, undefined, undefined, undefined, undefined, true), ).reduce((highestValue: number, value: number, i: number) => { if (value > highestValue) { highestStat = EFFECTIVE_STATS[i]; @@ -2240,7 +2242,9 @@ export class SaltCuredTag extends BattlerTag { if (!cancelled.value) { const pokemonSteelOrWater = pokemon.isOfType(PokemonType.STEEL) || pokemon.isOfType(PokemonType.WATER); - pokemon.damageAndUpdate(toDmgValue(pokemonSteelOrWater ? pokemon.getMaxHp() / 4 : pokemon.getMaxHp() / 8), { result: HitResult.INDIRECT }); + pokemon.damageAndUpdate(toDmgValue(pokemonSteelOrWater ? pokemon.getMaxHp() / 4 : pokemon.getMaxHp() / 8), { + result: HitResult.INDIRECT, + }); globalScene.queueMessage( i18next.t("battlerTags:saltCuredLapse", { diff --git a/src/data/moves/move.ts b/src/data/moves/move.ts index c85ec7db295..e18e898bc68 100644 --- a/src/data/moves/move.ts +++ b/src/data/moves/move.ts @@ -4798,8 +4798,8 @@ export class ShellSideArmCategoryAttr extends VariableMoveCategoryAttr { apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean { const category = (args[0] as Utils.NumberHolder); - const predictedPhysDmg = target.getBaseDamage(user, move, MoveCategory.PHYSICAL, true, true); - const predictedSpecDmg = target.getBaseDamage(user, move, MoveCategory.SPECIAL, true, true); + const predictedPhysDmg = target.getBaseDamage(user, move, MoveCategory.PHYSICAL, true, true, true, true); + const predictedSpecDmg = target.getBaseDamage(user, move, MoveCategory.SPECIAL, true, true, true, true); if (predictedPhysDmg > predictedSpecDmg) { category.value = MoveCategory.PHYSICAL; diff --git a/src/field/pokemon.ts b/src/field/pokemon.ts index a7532685bea..51a5a10b010 100644 --- a/src/field/pokemon.ts +++ b/src/field/pokemon.ts @@ -192,6 +192,9 @@ import { applyPreLeaveFieldAbAttrs, applyOnLoseAbAttrs, PreLeaveFieldRemoveSuppressAbilitiesSourceAbAttr, + applyAllyStatMultiplierAbAttrs, + AllyStatMultiplierAbAttr, + MoveAbilityBypassAbAttr, } from "#app/data/ability"; import type PokemonData from "#app/system/pokemon-data"; import { BattlerIndex } from "#app/battle"; @@ -260,6 +263,7 @@ import { import { Nature } from "#enums/nature"; import { StatusEffect } from "#enums/status-effect"; import { doShinySparkleAnim } from "#app/field/anims"; +import { MoveFlags } from "#enums/MoveFlags"; export enum LearnMoveSituation { MISC, @@ -1389,6 +1393,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { * @param move the {@linkcode Move} being used * @param ignoreAbility determines whether this Pokemon's abilities should be ignored during the stat calculation * @param ignoreOppAbility during an attack, determines whether the opposing Pokemon's abilities should be ignored during the stat calculation. + * @param ignoreAllyAbility during an attack, determines whether the ally Pokemon's abilities should be ignored during the stat calculation. * @param isCritical determines whether a critical hit has occurred or not (`false` by default) * @param simulated if `true`, nullifies any effects that produce any changes to game state from triggering * @param ignoreHeldItems determines whether this Pokemon's held items should be ignored during the stat calculation, default `false` @@ -1400,6 +1405,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { move?: Move, ignoreAbility = false, ignoreOppAbility = false, + ignoreAllyAbility = false, isCritical = false, simulated = true, ignoreHeldItems = false, @@ -1441,6 +1447,11 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { ); } + const ally = this.getAlly(); + if (ally) { + applyAllyStatMultiplierAbAttrs(AllyStatMultiplierAbAttr, ally, stat, statValue, simulated, this, move?.hasFlag(MoveFlags.IGNORE_ABILITIES) || ignoreAllyAbility); + } + let ret = statValue.value * this.getStatStageMultiplier( @@ -3889,6 +3900,13 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { evasionMultiplier, ); + const ally = this.getAlly(); + if (ally) { + const ignore = this.hasAbilityWithAttr(MoveAbilityBypassAbAttr) || sourceMove.hasFlag(MoveFlags.IGNORE_ABILITIES); + applyAllyStatMultiplierAbAttrs(AllyStatMultiplierAbAttr, ally, Stat.ACC, accuracyMultiplier, false, this, ignore); + applyAllyStatMultiplierAbAttrs(AllyStatMultiplierAbAttr, ally, Stat.EVA, evasionMultiplier, false, this, ignore); + } + return accuracyMultiplier.value / evasionMultiplier.value; } @@ -3900,6 +3918,8 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { * @param moveCategory the move's {@linkcode MoveCategory} after variable-category effects are applied. * @param ignoreAbility if `true`, ignores this Pokemon's defensive ability effects (defaults to `false`). * @param ignoreSourceAbility if `true`, ignore's the attacking Pokemon's ability effects (defaults to `false`). + * @param ignoreAllyAbility if `true`, ignores the ally Pokemon's ability effects (defaults to `false`). + * @param ignoreSourceAllyAbility if `true`, ignores the attacking Pokemon's ally's ability effects (defaults to `false`). * @param isCritical if `true`, calculates effective stats as if the hit were critical (defaults to `false`). * @param simulated if `true`, suppresses changes to game state during calculation (defaults to `true`). * @returns The move's base damage against this Pokemon when used by the source Pokemon. @@ -3910,6 +3930,8 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { moveCategory: MoveCategory, ignoreAbility = false, ignoreSourceAbility = false, + ignoreAllyAbility = false, + ignoreSourceAllyAbility = false, isCritical = false, simulated = true, ): number { @@ -3932,6 +3954,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { undefined, ignoreSourceAbility, ignoreAbility, + ignoreAllyAbility, isCritical, simulated, ), @@ -3949,6 +3972,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { move, ignoreAbility, ignoreSourceAbility, + ignoreSourceAllyAbility, isCritical, simulated, ), @@ -3983,6 +4007,8 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { * @param move {@linkcode Pokemon} the move used in the attack * @param ignoreAbility If `true`, ignores this Pokemon's defensive ability effects * @param ignoreSourceAbility If `true`, ignores the attacking Pokemon's ability effects + * @param ignoreAllyAbility If `true`, ignores the ally Pokemon's ability effects + * @param ignoreSourceAllyAbility If `true`, ignores the ability effects of the attacking pokemon's ally * @param isCritical If `true`, calculates damage for a critical hit. * @param simulated If `true`, suppresses changes to game state during the calculation. * @returns a {@linkcode DamageCalculationResult} object with three fields: @@ -3995,6 +4021,8 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { move: Move, ignoreAbility = false, ignoreSourceAbility = false, + ignoreAllyAbility = false, + ignoreSourceAllyAbility = false, isCritical = false, simulated = true, ): DamageCalculationResult { @@ -4104,6 +4132,8 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { moveCategory, ignoreAbility, ignoreSourceAbility, + ignoreAllyAbility, + ignoreSourceAllyAbility, isCritical, simulated, ); @@ -4429,7 +4459,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { cancelled, result, damage: dmg, - } = this.getAttackDamage(source, move, false, false, isCritical, false); + } = this.getAttackDamage(source, move, false, false, false, false, isCritical, false); const typeBoost = source.findTag( t => @@ -7114,6 +7144,8 @@ export class EnemyPokemon extends Pokemon { move, !p.battleData.abilityRevealed, false, + !p.getAlly()?.battleData.abilityRevealed, + false, isCritical, ).damage >= p.hp ); diff --git a/test/abilities/flower_gift.test.ts b/test/abilities/flower_gift.test.ts index fff509a1f00..1104a3c111f 100644 --- a/test/abilities/flower_gift.test.ts +++ b/test/abilities/flower_gift.test.ts @@ -1,12 +1,14 @@ import { BattlerIndex } from "#app/battle"; +import { allAbilities } from "#app/data/ability"; import { Abilities } from "#app/enums/abilities"; import { Stat } from "#app/enums/stat"; import { WeatherType } from "#app/enums/weather-type"; +import { TurnEndPhase } from "#app/phases/turn-end-phase"; import { Moves } from "#enums/moves"; import { Species } from "#enums/species"; import GameManager from "#test/testUtils/gameManager"; import Phaser from "phaser"; -import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest"; +import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest"; describe("Abilities - Flower Gift", () => { let phaserGame: Phaser.Game; @@ -28,6 +30,59 @@ describe("Abilities - Flower Gift", () => { expect(game.scene.getPlayerPokemon()?.formIndex).toBe(OVERCAST_FORM); }; + /** + * Tests damage dealt by a move used against a target before and after Flower Gift is activated. + * @param game The game manager instance + * @param move The move that should be used + * @param allyAttacker True if the ally is attacking the enemy, false if the enemy is attacking the ally + * @param ability The ability that the ally pokemon should have + * @param enemyAbility The ability that the enemy pokemon should have + * + * @returns Two numbers, the first being the damage done to the target without flower gift active, the second being the damage done with flower gift active + */ + const testDamageDealt = async (game: GameManager, move: Moves, allyAttacker: boolean, allyAbility = Abilities.BALL_FETCH, enemyAbility = Abilities.BALL_FETCH): Promise<[number, number]> => { + game.override.battleType("double"); + game.override.moveset([ Moves.SPLASH, Moves.SUNNY_DAY, move, Moves.HEAL_PULSE ]); + game.override.enemyMoveset([ Moves.SPLASH, Moves.HEAL_PULSE ]); + const target_index = allyAttacker ? BattlerIndex.ENEMY : BattlerIndex.PLAYER_2; + const attacker_index = allyAttacker ? BattlerIndex.PLAYER_2 : BattlerIndex.ENEMY; + const ally_move = allyAttacker ? move : Moves.SPLASH; + const enemy_move = allyAttacker ? Moves.SPLASH : move; + const ally_target = allyAttacker ? BattlerIndex.ENEMY : null; + + await game.classicMode.startBattle([ Species.CHERRIM, Species.MAGIKARP ]); + const target = allyAttacker ? game.scene.getEnemyField()[0] : game.scene.getPlayerField()[1]; + const initialHp = target.getMaxHp(); + + // Override the ability for the target and attacker only + vi.spyOn(game.scene.getPlayerField()[1], "getAbility").mockReturnValue(allAbilities[allyAbility]); + vi.spyOn(game.scene.getEnemyField()[0], "getAbility").mockReturnValue(allAbilities[enemyAbility]); + + // turn 1 + game.move.select(Moves.SUNNY_DAY, 0); + game.move.select(ally_move, 1, ally_target); + await game.forceEnemyMove(enemy_move, BattlerIndex.PLAYER_2); + await game.forceEnemyMove(Moves.SPLASH); + // Ensure sunny day is used last. + await game.setTurnOrder([ attacker_index, target_index, BattlerIndex.ENEMY_2, BattlerIndex.PLAYER ]); + await game.phaseInterceptor.to(TurnEndPhase); + const damageWithoutGift = initialHp - target.hp; + + target.hp = initialHp; + + // turn 2. Make target use recover to reset hp calculation. + game.move.select(Moves.SPLASH, 0, target_index); + game.move.select(ally_move, 1, ally_target); + await game.forceEnemyMove(enemy_move, BattlerIndex.PLAYER_2); + await game.forceEnemyMove(Moves.SPLASH); + await game.setTurnOrder([ BattlerIndex.PLAYER, BattlerIndex.ENEMY_2, target_index, attacker_index ]); + await game.phaseInterceptor.to(TurnEndPhase); + const damageWithGift = initialHp - target.hp; + + return [ damageWithoutGift, damageWithGift ]; + }; + + beforeAll(() => { phaserGame = new Phaser.Game({ type: Phaser.HEADLESS, @@ -41,23 +96,24 @@ describe("Abilities - Flower Gift", () => { beforeEach(() => { game = new GameManager(phaserGame); game.override - .moveset([Moves.SPLASH, Moves.RAIN_DANCE, Moves.SUNNY_DAY, Moves.SKILL_SWAP]) + .moveset([Moves.SPLASH, Moves.SUNSTEEL_STRIKE, Moves.SUNNY_DAY, Moves.MUD_SLAP]) .enemySpecies(Species.MAGIKARP) .enemyMoveset(Moves.SPLASH) - .enemyAbility(Abilities.BALL_FETCH); + .enemyAbility(Abilities.BALL_FETCH) + .enemyLevel(100) + .startingLevel(100); }); - // TODO: Uncomment expect statements when the ability is implemented - currently does not increase stats of allies it("increases the ATK and SPDEF stat stages of the Pokémon with this Ability and its allies by 1.5× during Harsh Sunlight", async () => { game.override.battleType("double"); await game.classicMode.startBattle([Species.CHERRIM, Species.MAGIKARP]); - const [cherrim] = game.scene.getPlayerField(); + const [cherrim, magikarp] = game.scene.getPlayerField(); const cherrimAtkStat = cherrim.getEffectiveStat(Stat.ATK); const cherrimSpDefStat = cherrim.getEffectiveStat(Stat.SPDEF); - // const magikarpAtkStat = magikarp.getEffectiveStat(Stat.ATK);; - // const magikarpSpDefStat = magikarp.getEffectiveStat(Stat.SPDEF); + const magikarpAtkStat = magikarp.getEffectiveStat(Stat.ATK); + const magikarpSpDefStat = magikarp.getEffectiveStat(Stat.SPDEF); game.move.select(Moves.SUNNY_DAY, 0); game.move.select(Moves.SPLASH, 1); @@ -68,8 +124,28 @@ describe("Abilities - Flower Gift", () => { expect(cherrim.formIndex).toBe(SUNSHINE_FORM); expect(cherrim.getEffectiveStat(Stat.ATK)).toBe(Math.floor(cherrimAtkStat * 1.5)); expect(cherrim.getEffectiveStat(Stat.SPDEF)).toBe(Math.floor(cherrimSpDefStat * 1.5)); - // expect(magikarp.getEffectiveStat(Stat.ATK)).toBe(Math.floor(magikarpAtkStat * 1.5)); - // expect(magikarp.getEffectiveStat(Stat.SPDEF)).toBe(Math.floor(magikarpSpDefStat * 1.5)); + expect(magikarp.getEffectiveStat(Stat.ATK)).toBe(Math.floor(magikarpAtkStat * 1.5)); + expect(magikarp.getEffectiveStat(Stat.SPDEF)).toBe(Math.floor(magikarpSpDefStat * 1.5)); + }); + + it("should not increase the damage of an ally using an ability ignoring move", async () => { + const [ damageWithGift, damageWithoutGift ] = await testDamageDealt(game, Moves.SUNSTEEL_STRIKE, true); + expect(damageWithGift).toBe(damageWithoutGift); + }); + + it("should not increase the damage of a mold breaker ally", async () => { + const [ damageWithGift, damageWithoutGift ] = await testDamageDealt(game, Moves.TACKLE, true, Abilities.MOLD_BREAKER); + expect(damageWithGift).toBe(damageWithoutGift); + }); + + it("should decrease the damage an ally takes from a special attack", async () => { + const [ damageWithoutGift, damageWithGift ] = await testDamageDealt(game, Moves.MUD_SLAP, false); + expect(damageWithGift).toBeLessThan(damageWithoutGift); + }); + + it("should not decrease the damage an ally takes from a mold breaker enemy using a special attack", async () => { + const [ damageWithoutGift, damageWithGift ] = await testDamageDealt(game, Moves.MUD_SLAP, false, Abilities.BALL_FETCH, Abilities.MOLD_BREAKER); + expect(damageWithGift).toBe(damageWithoutGift); }); it("changes the Pokemon's form during Harsh Sunlight", async () => { @@ -92,6 +168,7 @@ describe("Abilities - Flower Gift", () => { it("reverts to Overcast Form when the Pokémon loses Flower Gift, changes form under Harsh Sunlight/Sunny when it regains it", async () => { game.override.enemyMoveset([Moves.SKILL_SWAP]).weather(WeatherType.HARSH_SUN); + game.override.moveset([ Moves.SKILL_SWAP ]); await game.classicMode.startBattle([Species.CHERRIM]); diff --git a/test/abilities/protosynthesis.test.ts b/test/abilities/protosynthesis.test.ts index d0ae46cd951..882474b7cef 100644 --- a/test/abilities/protosynthesis.test.ts +++ b/test/abilities/protosynthesis.test.ts @@ -46,16 +46,56 @@ describe("Abilities - Protosynthesis", () => { // Nature of starting mon is randomized. We need to fix it to a neutral nature for the automated test. mew.setNature(Nature.HARDY); const enemy = game.scene.getEnemyPokemon()!; - const def_before_boost = mew.getEffectiveStat(Stat.DEF, undefined, undefined, false, undefined, false, false, true); - const atk_before_boost = mew.getEffectiveStat(Stat.ATK, undefined, undefined, false, undefined, false, false, true); + const def_before_boost = mew.getEffectiveStat( + Stat.DEF, + undefined, + undefined, + false, + undefined, + undefined, + false, + false, + true, + ); + const atk_before_boost = mew.getEffectiveStat( + Stat.ATK, + undefined, + undefined, + false, + undefined, + undefined, + false, + false, + true, + ); const initialHp = enemy.hp; game.move.select(Moves.TACKLE); await game.setTurnOrder([BattlerIndex.PLAYER, BattlerIndex.ENEMY]); await game.toNextTurn(); const unboosted_dmg = initialHp - enemy.hp; enemy.hp = initialHp; - const def_after_boost = mew.getEffectiveStat(Stat.DEF, undefined, undefined, false, undefined, false, false, true); - const atk_after_boost = mew.getEffectiveStat(Stat.ATK, undefined, undefined, false, undefined, false, false, true); + const def_after_boost = mew.getEffectiveStat( + Stat.DEF, + undefined, + undefined, + false, + undefined, + undefined, + false, + false, + true, + ); + const atk_after_boost = mew.getEffectiveStat( + Stat.ATK, + undefined, + undefined, + false, + undefined, + undefined, + false, + false, + true, + ); game.move.select(Moves.TACKLE); await game.setTurnOrder([BattlerIndex.PLAYER, BattlerIndex.ENEMY]); await game.toNextTurn(); diff --git a/test/abilities/victory_star.test.ts b/test/abilities/victory_star.test.ts new file mode 100644 index 00000000000..456f8cd7ddd --- /dev/null +++ b/test/abilities/victory_star.test.ts @@ -0,0 +1,60 @@ +import { BattlerIndex } from "#app/battle"; +import { TurnEndPhase } from "#app/phases/turn-end-phase"; +import { Abilities } from "#enums/abilities"; +import { Moves } from "#enums/moves"; +import { Species } from "#enums/species"; +import GameManager from "#test/testUtils/gameManager"; +import Phaser from "phaser"; +import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest"; + +describe("Abilities - Victory Star", () => { + let phaserGame: Phaser.Game; + let game: GameManager; + + beforeAll(() => { + phaserGame = new Phaser.Game({ + type: Phaser.HEADLESS, + }); + }); + + afterEach(() => { + game.phaseInterceptor.restoreOg(); + }); + + beforeEach(() => { + game = new GameManager(phaserGame); + game.override + .moveset([ Moves.TACKLE, Moves.SPLASH ]) + .battleType("double") + .disableCrits() + .enemySpecies(Species.MAGIKARP) + .enemyAbility(Abilities.BALL_FETCH) + .enemyMoveset(Moves.SPLASH); + }); + + it("should increase the accuracy of its user", async () => { + await game.classicMode.startBattle([ Species.VICTINI, Species.MAGIKARP ]); + + const user = game.scene.getPlayerField()[0]; + + vi.spyOn(user, "getAccuracyMultiplier"); + game.move.select(Moves.TACKLE, 0, BattlerIndex.ENEMY); + game.move.select(Moves.SPLASH, 1); + await game.phaseInterceptor.to(TurnEndPhase); + + expect(user.getAccuracyMultiplier).toHaveReturnedWith(1.1); + }); + + it("should increase the accuracy of its user's ally", async () => { + await game.classicMode.startBattle([ Species.MAGIKARP, Species.VICTINI ]); + + const ally = game.scene.getPlayerField()[0]; + vi.spyOn(ally, "getAccuracyMultiplier"); + + game.move.select(Moves.TACKLE, 0, BattlerIndex.ENEMY); + game.move.select(Moves.SPLASH, 1); + await game.phaseInterceptor.to(TurnEndPhase); + + expect(ally.getAccuracyMultiplier).toHaveReturnedWith(1.1); + }); +}); From 5f01caffae90556e879219108d6c6d80273bc2a9 Mon Sep 17 00:00:00 2001 From: Sirz Benjie <142067137+SirzBenjie@users.noreply.github.com> Date: Fri, 28 Mar 2025 23:19:35 -0500 Subject: [PATCH 2/2] [Refactor] Minor refactor of trainer-config files (#5573) * Move trainer-config.ts * move TeraAIMode enum to its own file * Move TrainerPoolTier enum to its own file * Move TrainerSlot enum to its own file * Reorder and group imports * Move TrainerPartyTemplate to its own file * Remove speciesPoolPerEvilTeamAdmin method * Apply kev's suggestions from code review Co-authored-by: NightKev <34855794+DayKev@users.noreply.github.com> * Fix typo in zinzolin's name --------- Co-authored-by: NightKev <34855794+DayKev@users.noreply.github.com> --- src/battle-scene.ts | 4 +- src/battle.ts | 2 +- src/data/dialogue.ts | 2 +- .../encounters/a-trainers-test-encounter.ts | 2 +- .../encounters/absolute-avarice-encounter.ts | 2 +- .../encounters/bug-type-superfan-encounter.ts | 11 +- .../encounters/clowning-around-encounter.ts | 4 +- .../encounters/dancing-lessons-encounter.ts | 2 +- .../encounters/fun-and-games-encounter.ts | 2 +- .../global-trade-system-encounter.ts | 2 +- .../mysterious-challengers-encounter.ts | 10 +- .../encounters/safari-zone-encounter.ts | 2 +- .../teleporting-hijinks-encounter.ts | 2 +- .../the-expert-pokemon-breeder-encounter.ts | 2 +- .../encounters/weird-dream-encounter.ts | 3 +- .../utils/encounter-phase-utils.ts | 5 +- src/data/trainers/TrainerPartyTemplate.ts | 255 ++++++ src/data/trainers/evil-admin-trainer-pools.ts | 436 ++++++++++ src/data/{ => trainers}/trainer-config.ts | 789 +----------------- src/data/trainers/typedefs.ts | 22 + src/enums/tera-ai-mode.ts | 5 + src/enums/trainer-pool-tier.ts | 7 + src/enums/trainer-slot.ts | 5 + src/field/pokemon.ts | 2 +- src/field/trainer.ts | 17 +- src/phases/battle-phase.ts | 2 +- src/phases/encounter-phase.ts | 2 +- src/phases/game-over-phase.ts | 2 +- src/phases/mystery-encounter-phases.ts | 2 +- src/phases/summon-phase.ts | 2 +- src/phases/switch-summon-phase.ts | 2 +- src/phases/trainer-message-test-phase.ts | 2 +- src/phases/trainer-victory-phase.ts | 2 +- src/system/game-data.ts | 2 +- src/system/pokemon-data.ts | 2 +- src/system/voucher.ts | 2 +- test/moves/effectiveness.test.ts | 2 +- .../mysterious-challengers-encounter.test.ts | 4 +- 38 files changed, 828 insertions(+), 795 deletions(-) create mode 100644 src/data/trainers/TrainerPartyTemplate.ts create mode 100644 src/data/trainers/evil-admin-trainer-pools.ts rename src/data/{ => trainers}/trainer-config.ts (88%) create mode 100644 src/data/trainers/typedefs.ts create mode 100644 src/enums/tera-ai-mode.ts create mode 100644 src/enums/trainer-pool-tier.ts create mode 100644 src/enums/trainer-slot.ts diff --git a/src/battle-scene.ts b/src/battle-scene.ts index 443113daef6..5797fda5611 100644 --- a/src/battle-scene.ts +++ b/src/battle-scene.ts @@ -72,8 +72,8 @@ import { GameModes, getGameMode } from "#app/game-mode"; import FieldSpritePipeline from "#app/pipelines/field-sprite"; import SpritePipeline from "#app/pipelines/sprite"; import PartyExpBar from "#app/ui/party-exp-bar"; -import type { TrainerSlot } from "#app/data/trainer-config"; -import { trainerConfigs } from "#app/data/trainer-config"; +import type { TrainerSlot } from "./enums/trainer-slot"; +import { trainerConfigs } from "#app/data/trainers/trainer-config"; import Trainer, { TrainerVariant } from "#app/field/trainer"; import type TrainerData from "#app/system/trainer-data"; import SoundFade from "phaser3-rex-plugins/plugins/soundfade"; diff --git a/src/battle.ts b/src/battle.ts index 5ada921bf5a..367c52568dc 100644 --- a/src/battle.ts +++ b/src/battle.ts @@ -5,7 +5,7 @@ import Trainer, { TrainerVariant } from "./field/trainer"; import type { GameMode } from "./game-mode"; import { MoneyMultiplierModifier, PokemonHeldItemModifier } from "./modifier/modifier"; import type { PokeballType } from "#enums/pokeball"; -import { trainerConfigs } from "#app/data/trainer-config"; +import { trainerConfigs } from "#app/data/trainers/trainer-config"; import { SpeciesFormKey } from "#enums/species-form-key"; import type { EnemyPokemon, PlayerPokemon, TurnMove } from "#app/field/pokemon"; import type Pokemon from "#app/field/pokemon"; diff --git a/src/data/dialogue.ts b/src/data/dialogue.ts index 0e755d54e15..fa640e92b00 100644 --- a/src/data/dialogue.ts +++ b/src/data/dialogue.ts @@ -1,6 +1,6 @@ import { BattleSpec } from "#enums/battle-spec"; import { TrainerType } from "#enums/trainer-type"; -import { trainerConfigs } from "./trainer-config"; +import { trainerConfigs } from "./trainers/trainer-config"; export interface TrainerTypeMessages { encounter?: string | string[]; diff --git a/src/data/mystery-encounters/encounters/a-trainers-test-encounter.ts b/src/data/mystery-encounters/encounters/a-trainers-test-encounter.ts index 6cea85346b3..a49157f8e88 100644 --- a/src/data/mystery-encounters/encounters/a-trainers-test-encounter.ts +++ b/src/data/mystery-encounters/encounters/a-trainers-test-encounter.ts @@ -6,7 +6,7 @@ import { setEncounterRewards, transitionMysteryEncounterIntroVisuals, } from "#app/data/mystery-encounters/utils/encounter-phase-utils"; -import { trainerConfigs } from "#app/data/trainer-config"; +import { trainerConfigs } from "#app/data/trainers/trainer-config"; import { MysteryEncounterType } from "#enums/mystery-encounter-type"; import type MysteryEncounter from "#app/data/mystery-encounters/mystery-encounter"; import { MysteryEncounterBuilder } from "#app/data/mystery-encounters/mystery-encounter"; diff --git a/src/data/mystery-encounters/encounters/absolute-avarice-encounter.ts b/src/data/mystery-encounters/encounters/absolute-avarice-encounter.ts index ca44782691d..85f40a41e51 100644 --- a/src/data/mystery-encounters/encounters/absolute-avarice-encounter.ts +++ b/src/data/mystery-encounters/encounters/absolute-avarice-encounter.ts @@ -31,7 +31,7 @@ import { catchPokemon, getHighestLevelPlayerPokemon, } from "#app/data/mystery-encounters/utils/encounter-pokemon-utils"; -import { TrainerSlot } from "#app/data/trainer-config"; +import { TrainerSlot } from "#enums/trainer-slot"; import { PokeballType } from "#enums/pokeball"; import type HeldModifierConfig from "#app/interfaces/held-modifier-config"; import type { BerryType } from "#enums/berry-type"; diff --git a/src/data/mystery-encounters/encounters/bug-type-superfan-encounter.ts b/src/data/mystery-encounters/encounters/bug-type-superfan-encounter.ts index 15cba1fa103..1e4c9a3b957 100644 --- a/src/data/mystery-encounters/encounters/bug-type-superfan-encounter.ts +++ b/src/data/mystery-encounters/encounters/bug-type-superfan-encounter.ts @@ -9,13 +9,10 @@ import { setEncounterRewards, transitionMysteryEncounterIntroVisuals, } from "#app/data/mystery-encounters/utils/encounter-phase-utils"; -import { - getRandomPartyMemberFunc, - trainerConfigs, - TrainerPartyCompoundTemplate, - TrainerPartyTemplate, - TrainerSlot, -} from "#app/data/trainer-config"; +import { getRandomPartyMemberFunc, trainerConfigs } from "#app/data/trainers/trainer-config"; +import { TrainerPartyCompoundTemplate } from "#app/data/trainers/TrainerPartyTemplate"; +import { TrainerPartyTemplate } from "#app/data/trainers/TrainerPartyTemplate"; +import { TrainerSlot } from "#enums/trainer-slot"; import { MysteryEncounterType } from "#enums/mystery-encounter-type"; import { PartyMemberStrength } from "#enums/party-member-strength"; import { globalScene } from "#app/global-scene"; diff --git a/src/data/mystery-encounters/encounters/clowning-around-encounter.ts b/src/data/mystery-encounters/encounters/clowning-around-encounter.ts index 2b499d938cd..eca99fc0c13 100644 --- a/src/data/mystery-encounters/encounters/clowning-around-encounter.ts +++ b/src/data/mystery-encounters/encounters/clowning-around-encounter.ts @@ -8,7 +8,9 @@ import { setEncounterRewards, transitionMysteryEncounterIntroVisuals, } from "#app/data/mystery-encounters/utils/encounter-phase-utils"; -import { trainerConfigs, TrainerPartyCompoundTemplate, TrainerPartyTemplate } from "#app/data/trainer-config"; +import { trainerConfigs } from "#app/data/trainers/trainer-config"; +import { TrainerPartyCompoundTemplate } from "#app/data/trainers/TrainerPartyTemplate"; +import { TrainerPartyTemplate } from "#app/data/trainers/TrainerPartyTemplate"; import { ModifierTier } from "#app/modifier/modifier-tier"; import type { PokemonHeldItemModifierType } from "#app/modifier/modifier-type"; import { ModifierPoolType, modifierTypes } from "#app/modifier/modifier-type"; diff --git a/src/data/mystery-encounters/encounters/dancing-lessons-encounter.ts b/src/data/mystery-encounters/encounters/dancing-lessons-encounter.ts index 91f168371cf..75527e1f8c1 100644 --- a/src/data/mystery-encounters/encounters/dancing-lessons-encounter.ts +++ b/src/data/mystery-encounters/encounters/dancing-lessons-encounter.ts @@ -20,7 +20,7 @@ import { STANDARD_ENCOUNTER_BOOSTED_LEVEL_MODIFIER, } from "#app/data/mystery-encounters/utils/encounter-pokemon-utils"; import { getPokemonSpecies } from "#app/data/pokemon-species"; -import { TrainerSlot } from "#app/data/trainer-config"; +import { TrainerSlot } from "#enums/trainer-slot"; import type { PlayerPokemon } from "#app/field/pokemon"; import type Pokemon from "#app/field/pokemon"; import { EnemyPokemon, PokemonMove } from "#app/field/pokemon"; diff --git a/src/data/mystery-encounters/encounters/fun-and-games-encounter.ts b/src/data/mystery-encounters/encounters/fun-and-games-encounter.ts index c95810b94d0..282c6c149ff 100644 --- a/src/data/mystery-encounters/encounters/fun-and-games-encounter.ts +++ b/src/data/mystery-encounters/encounters/fun-and-games-encounter.ts @@ -10,7 +10,7 @@ import { globalScene } from "#app/global-scene"; import type MysteryEncounter from "#app/data/mystery-encounters/mystery-encounter"; import { MysteryEncounterBuilder } from "#app/data/mystery-encounters/mystery-encounter"; import { MysteryEncounterOptionBuilder } from "#app/data/mystery-encounters/mystery-encounter-option"; -import { TrainerSlot } from "#app/data/trainer-config"; +import { TrainerSlot } from "#enums/trainer-slot"; import type { PlayerPokemon } from "#app/field/pokemon"; import type Pokemon from "#app/field/pokemon"; import { FieldPosition } from "#app/field/pokemon"; diff --git a/src/data/mystery-encounters/encounters/global-trade-system-encounter.ts b/src/data/mystery-encounters/encounters/global-trade-system-encounter.ts index 4f10a657e4e..c13501c4511 100644 --- a/src/data/mystery-encounters/encounters/global-trade-system-encounter.ts +++ b/src/data/mystery-encounters/encounters/global-trade-system-encounter.ts @@ -3,7 +3,7 @@ import { selectPokemonForOption, setEncounterRewards, } from "#app/data/mystery-encounters/utils/encounter-phase-utils"; -import { TrainerSlot } from "#app/data/trainer-config"; +import { TrainerSlot } from "#enums/trainer-slot"; import { ModifierTier } from "#app/modifier/modifier-tier"; import { MusicPreference } from "#app/system/settings/settings"; import type { ModifierTypeOption } from "#app/modifier/modifier-type"; diff --git a/src/data/mystery-encounters/encounters/mysterious-challengers-encounter.ts b/src/data/mystery-encounters/encounters/mysterious-challengers-encounter.ts index bf60e982b15..11924f93df4 100644 --- a/src/data/mystery-encounters/encounters/mysterious-challengers-encounter.ts +++ b/src/data/mystery-encounters/encounters/mysterious-challengers-encounter.ts @@ -3,12 +3,10 @@ import { initBattleWithEnemyConfig, setEncounterRewards, } from "#app/data/mystery-encounters/utils/encounter-phase-utils"; -import { - trainerConfigs, - TrainerPartyCompoundTemplate, - TrainerPartyTemplate, - trainerPartyTemplates, -} from "#app/data/trainer-config"; +import { trainerConfigs } from "#app/data/trainers/trainer-config"; +import { trainerPartyTemplates } from "#app/data/trainers/TrainerPartyTemplate"; +import { TrainerPartyCompoundTemplate } from "#app/data/trainers/TrainerPartyTemplate"; +import { TrainerPartyTemplate } from "#app/data/trainers/TrainerPartyTemplate"; import { ModifierTier } from "#app/modifier/modifier-tier"; import { modifierTypes } from "#app/modifier/modifier-type"; import { MysteryEncounterType } from "#enums/mystery-encounter-type"; diff --git a/src/data/mystery-encounters/encounters/safari-zone-encounter.ts b/src/data/mystery-encounters/encounters/safari-zone-encounter.ts index f231e4abdb8..8c45fde3079 100644 --- a/src/data/mystery-encounters/encounters/safari-zone-encounter.ts +++ b/src/data/mystery-encounters/encounters/safari-zone-encounter.ts @@ -10,7 +10,7 @@ import type MysteryEncounter from "#app/data/mystery-encounters/mystery-encounte import { MysteryEncounterBuilder } from "#app/data/mystery-encounters/mystery-encounter"; import type MysteryEncounterOption from "#app/data/mystery-encounters/mystery-encounter-option"; import { MysteryEncounterOptionBuilder } from "#app/data/mystery-encounters/mystery-encounter-option"; -import { TrainerSlot } from "#app/data/trainer-config"; +import { TrainerSlot } from "#enums/trainer-slot"; import { HiddenAbilityRateBoosterModifier, IvScannerModifier } from "#app/modifier/modifier"; import type { EnemyPokemon } from "#app/field/pokemon"; import { PokeballType } from "#enums/pokeball"; diff --git a/src/data/mystery-encounters/encounters/teleporting-hijinks-encounter.ts b/src/data/mystery-encounters/encounters/teleporting-hijinks-encounter.ts index c7220192caa..806a89a7131 100644 --- a/src/data/mystery-encounters/encounters/teleporting-hijinks-encounter.ts +++ b/src/data/mystery-encounters/encounters/teleporting-hijinks-encounter.ts @@ -24,7 +24,7 @@ import { Biome } from "#enums/biome"; import { getBiomeKey } from "#app/field/arena"; import { PokemonType } from "#enums/pokemon-type"; import { getPartyLuckValue, modifierTypes } from "#app/modifier/modifier-type"; -import { TrainerSlot } from "#app/data/trainer-config"; +import { TrainerSlot } from "#enums/trainer-slot"; import { BattlerTagType } from "#enums/battler-tag-type"; import { getPokemonNameWithAffix } from "#app/messages"; import { StatStageChangePhase } from "#app/phases/stat-stage-change-phase"; diff --git a/src/data/mystery-encounters/encounters/the-expert-pokemon-breeder-encounter.ts b/src/data/mystery-encounters/encounters/the-expert-pokemon-breeder-encounter.ts index 2b29046f738..84dd5002e83 100644 --- a/src/data/mystery-encounters/encounters/the-expert-pokemon-breeder-encounter.ts +++ b/src/data/mystery-encounters/encounters/the-expert-pokemon-breeder-encounter.ts @@ -4,7 +4,7 @@ import { initBattleWithEnemyConfig, setEncounterRewards, } from "#app/data/mystery-encounters/utils/encounter-phase-utils"; -import { trainerConfigs } from "#app/data/trainer-config"; +import { trainerConfigs } from "#app/data/trainers/trainer-config"; import { MysteryEncounterType } from "#enums/mystery-encounter-type"; import { globalScene } from "#app/global-scene"; import { randSeedShuffle } from "#app/utils"; diff --git a/src/data/mystery-encounters/encounters/weird-dream-encounter.ts b/src/data/mystery-encounters/encounters/weird-dream-encounter.ts index 5d3f834ed75..22ec52e976c 100644 --- a/src/data/mystery-encounters/encounters/weird-dream-encounter.ts +++ b/src/data/mystery-encounters/encounters/weird-dream-encounter.ts @@ -41,7 +41,8 @@ import { TrainerType } from "#enums/trainer-type"; import PokemonData from "#app/system/pokemon-data"; import { Nature } from "#enums/nature"; import type HeldModifierConfig from "#app/interfaces/held-modifier-config"; -import { trainerConfigs, TrainerPartyTemplate } from "#app/data/trainer-config"; +import { trainerConfigs } from "#app/data/trainers/trainer-config"; +import { TrainerPartyTemplate } from "#app/data/trainers/TrainerPartyTemplate"; import { PartyMemberStrength } from "#enums/party-member-strength"; /** i18n namespace for encounter */ diff --git a/src/data/mystery-encounters/utils/encounter-phase-utils.ts b/src/data/mystery-encounters/utils/encounter-phase-utils.ts index d37ac340a7c..5c6acf43e26 100644 --- a/src/data/mystery-encounters/utils/encounter-phase-utils.ts +++ b/src/data/mystery-encounters/utils/encounter-phase-utils.ts @@ -43,8 +43,9 @@ import type { Moves } from "#enums/moves"; import { initMoveAnim, loadMoveAnimAssets } from "#app/data/battle-anims"; import { MysteryEncounterMode } from "#enums/mystery-encounter-mode"; import { Status } from "#app/data/status-effect"; -import type { TrainerConfig } from "#app/data/trainer-config"; -import { trainerConfigs, TrainerSlot } from "#app/data/trainer-config"; +import type { TrainerConfig } from "#app/data/trainers/trainer-config"; +import { trainerConfigs } from "#app/data/trainers/trainer-config"; +import { TrainerSlot } from "#enums/trainer-slot"; import type PokemonSpecies from "#app/data/pokemon-species"; import type { IEggOptions } from "#app/data/egg"; import { Egg } from "#app/data/egg"; diff --git a/src/data/trainers/TrainerPartyTemplate.ts b/src/data/trainers/TrainerPartyTemplate.ts new file mode 100644 index 00000000000..adbaacc6b55 --- /dev/null +++ b/src/data/trainers/TrainerPartyTemplate.ts @@ -0,0 +1,255 @@ +import { startingWave } from "#app/battle-scene"; +import { globalScene } from "#app/global-scene"; +import { PartyMemberStrength } from "#enums/party-member-strength"; + +export class TrainerPartyTemplate { + public size: number; + public strength: PartyMemberStrength; + public sameSpecies: boolean; + public balanced: boolean; + + constructor(size: number, strength: PartyMemberStrength, sameSpecies?: boolean, balanced?: boolean) { + this.size = size; + this.strength = strength; + this.sameSpecies = !!sameSpecies; + this.balanced = !!balanced; + } + + getStrength(_index: number): PartyMemberStrength { + return this.strength; + } + + isSameSpecies(_index: number): boolean { + return this.sameSpecies; + } + + isBalanced(_index: number): boolean { + return this.balanced; + } +} + +export class TrainerPartyCompoundTemplate extends TrainerPartyTemplate { + public templates: TrainerPartyTemplate[]; + + constructor(...templates: TrainerPartyTemplate[]) { + super( + templates.reduce((total: number, template: TrainerPartyTemplate) => { + total += template.size; + return total; + }, 0), + PartyMemberStrength.AVERAGE, + ); + this.templates = templates; + } + + getStrength(index: number): PartyMemberStrength { + let t = 0; + for (const template of this.templates) { + if (t + template.size > index) { + return template.getStrength(index - t); + } + t += template.size; + } + + return super.getStrength(index); + } + + isSameSpecies(index: number): boolean { + let t = 0; + for (const template of this.templates) { + if (t + template.size > index) { + return template.isSameSpecies(index - t); + } + t += template.size; + } + + return super.isSameSpecies(index); + } + + isBalanced(index: number): boolean { + let t = 0; + for (const template of this.templates) { + if (t + template.size > index) { + return template.isBalanced(index - t); + } + t += template.size; + } + + return super.isBalanced(index); + } +} + +export const trainerPartyTemplates = { + 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.WEAK, 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_2: new TrainerPartyCompoundTemplate( + new TrainerPartyTemplate(1, PartyMemberStrength.AVERAGE), + new TrainerPartyTemplate(1, PartyMemberStrength.STRONG), + new TrainerPartyTemplate(1, PartyMemberStrength.STRONGER), + ), + 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(3, PartyMemberStrength.AVERAGE), + new TrainerPartyTemplate(2, PartyMemberStrength.STRONG), + new TrainerPartyTemplate(1, PartyMemberStrength.STRONGER), + ), + + ELITE_FOUR: new TrainerPartyCompoundTemplate( + new TrainerPartyTemplate(2, PartyMemberStrength.AVERAGE), + new TrainerPartyTemplate(3, PartyMemberStrength.STRONG), + new TrainerPartyTemplate(1, PartyMemberStrength.STRONGER), + ), + + CHAMPION: new TrainerPartyCompoundTemplate( + new TrainerPartyTemplate(4, PartyMemberStrength.STRONG), + new TrainerPartyTemplate(2, PartyMemberStrength.STRONGER, false, true), + ), + + 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.WEAK, false, true), + ), + RIVAL_3: new TrainerPartyCompoundTemplate( + new TrainerPartyTemplate(1, PartyMemberStrength.STRONG), + new TrainerPartyTemplate(1, PartyMemberStrength.AVERAGE), + new TrainerPartyTemplate(1, PartyMemberStrength.AVERAGE, false, true), + new TrainerPartyTemplate(1, PartyMemberStrength.WEAK, false, true), + ), + RIVAL_4: new TrainerPartyCompoundTemplate( + new TrainerPartyTemplate(1, PartyMemberStrength.STRONG), + new TrainerPartyTemplate(1, PartyMemberStrength.AVERAGE), + new TrainerPartyTemplate(2, PartyMemberStrength.AVERAGE, false, true), + new TrainerPartyTemplate(1, PartyMemberStrength.WEAK, 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), + ), +}; + +/** + * The function to get variable strength grunts + * @returns the correct TrainerPartyTemplate + */ +export function getEvilGruntPartyTemplate(): TrainerPartyTemplate { + const waveIndex = globalScene.currentBattle?.waveIndex; + if (waveIndex < 40) { + return trainerPartyTemplates.TWO_AVG; + } + if (waveIndex < 63) { + return trainerPartyTemplates.THREE_AVG; + } + if (waveIndex < 65) { + return trainerPartyTemplates.TWO_AVG_ONE_STRONG; + } + if (waveIndex < 112) { + return trainerPartyTemplates.GYM_LEADER_4; // 3avg 1 strong 1 stronger + } + return trainerPartyTemplates.GYM_LEADER_5; // 3 avg 2 strong 1 stronger +} + +export function getWavePartyTemplate(...templates: TrainerPartyTemplate[]) { + const { currentBattle, gameMode } = globalScene; + const wave = gameMode.getWaveForDifficulty(currentBattle?.waveIndex || startingWave, true); + const templateIndex = Math.ceil((wave - 20) / 30); + return templates[Phaser.Math.Clamp(templateIndex, 0, templates.length - 1)]; +} + +export function getGymLeaderPartyTemplate() { + return getWavePartyTemplate( + trainerPartyTemplates.GYM_LEADER_1, + trainerPartyTemplates.GYM_LEADER_2, + trainerPartyTemplates.GYM_LEADER_3, + trainerPartyTemplates.GYM_LEADER_4, + trainerPartyTemplates.GYM_LEADER_5, + ); +} diff --git a/src/data/trainers/evil-admin-trainer-pools.ts b/src/data/trainers/evil-admin-trainer-pools.ts new file mode 100644 index 00000000000..ecbd5952143 --- /dev/null +++ b/src/data/trainers/evil-admin-trainer-pools.ts @@ -0,0 +1,436 @@ +import type { TrainerTierPools } from "#app/data/trainers/typedefs"; +import { TrainerPoolTier } from "#enums/trainer-pool-tier"; +import { Species } from "#enums/species"; + +/** Team Rocket's admin trainer pool. */ +const ROCKET: TrainerTierPools = { + [TrainerPoolTier.COMMON]: [ + Species.RATICATE, + Species.ARBOK, + Species.VILEPLUME, + Species.ARCANINE, + Species.GENGAR, + Species.HYPNO, + Species.ELECTRODE, + Species.EXEGGUTOR, + Species.CUBONE, + Species.KOFFING, + Species.GYARADOS, + Species.CROBAT, + Species.STEELIX, + Species.HOUNDOOM, + Species.HONCHKROW, + ], + [TrainerPoolTier.UNCOMMON]: [ + Species.OMASTAR, + Species.KABUTOPS, + Species.MAGNEZONE, + Species.ELECTIVIRE, + Species.MAGMORTAR, + Species.PORYGON_Z, + Species.ANNIHILAPE, + Species.ALOLA_SANDSLASH, + Species.ALOLA_PERSIAN, + Species.ALOLA_GOLEM, + Species.ALOLA_MUK, + Species.PALDEA_TAUROS, + ], + [TrainerPoolTier.RARE]: [Species.DRAGONITE, Species.TYRANITAR], +}; + +/** Team Magma's admin trainer pool */ +const MAGMA: TrainerTierPools = { + [TrainerPoolTier.COMMON]: [ + Species.ARCANINE, + Species.MAGCARGO, + Species.HOUNDOOM, + Species.TORKOAL, + Species.SOLROCK, + Species.CLAYDOL, + Species.HIPPOWDON, + Species.MAGMORTAR, + Species.GLISCOR, + Species.COALOSSAL, + ], + [TrainerPoolTier.UNCOMMON]: [ + Species.AGGRON, + Species.FLYGON, + Species.CRADILY, + Species.ARMALDO, + Species.RHYPERIOR, + Species.TURTONATOR, + Species.SANDACONDA, + Species.TOEDSCRUEL, + Species.HISUI_ARCANINE, + ], + [TrainerPoolTier.RARE]: [Species.CHARCADET, Species.SCOVILLAIN], +}; + +const AQUA: TrainerTierPools = { + [TrainerPoolTier.COMMON]: [ + Species.TENTACRUEL, + Species.LANTURN, + Species.AZUMARILL, + Species.QUAGSIRE, + Species.OCTILLERY, + Species.LUDICOLO, + Species.PELIPPER, + Species.WAILORD, + Species.WHISCASH, + Species.CRAWDAUNT, + Species.WALREIN, + Species.CLAMPERL, + ], + [TrainerPoolTier.UNCOMMON]: [ + Species.QUAGSIRE, + Species.MANTINE, + Species.KINGDRA, + Species.MILOTIC, + Species.DRAGALGE, + Species.DHELMISE, + Species.BARRASKEWDA, + Species.GRAPPLOCT, + Species.OVERQWIL, + ], + [TrainerPoolTier.RARE]: [Species.BASCULEGION, Species.DONDOZO], +}; + +const GALACTIC: TrainerTierPools = { + [TrainerPoolTier.COMMON]: [ + Species.ELECTRODE, + Species.GYARADOS, + Species.CROBAT, + Species.HONCHKROW, + Species.BRONZONG, + Species.DRAPION, + Species.LICKILICKY, + Species.TANGROWTH, + Species.ELECTIVIRE, + Species.MAGMORTAR, + Species.YANMEGA, + Species.MAMOSWINE, + ], + [TrainerPoolTier.UNCOMMON]: [ + Species.ALAKAZAM, + Species.WEAVILE, + Species.GLISCOR, + Species.DUSKNOIR, + Species.ROTOM, + Species.OVERQWIL, + Species.HISUI_ARCANINE, + Species.HISUI_ELECTRODE, + ], + [TrainerPoolTier.RARE]: [Species.SPIRITOMB, Species.URSALUNA, Species.SNEASLER, Species.HISUI_LILLIGANT], +}; + +const PLASMA_ZINZOLIN: TrainerTierPools = { + [TrainerPoolTier.COMMON]: [ + Species.GIGALITH, + Species.CONKELDURR, + Species.SEISMITOAD, + Species.KROOKODILE, + Species.DARMANITAN, + Species.COFAGRIGUS, + Species.VANILLUXE, + Species.AMOONGUSS, + Species.JELLICENT, + Species.GALVANTULA, + Species.FERROTHORN, + Species.BEARTIC, + ], + [TrainerPoolTier.UNCOMMON]: [ + Species.EXCADRILL, + Species.SIGILYPH, + Species.ZOROARK, + Species.KLINKLANG, + Species.EELEKTROSS, + Species.MIENSHAO, + Species.GOLURK, + Species.BISHARP, + Species.MANDIBUZZ, + Species.DURANT, + Species.GALAR_DARMANITAN, + ], + [TrainerPoolTier.RARE]: [Species.HAXORUS, Species.HYDREIGON, Species.HISUI_ZOROARK, Species.HISUI_BRAVIARY], +}; + +const PLASMA_COLRESS: TrainerTierPools = { + [TrainerPoolTier.COMMON]: [ + Species.MUK, + Species.ELECTRODE, + Species.BRONZONG, + Species.MAGNEZONE, + Species.PORYGON_Z, + Species.MUSHARNA, + Species.REUNICLUS, + Species.GALVANTULA, + Species.FERROTHORN, + Species.EELEKTROSS, + Species.BEHEEYEM, + ], + [TrainerPoolTier.UNCOMMON]: [ + Species.METAGROSS, + Species.ROTOM, + Species.CARRACOSTA, + Species.ARCHEOPS, + Species.GOLURK, + Species.DURANT, + Species.VIKAVOLT, + Species.ORBEETLE, + Species.REVAVROOM, + Species.ALOLA_MUK, + Species.HISUI_ELECTRODE, + ], + [TrainerPoolTier.RARE]: [Species.ELECTIVIRE, Species.MAGMORTAR, Species.BISHARP, Species.ARCHALUDON], +}; + +const FLARE: TrainerTierPools = { + [TrainerPoolTier.COMMON]: [ + Species.MANECTRIC, + Species.DRAPION, + Species.LIEPARD, + Species.AMOONGUSS, + Species.DIGGERSBY, + Species.TALONFLAME, + Species.PYROAR, + Species.PANGORO, + Species.MEOWSTIC, + Species.MALAMAR, + Species.CLAWITZER, + Species.HELIOLISK, + ], + [TrainerPoolTier.UNCOMMON]: [ + Species.HOUNDOOM, + Species.WEAVILE, + Species.CHANDELURE, + Species.AEGISLASH, + Species.BARBARACLE, + Species.DRAGALGE, + Species.GOODRA, + Species.TREVENANT, + Species.GOURGEIST, + ], + [TrainerPoolTier.RARE]: [Species.NOIVERN, Species.HISUI_GOODRA, Species.HISUI_AVALUGG], +}; + +const AETHER: TrainerTierPools = { + [TrainerPoolTier.COMMON]: [ + Species.ALAKAZAM, + Species.SLOWBRO, + Species.EXEGGUTOR, + Species.XATU, + Species.CLAYDOL, + Species.BEHEEYEM, + Species.ORANGURU, + Species.BRUXISH, + Species.ORBEETLE, + Species.FARIGIRAF, + Species.ALOLA_RAICHU, + ], + [TrainerPoolTier.UNCOMMON]: [ + Species.KIRLIA, + Species.MEDICHAM, + Species.METAGROSS, + Species.MALAMAR, + Species.HATTERENE, + Species.MR_RIME, + Species.GALAR_SLOWKING, + ], + [TrainerPoolTier.RARE]: [Species.PORYGON_Z, Species.ARMAROUGE, Species.HISUI_BRAVIARY], +}; + +const SKULL: TrainerTierPools = { + [TrainerPoolTier.COMMON]: [ + Species.NIDOQUEEN, + Species.GENGAR, + Species.KOFFING, + Species.CROBAT, + Species.ROSERADE, + Species.SKUNTANK, + Species.TOXICROAK, + Species.SCOLIPEDE, + Species.TOXAPEX, + Species.LURANTIS, + Species.ALOLA_MUK, + ], + [TrainerPoolTier.UNCOMMON]: [ + Species.DRAPION, + Species.MANDIBUZZ, + Species.OVERQWIL, + Species.GLIMMORA, + Species.CLODSIRE, + Species.GALAR_SLOWBRO, + ], + [TrainerPoolTier.RARE]: [Species.DRAGALGE, Species.SNEASLER], +}; + +const MACRO_COSMOS: TrainerTierPools = { + [TrainerPoolTier.COMMON]: [ + Species.NINETALES, + Species.BELLOSSOM, + Species.MILOTIC, + Species.FROSLASS, + Species.GOTHITELLE, + Species.JELLICENT, + Species.SALAZZLE, + Species.TSAREENA, + Species.POLTEAGEIST, + Species.HATTERENE, + Species.GALAR_RAPIDASH, + ], + [TrainerPoolTier.UNCOMMON]: [ + Species.TOGEKISS, + Species.MANDIBUZZ, + Species.TOXAPEX, + Species.APPLETUN, + Species.CURSOLA, + Species.ALOLA_NINETALES, + ], + [TrainerPoolTier.RARE]: [Species.TINKATON, Species.HISUI_LILLIGANT], +}; + +const STAR_DARK: TrainerTierPools = { + [TrainerPoolTier.COMMON]: [ + Species.SHIFTRY, + Species.CACTURNE, + Species.HONCHKROW, + Species.SKUNTANK, + Species.KROOKODILE, + Species.OBSTAGOON, + Species.LOKIX, + Species.MABOSSTIFF, + ], + [TrainerPoolTier.UNCOMMON]: [ + Species.UMBREON, + Species.CRAWDAUNT, + Species.WEAVILE, + Species.ZOROARK, + Species.MALAMAR, + Species.BOMBIRDIER, + ], + [TrainerPoolTier.RARE]: [Species.HYDREIGON, Species.MEOWSCARADA], +}; + +const STAR_FIRE: TrainerTierPools = { + [TrainerPoolTier.COMMON]: [ + Species.ARCANINE, + Species.HOUNDOOM, + Species.CAMERUPT, + Species.CHANDELURE, + Species.TALONFLAME, + Species.PYROAR, + Species.COALOSSAL, + Species.SCOVILLAIN, + ], + [TrainerPoolTier.UNCOMMON]: [ + Species.RAPIDASH, + Species.FLAREON, + Species.TORKOAL, + Species.MAGMORTAR, + Species.SALAZZLE, + Species.TURTONATOR, + ], + [TrainerPoolTier.RARE]: [Species.VOLCARONA, Species.SKELEDIRGE], +}; + +const STAR_POISON: TrainerTierPools = { + [TrainerPoolTier.COMMON]: [ + Species.MUK, + Species.CROBAT, + Species.SKUNTANK, + Species.AMOONGUSS, + Species.TOXAPEX, + Species.TOXTRICITY, + Species.GRAFAIAI, + Species.CLODSIRE, + ], + [TrainerPoolTier.UNCOMMON]: [ + Species.GENGAR, + Species.SEVIPER, + Species.DRAGALGE, + Species.OVERQWIL, + Species.ALOLA_MUK, + Species.GALAR_SLOWBRO, + ], + [TrainerPoolTier.RARE]: [Species.GLIMMORA, Species.VENUSAUR], +}; + +const STAR_FAIRY: TrainerTierPools = { + [TrainerPoolTier.COMMON]: [ + Species.CLEFABLE, + Species.WIGGLYTUFF, + Species.AZUMARILL, + Species.WHIMSICOTT, + Species.FLORGES, + Species.HATTERENE, + Species.GRIMMSNARL, + Species.TINKATON, + ], + [TrainerPoolTier.UNCOMMON]: [ + Species.TOGEKISS, + Species.GARDEVOIR, + Species.SYLVEON, + Species.KLEFKI, + Species.MIMIKYU, + Species.ALOLA_NINETALES, + ], + [TrainerPoolTier.RARE]: [Species.GALAR_RAPIDASH, Species.PRIMARINA], +}; + +const STAR_FIGHTING: TrainerTierPools = { + [TrainerPoolTier.COMMON]: [ + Species.BRELOOM, + Species.HARIYAMA, + Species.MEDICHAM, + Species.TOXICROAK, + Species.SCRAFTY, + Species.MIENSHAO, + Species.PAWMOT, + Species.PALDEA_TAUROS, + ], + [TrainerPoolTier.UNCOMMON]: [ + Species.LUCARIO, + Species.CONKELDURR, + Species.HAWLUCHA, + Species.PASSIMIAN, + Species.FALINKS, + Species.FLAMIGO, + ], + [TrainerPoolTier.RARE]: [Species.KOMMO_O, Species.QUAQUAVAL], +}; + +export type EvilTeam = + | "rocket" + | "magma" + | "aqua" + | "galactic" + | "plasma_zinzolin" + | "plasma_colress" + | "flare" + | "aether" + | "skull" + | "macro_cosmos" + | "star_dark" + | "star_fire" + | "star_poison" + | "star_fairy" + | "star_fighting"; + +/** Trainer pools for each evil admin team */ +export const evilAdminTrainerPools: Record = { + rocket: ROCKET, + magma: MAGMA, + aqua: AQUA, + galactic: GALACTIC, + plasma_zinzolin: PLASMA_ZINZOLIN, + plasma_colress: PLASMA_COLRESS, + flare: FLARE, + aether: AETHER, + macro_cosmos: MACRO_COSMOS, + skull: SKULL, + star_dark: STAR_DARK, + star_fire: STAR_FIRE, + star_poison: STAR_POISON, + star_fairy: STAR_FAIRY, + star_fighting: STAR_FIGHTING, +}; diff --git a/src/data/trainer-config.ts b/src/data/trainers/trainer-config.ts similarity index 88% rename from src/data/trainer-config.ts rename to src/data/trainers/trainer-config.ts index 0417e7abc32..f23027ffee8 100644 --- a/src/data/trainer-config.ts +++ b/src/data/trainers/trainer-config.ts @@ -1,29 +1,53 @@ -import { startingWave } from "#app/battle-scene"; import { globalScene } from "#app/global-scene"; -import type { ModifierTypeFunc } from "#app/modifier/modifier-type"; import { modifierTypes } from "#app/modifier/modifier-type"; -import type { EnemyPokemon } from "#app/field/pokemon"; import { PokemonMove } from "#app/field/pokemon"; import * as Utils from "#app/utils"; -import { PokeballType } from "#enums/pokeball"; import { pokemonEvolutions, pokemonPrevolutions } from "#app/data/balance/pokemon-evolutions"; -import type { PokemonSpeciesFilter } from "#app/data/pokemon-species"; -import type PokemonSpecies from "#app/data/pokemon-species"; import { getPokemonSpecies } from "#app/data/pokemon-species"; import { tmSpecies } from "#app/data/balance/tms"; -import { PokemonType } from "#enums/pokemon-type"; import { doubleBattleDialogue } from "#app/data/dialogue"; -import type { PersistentModifier } from "#app/modifier/modifier"; import { TrainerVariant } from "#app/field/trainer"; import { getIsInitialized, initI18n } from "#app/plugins/i18n"; import i18next from "i18next"; -import { Moves } from "#enums/moves"; +import { Gender } from "#app/data/gender"; +import { signatureSpecies } from "../balance/signature-species"; +import { + getEvilGruntPartyTemplate, + getGymLeaderPartyTemplate, + getWavePartyTemplate, + TrainerPartyCompoundTemplate, + TrainerPartyTemplate, + trainerPartyTemplates, +} from "./TrainerPartyTemplate"; +import { evilAdminTrainerPools } from "./evil-admin-trainer-pools"; + +// Enum imports import { PartyMemberStrength } from "#enums/party-member-strength"; import { Species } from "#enums/species"; -import { TrainerType } from "#enums/trainer-type"; -import { Gender } from "#app/data/gender"; -import { signatureSpecies } from "./balance/signature-species"; +import { PokeballType } from "#enums/pokeball"; +import { PokemonType } from "#enums/pokemon-type"; +import { Moves } from "#enums/moves"; import { Abilities } from "#enums/abilities"; +import { TeraAIMode } from "#enums/tera-ai-mode"; +import { TrainerPoolTier } from "#enums/trainer-pool-tier"; +import { TrainerSlot } from "#enums/trainer-slot"; +import { TrainerType } from "#enums/trainer-type"; + +// Type imports +import type { PokemonSpeciesFilter } from "#app/data/pokemon-species"; +import type PokemonSpecies from "#app/data/pokemon-species"; +import type { ModifierTypeFunc } from "#app/modifier/modifier-type"; +import type { EnemyPokemon } from "#app/field/pokemon"; +import type { EvilTeam } from "./evil-admin-trainer-pools"; +import type { + PartyMemberFunc, + GenModifiersFunc, + GenAIFunc, + PartyTemplateFunc, + TrainerTierPools, + TrainerConfigs, + PartyMemberFuncs, +} from "./typedefs"; /** Minimum BST for Pokemon generated onto the Elite Four's teams */ const ELITE_FOUR_MINIMUM_BST = 460; @@ -31,253 +55,6 @@ const ELITE_FOUR_MINIMUM_BST = 460; /** The wave at which (non-Paldean) Gym Leaders start having Tera mons*/ const GYM_LEADER_TERA_WAVE = 100; -export enum TrainerPoolTier { - COMMON, - UNCOMMON, - RARE, - SUPER_RARE, - ULTRA_RARE, -} - -export interface TrainerTierPools { - [key: number]: Species[]; -} - -export enum TrainerSlot { - NONE, - TRAINER, - TRAINER_PARTNER, -} - -export class TrainerPartyTemplate { - public size: number; - public strength: PartyMemberStrength; - public sameSpecies: boolean; - public balanced: boolean; - - constructor(size: number, strength: PartyMemberStrength, sameSpecies?: boolean, balanced?: boolean) { - this.size = size; - this.strength = strength; - this.sameSpecies = !!sameSpecies; - this.balanced = !!balanced; - } - - getStrength(_index: number): PartyMemberStrength { - return this.strength; - } - - isSameSpecies(_index: number): boolean { - return this.sameSpecies; - } - - isBalanced(_index: number): boolean { - return this.balanced; - } -} - -export class TrainerPartyCompoundTemplate extends TrainerPartyTemplate { - public templates: TrainerPartyTemplate[]; - - constructor(...templates: TrainerPartyTemplate[]) { - super( - templates.reduce((total: number, template: TrainerPartyTemplate) => { - total += template.size; - return total; - }, 0), - PartyMemberStrength.AVERAGE, - ); - this.templates = templates; - } - - getStrength(index: number): PartyMemberStrength { - let t = 0; - for (const template of this.templates) { - if (t + template.size > index) { - return template.getStrength(index - t); - } - t += template.size; - } - - return super.getStrength(index); - } - - isSameSpecies(index: number): boolean { - let t = 0; - for (const template of this.templates) { - if (t + template.size > index) { - return template.isSameSpecies(index - t); - } - t += template.size; - } - - return super.isSameSpecies(index); - } - - isBalanced(index: number): boolean { - let t = 0; - for (const template of this.templates) { - if (t + template.size > index) { - return template.isBalanced(index - t); - } - t += template.size; - } - - return super.isBalanced(index); - } -} - -export const trainerPartyTemplates = { - 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.WEAK, 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_2: new TrainerPartyCompoundTemplate( - new TrainerPartyTemplate(1, PartyMemberStrength.AVERAGE), - new TrainerPartyTemplate(1, PartyMemberStrength.STRONG), - new TrainerPartyTemplate(1, PartyMemberStrength.STRONGER), - ), - 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(3, PartyMemberStrength.AVERAGE), - new TrainerPartyTemplate(2, PartyMemberStrength.STRONG), - new TrainerPartyTemplate(1, PartyMemberStrength.STRONGER), - ), - - ELITE_FOUR: new TrainerPartyCompoundTemplate( - new TrainerPartyTemplate(2, PartyMemberStrength.AVERAGE), - new TrainerPartyTemplate(3, PartyMemberStrength.STRONG), - new TrainerPartyTemplate(1, PartyMemberStrength.STRONGER), - ), - - CHAMPION: new TrainerPartyCompoundTemplate( - new TrainerPartyTemplate(4, PartyMemberStrength.STRONG), - new TrainerPartyTemplate(2, PartyMemberStrength.STRONGER, false, true), - ), - - 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.WEAK, false, true), - ), - RIVAL_3: new TrainerPartyCompoundTemplate( - new TrainerPartyTemplate(1, PartyMemberStrength.STRONG), - new TrainerPartyTemplate(1, PartyMemberStrength.AVERAGE), - new TrainerPartyTemplate(1, PartyMemberStrength.AVERAGE, false, true), - new TrainerPartyTemplate(1, PartyMemberStrength.WEAK, false, true), - ), - RIVAL_4: new TrainerPartyCompoundTemplate( - new TrainerPartyTemplate(1, PartyMemberStrength.STRONG), - new TrainerPartyTemplate(1, PartyMemberStrength.AVERAGE), - new TrainerPartyTemplate(2, PartyMemberStrength.AVERAGE, false, true), - new TrainerPartyTemplate(1, PartyMemberStrength.WEAK, 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 = () => TrainerPartyTemplate; -type PartyMemberFunc = (level: number, strength: PartyMemberStrength) => EnemyPokemon; -type GenModifiersFunc = (party: EnemyPokemon[]) => PersistentModifier[]; -type GenAIFunc = (party: EnemyPokemon[]) => void; - -export interface PartyMemberFuncs { - [key: number]: PartyMemberFunc; -} - -export enum TeraAIMode { - NO_TERA, - INSTANT_TERA, - SMART_TERA, -} - /** * Stores data and helper functions about a trainers AI options. */ @@ -759,430 +536,6 @@ export class TrainerConfig { return this; } - /** - * Returns the pool of species for an evil team admin - * @param team - The evil team the admin belongs to. - * @returns {TrainerTierPools} - */ - speciesPoolPerEvilTeamAdmin(team): TrainerTierPools { - team = team.toLowerCase(); - switch (team) { - case "rocket": { - return { - [TrainerPoolTier.COMMON]: [ - Species.RATICATE, - Species.ARBOK, - Species.VILEPLUME, - Species.ARCANINE, - Species.GENGAR, - Species.HYPNO, - Species.ELECTRODE, - Species.EXEGGUTOR, - Species.CUBONE, - Species.KOFFING, - Species.GYARADOS, - Species.CROBAT, - Species.STEELIX, - Species.HOUNDOOM, - Species.HONCHKROW, - ], - [TrainerPoolTier.UNCOMMON]: [ - Species.OMASTAR, - Species.KABUTOPS, - Species.MAGNEZONE, - Species.ELECTIVIRE, - Species.MAGMORTAR, - Species.PORYGON_Z, - Species.ANNIHILAPE, - Species.ALOLA_SANDSLASH, - Species.ALOLA_PERSIAN, - Species.ALOLA_GOLEM, - Species.ALOLA_MUK, - Species.PALDEA_TAUROS, - ], - [TrainerPoolTier.RARE]: [Species.DRAGONITE, Species.TYRANITAR], - }; - } - case "magma": { - return { - [TrainerPoolTier.COMMON]: [ - Species.ARCANINE, - Species.MAGCARGO, - Species.HOUNDOOM, - Species.TORKOAL, - Species.SOLROCK, - Species.CLAYDOL, - Species.HIPPOWDON, - Species.MAGMORTAR, - Species.GLISCOR, - Species.COALOSSAL, - ], - [TrainerPoolTier.UNCOMMON]: [ - Species.AGGRON, - Species.FLYGON, - Species.CRADILY, - Species.ARMALDO, - Species.RHYPERIOR, - Species.TURTONATOR, - Species.SANDACONDA, - Species.TOEDSCRUEL, - Species.HISUI_ARCANINE, - ], - [TrainerPoolTier.RARE]: [Species.CHARCADET, Species.SCOVILLAIN], - }; - } - case "aqua": { - return { - [TrainerPoolTier.COMMON]: [ - Species.TENTACRUEL, - Species.LANTURN, - Species.AZUMARILL, - Species.QUAGSIRE, - Species.OCTILLERY, - Species.LUDICOLO, - Species.PELIPPER, - Species.WAILORD, - Species.WHISCASH, - Species.CRAWDAUNT, - Species.WALREIN, - Species.CLAMPERL, - ], - [TrainerPoolTier.UNCOMMON]: [ - Species.QUAGSIRE, - Species.MANTINE, - Species.KINGDRA, - Species.MILOTIC, - Species.DRAGALGE, - Species.DHELMISE, - Species.BARRASKEWDA, - Species.GRAPPLOCT, - Species.OVERQWIL, - ], - [TrainerPoolTier.RARE]: [Species.BASCULEGION, Species.DONDOZO], - }; - } - case "galactic": { - return { - [TrainerPoolTier.COMMON]: [ - Species.ELECTRODE, - Species.GYARADOS, - Species.CROBAT, - Species.HONCHKROW, - Species.BRONZONG, - Species.DRAPION, - Species.LICKILICKY, - Species.TANGROWTH, - Species.ELECTIVIRE, - Species.MAGMORTAR, - Species.YANMEGA, - Species.MAMOSWINE, - ], - [TrainerPoolTier.UNCOMMON]: [ - Species.ALAKAZAM, - Species.WEAVILE, - Species.GLISCOR, - Species.DUSKNOIR, - Species.ROTOM, - Species.OVERQWIL, - Species.HISUI_ARCANINE, - Species.HISUI_ELECTRODE, - ], - [TrainerPoolTier.RARE]: [Species.SPIRITOMB, Species.URSALUNA, Species.SNEASLER, Species.HISUI_LILLIGANT], - }; - } - case "plasma": { - return { - [TrainerPoolTier.COMMON]: [ - Species.GIGALITH, - Species.CONKELDURR, - Species.SEISMITOAD, - Species.KROOKODILE, - Species.DARMANITAN, - Species.COFAGRIGUS, - Species.VANILLUXE, - Species.AMOONGUSS, - Species.JELLICENT, - Species.GALVANTULA, - Species.FERROTHORN, - Species.BEARTIC, - ], - [TrainerPoolTier.UNCOMMON]: [ - Species.EXCADRILL, - Species.SIGILYPH, - Species.ZOROARK, - Species.KLINKLANG, - Species.EELEKTROSS, - Species.MIENSHAO, - Species.GOLURK, - Species.BISHARP, - Species.MANDIBUZZ, - Species.DURANT, - Species.GALAR_DARMANITAN, - ], - [TrainerPoolTier.RARE]: [Species.HAXORUS, Species.HYDREIGON, Species.HISUI_ZOROARK, Species.HISUI_BRAVIARY], - }; - } - case "plasma_2": { - return { - [TrainerPoolTier.COMMON]: [ - Species.MUK, - Species.ELECTRODE, - Species.BRONZONG, - Species.MAGNEZONE, - Species.PORYGON_Z, - Species.MUSHARNA, - Species.REUNICLUS, - Species.GALVANTULA, - Species.FERROTHORN, - Species.EELEKTROSS, - Species.BEHEEYEM, - ], - [TrainerPoolTier.UNCOMMON]: [ - Species.METAGROSS, - Species.ROTOM, - Species.CARRACOSTA, - Species.ARCHEOPS, - Species.GOLURK, - Species.DURANT, - Species.VIKAVOLT, - Species.ORBEETLE, - Species.REVAVROOM, - Species.ALOLA_MUK, - Species.HISUI_ELECTRODE, - ], - [TrainerPoolTier.RARE]: [Species.ELECTIVIRE, Species.MAGMORTAR, Species.BISHARP, Species.ARCHALUDON], - }; - } - case "flare": { - return { - [TrainerPoolTier.COMMON]: [ - Species.MANECTRIC, - Species.DRAPION, - Species.LIEPARD, - Species.AMOONGUSS, - Species.DIGGERSBY, - Species.TALONFLAME, - Species.PYROAR, - Species.PANGORO, - Species.MEOWSTIC, - Species.MALAMAR, - Species.CLAWITZER, - Species.HELIOLISK, - ], - [TrainerPoolTier.UNCOMMON]: [ - Species.HOUNDOOM, - Species.WEAVILE, - Species.CHANDELURE, - Species.AEGISLASH, - Species.BARBARACLE, - Species.DRAGALGE, - Species.GOODRA, - Species.TREVENANT, - Species.GOURGEIST, - ], - [TrainerPoolTier.RARE]: [Species.NOIVERN, Species.HISUI_GOODRA, Species.HISUI_AVALUGG], - }; - } - case "aether": { - return { - [TrainerPoolTier.COMMON]: [ - Species.ALAKAZAM, - Species.SLOWBRO, - Species.EXEGGUTOR, - Species.XATU, - Species.CLAYDOL, - Species.BEHEEYEM, - Species.ORANGURU, - Species.BRUXISH, - Species.ORBEETLE, - Species.FARIGIRAF, - Species.ALOLA_RAICHU, - ], - [TrainerPoolTier.UNCOMMON]: [ - Species.KIRLIA, - Species.MEDICHAM, - Species.METAGROSS, - Species.MALAMAR, - Species.HATTERENE, - Species.MR_RIME, - Species.GALAR_SLOWKING, - ], - [TrainerPoolTier.RARE]: [Species.PORYGON_Z, Species.ARMAROUGE, Species.HISUI_BRAVIARY], - }; - } - case "skull": { - return { - [TrainerPoolTier.COMMON]: [ - Species.NIDOQUEEN, - Species.GENGAR, - Species.KOFFING, - Species.CROBAT, - Species.ROSERADE, - Species.SKUNTANK, - Species.TOXICROAK, - Species.SCOLIPEDE, - Species.TOXAPEX, - Species.LURANTIS, - Species.ALOLA_MUK, - ], - [TrainerPoolTier.UNCOMMON]: [ - Species.DRAPION, - Species.MANDIBUZZ, - Species.OVERQWIL, - Species.GLIMMORA, - Species.CLODSIRE, - Species.GALAR_SLOWBRO, - ], - [TrainerPoolTier.RARE]: [Species.DRAGALGE, Species.SNEASLER], - }; - } - case "macro": { - return { - [TrainerPoolTier.COMMON]: [ - Species.NINETALES, - Species.BELLOSSOM, - Species.MILOTIC, - Species.FROSLASS, - Species.GOTHITELLE, - Species.JELLICENT, - Species.SALAZZLE, - Species.TSAREENA, - Species.POLTEAGEIST, - Species.HATTERENE, - Species.GALAR_RAPIDASH, - ], - [TrainerPoolTier.UNCOMMON]: [ - Species.TOGEKISS, - Species.MANDIBUZZ, - Species.TOXAPEX, - Species.APPLETUN, - Species.CURSOLA, - Species.ALOLA_NINETALES, - ], - [TrainerPoolTier.RARE]: [Species.TINKATON, Species.HISUI_LILLIGANT], - }; - } - case "star_1": { - return { - [TrainerPoolTier.COMMON]: [ - Species.SHIFTRY, - Species.CACTURNE, - Species.HONCHKROW, - Species.SKUNTANK, - Species.KROOKODILE, - Species.OBSTAGOON, - Species.LOKIX, - Species.MABOSSTIFF, - ], - [TrainerPoolTier.UNCOMMON]: [ - Species.UMBREON, - Species.CRAWDAUNT, - Species.WEAVILE, - Species.ZOROARK, - Species.MALAMAR, - Species.BOMBIRDIER, - ], - [TrainerPoolTier.RARE]: [Species.HYDREIGON, Species.MEOWSCARADA], - }; - } - case "star_2": { - return { - [TrainerPoolTier.COMMON]: [ - Species.ARCANINE, - Species.HOUNDOOM, - Species.CAMERUPT, - Species.CHANDELURE, - Species.TALONFLAME, - Species.PYROAR, - Species.COALOSSAL, - Species.SCOVILLAIN, - ], - [TrainerPoolTier.UNCOMMON]: [ - Species.RAPIDASH, - Species.FLAREON, - Species.TORKOAL, - Species.MAGMORTAR, - Species.SALAZZLE, - Species.TURTONATOR, - ], - [TrainerPoolTier.RARE]: [Species.VOLCARONA, Species.SKELEDIRGE], - }; - } - case "star_3": { - return { - [TrainerPoolTier.COMMON]: [ - Species.MUK, - Species.CROBAT, - Species.SKUNTANK, - Species.AMOONGUSS, - Species.TOXAPEX, - Species.TOXTRICITY, - Species.GRAFAIAI, - Species.CLODSIRE, - ], - [TrainerPoolTier.UNCOMMON]: [ - Species.GENGAR, - Species.SEVIPER, - Species.DRAGALGE, - Species.OVERQWIL, - Species.ALOLA_MUK, - Species.GALAR_SLOWBRO, - ], - [TrainerPoolTier.RARE]: [Species.GLIMMORA, Species.VENUSAUR], - }; - } - case "star_4": { - return { - [TrainerPoolTier.COMMON]: [ - Species.CLEFABLE, - Species.WIGGLYTUFF, - Species.AZUMARILL, - Species.WHIMSICOTT, - Species.FLORGES, - Species.HATTERENE, - Species.GRIMMSNARL, - Species.TINKATON, - ], - [TrainerPoolTier.UNCOMMON]: [ - Species.TOGEKISS, - Species.GARDEVOIR, - Species.SYLVEON, - Species.KLEFKI, - Species.MIMIKYU, - Species.ALOLA_NINETALES, - ], - [TrainerPoolTier.RARE]: [Species.GALAR_RAPIDASH, Species.PRIMARINA], - }; - } - case "star_5": { - return { - [TrainerPoolTier.COMMON]: [ - Species.BRELOOM, - Species.HARIYAMA, - Species.MEDICHAM, - Species.TOXICROAK, - Species.SCRAFTY, - Species.MIENSHAO, - Species.PAWMOT, - Species.PALDEA_TAUROS, - ], - [TrainerPoolTier.UNCOMMON]: [ - Species.LUCARIO, - Species.CONKELDURR, - Species.HAWLUCHA, - Species.PASSIMIAN, - Species.FALINKS, - Species.FLAMIGO, - ], - [TrainerPoolTier.RARE]: [Species.KOMMO_O, Species.QUAQUAVAL], - }; - } - } - - console.warn(`Evil team admin for ${team} not found. Returning empty species pools.`); - return []; - } - /** * Initializes the trainer configuration for an evil team admin. * @param title The title of the evil team admin. @@ -1193,7 +546,7 @@ export class TrainerConfig { * **/ initForEvilTeamAdmin( title: string, - poolName: string, + poolName: EvilTeam, signatureSpecies: (Species | Species[])[], specialtyType?: PokemonType, ): TrainerConfig { @@ -1208,7 +561,7 @@ export class TrainerConfig { this.setPartyTemplates(trainerPartyTemplates.RIVAL_5); // Set the species pools for the evil team admin. - this.speciesPools = this.speciesPoolPerEvilTeamAdmin(poolName); + this.speciesPools = evilAdminTrainerPools[poolName]; signatureSpecies.forEach((speciesPool, s) => { if (!Array.isArray(speciesPool)) { @@ -1637,56 +990,6 @@ export class TrainerConfig { let t = 0; -interface TrainerConfigs { - [key: number]: TrainerConfig; -} - -/** - * The function to get variable strength grunts - * @returns the correct TrainerPartyTemplate - */ -function getEvilGruntPartyTemplate(): TrainerPartyTemplate { - const waveIndex = globalScene.currentBattle?.waveIndex; - if (waveIndex < 40) { - return trainerPartyTemplates.TWO_AVG; - } - if (waveIndex < 63) { - return trainerPartyTemplates.THREE_AVG; - } - if (waveIndex < 65) { - return trainerPartyTemplates.TWO_AVG_ONE_STRONG; - } - if (waveIndex < 112) { - return trainerPartyTemplates.GYM_LEADER_4; // 3avg 1 strong 1 stronger - } - return trainerPartyTemplates.GYM_LEADER_5; // 3 avg 2 strong 1 stronger -} - -function getWavePartyTemplate(...templates: TrainerPartyTemplate[]) { - return templates[ - Math.min( - Math.max( - Math.ceil( - (globalScene.gameMode.getWaveForDifficulty(globalScene.currentBattle?.waveIndex || startingWave, true) - 20) / - 30, - ), - 0, - ), - templates.length - 1, - ) - ]; -} - -function getGymLeaderPartyTemplate() { - return getWavePartyTemplate( - trainerPartyTemplates.GYM_LEADER_1, - trainerPartyTemplates.GYM_LEADER_2, - trainerPartyTemplates.GYM_LEADER_3, - trainerPartyTemplates.GYM_LEADER_4, - trainerPartyTemplates.GYM_LEADER_5, - ); -} - /** * Randomly selects one of the `Species` from `speciesPool`, determines its evolution, level, and strength. * Then adds Pokemon to globalScene. @@ -2878,7 +2181,7 @@ export const trainerConfigs: TrainerConfigs = { }), [TrainerType.ZINZOLIN]: new TrainerConfig(++t) .setMoneyMultiplier(1.5) - .initForEvilTeamAdmin("plasma_sage", "plasma", [Species.CRYOGONAL]) + .initForEvilTeamAdmin("plasma_sage", "plasma_zinzolin", [Species.CRYOGONAL]) .setEncounterBgm(TrainerType.PLASMA_GRUNT) .setBattleBgm("battle_plasma_grunt") .setMixedBattleBgm("battle_plasma_grunt") @@ -2886,7 +2189,7 @@ export const trainerConfigs: TrainerConfigs = { .setPartyTemplateFunc(() => getEvilGruntPartyTemplate()), [TrainerType.COLRESS]: new TrainerConfig(++t) .setMoneyMultiplier(1.5) - .initForEvilTeamAdmin("plasma_boss", "plasma_2", [Species.KLINKLANG]) + .initForEvilTeamAdmin("plasma_boss", "plasma_colress", [Species.KLINKLANG]) .setEncounterBgm(TrainerType.PLASMA_GRUNT) .setBattleBgm("battle_colress") .setMixedBattleBgm("battle_colress") @@ -3105,7 +2408,7 @@ export const trainerConfigs: TrainerConfigs = { }), [TrainerType.OLEANA]: new TrainerConfig(++t) .setMoneyMultiplier(1.5) - .initForEvilTeamAdmin("macro_admin", "macro", [Species.GARBODOR]) + .initForEvilTeamAdmin("macro_admin", "macro_cosmos", [Species.GARBODOR]) .setEncounterBgm(TrainerType.PLASMA_GRUNT) .setBattleBgm("battle_plasma_grunt") .setMixedBattleBgm("battle_oleana") @@ -3172,7 +2475,7 @@ export const trainerConfigs: TrainerConfigs = { }), [TrainerType.GIACOMO]: new TrainerConfig(++t) .setMoneyMultiplier(1.5) - .initForEvilTeamAdmin("star_admin", "star_1", [Species.KINGAMBIT], PokemonType.DARK) + .initForEvilTeamAdmin("star_admin", "star_dark", [Species.KINGAMBIT], PokemonType.DARK) .setEncounterBgm(TrainerType.PLASMA_GRUNT) .setBattleBgm("battle_plasma_grunt") .setMixedBattleBgm("battle_star_admin") @@ -3192,7 +2495,7 @@ export const trainerConfigs: TrainerConfigs = { ), [TrainerType.MELA]: new TrainerConfig(++t) .setMoneyMultiplier(1.5) - .initForEvilTeamAdmin("star_admin", "star_2", [Species.ARMAROUGE], PokemonType.FIRE) + .initForEvilTeamAdmin("star_admin", "star_fire", [Species.ARMAROUGE], PokemonType.FIRE) .setEncounterBgm(TrainerType.PLASMA_GRUNT) .setBattleBgm("battle_plasma_grunt") .setMixedBattleBgm("battle_star_admin") @@ -3212,7 +2515,7 @@ export const trainerConfigs: TrainerConfigs = { ), [TrainerType.ATTICUS]: new TrainerConfig(++t) .setMoneyMultiplier(1.5) - .initForEvilTeamAdmin("star_admin", "star_3", [Species.REVAVROOM], PokemonType.POISON) + .initForEvilTeamAdmin("star_admin", "star_poison", [Species.REVAVROOM], PokemonType.POISON) .setEncounterBgm(TrainerType.PLASMA_GRUNT) .setBattleBgm("battle_plasma_grunt") .setMixedBattleBgm("battle_star_admin") @@ -3232,7 +2535,7 @@ export const trainerConfigs: TrainerConfigs = { ), [TrainerType.ORTEGA]: new TrainerConfig(++t) .setMoneyMultiplier(1.5) - .initForEvilTeamAdmin("star_admin", "star_4", [Species.DACHSBUN], PokemonType.FAIRY) + .initForEvilTeamAdmin("star_admin", "star_fairy", [Species.DACHSBUN], PokemonType.FAIRY) .setEncounterBgm(TrainerType.PLASMA_GRUNT) .setBattleBgm("battle_plasma_grunt") .setMixedBattleBgm("battle_star_admin") @@ -3252,7 +2555,7 @@ export const trainerConfigs: TrainerConfigs = { ), [TrainerType.ERI]: new TrainerConfig(++t) .setMoneyMultiplier(1.5) - .initForEvilTeamAdmin("star_admin", "star_5", [Species.ANNIHILAPE], PokemonType.FIGHTING) + .initForEvilTeamAdmin("star_admin", "star_fighting", [Species.ANNIHILAPE], PokemonType.FIGHTING) .setEncounterBgm(TrainerType.PLASMA_GRUNT) .setBattleBgm("battle_plasma_grunt") .setMixedBattleBgm("battle_star_admin") diff --git a/src/data/trainers/typedefs.ts b/src/data/trainers/typedefs.ts new file mode 100644 index 00000000000..c6d286e961e --- /dev/null +++ b/src/data/trainers/typedefs.ts @@ -0,0 +1,22 @@ +import type { EnemyPokemon } from "#app/field/pokemon"; +import type { PersistentModifier } from "#app/modifier/modifier"; +import type { PartyMemberStrength } from "#enums/party-member-strength"; +import type { Species } from "#enums/species"; +import type { TrainerConfig } from "./trainer-config"; +import type { TrainerPartyTemplate } from "./TrainerPartyTemplate"; + +export type PartyTemplateFunc = () => TrainerPartyTemplate; +export type PartyMemberFunc = (level: number, strength: PartyMemberStrength) => EnemyPokemon; +export type GenModifiersFunc = (party: EnemyPokemon[]) => PersistentModifier[]; +export type GenAIFunc = (party: EnemyPokemon[]) => void; + +export interface TrainerTierPools { + [key: number]: Species[]; +} +export interface TrainerConfigs { + [key: number]: TrainerConfig; +} + +export interface PartyMemberFuncs { + [key: number]: PartyMemberFunc; +} diff --git a/src/enums/tera-ai-mode.ts b/src/enums/tera-ai-mode.ts new file mode 100644 index 00000000000..35d4e4f3420 --- /dev/null +++ b/src/enums/tera-ai-mode.ts @@ -0,0 +1,5 @@ +export enum TeraAIMode { + NO_TERA, + INSTANT_TERA, + SMART_TERA +} diff --git a/src/enums/trainer-pool-tier.ts b/src/enums/trainer-pool-tier.ts new file mode 100644 index 00000000000..da6355d021b --- /dev/null +++ b/src/enums/trainer-pool-tier.ts @@ -0,0 +1,7 @@ +export enum TrainerPoolTier { + COMMON, + UNCOMMON, + RARE, + SUPER_RARE, + ULTRA_RARE +} diff --git a/src/enums/trainer-slot.ts b/src/enums/trainer-slot.ts new file mode 100644 index 00000000000..2dfa468f74c --- /dev/null +++ b/src/enums/trainer-slot.ts @@ -0,0 +1,5 @@ +export enum TrainerSlot { + NONE, + TRAINER, + TRAINER_PARTNER +} diff --git a/src/field/pokemon.ts b/src/field/pokemon.ts index 51a5a10b010..aba13b2e51b 100644 --- a/src/field/pokemon.ts +++ b/src/field/pokemon.ts @@ -225,7 +225,7 @@ import { SpeciesFormChangeStatusEffectTrigger, } from "#app/data/pokemon-forms"; import { TerrainType } from "#app/data/terrain"; -import type { TrainerSlot } from "#app/data/trainer-config"; +import type { TrainerSlot } from "#enums/trainer-slot"; import Overrides from "#app/overrides"; import i18next from "i18next"; import { speciesEggMoves } from "#app/data/balance/egg-moves"; diff --git a/src/field/trainer.ts b/src/field/trainer.ts index 2af3e25050f..c52957eef75 100644 --- a/src/field/trainer.ts +++ b/src/field/trainer.ts @@ -2,15 +2,14 @@ import { globalScene } from "#app/global-scene"; import { pokemonPrevolutions } from "#app/data/balance/pokemon-evolutions"; import type PokemonSpecies from "#app/data/pokemon-species"; import { getPokemonSpecies } from "#app/data/pokemon-species"; -import type { TrainerConfig, TrainerPartyTemplate } from "#app/data/trainer-config"; -import { - TrainerPartyCompoundTemplate, - TrainerPoolTier, - TrainerSlot, - trainerConfigs, - trainerPartyTemplates, - TeraAIMode, -} from "#app/data/trainer-config"; +import type { TrainerConfig } from "#app/data/trainers/trainer-config"; +import type { TrainerPartyTemplate } from "#app/data/trainers/TrainerPartyTemplate"; +import { trainerConfigs } from "#app/data/trainers/trainer-config"; +import { trainerPartyTemplates } from "#app/data/trainers/TrainerPartyTemplate"; +import { TrainerPartyCompoundTemplate } from "#app/data/trainers/TrainerPartyTemplate"; +import { TrainerSlot } from "#enums/trainer-slot"; +import { TrainerPoolTier } from "#enums/trainer-pool-tier"; +import { TeraAIMode } from "#enums/tera-ai-mode"; import type { EnemyPokemon } from "#app/field/pokemon"; import * as Utils from "#app/utils"; import type { PersistentModifier } from "#app/modifier/modifier"; diff --git a/src/phases/battle-phase.ts b/src/phases/battle-phase.ts index 3fc2b9c0467..72bcc85bc62 100644 --- a/src/phases/battle-phase.ts +++ b/src/phases/battle-phase.ts @@ -1,5 +1,5 @@ import { globalScene } from "#app/global-scene"; -import { TrainerSlot } from "#app/data/trainer-config"; +import { TrainerSlot } from "#enums/trainer-slot"; import { Phase } from "#app/phase"; export class BattlePhase extends Phase { diff --git a/src/phases/encounter-phase.ts b/src/phases/encounter-phase.ts index 7afd4176788..ad2bf689e38 100644 --- a/src/phases/encounter-phase.ts +++ b/src/phases/encounter-phase.ts @@ -7,7 +7,7 @@ import { getCharVariantFromDialogue } from "#app/data/dialogue"; import { getEncounterText } from "#app/data/mystery-encounters/utils/encounter-dialogue-utils"; import { doTrainerExclamation } from "#app/data/mystery-encounters/utils/encounter-phase-utils"; import { getGoldenBugNetSpecies } from "#app/data/mystery-encounters/utils/encounter-pokemon-utils"; -import { TrainerSlot } from "#app/data/trainer-config"; +import { TrainerSlot } from "#enums/trainer-slot"; import { getRandomWeatherType } from "#app/data/weather"; import { EncounterPhaseEvent } from "#app/events/battle-scene"; import type Pokemon from "#app/field/pokemon"; diff --git a/src/phases/game-over-phase.ts b/src/phases/game-over-phase.ts index af948ad0632..2090592367d 100644 --- a/src/phases/game-over-phase.ts +++ b/src/phases/game-over-phase.ts @@ -5,7 +5,7 @@ import { pokemonEvolutions } from "#app/data/balance/pokemon-evolutions"; import { getCharVariantFromDialogue } from "#app/data/dialogue"; import type PokemonSpecies from "#app/data/pokemon-species"; import { getPokemonSpecies } from "#app/data/pokemon-species"; -import { trainerConfigs } from "#app/data/trainer-config"; +import { trainerConfigs } from "#app/data/trainers/trainer-config"; import type Pokemon from "#app/field/pokemon"; import { modifierTypes } from "#app/modifier/modifier-type"; import { BattlePhase } from "#app/phases/battle-phase"; diff --git a/src/phases/mystery-encounter-phases.ts b/src/phases/mystery-encounter-phases.ts index 26012df191d..eb187617e69 100644 --- a/src/phases/mystery-encounter-phases.ts +++ b/src/phases/mystery-encounter-phases.ts @@ -22,7 +22,7 @@ import { globalScene } from "#app/global-scene"; import { getCharVariantFromDialogue } from "../data/dialogue"; import type { OptionSelectSettings } from "../data/mystery-encounters/utils/encounter-phase-utils"; import { transitionMysteryEncounterIntroVisuals } from "../data/mystery-encounters/utils/encounter-phase-utils"; -import { TrainerSlot } from "../data/trainer-config"; +import { TrainerSlot } from "#enums/trainer-slot"; import { IvScannerModifier } from "../modifier/modifier"; import { Phase } from "../phase"; import { Mode } from "../ui/ui"; diff --git a/src/phases/summon-phase.ts b/src/phases/summon-phase.ts index 42463e7edb0..621c8c8c2a9 100644 --- a/src/phases/summon-phase.ts +++ b/src/phases/summon-phase.ts @@ -1,7 +1,7 @@ import { BattleType } from "#app/battle"; import { getPokeballAtlasKey, getPokeballTintColor } from "#app/data/pokeball"; import { SpeciesFormChangeActiveTrigger } from "#app/data/pokemon-forms"; -import { TrainerSlot } from "#app/data/trainer-config"; +import { TrainerSlot } from "#enums/trainer-slot"; import { PlayerGender } from "#app/enums/player-gender"; import { addPokeballOpenParticles } from "#app/field/anims"; import type Pokemon from "#app/field/pokemon"; diff --git a/src/phases/switch-summon-phase.ts b/src/phases/switch-summon-phase.ts index 48bcd0c4ebd..16868bf9bc0 100644 --- a/src/phases/switch-summon-phase.ts +++ b/src/phases/switch-summon-phase.ts @@ -3,7 +3,7 @@ import { applyPreSwitchOutAbAttrs, PostDamageForceSwitchAbAttr, PreSwitchOutAbAt import { allMoves, ForceSwitchOutAttr } from "#app/data/moves/move"; import { getPokeballTintColor } from "#app/data/pokeball"; import { SpeciesFormChangeActiveTrigger } from "#app/data/pokemon-forms"; -import { TrainerSlot } from "#app/data/trainer-config"; +import { TrainerSlot } from "#enums/trainer-slot"; import type Pokemon from "#app/field/pokemon"; import { getPokemonNameWithAffix } from "#app/messages"; import { SwitchEffectTransferModifier } from "#app/modifier/modifier"; diff --git a/src/phases/trainer-message-test-phase.ts b/src/phases/trainer-message-test-phase.ts index fa3f553cdd6..23c2c86361c 100644 --- a/src/phases/trainer-message-test-phase.ts +++ b/src/phases/trainer-message-test-phase.ts @@ -1,5 +1,5 @@ import { globalScene } from "#app/global-scene"; -import { trainerConfigs } from "#app/data/trainer-config"; +import { trainerConfigs } from "#app/data/trainers/trainer-config"; import type { TrainerType } from "#app/enums/trainer-type"; import { BattlePhase } from "./battle-phase"; import { TestMessagePhase } from "./test-message-phase"; diff --git a/src/phases/trainer-victory-phase.ts b/src/phases/trainer-victory-phase.ts index 024c1e3f837..f7b2eb2bb66 100644 --- a/src/phases/trainer-victory-phase.ts +++ b/src/phases/trainer-victory-phase.ts @@ -7,7 +7,7 @@ import * as Utils from "#app/utils"; import { BattlePhase } from "./battle-phase"; import { ModifierRewardPhase } from "./modifier-reward-phase"; import { MoneyRewardPhase } from "./money-reward-phase"; -import { TrainerSlot } from "#app/data/trainer-config"; +import { TrainerSlot } from "#enums/trainer-slot"; import { globalScene } from "#app/global-scene"; import { Biome } from "#app/enums/biome"; import { achvs } from "#app/system/achv"; diff --git a/src/system/game-data.ts b/src/system/game-data.ts index 7845d50b2ad..3a098a55a56 100644 --- a/src/system/game-data.ts +++ b/src/system/game-data.ts @@ -17,7 +17,7 @@ import { Unlockables } from "#app/system/unlockables"; import { GameModes, getGameMode } from "#app/game-mode"; import { BattleType } from "#app/battle"; import TrainerData from "#app/system/trainer-data"; -import { trainerConfigs } from "#app/data/trainer-config"; +import { trainerConfigs } from "#app/data/trainers/trainer-config"; import { resetSettings, setSetting, SettingKeys } from "#app/system/settings/settings"; import { achvs } from "#app/system/achv"; import EggData from "#app/system/egg-data"; diff --git a/src/system/pokemon-data.ts b/src/system/pokemon-data.ts index 3fa07e8b085..a1d27394d9f 100644 --- a/src/system/pokemon-data.ts +++ b/src/system/pokemon-data.ts @@ -6,7 +6,7 @@ import type { PokeballType } from "#enums/pokeball"; import { getPokemonSpecies, getPokemonSpeciesForm } from "../data/pokemon-species"; import { Status } from "../data/status-effect"; import Pokemon, { EnemyPokemon, PokemonMove, PokemonSummonData } from "../field/pokemon"; -import { TrainerSlot } from "../data/trainer-config"; +import { TrainerSlot } from "#enums/trainer-slot"; import type { Variant } from "#app/data/variant"; import { loadBattlerTag } from "../data/battler-tags"; import type { Biome } from "#enums/biome"; diff --git a/src/system/voucher.ts b/src/system/voucher.ts index 39294bccf13..ce10560c3e2 100644 --- a/src/system/voucher.ts +++ b/src/system/voucher.ts @@ -3,7 +3,7 @@ import { AchvTier, achvs, getAchievementDescription } from "./achv"; import type { PlayerGender } from "#enums/player-gender"; import { TrainerType } from "#enums/trainer-type"; import type { ConditionFn } from "#app/@types/common"; -import { trainerConfigs } from "#app/data/trainer-config"; +import { trainerConfigs } from "#app/data/trainers/trainer-config"; export enum VoucherType { REGULAR, diff --git a/test/moves/effectiveness.test.ts b/test/moves/effectiveness.test.ts index dc55392f8bf..fb03f1c10a0 100644 --- a/test/moves/effectiveness.test.ts +++ b/test/moves/effectiveness.test.ts @@ -1,6 +1,6 @@ import { allMoves } from "#app/data/moves/move"; import { getPokemonSpecies } from "#app/data/pokemon-species"; -import { TrainerSlot } from "#app/data/trainer-config"; +import { TrainerSlot } from "#enums/trainer-slot"; import { PokemonType } from "#enums/pokemon-type"; import { Abilities } from "#app/enums/abilities"; import { Moves } from "#app/enums/moves"; diff --git a/test/mystery-encounter/encounters/mysterious-challengers-encounter.test.ts b/test/mystery-encounter/encounters/mysterious-challengers-encounter.test.ts index 8e825dc2c9b..f620cbd6c36 100644 --- a/test/mystery-encounter/encounters/mysterious-challengers-encounter.test.ts +++ b/test/mystery-encounter/encounters/mysterious-challengers-encounter.test.ts @@ -16,7 +16,9 @@ import { MysteryEncounterTier } from "#enums/mystery-encounter-tier"; import { initSceneWithoutEncounterPhase } from "#test/testUtils/gameManagerUtils"; import { ModifierTier } from "#app/modifier/modifier-tier"; import { MysteriousChallengersEncounter } from "#app/data/mystery-encounters/encounters/mysterious-challengers-encounter"; -import { TrainerConfig, TrainerPartyCompoundTemplate, TrainerPartyTemplate } from "#app/data/trainer-config"; +import { TrainerConfig } from "#app/data/trainers/trainer-config"; +import { TrainerPartyCompoundTemplate } from "#app/data/trainers/TrainerPartyTemplate"; +import { TrainerPartyTemplate } from "#app/data/trainers/TrainerPartyTemplate"; import { PartyMemberStrength } from "#enums/party-member-strength"; import { MysteryEncounterMode } from "#enums/mystery-encounter-mode"; import ModifierSelectUiHandler from "#app/ui/modifier-select-ui-handler";