mirror of
https://github.com/pagefaultgames/pokerogue.git
synced 2025-08-11 18:09:29 +02:00
Merge branch 'beta' into WorkingDiscardFunction
This commit is contained in:
commit
4478f41ff9
2
.github/workflows/deploy-beta.yml
vendored
2
.github/workflows/deploy-beta.yml
vendored
@ -11,7 +11,7 @@ on:
|
||||
|
||||
jobs:
|
||||
deploy:
|
||||
if: github.repository == 'pagefaultgames/pokerogue' && github.ref_name == ${{ vars.BETA_DEPLOY_BRANCH || 'beta' }}
|
||||
if: github.repository == 'pagefaultgames/pokerogue' && github.ref_name == (vars.BETA_DEPLOY_BRANCH || 'beta')
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
32
package.json
32
package.json
@ -29,34 +29,34 @@
|
||||
"devDependencies": {
|
||||
"@biomejs/biome": "2.0.0",
|
||||
"@types/jsdom": "^21.1.7",
|
||||
"@types/node": "^22.13.14",
|
||||
"@vitest/coverage-istanbul": "^3.0.9",
|
||||
"@types/node": "^22.16.3",
|
||||
"@vitest/coverage-istanbul": "^3.2.4",
|
||||
"chalk": "^5.4.1",
|
||||
"dependency-cruiser": "^16.3.10",
|
||||
"inquirer": "^12.4.2",
|
||||
"jsdom": "^26.0.0",
|
||||
"lefthook": "^1.11.5",
|
||||
"msw": "^2.7.3",
|
||||
"dependency-cruiser": "^16.10.4",
|
||||
"inquirer": "^12.7.0",
|
||||
"jsdom": "^26.1.0",
|
||||
"lefthook": "^1.12.2",
|
||||
"msw": "^2.10.4",
|
||||
"phaser3spectorjs": "^0.0.8",
|
||||
"typedoc": "^0.28.1",
|
||||
"typescript": "^5.8.2",
|
||||
"vite": "^6.3.4",
|
||||
"typedoc": "^0.28.7",
|
||||
"typescript": "^5.8.3",
|
||||
"vite": "^6.3.5",
|
||||
"vite-tsconfig-paths": "^5.1.4",
|
||||
"vitest": "^3.0.9",
|
||||
"vitest": "^3.2.4",
|
||||
"vitest-canvas-mock": "^0.3.3"
|
||||
},
|
||||
"dependencies": {
|
||||
"@material/material-color-utilities": "^0.2.7",
|
||||
"compare-versions": "^6.1.1",
|
||||
"crypto-js": "^4.2.0",
|
||||
"i18next": "^24.2.2",
|
||||
"i18next-browser-languagedetector": "^8.0.4",
|
||||
"i18next": "^24.2.3",
|
||||
"i18next-browser-languagedetector": "^8.2.0",
|
||||
"i18next-http-backend": "^3.0.2",
|
||||
"i18next-korean-postposition-processor": "^1.0.0",
|
||||
"json-stable-stringify": "^1.2.0",
|
||||
"json-stable-stringify": "^1.3.0",
|
||||
"jszip": "^3.10.1",
|
||||
"phaser": "^3.88.2",
|
||||
"phaser3-rex-plugins": "^1.80.15"
|
||||
"phaser": "^3.90.0",
|
||||
"phaser3-rex-plugins": "^1.80.16"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=22.0.0"
|
||||
|
1987
pnpm-lock.yaml
1987
pnpm-lock.yaml
File diff suppressed because it is too large
Load Diff
@ -2,8 +2,8 @@ import type { PartyMemberStrength } from "#enums/party-member-strength";
|
||||
import type { SpeciesId } from "#enums/species-id";
|
||||
import type { EnemyPokemon } from "#field/pokemon";
|
||||
import type { PersistentModifier } from "#modifiers/modifier";
|
||||
import type { TrainerPartyTemplate } from "#trainers/TrainerPartyTemplate";
|
||||
import type { TrainerConfig } from "#trainers/trainer-config";
|
||||
import type { TrainerPartyTemplate } from "#trainers/trainer-party-template";
|
||||
|
||||
export type PartyTemplateFunc = () => TrainerPartyTemplate;
|
||||
export type PartyMemberFunc = (level: number, strength: PartyMemberStrength) => EnemyPokemon;
|
||||
|
369
src/battle.ts
369
src/battle.ts
@ -5,12 +5,9 @@ import { BattleSpec } from "#enums/battle-spec";
|
||||
import { BattleType } from "#enums/battle-type";
|
||||
import { BattlerIndex } from "#enums/battler-index";
|
||||
import type { Command } from "#enums/command";
|
||||
import { ClassicFixedBossWaves } from "#enums/fixed-boss-waves";
|
||||
import { ModifierTier } from "#enums/modifier-tier";
|
||||
import type { MoveId } from "#enums/move-id";
|
||||
import { MysteryEncounterMode } from "#enums/mystery-encounter-mode";
|
||||
import type { MysteryEncounterType } from "#enums/mystery-encounter-type";
|
||||
import { PlayerGender } from "#enums/player-gender";
|
||||
import type { PokeballType } from "#enums/pokeball";
|
||||
import { SpeciesFormKey } from "#enums/species-form-key";
|
||||
import { SpeciesId } from "#enums/species-id";
|
||||
@ -577,369 +574,3 @@ export function getRandomTrainerFunc(
|
||||
return new Trainer(trainerTypes[rand], trainerGender);
|
||||
};
|
||||
}
|
||||
|
||||
export interface FixedBattleConfigs {
|
||||
[key: number]: FixedBattleConfig;
|
||||
}
|
||||
/**
|
||||
* Youngster/Lass on 5
|
||||
* Rival on 8, 55, 95, 145, 195
|
||||
* Evil team grunts on 35, 62, 64, and 112
|
||||
* Evil team admin on 66 and 114
|
||||
* Evil leader on 115, 165
|
||||
* E4 on 182, 184, 186, 188
|
||||
* Champion on 190
|
||||
*/
|
||||
export const classicFixedBattles: FixedBattleConfigs = {
|
||||
[ClassicFixedBossWaves.TOWN_YOUNGSTER]: new FixedBattleConfig()
|
||||
.setBattleType(BattleType.TRAINER)
|
||||
.setGetTrainerFunc(
|
||||
() => new Trainer(TrainerType.YOUNGSTER, randSeedInt(2) ? TrainerVariant.FEMALE : TrainerVariant.DEFAULT),
|
||||
),
|
||||
[ClassicFixedBossWaves.RIVAL_1]: new FixedBattleConfig()
|
||||
.setBattleType(BattleType.TRAINER)
|
||||
.setGetTrainerFunc(
|
||||
() =>
|
||||
new Trainer(
|
||||
TrainerType.RIVAL,
|
||||
globalScene.gameData.gender === PlayerGender.MALE ? TrainerVariant.FEMALE : TrainerVariant.DEFAULT,
|
||||
),
|
||||
),
|
||||
[ClassicFixedBossWaves.RIVAL_2]: new FixedBattleConfig()
|
||||
.setBattleType(BattleType.TRAINER)
|
||||
.setGetTrainerFunc(
|
||||
() =>
|
||||
new Trainer(
|
||||
TrainerType.RIVAL_2,
|
||||
globalScene.gameData.gender === PlayerGender.MALE ? TrainerVariant.FEMALE : TrainerVariant.DEFAULT,
|
||||
),
|
||||
)
|
||||
.setCustomModifierRewards({
|
||||
guaranteedModifierTiers: [ModifierTier.ULTRA, ModifierTier.GREAT, ModifierTier.GREAT],
|
||||
allowLuckUpgrades: false,
|
||||
}),
|
||||
[ClassicFixedBossWaves.EVIL_GRUNT_1]: new FixedBattleConfig()
|
||||
.setBattleType(BattleType.TRAINER)
|
||||
.setGetTrainerFunc(
|
||||
getRandomTrainerFunc(
|
||||
[
|
||||
TrainerType.ROCKET_GRUNT,
|
||||
TrainerType.MAGMA_GRUNT,
|
||||
TrainerType.AQUA_GRUNT,
|
||||
TrainerType.GALACTIC_GRUNT,
|
||||
TrainerType.PLASMA_GRUNT,
|
||||
TrainerType.FLARE_GRUNT,
|
||||
TrainerType.AETHER_GRUNT,
|
||||
TrainerType.SKULL_GRUNT,
|
||||
TrainerType.MACRO_GRUNT,
|
||||
TrainerType.STAR_GRUNT,
|
||||
],
|
||||
true,
|
||||
),
|
||||
),
|
||||
[ClassicFixedBossWaves.RIVAL_3]: new FixedBattleConfig()
|
||||
.setBattleType(BattleType.TRAINER)
|
||||
.setGetTrainerFunc(
|
||||
() =>
|
||||
new Trainer(
|
||||
TrainerType.RIVAL_3,
|
||||
globalScene.gameData.gender === PlayerGender.MALE ? TrainerVariant.FEMALE : TrainerVariant.DEFAULT,
|
||||
),
|
||||
)
|
||||
.setCustomModifierRewards({
|
||||
guaranteedModifierTiers: [ModifierTier.ULTRA, ModifierTier.ULTRA, ModifierTier.GREAT, ModifierTier.GREAT],
|
||||
allowLuckUpgrades: false,
|
||||
}),
|
||||
[ClassicFixedBossWaves.EVIL_GRUNT_2]: new FixedBattleConfig()
|
||||
.setBattleType(BattleType.TRAINER)
|
||||
.setSeedOffsetWave(ClassicFixedBossWaves.EVIL_GRUNT_1)
|
||||
.setGetTrainerFunc(
|
||||
getRandomTrainerFunc(
|
||||
[
|
||||
TrainerType.ROCKET_GRUNT,
|
||||
TrainerType.MAGMA_GRUNT,
|
||||
TrainerType.AQUA_GRUNT,
|
||||
TrainerType.GALACTIC_GRUNT,
|
||||
TrainerType.PLASMA_GRUNT,
|
||||
TrainerType.FLARE_GRUNT,
|
||||
TrainerType.AETHER_GRUNT,
|
||||
TrainerType.SKULL_GRUNT,
|
||||
TrainerType.MACRO_GRUNT,
|
||||
TrainerType.STAR_GRUNT,
|
||||
],
|
||||
true,
|
||||
),
|
||||
),
|
||||
[ClassicFixedBossWaves.EVIL_GRUNT_3]: new FixedBattleConfig()
|
||||
.setBattleType(BattleType.TRAINER)
|
||||
.setSeedOffsetWave(ClassicFixedBossWaves.EVIL_GRUNT_1)
|
||||
.setGetTrainerFunc(
|
||||
getRandomTrainerFunc(
|
||||
[
|
||||
TrainerType.ROCKET_GRUNT,
|
||||
TrainerType.MAGMA_GRUNT,
|
||||
TrainerType.AQUA_GRUNT,
|
||||
TrainerType.GALACTIC_GRUNT,
|
||||
TrainerType.PLASMA_GRUNT,
|
||||
TrainerType.FLARE_GRUNT,
|
||||
TrainerType.AETHER_GRUNT,
|
||||
TrainerType.SKULL_GRUNT,
|
||||
TrainerType.MACRO_GRUNT,
|
||||
TrainerType.STAR_GRUNT,
|
||||
],
|
||||
true,
|
||||
),
|
||||
),
|
||||
[ClassicFixedBossWaves.EVIL_ADMIN_1]: new FixedBattleConfig()
|
||||
.setBattleType(BattleType.TRAINER)
|
||||
.setSeedOffsetWave(ClassicFixedBossWaves.EVIL_GRUNT_1)
|
||||
.setGetTrainerFunc(
|
||||
getRandomTrainerFunc(
|
||||
[
|
||||
[TrainerType.ARCHER, TrainerType.ARIANA, TrainerType.PROTON, TrainerType.PETREL],
|
||||
[TrainerType.TABITHA, TrainerType.COURTNEY],
|
||||
[TrainerType.MATT, TrainerType.SHELLY],
|
||||
[TrainerType.JUPITER, TrainerType.MARS, TrainerType.SATURN],
|
||||
[TrainerType.ZINZOLIN, TrainerType.COLRESS],
|
||||
[TrainerType.XEROSIC, TrainerType.BRYONY],
|
||||
TrainerType.FABA,
|
||||
TrainerType.PLUMERIA,
|
||||
TrainerType.OLEANA,
|
||||
[TrainerType.GIACOMO, TrainerType.MELA, TrainerType.ATTICUS, TrainerType.ORTEGA, TrainerType.ERI],
|
||||
],
|
||||
true,
|
||||
),
|
||||
),
|
||||
[ClassicFixedBossWaves.RIVAL_4]: new FixedBattleConfig()
|
||||
.setBattleType(BattleType.TRAINER)
|
||||
.setGetTrainerFunc(
|
||||
() =>
|
||||
new Trainer(
|
||||
TrainerType.RIVAL_4,
|
||||
globalScene.gameData.gender === PlayerGender.MALE ? TrainerVariant.FEMALE : TrainerVariant.DEFAULT,
|
||||
),
|
||||
)
|
||||
.setCustomModifierRewards({
|
||||
guaranteedModifierTiers: [ModifierTier.ULTRA, ModifierTier.ULTRA, ModifierTier.ULTRA, ModifierTier.ULTRA],
|
||||
allowLuckUpgrades: false,
|
||||
}),
|
||||
[ClassicFixedBossWaves.EVIL_GRUNT_4]: new FixedBattleConfig()
|
||||
.setBattleType(BattleType.TRAINER)
|
||||
.setSeedOffsetWave(ClassicFixedBossWaves.EVIL_GRUNT_1)
|
||||
.setGetTrainerFunc(
|
||||
getRandomTrainerFunc(
|
||||
[
|
||||
TrainerType.ROCKET_GRUNT,
|
||||
TrainerType.MAGMA_GRUNT,
|
||||
TrainerType.AQUA_GRUNT,
|
||||
TrainerType.GALACTIC_GRUNT,
|
||||
TrainerType.PLASMA_GRUNT,
|
||||
TrainerType.FLARE_GRUNT,
|
||||
TrainerType.AETHER_GRUNT,
|
||||
TrainerType.SKULL_GRUNT,
|
||||
TrainerType.MACRO_GRUNT,
|
||||
TrainerType.STAR_GRUNT,
|
||||
],
|
||||
true,
|
||||
),
|
||||
),
|
||||
[ClassicFixedBossWaves.EVIL_ADMIN_2]: new FixedBattleConfig()
|
||||
.setBattleType(BattleType.TRAINER)
|
||||
.setSeedOffsetWave(ClassicFixedBossWaves.EVIL_GRUNT_1)
|
||||
.setGetTrainerFunc(
|
||||
getRandomTrainerFunc(
|
||||
[
|
||||
[TrainerType.ARCHER, TrainerType.ARIANA, TrainerType.PROTON, TrainerType.PETREL],
|
||||
[TrainerType.TABITHA, TrainerType.COURTNEY],
|
||||
[TrainerType.MATT, TrainerType.SHELLY],
|
||||
[TrainerType.JUPITER, TrainerType.MARS, TrainerType.SATURN],
|
||||
[TrainerType.ZINZOLIN, TrainerType.COLRESS],
|
||||
[TrainerType.XEROSIC, TrainerType.BRYONY],
|
||||
TrainerType.FABA,
|
||||
TrainerType.PLUMERIA,
|
||||
TrainerType.OLEANA,
|
||||
[TrainerType.GIACOMO, TrainerType.MELA, TrainerType.ATTICUS, TrainerType.ORTEGA, TrainerType.ERI],
|
||||
],
|
||||
true,
|
||||
1,
|
||||
),
|
||||
),
|
||||
[ClassicFixedBossWaves.EVIL_BOSS_1]: new FixedBattleConfig()
|
||||
.setBattleType(BattleType.TRAINER)
|
||||
.setSeedOffsetWave(ClassicFixedBossWaves.EVIL_GRUNT_1)
|
||||
.setGetTrainerFunc(
|
||||
getRandomTrainerFunc([
|
||||
TrainerType.ROCKET_BOSS_GIOVANNI_1,
|
||||
TrainerType.MAXIE,
|
||||
TrainerType.ARCHIE,
|
||||
TrainerType.CYRUS,
|
||||
TrainerType.GHETSIS,
|
||||
TrainerType.LYSANDRE,
|
||||
TrainerType.LUSAMINE,
|
||||
TrainerType.GUZMA,
|
||||
TrainerType.ROSE,
|
||||
TrainerType.PENNY,
|
||||
]),
|
||||
)
|
||||
.setCustomModifierRewards({
|
||||
guaranteedModifierTiers: [
|
||||
ModifierTier.ROGUE,
|
||||
ModifierTier.ROGUE,
|
||||
ModifierTier.ULTRA,
|
||||
ModifierTier.ULTRA,
|
||||
ModifierTier.ULTRA,
|
||||
],
|
||||
allowLuckUpgrades: false,
|
||||
}),
|
||||
[ClassicFixedBossWaves.RIVAL_5]: new FixedBattleConfig()
|
||||
.setBattleType(BattleType.TRAINER)
|
||||
.setGetTrainerFunc(
|
||||
() =>
|
||||
new Trainer(
|
||||
TrainerType.RIVAL_5,
|
||||
globalScene.gameData.gender === PlayerGender.MALE ? TrainerVariant.FEMALE : TrainerVariant.DEFAULT,
|
||||
),
|
||||
)
|
||||
.setCustomModifierRewards({
|
||||
guaranteedModifierTiers: [
|
||||
ModifierTier.ROGUE,
|
||||
ModifierTier.ROGUE,
|
||||
ModifierTier.ROGUE,
|
||||
ModifierTier.ULTRA,
|
||||
ModifierTier.ULTRA,
|
||||
],
|
||||
allowLuckUpgrades: false,
|
||||
}),
|
||||
[ClassicFixedBossWaves.EVIL_BOSS_2]: new FixedBattleConfig()
|
||||
.setBattleType(BattleType.TRAINER)
|
||||
.setSeedOffsetWave(ClassicFixedBossWaves.EVIL_GRUNT_1)
|
||||
.setGetTrainerFunc(
|
||||
getRandomTrainerFunc([
|
||||
TrainerType.ROCKET_BOSS_GIOVANNI_2,
|
||||
TrainerType.MAXIE_2,
|
||||
TrainerType.ARCHIE_2,
|
||||
TrainerType.CYRUS_2,
|
||||
TrainerType.GHETSIS_2,
|
||||
TrainerType.LYSANDRE_2,
|
||||
TrainerType.LUSAMINE_2,
|
||||
TrainerType.GUZMA_2,
|
||||
TrainerType.ROSE_2,
|
||||
TrainerType.PENNY_2,
|
||||
]),
|
||||
)
|
||||
.setCustomModifierRewards({
|
||||
guaranteedModifierTiers: [
|
||||
ModifierTier.ROGUE,
|
||||
ModifierTier.ROGUE,
|
||||
ModifierTier.ULTRA,
|
||||
ModifierTier.ULTRA,
|
||||
ModifierTier.ULTRA,
|
||||
ModifierTier.ULTRA,
|
||||
],
|
||||
allowLuckUpgrades: false,
|
||||
}),
|
||||
[ClassicFixedBossWaves.ELITE_FOUR_1]: new FixedBattleConfig()
|
||||
.setBattleType(BattleType.TRAINER)
|
||||
.setGetTrainerFunc(
|
||||
getRandomTrainerFunc([
|
||||
TrainerType.LORELEI,
|
||||
TrainerType.WILL,
|
||||
TrainerType.SIDNEY,
|
||||
TrainerType.AARON,
|
||||
TrainerType.SHAUNTAL,
|
||||
TrainerType.MALVA,
|
||||
[TrainerType.HALA, TrainerType.MOLAYNE],
|
||||
TrainerType.MARNIE_ELITE,
|
||||
TrainerType.RIKA,
|
||||
TrainerType.CRISPIN,
|
||||
]),
|
||||
),
|
||||
[ClassicFixedBossWaves.ELITE_FOUR_2]: new FixedBattleConfig()
|
||||
.setBattleType(BattleType.TRAINER)
|
||||
.setSeedOffsetWave(ClassicFixedBossWaves.ELITE_FOUR_1)
|
||||
.setGetTrainerFunc(
|
||||
getRandomTrainerFunc([
|
||||
TrainerType.BRUNO,
|
||||
TrainerType.KOGA,
|
||||
TrainerType.PHOEBE,
|
||||
TrainerType.BERTHA,
|
||||
TrainerType.MARSHAL,
|
||||
TrainerType.SIEBOLD,
|
||||
TrainerType.OLIVIA,
|
||||
TrainerType.NESSA_ELITE,
|
||||
TrainerType.POPPY,
|
||||
TrainerType.AMARYS,
|
||||
]),
|
||||
),
|
||||
[ClassicFixedBossWaves.ELITE_FOUR_3]: new FixedBattleConfig()
|
||||
.setBattleType(BattleType.TRAINER)
|
||||
.setSeedOffsetWave(ClassicFixedBossWaves.ELITE_FOUR_1)
|
||||
.setGetTrainerFunc(
|
||||
getRandomTrainerFunc([
|
||||
TrainerType.AGATHA,
|
||||
TrainerType.BRUNO,
|
||||
TrainerType.GLACIA,
|
||||
TrainerType.FLINT,
|
||||
TrainerType.GRIMSLEY,
|
||||
TrainerType.WIKSTROM,
|
||||
TrainerType.ACEROLA,
|
||||
[TrainerType.BEA_ELITE, TrainerType.ALLISTER_ELITE],
|
||||
TrainerType.LARRY_ELITE,
|
||||
TrainerType.LACEY,
|
||||
]),
|
||||
),
|
||||
[ClassicFixedBossWaves.ELITE_FOUR_4]: new FixedBattleConfig()
|
||||
.setBattleType(BattleType.TRAINER)
|
||||
.setSeedOffsetWave(ClassicFixedBossWaves.ELITE_FOUR_1)
|
||||
.setGetTrainerFunc(
|
||||
getRandomTrainerFunc([
|
||||
TrainerType.LANCE,
|
||||
TrainerType.KAREN,
|
||||
TrainerType.DRAKE,
|
||||
TrainerType.LUCIAN,
|
||||
TrainerType.CAITLIN,
|
||||
TrainerType.DRASNA,
|
||||
TrainerType.KAHILI,
|
||||
TrainerType.RAIHAN_ELITE,
|
||||
TrainerType.HASSEL,
|
||||
TrainerType.DRAYTON,
|
||||
]),
|
||||
),
|
||||
[ClassicFixedBossWaves.CHAMPION]: new FixedBattleConfig()
|
||||
.setBattleType(BattleType.TRAINER)
|
||||
.setSeedOffsetWave(ClassicFixedBossWaves.ELITE_FOUR_1)
|
||||
.setGetTrainerFunc(
|
||||
getRandomTrainerFunc([
|
||||
TrainerType.BLUE,
|
||||
[TrainerType.RED, TrainerType.LANCE_CHAMPION],
|
||||
[TrainerType.STEVEN, TrainerType.WALLACE],
|
||||
TrainerType.CYNTHIA,
|
||||
[TrainerType.ALDER, TrainerType.IRIS],
|
||||
TrainerType.DIANTHA,
|
||||
[TrainerType.KUKUI, TrainerType.HAU],
|
||||
[TrainerType.LEON, TrainerType.MUSTARD],
|
||||
[TrainerType.GEETA, TrainerType.NEMONA],
|
||||
TrainerType.KIERAN,
|
||||
]),
|
||||
),
|
||||
[ClassicFixedBossWaves.RIVAL_6]: new FixedBattleConfig()
|
||||
.setBattleType(BattleType.TRAINER)
|
||||
.setGetTrainerFunc(
|
||||
() =>
|
||||
new Trainer(
|
||||
TrainerType.RIVAL_6,
|
||||
globalScene.gameData.gender === PlayerGender.MALE ? TrainerVariant.FEMALE : TrainerVariant.DEFAULT,
|
||||
),
|
||||
)
|
||||
.setCustomModifierRewards({
|
||||
guaranteedModifierTiers: [
|
||||
ModifierTier.ROGUE,
|
||||
ModifierTier.ROGUE,
|
||||
ModifierTier.ULTRA,
|
||||
ModifierTier.ULTRA,
|
||||
ModifierTier.GREAT,
|
||||
ModifierTier.GREAT,
|
||||
],
|
||||
allowLuckUpgrades: false,
|
||||
}),
|
||||
};
|
||||
|
@ -490,7 +490,7 @@ export const biomePokemonPools: BiomePokemonPools = {
|
||||
[TimeOfDay.NIGHT]: [],
|
||||
[TimeOfDay.ALL]: [ SpeciesId.POLITOED, SpeciesId.GALAR_STUNFISK ]
|
||||
},
|
||||
[BiomePoolTier.ULTRA_RARE]: { [TimeOfDay.DAWN]: [], [TimeOfDay.DAY]: [], [TimeOfDay.DUSK]: [], [TimeOfDay.NIGHT]: [], [TimeOfDay.ALL]: [ SpeciesId.AZELF, SpeciesId.POIPOLE ] },
|
||||
[BiomePoolTier.ULTRA_RARE]: { [TimeOfDay.DAWN]: [], [TimeOfDay.DAY]: [], [TimeOfDay.DUSK]: [], [TimeOfDay.NIGHT]: [], [TimeOfDay.ALL]: [ SpeciesId.AZELF, { 1: [ SpeciesId.POIPOLE ], 60: [ SpeciesId.NAGANADEL ] } ] },
|
||||
[BiomePoolTier.BOSS]: {
|
||||
[TimeOfDay.DAWN]: [ SpeciesId.QUAGSIRE, SpeciesId.LUDICOLO ],
|
||||
[TimeOfDay.DAY]: [ SpeciesId.QUAGSIRE, SpeciesId.LUDICOLO ],
|
||||
@ -505,7 +505,7 @@ export const biomePokemonPools: BiomePokemonPools = {
|
||||
[TimeOfDay.NIGHT]: [],
|
||||
[TimeOfDay.ALL]: [ SpeciesId.FERALIGATR, SpeciesId.POLITOED, SpeciesId.SWAMPERT, SpeciesId.GALAR_STUNFISK ]
|
||||
},
|
||||
[BiomePoolTier.BOSS_SUPER_RARE]: { [TimeOfDay.DAWN]: [], [TimeOfDay.DAY]: [], [TimeOfDay.DUSK]: [], [TimeOfDay.NIGHT]: [], [TimeOfDay.ALL]: [ SpeciesId.AZELF, SpeciesId.NAGANADEL ] },
|
||||
[BiomePoolTier.BOSS_SUPER_RARE]: { [TimeOfDay.DAWN]: [], [TimeOfDay.DAY]: [], [TimeOfDay.DUSK]: [], [TimeOfDay.NIGHT]: [], [TimeOfDay.ALL]: [ SpeciesId.AZELF, { 1: [ SpeciesId.POIPOLE ], 60: [ SpeciesId.NAGANADEL ] } ] },
|
||||
[BiomePoolTier.BOSS_ULTRA_RARE]: { [TimeOfDay.DAWN]: [], [TimeOfDay.DAY]: [], [TimeOfDay.DUSK]: [], [TimeOfDay.NIGHT]: [], [TimeOfDay.ALL]: [] }
|
||||
},
|
||||
[BiomeId.BEACH]: {
|
||||
@ -1118,7 +1118,7 @@ export const biomePokemonPools: BiomePokemonPools = {
|
||||
},
|
||||
[BiomePoolTier.RARE]: { [TimeOfDay.DAWN]: [], [TimeOfDay.DAY]: [], [TimeOfDay.DUSK]: [], [TimeOfDay.NIGHT]: [], [TimeOfDay.ALL]: [ SpeciesId.HITMONLEE, SpeciesId.HITMONCHAN, SpeciesId.LUCARIO, SpeciesId.THROH, SpeciesId.SAWK, { 1: [ SpeciesId.PANCHAM ], 52: [ SpeciesId.PANGORO ] } ] },
|
||||
[BiomePoolTier.SUPER_RARE]: { [TimeOfDay.DAWN]: [], [TimeOfDay.DAY]: [], [TimeOfDay.DUSK]: [], [TimeOfDay.NIGHT]: [], [TimeOfDay.ALL]: [ SpeciesId.HITMONTOP, SpeciesId.GALLADE, SpeciesId.GALAR_FARFETCHD ] },
|
||||
[BiomePoolTier.ULTRA_RARE]: { [TimeOfDay.DAWN]: [], [TimeOfDay.DAY]: [], [TimeOfDay.DUSK]: [], [TimeOfDay.NIGHT]: [], [TimeOfDay.ALL]: [ SpeciesId.TERRAKION, SpeciesId.KUBFU, SpeciesId.GALAR_ZAPDOS ] },
|
||||
[BiomePoolTier.ULTRA_RARE]: { [TimeOfDay.DAWN]: [], [TimeOfDay.DAY]: [], [TimeOfDay.DUSK]: [], [TimeOfDay.NIGHT]: [], [TimeOfDay.ALL]: [ SpeciesId.TERRAKION, { 1: [ SpeciesId.KUBFU ], 60: [ SpeciesId.URSHIFU] }, SpeciesId.GALAR_ZAPDOS ] },
|
||||
[BiomePoolTier.BOSS]: {
|
||||
[TimeOfDay.DAWN]: [],
|
||||
[TimeOfDay.DAY]: [],
|
||||
@ -1127,7 +1127,7 @@ export const biomePokemonPools: BiomePokemonPools = {
|
||||
[TimeOfDay.ALL]: [ SpeciesId.HITMONLEE, SpeciesId.HITMONCHAN, SpeciesId.HARIYAMA, SpeciesId.MEDICHAM, SpeciesId.LUCARIO, SpeciesId.TOXICROAK, SpeciesId.THROH, SpeciesId.SAWK, SpeciesId.SCRAFTY, SpeciesId.MIENSHAO, SpeciesId.BEWEAR, SpeciesId.GRAPPLOCT, SpeciesId.ANNIHILAPE ]
|
||||
},
|
||||
[BiomePoolTier.BOSS_RARE]: { [TimeOfDay.DAWN]: [], [TimeOfDay.DAY]: [], [TimeOfDay.DUSK]: [], [TimeOfDay.NIGHT]: [], [TimeOfDay.ALL]: [ SpeciesId.HITMONTOP, SpeciesId.GALLADE, SpeciesId.PANGORO, SpeciesId.SIRFETCHD, SpeciesId.HISUI_DECIDUEYE ] },
|
||||
[BiomePoolTier.BOSS_SUPER_RARE]: { [TimeOfDay.DAWN]: [], [TimeOfDay.DAY]: [], [TimeOfDay.DUSK]: [], [TimeOfDay.NIGHT]: [], [TimeOfDay.ALL]: [ SpeciesId.TERRAKION, SpeciesId.URSHIFU ] },
|
||||
[BiomePoolTier.BOSS_SUPER_RARE]: { [TimeOfDay.DAWN]: [], [TimeOfDay.DAY]: [], [TimeOfDay.DUSK]: [], [TimeOfDay.NIGHT]: [], [TimeOfDay.ALL]: [ SpeciesId.TERRAKION, { 1: [ SpeciesId.KUBFU ], 60: [ SpeciesId.URSHIFU] } ] },
|
||||
[BiomePoolTier.BOSS_ULTRA_RARE]: { [TimeOfDay.DAWN]: [], [TimeOfDay.DAY]: [], [TimeOfDay.DUSK]: [], [TimeOfDay.NIGHT]: [], [TimeOfDay.ALL]: [ SpeciesId.ZAMAZENTA, SpeciesId.GALAR_ZAPDOS ] }
|
||||
},
|
||||
[BiomeId.FACTORY]: {
|
||||
@ -1418,8 +1418,8 @@ export const biomePokemonPools: BiomePokemonPools = {
|
||||
{ 1: [ SpeciesId.HATENNA ], 32: [ SpeciesId.HATTREM ], 42: [ SpeciesId.HATTERENE ] }
|
||||
]
|
||||
},
|
||||
[BiomePoolTier.RARE]: { [TimeOfDay.DAWN]: [], [TimeOfDay.DAY]: [], [TimeOfDay.DUSK]: [], [TimeOfDay.NIGHT]: [], [TimeOfDay.ALL]: [ SpeciesId.AUDINO, SpeciesId.ETERNAL_FLOETTE ] },
|
||||
[BiomePoolTier.SUPER_RARE]: { [TimeOfDay.DAWN]: [], [TimeOfDay.DAY]: [], [TimeOfDay.DUSK]: [], [TimeOfDay.NIGHT]: [], [TimeOfDay.ALL]: [] },
|
||||
[BiomePoolTier.RARE]: { [TimeOfDay.DAWN]: [], [TimeOfDay.DAY]: [], [TimeOfDay.DUSK]: [], [TimeOfDay.NIGHT]: [], [TimeOfDay.ALL]: [ SpeciesId.AUDINO ] },
|
||||
[BiomePoolTier.SUPER_RARE]: { [TimeOfDay.DAWN]: [], [TimeOfDay.DAY]: [], [TimeOfDay.DUSK]: [], [TimeOfDay.NIGHT]: [], [TimeOfDay.ALL]: [ SpeciesId.ETERNAL_FLOETTE ] },
|
||||
[BiomePoolTier.ULTRA_RARE]: { [TimeOfDay.DAWN]: [], [TimeOfDay.DAY]: [], [TimeOfDay.DUSK]: [], [TimeOfDay.NIGHT]: [], [TimeOfDay.ALL]: [ SpeciesId.DIANCIE, SpeciesId.ENAMORUS ] },
|
||||
[BiomePoolTier.BOSS]: {
|
||||
[TimeOfDay.DAWN]: [],
|
||||
@ -1596,10 +1596,10 @@ export const biomePokemonPools: BiomePokemonPools = {
|
||||
[BiomePoolTier.UNCOMMON]: { [TimeOfDay.DAWN]: [], [TimeOfDay.DAY]: [], [TimeOfDay.DUSK]: [], [TimeOfDay.NIGHT]: [], [TimeOfDay.ALL]: [ { 1: [ SpeciesId.SOLOSIS ], 32: [ SpeciesId.DUOSION ], 41: [ SpeciesId.REUNICLUS ] } ] },
|
||||
[BiomePoolTier.RARE]: { [TimeOfDay.DAWN]: [], [TimeOfDay.DAY]: [], [TimeOfDay.DUSK]: [], [TimeOfDay.NIGHT]: [], [TimeOfDay.ALL]: [ SpeciesId.DITTO, { 1: [ SpeciesId.PORYGON ], 30: [ SpeciesId.PORYGON2 ] } ] },
|
||||
[BiomePoolTier.SUPER_RARE]: { [TimeOfDay.DAWN]: [], [TimeOfDay.DAY]: [], [TimeOfDay.DUSK]: [], [TimeOfDay.NIGHT]: [], [TimeOfDay.ALL]: [ SpeciesId.ROTOM ] },
|
||||
[BiomePoolTier.ULTRA_RARE]: { [TimeOfDay.DAWN]: [], [TimeOfDay.DAY]: [], [TimeOfDay.DUSK]: [], [TimeOfDay.NIGHT]: [], [TimeOfDay.ALL]: [ SpeciesId.TYPE_NULL ] },
|
||||
[BiomePoolTier.ULTRA_RARE]: { [TimeOfDay.DAWN]: [], [TimeOfDay.DAY]: [], [TimeOfDay.DUSK]: [], [TimeOfDay.NIGHT]: [], [TimeOfDay.ALL]: [ { 1: [SpeciesId.TYPE_NULL], 60: [ SpeciesId.SILVALLY ] } ] },
|
||||
[BiomePoolTier.BOSS]: { [TimeOfDay.DAWN]: [], [TimeOfDay.DAY]: [], [TimeOfDay.DUSK]: [], [TimeOfDay.NIGHT]: [], [TimeOfDay.ALL]: [ SpeciesId.MUK, SpeciesId.ELECTRODE, SpeciesId.BRONZONG, SpeciesId.MAGNEZONE, SpeciesId.PORYGON_Z, SpeciesId.REUNICLUS, SpeciesId.KLINKLANG ] },
|
||||
[BiomePoolTier.BOSS_RARE]: { [TimeOfDay.DAWN]: [], [TimeOfDay.DAY]: [], [TimeOfDay.DUSK]: [], [TimeOfDay.NIGHT]: [], [TimeOfDay.ALL]: [] },
|
||||
[BiomePoolTier.BOSS_SUPER_RARE]: { [TimeOfDay.DAWN]: [], [TimeOfDay.DAY]: [], [TimeOfDay.DUSK]: [], [TimeOfDay.NIGHT]: [], [TimeOfDay.ALL]: [ SpeciesId.ROTOM, SpeciesId.ZYGARDE, SpeciesId.SILVALLY ] },
|
||||
[BiomePoolTier.BOSS_SUPER_RARE]: { [TimeOfDay.DAWN]: [], [TimeOfDay.DAY]: [], [TimeOfDay.DUSK]: [], [TimeOfDay.NIGHT]: [], [TimeOfDay.ALL]: [ SpeciesId.ROTOM, SpeciesId.ZYGARDE, { 1: [SpeciesId.TYPE_NULL], 60: [ SpeciesId.SILVALLY ] } ] },
|
||||
[BiomePoolTier.BOSS_ULTRA_RARE]: { [TimeOfDay.DAWN]: [], [TimeOfDay.DAY]: [], [TimeOfDay.DUSK]: [], [TimeOfDay.NIGHT]: [], [TimeOfDay.ALL]: [ SpeciesId.MEWTWO, SpeciesId.MIRAIDON ] }
|
||||
},
|
||||
[BiomeId.END]: {
|
||||
@ -6969,7 +6969,7 @@ export function initBiomes() {
|
||||
]
|
||||
],
|
||||
[ SpeciesId.ETERNAL_FLOETTE, PokemonType.FAIRY, -1, [
|
||||
[ BiomeId.FAIRY_CAVE, BiomePoolTier.RARE ],
|
||||
[ BiomeId.FAIRY_CAVE, BiomePoolTier.SUPER_RARE ],
|
||||
[ BiomeId.FAIRY_CAVE, BiomePoolTier.BOSS_RARE ]
|
||||
]
|
||||
],
|
||||
|
@ -1630,7 +1630,7 @@ export const pokemonEvolutions: PokemonEvolutions = {
|
||||
new SpeciesEvolution(SpeciesId.TSAREENA, 28, null, {key: EvoCondKey.MOVE, move: MoveId.STOMP}, SpeciesWildEvolutionDelay.LONG)
|
||||
],
|
||||
[SpeciesId.POIPOLE]: [
|
||||
new SpeciesEvolution(SpeciesId.NAGANADEL, 1, null, {key: EvoCondKey.MOVE, move: MoveId.DRAGON_PULSE}, SpeciesWildEvolutionDelay.LONG)
|
||||
new SpeciesEvolution(SpeciesId.NAGANADEL, 1, null, {key: EvoCondKey.MOVE, move: MoveId.DRAGON_PULSE}, SpeciesWildEvolutionDelay.VERY_LONG)
|
||||
],
|
||||
[SpeciesId.ALOLA_SANDSHREW]: [
|
||||
new SpeciesEvolution(SpeciesId.ALOLA_SANDSLASH, 1, EvolutionItem.ICE_STONE, null, SpeciesWildEvolutionDelay.LONG)
|
||||
@ -1845,7 +1845,7 @@ export const pokemonEvolutions: PokemonEvolutions = {
|
||||
new SpeciesEvolution(SpeciesId.LEAVANNY, 1, null, {key: EvoCondKey.FRIENDSHIP, value: 120}, SpeciesWildEvolutionDelay.LONG)
|
||||
],
|
||||
[SpeciesId.TYPE_NULL]: [
|
||||
new SpeciesEvolution(SpeciesId.SILVALLY, 1, null, {key: EvoCondKey.FRIENDSHIP, value: 100}, SpeciesWildEvolutionDelay.LONG)
|
||||
new SpeciesEvolution(SpeciesId.SILVALLY, 1, null, {key: EvoCondKey.FRIENDSHIP, value: 100}, SpeciesWildEvolutionDelay.VERY_LONG)
|
||||
],
|
||||
[SpeciesId.ALOLA_MEOWTH]: [
|
||||
new SpeciesEvolution(SpeciesId.ALOLA_PERSIAN, 1, null, {key: EvoCondKey.FRIENDSHIP, value: 120}, SpeciesWildEvolutionDelay.LONG)
|
||||
|
@ -44,8 +44,8 @@ import {
|
||||
HeldItemRequirement,
|
||||
TypeRequirement,
|
||||
} from "#mystery-encounters/mystery-encounter-requirements";
|
||||
import { TrainerPartyCompoundTemplate, TrainerPartyTemplate } from "#trainers/TrainerPartyTemplate";
|
||||
import { getRandomPartyMemberFunc, trainerConfigs } from "#trainers/trainer-config";
|
||||
import { TrainerPartyCompoundTemplate, TrainerPartyTemplate } from "#trainers/trainer-party-template";
|
||||
import type { OptionSelectItem } from "#ui/abstact-option-select-ui-handler";
|
||||
import { MoveInfoOverlay } from "#ui/move-info-overlay";
|
||||
import { isNullOrUndefined, randSeedInt, randSeedShuffle } from "#utils/common";
|
||||
|
@ -43,8 +43,8 @@ import {
|
||||
import type { MysteryEncounter } from "#mystery-encounters/mystery-encounter";
|
||||
import { MysteryEncounterBuilder } from "#mystery-encounters/mystery-encounter";
|
||||
import { MysteryEncounterOptionBuilder } from "#mystery-encounters/mystery-encounter-option";
|
||||
import { TrainerPartyCompoundTemplate, TrainerPartyTemplate } from "#trainers/TrainerPartyTemplate";
|
||||
import { trainerConfigs } from "#trainers/trainer-config";
|
||||
import { TrainerPartyCompoundTemplate, TrainerPartyTemplate } from "#trainers/trainer-party-template";
|
||||
import type { OptionSelectConfig } from "#ui/abstact-option-select-ui-handler";
|
||||
import { randSeedInt, randSeedShuffle } from "#utils/common";
|
||||
import { getPokemonSpecies } from "#utils/pokemon-utils";
|
||||
|
@ -9,12 +9,12 @@ import type { EnemyPartyConfig } from "#mystery-encounters/encounter-phase-utils
|
||||
import { initBattleWithEnemyConfig, setEncounterRewards } from "#mystery-encounters/encounter-phase-utils";
|
||||
import type { MysteryEncounter } from "#mystery-encounters/mystery-encounter";
|
||||
import { MysteryEncounterBuilder } from "#mystery-encounters/mystery-encounter";
|
||||
import { trainerConfigs } from "#trainers/trainer-config";
|
||||
import {
|
||||
TrainerPartyCompoundTemplate,
|
||||
TrainerPartyTemplate,
|
||||
trainerPartyTemplates,
|
||||
} from "#trainers/TrainerPartyTemplate";
|
||||
import { trainerConfigs } from "#trainers/trainer-config";
|
||||
} from "#trainers/trainer-party-template";
|
||||
import { randSeedInt } from "#utils/common";
|
||||
|
||||
/** the i18n namespace for the encounter */
|
||||
|
@ -36,8 +36,8 @@ import { MysteryEncounterOptionBuilder } from "#mystery-encounters/mystery-encou
|
||||
import i18next from "#plugins/i18n";
|
||||
import { achvs } from "#system/achv";
|
||||
import { PokemonData } from "#system/pokemon-data";
|
||||
import { TrainerPartyTemplate } from "#trainers/TrainerPartyTemplate";
|
||||
import { trainerConfigs } from "#trainers/trainer-config";
|
||||
import { TrainerPartyTemplate } from "#trainers/trainer-party-template";
|
||||
import type { HeldModifierConfig } from "#types/held-modifier-config";
|
||||
import { isNullOrUndefined, NumberHolder, randSeedInt, randSeedShuffle } from "#utils/common";
|
||||
import { getPokemonSpecies } from "#utils/pokemon-utils";
|
||||
|
@ -521,7 +521,7 @@ export function trainerThrowPokeball(
|
||||
repeatDelay: 500,
|
||||
onUpdate: t => {
|
||||
if (shakeCount && shakeCount < 4) {
|
||||
const value = t.getValue();
|
||||
const value = t.getValue() ?? 0;
|
||||
const directionMultiplier = shakeCount % 2 === 1 ? 1 : -1;
|
||||
pokeball.setX(pbX + value * 4 * directionMultiplier);
|
||||
pokeball.setAngle(value * 27.5 * directionMultiplier);
|
||||
|
@ -127,7 +127,7 @@ export function doPokemonTransformationSequence(
|
||||
to: 1,
|
||||
duration: 1000,
|
||||
onUpdate: t => {
|
||||
pokemonTintSprite.setAlpha(t.getValue());
|
||||
pokemonTintSprite.setAlpha(t.getValue() ?? 1);
|
||||
},
|
||||
onComplete: () => {
|
||||
pokemonSprite.setVisible(false);
|
||||
|
376
src/data/trainers/fixed-battle-configs.ts
Normal file
376
src/data/trainers/fixed-battle-configs.ts
Normal file
@ -0,0 +1,376 @@
|
||||
import { FixedBattleConfig, getRandomTrainerFunc } from "#app/battle";
|
||||
import { Trainer } from "#app/field/trainer";
|
||||
import { globalScene } from "#app/global-scene";
|
||||
import { randSeedInt } from "#app/utils/common";
|
||||
import { BattleType } from "#enums/battle-type";
|
||||
import { ClassicFixedBossWaves } from "#enums/fixed-boss-waves";
|
||||
import { ModifierTier } from "#enums/modifier-tier";
|
||||
import { PlayerGender } from "#enums/player-gender";
|
||||
import { TrainerType } from "#enums/trainer-type";
|
||||
import { TrainerVariant } from "#enums/trainer-variant";
|
||||
|
||||
export interface FixedBattleConfigs {
|
||||
[key: number]: FixedBattleConfig;
|
||||
}
|
||||
/**
|
||||
* Youngster/Lass on 5
|
||||
* Rival on 8, 55, 95, 145, 195
|
||||
* Evil team grunts on 35, 62, 64, and 112
|
||||
* Evil team admin on 66 and 114
|
||||
* Evil leader on 115, 165
|
||||
* E4 on 182, 184, 186, 188
|
||||
* Champion on 190
|
||||
*/
|
||||
export const classicFixedBattles: FixedBattleConfigs = {
|
||||
[ClassicFixedBossWaves.TOWN_YOUNGSTER]: new FixedBattleConfig()
|
||||
.setBattleType(BattleType.TRAINER)
|
||||
.setGetTrainerFunc(
|
||||
() => new Trainer(TrainerType.YOUNGSTER, randSeedInt(2) ? TrainerVariant.FEMALE : TrainerVariant.DEFAULT),
|
||||
),
|
||||
[ClassicFixedBossWaves.RIVAL_1]: new FixedBattleConfig()
|
||||
.setBattleType(BattleType.TRAINER)
|
||||
.setGetTrainerFunc(
|
||||
() =>
|
||||
new Trainer(
|
||||
TrainerType.RIVAL,
|
||||
globalScene.gameData.gender === PlayerGender.MALE ? TrainerVariant.FEMALE : TrainerVariant.DEFAULT,
|
||||
),
|
||||
),
|
||||
[ClassicFixedBossWaves.RIVAL_2]: new FixedBattleConfig()
|
||||
.setBattleType(BattleType.TRAINER)
|
||||
.setGetTrainerFunc(
|
||||
() =>
|
||||
new Trainer(
|
||||
TrainerType.RIVAL_2,
|
||||
globalScene.gameData.gender === PlayerGender.MALE ? TrainerVariant.FEMALE : TrainerVariant.DEFAULT,
|
||||
),
|
||||
)
|
||||
.setCustomModifierRewards({
|
||||
guaranteedModifierTiers: [ModifierTier.ULTRA, ModifierTier.GREAT, ModifierTier.GREAT],
|
||||
allowLuckUpgrades: false,
|
||||
}),
|
||||
[ClassicFixedBossWaves.EVIL_GRUNT_1]: new FixedBattleConfig()
|
||||
.setBattleType(BattleType.TRAINER)
|
||||
.setGetTrainerFunc(
|
||||
getRandomTrainerFunc(
|
||||
[
|
||||
TrainerType.ROCKET_GRUNT,
|
||||
TrainerType.MAGMA_GRUNT,
|
||||
TrainerType.AQUA_GRUNT,
|
||||
TrainerType.GALACTIC_GRUNT,
|
||||
TrainerType.PLASMA_GRUNT,
|
||||
TrainerType.FLARE_GRUNT,
|
||||
TrainerType.AETHER_GRUNT,
|
||||
TrainerType.SKULL_GRUNT,
|
||||
TrainerType.MACRO_GRUNT,
|
||||
TrainerType.STAR_GRUNT,
|
||||
],
|
||||
true,
|
||||
),
|
||||
),
|
||||
[ClassicFixedBossWaves.RIVAL_3]: new FixedBattleConfig()
|
||||
.setBattleType(BattleType.TRAINER)
|
||||
.setGetTrainerFunc(
|
||||
() =>
|
||||
new Trainer(
|
||||
TrainerType.RIVAL_3,
|
||||
globalScene.gameData.gender === PlayerGender.MALE ? TrainerVariant.FEMALE : TrainerVariant.DEFAULT,
|
||||
),
|
||||
)
|
||||
.setCustomModifierRewards({
|
||||
guaranteedModifierTiers: [ModifierTier.ULTRA, ModifierTier.ULTRA, ModifierTier.GREAT, ModifierTier.GREAT],
|
||||
allowLuckUpgrades: false,
|
||||
}),
|
||||
[ClassicFixedBossWaves.EVIL_GRUNT_2]: new FixedBattleConfig()
|
||||
.setBattleType(BattleType.TRAINER)
|
||||
.setSeedOffsetWave(ClassicFixedBossWaves.EVIL_GRUNT_1)
|
||||
.setGetTrainerFunc(
|
||||
getRandomTrainerFunc(
|
||||
[
|
||||
TrainerType.ROCKET_GRUNT,
|
||||
TrainerType.MAGMA_GRUNT,
|
||||
TrainerType.AQUA_GRUNT,
|
||||
TrainerType.GALACTIC_GRUNT,
|
||||
TrainerType.PLASMA_GRUNT,
|
||||
TrainerType.FLARE_GRUNT,
|
||||
TrainerType.AETHER_GRUNT,
|
||||
TrainerType.SKULL_GRUNT,
|
||||
TrainerType.MACRO_GRUNT,
|
||||
TrainerType.STAR_GRUNT,
|
||||
],
|
||||
true,
|
||||
),
|
||||
),
|
||||
[ClassicFixedBossWaves.EVIL_GRUNT_3]: new FixedBattleConfig()
|
||||
.setBattleType(BattleType.TRAINER)
|
||||
.setSeedOffsetWave(ClassicFixedBossWaves.EVIL_GRUNT_1)
|
||||
.setGetTrainerFunc(
|
||||
getRandomTrainerFunc(
|
||||
[
|
||||
TrainerType.ROCKET_GRUNT,
|
||||
TrainerType.MAGMA_GRUNT,
|
||||
TrainerType.AQUA_GRUNT,
|
||||
TrainerType.GALACTIC_GRUNT,
|
||||
TrainerType.PLASMA_GRUNT,
|
||||
TrainerType.FLARE_GRUNT,
|
||||
TrainerType.AETHER_GRUNT,
|
||||
TrainerType.SKULL_GRUNT,
|
||||
TrainerType.MACRO_GRUNT,
|
||||
TrainerType.STAR_GRUNT,
|
||||
],
|
||||
true,
|
||||
),
|
||||
),
|
||||
[ClassicFixedBossWaves.EVIL_ADMIN_1]: new FixedBattleConfig()
|
||||
.setBattleType(BattleType.TRAINER)
|
||||
.setSeedOffsetWave(ClassicFixedBossWaves.EVIL_GRUNT_1)
|
||||
.setGetTrainerFunc(
|
||||
getRandomTrainerFunc(
|
||||
[
|
||||
[TrainerType.ARCHER, TrainerType.ARIANA, TrainerType.PROTON, TrainerType.PETREL],
|
||||
[TrainerType.TABITHA, TrainerType.COURTNEY],
|
||||
[TrainerType.MATT, TrainerType.SHELLY],
|
||||
[TrainerType.JUPITER, TrainerType.MARS, TrainerType.SATURN],
|
||||
[TrainerType.ZINZOLIN, TrainerType.COLRESS],
|
||||
[TrainerType.XEROSIC, TrainerType.BRYONY],
|
||||
TrainerType.FABA,
|
||||
TrainerType.PLUMERIA,
|
||||
TrainerType.OLEANA,
|
||||
[TrainerType.GIACOMO, TrainerType.MELA, TrainerType.ATTICUS, TrainerType.ORTEGA, TrainerType.ERI],
|
||||
],
|
||||
true,
|
||||
),
|
||||
),
|
||||
[ClassicFixedBossWaves.RIVAL_4]: new FixedBattleConfig()
|
||||
.setBattleType(BattleType.TRAINER)
|
||||
.setGetTrainerFunc(
|
||||
() =>
|
||||
new Trainer(
|
||||
TrainerType.RIVAL_4,
|
||||
globalScene.gameData.gender === PlayerGender.MALE ? TrainerVariant.FEMALE : TrainerVariant.DEFAULT,
|
||||
),
|
||||
)
|
||||
.setCustomModifierRewards({
|
||||
guaranteedModifierTiers: [ModifierTier.ULTRA, ModifierTier.ULTRA, ModifierTier.ULTRA, ModifierTier.ULTRA],
|
||||
allowLuckUpgrades: false,
|
||||
}),
|
||||
[ClassicFixedBossWaves.EVIL_GRUNT_4]: new FixedBattleConfig()
|
||||
.setBattleType(BattleType.TRAINER)
|
||||
.setSeedOffsetWave(ClassicFixedBossWaves.EVIL_GRUNT_1)
|
||||
.setGetTrainerFunc(
|
||||
getRandomTrainerFunc(
|
||||
[
|
||||
TrainerType.ROCKET_GRUNT,
|
||||
TrainerType.MAGMA_GRUNT,
|
||||
TrainerType.AQUA_GRUNT,
|
||||
TrainerType.GALACTIC_GRUNT,
|
||||
TrainerType.PLASMA_GRUNT,
|
||||
TrainerType.FLARE_GRUNT,
|
||||
TrainerType.AETHER_GRUNT,
|
||||
TrainerType.SKULL_GRUNT,
|
||||
TrainerType.MACRO_GRUNT,
|
||||
TrainerType.STAR_GRUNT,
|
||||
],
|
||||
true,
|
||||
),
|
||||
),
|
||||
[ClassicFixedBossWaves.EVIL_ADMIN_2]: new FixedBattleConfig()
|
||||
.setBattleType(BattleType.TRAINER)
|
||||
.setSeedOffsetWave(ClassicFixedBossWaves.EVIL_GRUNT_1)
|
||||
.setGetTrainerFunc(
|
||||
getRandomTrainerFunc(
|
||||
[
|
||||
[TrainerType.ARCHER, TrainerType.ARIANA, TrainerType.PROTON, TrainerType.PETREL],
|
||||
[TrainerType.TABITHA, TrainerType.COURTNEY],
|
||||
[TrainerType.MATT, TrainerType.SHELLY],
|
||||
[TrainerType.JUPITER, TrainerType.MARS, TrainerType.SATURN],
|
||||
[TrainerType.ZINZOLIN, TrainerType.COLRESS],
|
||||
[TrainerType.XEROSIC, TrainerType.BRYONY],
|
||||
TrainerType.FABA,
|
||||
TrainerType.PLUMERIA,
|
||||
TrainerType.OLEANA,
|
||||
[TrainerType.GIACOMO, TrainerType.MELA, TrainerType.ATTICUS, TrainerType.ORTEGA, TrainerType.ERI],
|
||||
],
|
||||
true,
|
||||
1,
|
||||
),
|
||||
),
|
||||
[ClassicFixedBossWaves.EVIL_BOSS_1]: new FixedBattleConfig()
|
||||
.setBattleType(BattleType.TRAINER)
|
||||
.setSeedOffsetWave(ClassicFixedBossWaves.EVIL_GRUNT_1)
|
||||
.setGetTrainerFunc(
|
||||
getRandomTrainerFunc([
|
||||
TrainerType.ROCKET_BOSS_GIOVANNI_1,
|
||||
TrainerType.MAXIE,
|
||||
TrainerType.ARCHIE,
|
||||
TrainerType.CYRUS,
|
||||
TrainerType.GHETSIS,
|
||||
TrainerType.LYSANDRE,
|
||||
TrainerType.LUSAMINE,
|
||||
TrainerType.GUZMA,
|
||||
TrainerType.ROSE,
|
||||
TrainerType.PENNY,
|
||||
]),
|
||||
)
|
||||
.setCustomModifierRewards({
|
||||
guaranteedModifierTiers: [
|
||||
ModifierTier.ROGUE,
|
||||
ModifierTier.ROGUE,
|
||||
ModifierTier.ULTRA,
|
||||
ModifierTier.ULTRA,
|
||||
ModifierTier.ULTRA,
|
||||
],
|
||||
allowLuckUpgrades: false,
|
||||
}),
|
||||
[ClassicFixedBossWaves.RIVAL_5]: new FixedBattleConfig()
|
||||
.setBattleType(BattleType.TRAINER)
|
||||
.setGetTrainerFunc(
|
||||
() =>
|
||||
new Trainer(
|
||||
TrainerType.RIVAL_5,
|
||||
globalScene.gameData.gender === PlayerGender.MALE ? TrainerVariant.FEMALE : TrainerVariant.DEFAULT,
|
||||
),
|
||||
)
|
||||
.setCustomModifierRewards({
|
||||
guaranteedModifierTiers: [
|
||||
ModifierTier.ROGUE,
|
||||
ModifierTier.ROGUE,
|
||||
ModifierTier.ROGUE,
|
||||
ModifierTier.ULTRA,
|
||||
ModifierTier.ULTRA,
|
||||
],
|
||||
allowLuckUpgrades: false,
|
||||
}),
|
||||
[ClassicFixedBossWaves.EVIL_BOSS_2]: new FixedBattleConfig()
|
||||
.setBattleType(BattleType.TRAINER)
|
||||
.setSeedOffsetWave(ClassicFixedBossWaves.EVIL_GRUNT_1)
|
||||
.setGetTrainerFunc(
|
||||
getRandomTrainerFunc([
|
||||
TrainerType.ROCKET_BOSS_GIOVANNI_2,
|
||||
TrainerType.MAXIE_2,
|
||||
TrainerType.ARCHIE_2,
|
||||
TrainerType.CYRUS_2,
|
||||
TrainerType.GHETSIS_2,
|
||||
TrainerType.LYSANDRE_2,
|
||||
TrainerType.LUSAMINE_2,
|
||||
TrainerType.GUZMA_2,
|
||||
TrainerType.ROSE_2,
|
||||
TrainerType.PENNY_2,
|
||||
]),
|
||||
)
|
||||
.setCustomModifierRewards({
|
||||
guaranteedModifierTiers: [
|
||||
ModifierTier.ROGUE,
|
||||
ModifierTier.ROGUE,
|
||||
ModifierTier.ULTRA,
|
||||
ModifierTier.ULTRA,
|
||||
ModifierTier.ULTRA,
|
||||
ModifierTier.ULTRA,
|
||||
],
|
||||
allowLuckUpgrades: false,
|
||||
}),
|
||||
[ClassicFixedBossWaves.ELITE_FOUR_1]: new FixedBattleConfig()
|
||||
.setBattleType(BattleType.TRAINER)
|
||||
.setGetTrainerFunc(
|
||||
getRandomTrainerFunc([
|
||||
TrainerType.LORELEI,
|
||||
TrainerType.WILL,
|
||||
TrainerType.SIDNEY,
|
||||
TrainerType.AARON,
|
||||
TrainerType.SHAUNTAL,
|
||||
TrainerType.MALVA,
|
||||
[TrainerType.HALA, TrainerType.MOLAYNE],
|
||||
TrainerType.MARNIE_ELITE,
|
||||
TrainerType.RIKA,
|
||||
TrainerType.CRISPIN,
|
||||
]),
|
||||
),
|
||||
[ClassicFixedBossWaves.ELITE_FOUR_2]: new FixedBattleConfig()
|
||||
.setBattleType(BattleType.TRAINER)
|
||||
.setSeedOffsetWave(ClassicFixedBossWaves.ELITE_FOUR_1)
|
||||
.setGetTrainerFunc(
|
||||
getRandomTrainerFunc([
|
||||
TrainerType.BRUNO,
|
||||
TrainerType.KOGA,
|
||||
TrainerType.PHOEBE,
|
||||
TrainerType.BERTHA,
|
||||
TrainerType.MARSHAL,
|
||||
TrainerType.SIEBOLD,
|
||||
TrainerType.OLIVIA,
|
||||
TrainerType.NESSA_ELITE,
|
||||
TrainerType.POPPY,
|
||||
TrainerType.AMARYS,
|
||||
]),
|
||||
),
|
||||
[ClassicFixedBossWaves.ELITE_FOUR_3]: new FixedBattleConfig()
|
||||
.setBattleType(BattleType.TRAINER)
|
||||
.setSeedOffsetWave(ClassicFixedBossWaves.ELITE_FOUR_1)
|
||||
.setGetTrainerFunc(
|
||||
getRandomTrainerFunc([
|
||||
TrainerType.AGATHA,
|
||||
TrainerType.BRUNO,
|
||||
TrainerType.GLACIA,
|
||||
TrainerType.FLINT,
|
||||
TrainerType.GRIMSLEY,
|
||||
TrainerType.WIKSTROM,
|
||||
TrainerType.ACEROLA,
|
||||
[TrainerType.BEA_ELITE, TrainerType.ALLISTER_ELITE],
|
||||
TrainerType.LARRY_ELITE,
|
||||
TrainerType.LACEY,
|
||||
]),
|
||||
),
|
||||
[ClassicFixedBossWaves.ELITE_FOUR_4]: new FixedBattleConfig()
|
||||
.setBattleType(BattleType.TRAINER)
|
||||
.setSeedOffsetWave(ClassicFixedBossWaves.ELITE_FOUR_1)
|
||||
.setGetTrainerFunc(
|
||||
getRandomTrainerFunc([
|
||||
TrainerType.LANCE,
|
||||
TrainerType.KAREN,
|
||||
TrainerType.DRAKE,
|
||||
TrainerType.LUCIAN,
|
||||
TrainerType.CAITLIN,
|
||||
TrainerType.DRASNA,
|
||||
TrainerType.KAHILI,
|
||||
TrainerType.RAIHAN_ELITE,
|
||||
TrainerType.HASSEL,
|
||||
TrainerType.DRAYTON,
|
||||
]),
|
||||
),
|
||||
[ClassicFixedBossWaves.CHAMPION]: new FixedBattleConfig()
|
||||
.setBattleType(BattleType.TRAINER)
|
||||
.setSeedOffsetWave(ClassicFixedBossWaves.ELITE_FOUR_1)
|
||||
.setGetTrainerFunc(
|
||||
getRandomTrainerFunc([
|
||||
TrainerType.BLUE,
|
||||
[TrainerType.RED, TrainerType.LANCE_CHAMPION],
|
||||
[TrainerType.STEVEN, TrainerType.WALLACE],
|
||||
TrainerType.CYNTHIA,
|
||||
[TrainerType.ALDER, TrainerType.IRIS],
|
||||
TrainerType.DIANTHA,
|
||||
[TrainerType.KUKUI, TrainerType.HAU],
|
||||
[TrainerType.LEON, TrainerType.MUSTARD],
|
||||
[TrainerType.GEETA, TrainerType.NEMONA],
|
||||
TrainerType.KIERAN,
|
||||
]),
|
||||
),
|
||||
[ClassicFixedBossWaves.RIVAL_6]: new FixedBattleConfig()
|
||||
.setBattleType(BattleType.TRAINER)
|
||||
.setGetTrainerFunc(
|
||||
() =>
|
||||
new Trainer(
|
||||
TrainerType.RIVAL_6,
|
||||
globalScene.gameData.gender === PlayerGender.MALE ? TrainerVariant.FEMALE : TrainerVariant.DEFAULT,
|
||||
),
|
||||
)
|
||||
.setCustomModifierRewards({
|
||||
guaranteedModifierTiers: [
|
||||
ModifierTier.ROGUE,
|
||||
ModifierTier.ROGUE,
|
||||
ModifierTier.ULTRA,
|
||||
ModifierTier.ULTRA,
|
||||
ModifierTier.GREAT,
|
||||
ModifierTier.GREAT,
|
||||
],
|
||||
allowLuckUpgrades: false,
|
||||
}),
|
||||
};
|
@ -30,7 +30,7 @@ import {
|
||||
TrainerPartyCompoundTemplate,
|
||||
TrainerPartyTemplate,
|
||||
trainerPartyTemplates,
|
||||
} from "#trainers/TrainerPartyTemplate";
|
||||
} from "#trainers/trainer-party-template";
|
||||
import type { ModifierTypeFunc } from "#types/modifier-types";
|
||||
import type {
|
||||
GenAIFunc,
|
||||
|
@ -168,19 +168,11 @@ export class Arena {
|
||||
ret = getPokemonSpecies(species!);
|
||||
|
||||
if (ret.subLegendary || ret.legendary || ret.mythical) {
|
||||
switch (true) {
|
||||
case ret.baseTotal >= 720:
|
||||
regen = level < 90;
|
||||
break;
|
||||
case ret.baseTotal >= 670:
|
||||
regen = level < 70;
|
||||
break;
|
||||
case ret.baseTotal >= 580:
|
||||
regen = level < 50;
|
||||
break;
|
||||
default:
|
||||
regen = level < 30;
|
||||
break;
|
||||
const waveDifficulty = globalScene.gameMode.getWaveForDifficulty(waveIndex);
|
||||
if (ret.baseTotal >= 660) {
|
||||
regen = waveDifficulty < 80; // Wave 50+ in daily (however, max Daily wave is 50 currently so not possible)
|
||||
} else {
|
||||
regen = waveDifficulty < 55; // Wave 25+ in daily
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -498,38 +490,37 @@ export class Arena {
|
||||
getTrainerChance(): number {
|
||||
switch (this.biomeType) {
|
||||
case BiomeId.METROPOLIS:
|
||||
return 2;
|
||||
case BiomeId.SLUM:
|
||||
case BiomeId.BEACH:
|
||||
case BiomeId.DOJO:
|
||||
case BiomeId.CONSTRUCTION_SITE:
|
||||
return 4;
|
||||
case BiomeId.PLAINS:
|
||||
case BiomeId.GRASS:
|
||||
case BiomeId.BEACH:
|
||||
case BiomeId.LAKE:
|
||||
case BiomeId.CAVE:
|
||||
case BiomeId.DESERT:
|
||||
case BiomeId.CONSTRUCTION_SITE:
|
||||
case BiomeId.SLUM:
|
||||
return 6;
|
||||
case BiomeId.TALL_GRASS:
|
||||
case BiomeId.FOREST:
|
||||
case BiomeId.SEA:
|
||||
case BiomeId.SWAMP:
|
||||
case BiomeId.MOUNTAIN:
|
||||
case BiomeId.BADLANDS:
|
||||
case BiomeId.DESERT:
|
||||
case BiomeId.MEADOW:
|
||||
case BiomeId.POWER_PLANT:
|
||||
case BiomeId.GRAVEYARD:
|
||||
case BiomeId.FACTORY:
|
||||
case BiomeId.SNOWY_FOREST:
|
||||
return 8;
|
||||
case BiomeId.SEA:
|
||||
case BiomeId.ICE_CAVE:
|
||||
case BiomeId.VOLCANO:
|
||||
case BiomeId.GRAVEYARD:
|
||||
case BiomeId.RUINS:
|
||||
case BiomeId.WASTELAND:
|
||||
case BiomeId.JUNGLE:
|
||||
case BiomeId.FAIRY_CAVE:
|
||||
case BiomeId.ISLAND:
|
||||
return 12;
|
||||
case BiomeId.SEABED:
|
||||
case BiomeId.ABYSS:
|
||||
case BiomeId.SPACE:
|
||||
case BiomeId.TEMPLE:
|
||||
|
@ -2520,41 +2520,50 @@ export abstract class Pokemon extends Phaser.GameObjects.Container {
|
||||
* @returns A score value based on how favorable this Pokemon is when fighting the given Pokemon
|
||||
*/
|
||||
getMatchupScore(opponent: Pokemon): number {
|
||||
const types = this.getTypes(true);
|
||||
|
||||
const enemyTypes = opponent.getTypes(true, true, false, true);
|
||||
const enemyTypes = opponent.getTypes(true, false, false, true);
|
||||
/** Is this Pokemon faster than the opponent? */
|
||||
const outspeed =
|
||||
(this.isActive(true) ? this.getEffectiveStat(Stat.SPD, opponent) : this.getStat(Stat.SPD, false)) >=
|
||||
opponent.getEffectiveStat(Stat.SPD, this);
|
||||
/**
|
||||
* Based on how effective this Pokemon's types are offensively against the opponent's types.
|
||||
* This score is increased by 25 percent if this Pokemon is faster than the opponent.
|
||||
*/
|
||||
let atkScore =
|
||||
opponent.getAttackTypeEffectiveness(types[0], this, false, true, undefined, true) * (outspeed ? 1.25 : 1);
|
||||
|
||||
/**
|
||||
* Based on how effectively this Pokemon defends against the opponent's types.
|
||||
* This score cannot be higher than 4.
|
||||
*/
|
||||
let defScore = 1 / Math.max(this.getAttackTypeEffectiveness(enemyTypes[0], opponent), 0.25);
|
||||
if (types.length > 1) {
|
||||
atkScore *= opponent.getAttackTypeEffectiveness(types[1], this);
|
||||
}
|
||||
if (enemyTypes.length > 1) {
|
||||
defScore *=
|
||||
1 / Math.max(this.getAttackTypeEffectiveness(enemyTypes[1], opponent, false, false, undefined, true), 0.25);
|
||||
}
|
||||
atkScore *= 1.25; //give more value for the pokemon's typing
|
||||
|
||||
const moveset = this.moveset;
|
||||
let moveAtkScoreLength = 0;
|
||||
let atkScore = 0;
|
||||
// TODO: this calculation needs to consider more factors; it's currently very simplistic
|
||||
for (const move of moveset) {
|
||||
if (move.getMove().category === MoveCategory.SPECIAL || move.getMove().category === MoveCategory.PHYSICAL) {
|
||||
atkScore += opponent.getAttackTypeEffectiveness(move.getMove().type, this, false, true, undefined, true);
|
||||
const resolvedMove = move.getMove();
|
||||
// NOTE: Counter and Mirror Coat are considered as attack moves here
|
||||
if (resolvedMove.category === MoveCategory.STATUS || move.getPpRatio() <= 0) {
|
||||
continue;
|
||||
}
|
||||
const moveType = resolvedMove.type;
|
||||
let thisScore = opponent.getAttackTypeEffectiveness(moveType, this, false, true, undefined, true);
|
||||
|
||||
// Add STAB multiplier for attack type effectiveness.
|
||||
// For now, simply don't apply STAB to moves that may change type
|
||||
if (this.getTypes(true).includes(moveType) && !move.getMove().hasAttr("VariableMoveTypeAttr")) {
|
||||
thisScore *= 1.5;
|
||||
}
|
||||
|
||||
atkScore += thisScore;
|
||||
moveAtkScoreLength++;
|
||||
}
|
||||
}
|
||||
atkScore = atkScore / (moveAtkScoreLength + 1); //calculate the median for the attack score
|
||||
// Get average attack score of all damaging moves (|| 1 prevents division by zero))
|
||||
// TODO: Averaging the attack score is excessively simplistic, and doesn't reflect the AI's move selection logic
|
||||
// e.g. if the mon has one 4x effective move and three 0.5x effective moves, this score would be ~1.375
|
||||
// which does not seem fair, given that if the AI were to switch, in all likelihood it would use the 4x move.
|
||||
// We could consider a weighted average...
|
||||
atkScore /= moveAtkScoreLength || 1;
|
||||
/**
|
||||
* Based on this Pokemon's HP ratio compared to that of the opponent.
|
||||
* This ratio is multiplied by 1.5 if this Pokemon outspeeds the opponent;
|
||||
@ -2562,6 +2571,9 @@ export abstract class Pokemon extends Phaser.GameObjects.Container {
|
||||
*/
|
||||
const hpRatio = this.getHpRatio();
|
||||
const oppHpRatio = opponent.getHpRatio();
|
||||
// TODO: use better logic for predicting whether the pokemon "is dying"
|
||||
// E.g., perhaps check if it would faint if the opponent were to use the same move it just used
|
||||
// (twice if the user is slower)
|
||||
const isDying = hpRatio <= 0.2;
|
||||
let hpDiffRatio = hpRatio + (1 - oppHpRatio);
|
||||
if (isDying && this.isActive(true)) {
|
||||
@ -2571,15 +2583,15 @@ export abstract class Pokemon extends Phaser.GameObjects.Container {
|
||||
//It might not be a worthy sacrifice if it doesn't outspeed or doesn't do enough damage
|
||||
hpDiffRatio *= 0.85;
|
||||
} else {
|
||||
hpDiffRatio = Math.min(1 - hpRatio + (outspeed ? 0.2 : 0.1), 1);
|
||||
hpDiffRatio = 1 - hpRatio + (outspeed ? 0.2 : 0.1);
|
||||
}
|
||||
} else if (outspeed) {
|
||||
hpDiffRatio = Math.min(hpDiffRatio * 1.25, 1);
|
||||
hpDiffRatio = hpDiffRatio * 1.25;
|
||||
} else if (hpRatio > 0.2 && hpRatio <= 0.4) {
|
||||
// Might be considered to be switched because it's not in low enough health
|
||||
hpDiffRatio = Math.min(hpDiffRatio * 0.5, 1);
|
||||
hpDiffRatio = hpDiffRatio * 0.5;
|
||||
}
|
||||
return (atkScore + defScore) * hpDiffRatio;
|
||||
return (atkScore + defScore) * Math.min(hpDiffRatio, 1);
|
||||
}
|
||||
|
||||
getEvolution(): SpeciesFormEvolution | null {
|
||||
|
@ -14,10 +14,13 @@ import { TrainerVariant } from "#enums/trainer-variant";
|
||||
import type { EnemyPokemon } from "#field/pokemon";
|
||||
import type { PersistentModifier } from "#modifiers/modifier";
|
||||
import { getIsInitialized, initI18n } from "#plugins/i18n";
|
||||
import type { TrainerPartyTemplate } from "#trainers/TrainerPartyTemplate";
|
||||
import { TrainerPartyCompoundTemplate, trainerPartyTemplates } from "#trainers/TrainerPartyTemplate";
|
||||
import type { TrainerConfig } from "#trainers/trainer-config";
|
||||
import { trainerConfigs } from "#trainers/trainer-config";
|
||||
import {
|
||||
TrainerPartyCompoundTemplate,
|
||||
type TrainerPartyTemplate,
|
||||
trainerPartyTemplates,
|
||||
} from "#trainers/trainer-party-template";
|
||||
import { randSeedInt, randSeedItem, randSeedWeightedItem } from "#utils/common";
|
||||
import { getPokemonSpecies } from "#utils/pokemon-utils";
|
||||
import i18next from "i18next";
|
||||
|
@ -1,5 +1,4 @@
|
||||
import type { FixedBattleConfigs } from "#app/battle";
|
||||
import { classicFixedBattles, FixedBattleConfig } from "#app/battle";
|
||||
import { FixedBattleConfig } from "#app/battle";
|
||||
import { CHALLENGE_MODE_MYSTERY_ENCOUNTER_WAVES, CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES } from "#app/constants";
|
||||
import { globalScene } from "#app/global-scene";
|
||||
import Overrides from "#app/overrides";
|
||||
@ -14,6 +13,7 @@ import { Challenges } from "#enums/challenges";
|
||||
import { GameModes } from "#enums/game-modes";
|
||||
import { SpeciesId } from "#enums/species-id";
|
||||
import type { Arena } from "#field/arena";
|
||||
import { classicFixedBattles, type FixedBattleConfigs } from "#trainers/fixed-battle-configs";
|
||||
import { isNullOrUndefined, randSeedInt, randSeedItem } from "#utils/common";
|
||||
import i18next from "i18next";
|
||||
|
||||
@ -164,14 +164,14 @@ export class GameMode implements GameModeConfig {
|
||||
if (waveIndex % 10 !== 1 && waveIndex % 10) {
|
||||
/**
|
||||
* Do not check X1 floors since there's a bug that stops trainer sprites from appearing
|
||||
* after a X0 full party heal
|
||||
* after a X0 full party heal, this also allows for a smoother biome transition for general gameplay feel
|
||||
*/
|
||||
const trainerChance = arena.getTrainerChance();
|
||||
let allowTrainerBattle = true;
|
||||
if (trainerChance) {
|
||||
const waveBase = Math.floor(waveIndex / 10) * 10;
|
||||
// Stop generic trainers from spawning in within 3 waves of a trainer battle
|
||||
for (let w = Math.max(waveIndex - 3, waveBase + 2); w <= Math.min(waveIndex + 3, waveBase + 9); w++) {
|
||||
// Stop generic trainers from spawning in within 2 waves of a fixed trainer battle
|
||||
for (let w = Math.max(waveIndex - 2, waveBase + 2); w <= Math.min(waveIndex + 2, waveBase + 9); w++) {
|
||||
if (w === waveIndex) {
|
||||
continue;
|
||||
}
|
||||
|
@ -120,7 +120,7 @@ export class AttemptCapturePhase extends PokemonPhase {
|
||||
repeatDelay: 500,
|
||||
onUpdate: t => {
|
||||
if (shakeCount && shakeCount < (isCritical ? 2 : 4)) {
|
||||
const value = t.getValue();
|
||||
const value = t.getValue() ?? 0;
|
||||
const directionMultiplier = shakeCount % 2 === 1 ? 1 : -1;
|
||||
this.pokeball.setX(pbX + value * 4 * directionMultiplier);
|
||||
this.pokeball.setAngle(value * 27.5 * directionMultiplier);
|
||||
|
@ -239,7 +239,7 @@ export class EvolutionPhase extends Phase {
|
||||
to: 1,
|
||||
duration: 2000,
|
||||
onUpdate: t => {
|
||||
this.pokemonTintSprite.setAlpha(t.getValue());
|
||||
this.pokemonTintSprite.setAlpha(t.getValue() ?? 1);
|
||||
},
|
||||
onComplete: () => {
|
||||
this.pokemonSprite.setVisible(false);
|
||||
|
@ -179,7 +179,7 @@ export class SelectModifierPhase extends BattlePhase {
|
||||
} else {
|
||||
this.applyModifier(modifierType.newModifier()!);
|
||||
}
|
||||
return !cost;
|
||||
return cost === -1;
|
||||
}
|
||||
|
||||
// Reroll rewards
|
||||
|
@ -269,13 +269,22 @@ export class ModifierSelectUiHandler extends AwaitableUiHandler {
|
||||
globalScene.updateBiomeWaveText();
|
||||
globalScene.updateMoneyText();
|
||||
|
||||
// DO NOT REMOVE: Fixes bug which allows action input to be processed before the UI is shown,
|
||||
// causing errors if reroll is selected
|
||||
this.awaitingActionInput = false;
|
||||
|
||||
// TODO: Replace with `Promise.withResolvers` when possible.
|
||||
let tweenResolve: () => void;
|
||||
const tweenPromise = new Promise<void>(resolve => (tweenResolve = resolve));
|
||||
let i = 0;
|
||||
|
||||
// TODO: Rework this bespoke logic for animating the modifier options.
|
||||
globalScene.tweens.addCounter({
|
||||
ease: "Sine.easeIn",
|
||||
duration: 1250,
|
||||
onUpdate: t => {
|
||||
const value = t.getValue();
|
||||
// The bang here is safe, as `getValue()` only returns null if the tween has been destroyed (which obviously isn't the case inside onUpdate)
|
||||
const value = t.getValue()!;
|
||||
const index = Math.floor(value * typeOptions.length);
|
||||
if (index > i && index <= typeOptions.length) {
|
||||
const option = this.options[i];
|
||||
@ -286,15 +295,24 @@ export class ModifierSelectUiHandler extends AwaitableUiHandler {
|
||||
i++;
|
||||
}
|
||||
},
|
||||
onComplete: () => {
|
||||
tweenResolve();
|
||||
},
|
||||
});
|
||||
|
||||
globalScene.time.delayedCall(1000 + maxUpgradeCount * 2000, () => {
|
||||
let shopResolve: () => void;
|
||||
const shopPromise = new Promise<void>(resolve => (shopResolve = resolve));
|
||||
tweenPromise.then(() => {
|
||||
globalScene.time.delayedCall(1000, () => {
|
||||
for (const shopOption of this.shopOptionsRows.flat()) {
|
||||
shopOption.show(0, 0);
|
||||
}
|
||||
shopResolve();
|
||||
});
|
||||
});
|
||||
|
||||
globalScene.time.delayedCall(4000 + maxUpgradeCount * 2000, () => {
|
||||
shopPromise.then(() => {
|
||||
globalScene.time.delayedCall(500, () => {
|
||||
if (partyHasHeldItem) {
|
||||
this.transferButtonContainer.setAlpha(0);
|
||||
this.transferButtonContainer.setVisible(true);
|
||||
@ -349,6 +367,7 @@ export class ModifierSelectUiHandler extends AwaitableUiHandler {
|
||||
this.onActionInput = args[2];
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
return true;
|
||||
}
|
||||
@ -687,7 +706,11 @@ export class ModifierSelectUiHandler extends AwaitableUiHandler {
|
||||
scale: 0.01,
|
||||
duration: 250,
|
||||
ease: "Cubic.easeIn",
|
||||
onComplete: () => options.forEach(o => o.destroy()),
|
||||
onComplete: () => {
|
||||
options.forEach(o => {
|
||||
o.destroy();
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
[
|
||||
@ -819,7 +842,7 @@ class ModifierOption extends Phaser.GameObjects.Container {
|
||||
if (!globalScene) {
|
||||
return;
|
||||
}
|
||||
const value = t.getValue();
|
||||
const value = t.getValue()!;
|
||||
if (!bounce && value > lastValue) {
|
||||
globalScene.playSound("se/pb_bounce_1", {
|
||||
volume: 1 / ++bounceCount,
|
||||
@ -832,29 +855,28 @@ class ModifierOption extends Phaser.GameObjects.Container {
|
||||
},
|
||||
});
|
||||
|
||||
// TODO: Figure out proper delay between chains and then convert this into a single tween chain
|
||||
// rather than starting multiple tween chains.
|
||||
for (let u = 0; u < this.modifierTypeOption.upgradeCount; u++) {
|
||||
const upgradeIndex = u;
|
||||
globalScene.time.delayedCall(
|
||||
remainingDuration - 2000 * (this.modifierTypeOption.upgradeCount - (upgradeIndex + 1 + upgradeCountOffset)),
|
||||
() => {
|
||||
globalScene.tweens.chain({
|
||||
tweens: [
|
||||
{
|
||||
delay: remainingDuration - 2000 * (this.modifierTypeOption.upgradeCount - (u + 1 + upgradeCountOffset)),
|
||||
onStart: () => {
|
||||
globalScene.playSound("se/upgrade", {
|
||||
rate: 1 + 0.25 * upgradeIndex,
|
||||
rate: 1 + 0.25 * u,
|
||||
});
|
||||
this.pbTint.setPosition(this.pb.x, this.pb.y);
|
||||
this.pbTint.setTintFill(0xffffff);
|
||||
this.pbTint.setAlpha(0);
|
||||
this.pbTint.setVisible(true);
|
||||
globalScene.tweens.add({
|
||||
this.pbTint.setPosition(this.pb.x, this.pb.y).setTintFill(0xffffff).setVisible(true).setAlpha(0);
|
||||
},
|
||||
targets: this.pbTint,
|
||||
alpha: 1,
|
||||
duration: 1000,
|
||||
ease: "Sine.easeIn",
|
||||
onComplete: () => {
|
||||
this.pb.setTexture(
|
||||
"pb",
|
||||
this.getPbAtlasKey(-this.modifierTypeOption.upgradeCount + (upgradeIndex + 1)),
|
||||
);
|
||||
globalScene.tweens.add({
|
||||
this.pb.setTexture("pb", this.getPbAtlasKey(-this.modifierTypeOption.upgradeCount + (u + 1)));
|
||||
},
|
||||
},
|
||||
{
|
||||
targets: this.pbTint,
|
||||
alpha: 0,
|
||||
duration: 750,
|
||||
@ -862,11 +884,9 @@ class ModifierOption extends Phaser.GameObjects.Container {
|
||||
onComplete: () => {
|
||||
this.pbTint.setVisible(false);
|
||||
},
|
||||
});
|
||||
},
|
||||
],
|
||||
});
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -147,7 +147,7 @@ export class StatsContainer extends Phaser.GameObjects.Container {
|
||||
duration: 1000,
|
||||
ease: "Cubic.easeOut",
|
||||
onUpdate: (tween: Phaser.Tweens.Tween) => {
|
||||
const progress = tween.getValue();
|
||||
const progress = tween.getValue() ?? 1;
|
||||
const interpolatedData = ivChartData.map(
|
||||
(v: number, i: number) => v * progress + lastIvChartData[i] * (1 - progress),
|
||||
);
|
||||
|
@ -157,8 +157,8 @@ export class TargetSelectUiHandler extends UiHandler {
|
||||
yoyo: true,
|
||||
onUpdate: t => {
|
||||
for (const target of this.targetsHighlighted) {
|
||||
target.setAlpha(t.getValue());
|
||||
this.highlightItems(target.id, t.getValue());
|
||||
target.setAlpha(t.getValue() ?? 1);
|
||||
this.highlightItems(target.id, t.getValue() ?? 1);
|
||||
}
|
||||
},
|
||||
});
|
||||
|
@ -5,7 +5,7 @@ import { UiTheme } from "#enums/ui-theme";
|
||||
import i18next from "#plugins/i18n";
|
||||
import type Phaser from "phaser";
|
||||
import BBCodeText from "phaser3-rex-plugins/plugins/gameobjects/tagtext/bbcodetext/BBCodeText";
|
||||
import InputText from "phaser3-rex-plugins/plugins/inputtext";
|
||||
import type InputText from "phaser3-rex-plugins/plugins/inputtext";
|
||||
|
||||
export enum TextStyle {
|
||||
MESSAGE,
|
||||
@ -152,8 +152,7 @@ export function addTextInputObject(
|
||||
): InputText {
|
||||
const { scale, styleOptions } = getTextStyleOptions(style, globalScene.uiTheme, extraStyleOptions);
|
||||
|
||||
const ret = new InputText(globalScene, x, y, width, height, styleOptions as InputText.IConfig);
|
||||
globalScene.add.existing(ret);
|
||||
const ret = globalScene.add.rexInputText(x, y, width, height, styleOptions as InputText.IConfig);
|
||||
ret.setScale(scale);
|
||||
|
||||
return ret;
|
||||
|
@ -159,7 +159,8 @@ describe("Abilities - Magic Bounce", () => {
|
||||
expect(game.scene.getEnemyPokemon()!.getTag(BattlerTagType.CURSED)).toBeDefined();
|
||||
});
|
||||
|
||||
it("should not cause encore to be interrupted after bouncing", async () => {
|
||||
// TODO: enable when Magic Bounce is fixed to properly reset the hit count
|
||||
it.todo("should not cause encore to be interrupted after bouncing", async () => {
|
||||
game.override.moveset([MoveId.SPLASH, MoveId.GROWL, MoveId.ENCORE]).enemyMoveset([MoveId.TACKLE, MoveId.GROWL]);
|
||||
// game.override.ability(AbilityId.MOLD_BREAKER);
|
||||
await game.classicMode.startBattle([SpeciesId.MAGIKARP]);
|
||||
@ -167,7 +168,7 @@ describe("Abilities - Magic Bounce", () => {
|
||||
const enemyPokemon = game.scene.getEnemyPokemon()!;
|
||||
|
||||
// Give the player MOLD_BREAKER for this turn to bypass Magic Bounce.
|
||||
vi.spyOn(playerPokemon, "getAbility").mockReturnValue(allAbilities[AbilityId.MOLD_BREAKER]);
|
||||
const playerAbilitySpy = game.field.mockAbility(playerPokemon, AbilityId.MOLD_BREAKER);
|
||||
|
||||
// turn 1
|
||||
game.move.select(MoveId.ENCORE);
|
||||
@ -177,7 +178,7 @@ describe("Abilities - Magic Bounce", () => {
|
||||
expect(enemyPokemon.getTag(BattlerTagType.ENCORE)!["moveId"]).toBe(MoveId.TACKLE);
|
||||
|
||||
// turn 2
|
||||
vi.spyOn(playerPokemon, "getAbility").mockRestore();
|
||||
playerAbilitySpy.mockRestore();
|
||||
game.move.select(MoveId.GROWL);
|
||||
await game.setTurnOrder([BattlerIndex.PLAYER, BattlerIndex.ENEMY]);
|
||||
await game.phaseInterceptor.to("BerryPhase");
|
||||
|
@ -101,7 +101,8 @@ describe("BattlerTag - StockpilingTag", () => {
|
||||
});
|
||||
|
||||
describe("stack limit, stat tracking, and removal", () => {
|
||||
it("can be added up to three times, even when one stat does not change", async () => {
|
||||
// TODO: do we even want this file at all? regardless, this test is broken and is also likely unimportant
|
||||
it.todo("can be added up to three times, even when one stat does not change", async () => {
|
||||
const mockPokemon = {
|
||||
summonData: new PokemonSummonData(),
|
||||
getBattlerIndex: () => 0,
|
||||
@ -150,7 +151,7 @@ describe("BattlerTag - StockpilingTag", () => {
|
||||
expect(subject.stockpiledCount).toBe(3);
|
||||
|
||||
vi.spyOn(game.scene.phaseManager, "unshiftPhase").mockImplementationOnce(_phase => {
|
||||
throw new Error("Should not be called a fourth time");
|
||||
expect.fail("Should not be called a fourth time");
|
||||
});
|
||||
|
||||
// fourth stack should not be applied
|
||||
|
@ -1,11 +1,9 @@
|
||||
import { allMoves } from "#data/data-lists";
|
||||
import { AbilityId } from "#enums/ability-id";
|
||||
import { BattleType } from "#enums/battle-type";
|
||||
import { BattlerIndex } from "#enums/battler-index";
|
||||
import { MoveId } from "#enums/move-id";
|
||||
import { MoveUseMode } from "#enums/move-use-mode";
|
||||
import { SpeciesId } from "#enums/species-id";
|
||||
import { TrainerType } from "#enums/trainer-type";
|
||||
import { GameManager } from "#test/testUtils/gameManager";
|
||||
import Phaser from "phaser";
|
||||
import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
|
||||
@ -29,8 +27,7 @@ describe("Moves - Fishious Rend & Bolt Beak", () => {
|
||||
game.override
|
||||
.ability(AbilityId.STURDY)
|
||||
.battleStyle("single")
|
||||
.battleType(BattleType.TRAINER)
|
||||
.randomTrainer({ trainerType: TrainerType.YOUNGSTER })
|
||||
.startingWave(5)
|
||||
.criticalHits(false)
|
||||
.enemyLevel(100)
|
||||
.enemySpecies(SpeciesId.DRACOVISH)
|
||||
|
@ -20,8 +20,8 @@ import {
|
||||
} from "#test/mystery-encounter/encounter-test-utils";
|
||||
import { GameManager } from "#test/testUtils/gameManager";
|
||||
import { initSceneWithoutEncounterPhase } from "#test/testUtils/gameManagerUtils";
|
||||
import { TrainerPartyCompoundTemplate, TrainerPartyTemplate } from "#trainers/TrainerPartyTemplate";
|
||||
import { TrainerConfig } from "#trainers/trainer-config";
|
||||
import { TrainerPartyCompoundTemplate, TrainerPartyTemplate } from "#trainers/trainer-party-template";
|
||||
import { ModifierSelectUiHandler } from "#ui/modifier-select-ui-handler";
|
||||
import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
|
||||
|
||||
|
@ -1,4 +1,6 @@
|
||||
import type { MockGameObject } from "#test/testUtils/mocks/mockGameObject";
|
||||
import { MockBBCodeText } from "#test/testUtils/mocks/mocksContainer/mock-bbcode-text";
|
||||
import { MockInputText } from "#test/testUtils/mocks/mocksContainer/mock-input-text";
|
||||
import { MockContainer } from "#test/testUtils/mocks/mocksContainer/mockContainer";
|
||||
import { MockImage } from "#test/testUtils/mocks/mocksContainer/mockImage";
|
||||
import { MockNineslice } from "#test/testUtils/mocks/mocksContainer/mockNineslice";
|
||||
@ -33,6 +35,8 @@ export class MockTextureManager {
|
||||
image: this.image.bind(this),
|
||||
polygon: this.polygon.bind(this),
|
||||
text: this.text.bind(this),
|
||||
rexBBCodeText: this.rexBBCodeText.bind(this),
|
||||
rexInputText: this.rexInputText.bind(this),
|
||||
bitmapText: this.text.bind(this),
|
||||
displayList: this.displayList,
|
||||
video: () => new MockVideoGameObject(),
|
||||
@ -103,9 +107,25 @@ export class MockTextureManager {
|
||||
return text;
|
||||
}
|
||||
|
||||
rexBBCodeText(x, y, content, styleOptions) {
|
||||
const text = new MockBBCodeText(this, x, y, content, styleOptions);
|
||||
this.list.push(text);
|
||||
return text;
|
||||
}
|
||||
|
||||
rexInputText(x, y, w, h, content, styleOptions) {
|
||||
const text = new MockInputText(this, x, y, w, h, content, styleOptions);
|
||||
this.list.push(text);
|
||||
return text;
|
||||
}
|
||||
|
||||
polygon(x, y, content, fillColor, fillAlpha) {
|
||||
const polygon = new MockPolygon(this, x, y, content, fillColor, fillAlpha);
|
||||
this.list.push(polygon);
|
||||
return polygon;
|
||||
}
|
||||
|
||||
exists(key: string): boolean {
|
||||
return this.textures.has(key);
|
||||
}
|
||||
}
|
||||
|
6
test/testUtils/mocks/mocksContainer/mock-bbcode-text.ts
Normal file
6
test/testUtils/mocks/mocksContainer/mock-bbcode-text.ts
Normal file
@ -0,0 +1,6 @@
|
||||
import { MockText } from "#test/testUtils/mocks/mocksContainer/mockText";
|
||||
|
||||
export class MockBBCodeText extends MockText {
|
||||
setMaxLines(_lines: number) {}
|
||||
setWrapMode(_mode: 0 | 1 | 2 | 3 | "none" | "word" | "char" | "character" | "mix") {}
|
||||
}
|
24
test/testUtils/mocks/mocksContainer/mock-input-text.ts
Normal file
24
test/testUtils/mocks/mocksContainer/mock-input-text.ts
Normal file
@ -0,0 +1,24 @@
|
||||
import { MockText } from "#test/testUtils/mocks/mocksContainer/mockText";
|
||||
|
||||
export class MockInputText extends MockText {
|
||||
public inputType: string;
|
||||
public selectionStart: number;
|
||||
public selectionEnd: number;
|
||||
public selectedText: string;
|
||||
|
||||
constructor(textureManager, x, y, _w, _h, content, styleOptions) {
|
||||
super(textureManager, x, y, content, styleOptions);
|
||||
}
|
||||
|
||||
selectText(_selectionStart?: number, _selectionEnd?: number) {}
|
||||
|
||||
selectAll() {}
|
||||
|
||||
setCursorPosition(_value: number) {}
|
||||
|
||||
scrollToBottom() {}
|
||||
|
||||
resize(_width: number, _height: number) {}
|
||||
|
||||
setElement(_element, _style, _innerText) {}
|
||||
}
|
@ -47,11 +47,5 @@
|
||||
"outDir": "./build",
|
||||
"noEmit": true
|
||||
},
|
||||
"typedocOptions": {
|
||||
"entryPoints": ["./src"],
|
||||
"entryPointStrategy": "expand",
|
||||
"exclude": "**/*+.test.ts",
|
||||
"out": "typedoc"
|
||||
},
|
||||
"exclude": ["node_modules", "dist", "vite.config.ts", "vitest.config.ts", "vitest.workspace.ts"]
|
||||
}
|
||||
|
14
tsdoc.json
Normal file
14
tsdoc.json
Normal file
@ -0,0 +1,14 @@
|
||||
{
|
||||
"$schema": "https://developer.microsoft.com/en-us/json-schemas/tsdoc/v0/tsdoc.schema.json",
|
||||
"noStandardTags": false,
|
||||
"tagDefinitions": [
|
||||
{
|
||||
"tagName": "@todo",
|
||||
"syntaxKind": "block"
|
||||
},
|
||||
{
|
||||
"tagName": "@linkcode",
|
||||
"syntaxKind": "inline"
|
||||
}
|
||||
]
|
||||
}
|
7
typedoc.json
Normal file
7
typedoc.json
Normal file
@ -0,0 +1,7 @@
|
||||
{
|
||||
"entryPoints": ["./src"],
|
||||
"entryPointStrategy": "expand",
|
||||
"exclude": ["**/*+.test.ts"],
|
||||
"out": "typedoc",
|
||||
"highlightLanguages": ["javascript", "json", "jsonc", "json5", "tsx", "typescript", "markdown"]
|
||||
}
|
@ -2,31 +2,13 @@ import { defineProject } from "vitest/config";
|
||||
import { BaseSequencer, type TestSpecification } from "vitest/node";
|
||||
import { defaultConfig } from "./vite.config";
|
||||
|
||||
function getTestOrder(testName: string): number {
|
||||
if (testName.includes("battle-scene.test.ts")) {
|
||||
return 1;
|
||||
}
|
||||
if (testName.includes("inputs.test.ts")) {
|
||||
return 2;
|
||||
}
|
||||
return 3;
|
||||
}
|
||||
|
||||
export default defineProject(({ mode }) => ({
|
||||
...defaultConfig,
|
||||
test: {
|
||||
testTimeout: 20000,
|
||||
setupFiles: ["./test/fontFace.setup.ts", "./test/vitest.setup.ts"],
|
||||
sequence: {
|
||||
sequencer: class CustomSequencer extends BaseSequencer {
|
||||
async sort(files: TestSpecification[]) {
|
||||
// use default sorting at first.
|
||||
files = await super.sort(files);
|
||||
// Except, forcibly reorder
|
||||
|
||||
return files.sort((a, b) => getTestOrder(a.moduleId) - getTestOrder(b.moduleId));
|
||||
}
|
||||
},
|
||||
sequencer: MySequencer,
|
||||
},
|
||||
environment: "jsdom" as const,
|
||||
environmentOptions: {
|
||||
@ -55,3 +37,38 @@ export default defineProject(({ mode }) => ({
|
||||
keepNames: true,
|
||||
},
|
||||
}));
|
||||
|
||||
//#region Helpers
|
||||
|
||||
/**
|
||||
* Class for sorting test files in the desired order.
|
||||
*/
|
||||
class MySequencer extends BaseSequencer {
|
||||
async sort(files: TestSpecification[]) {
|
||||
files = await super.sort(files);
|
||||
|
||||
return files.sort((a, b) => {
|
||||
const aTestOrder = getTestOrder(a.moduleId);
|
||||
const bTestOrder = getTestOrder(b.moduleId);
|
||||
return aTestOrder - bTestOrder;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A helper function for sorting test files in a desired order.
|
||||
*
|
||||
* A lower number means that a test file must be run earlier,
|
||||
* or else it breaks due to running tests with `--no-isolate.`
|
||||
*/
|
||||
function getTestOrder(testName: string): number {
|
||||
if (testName.includes("battle-scene.test.ts")) {
|
||||
return 1;
|
||||
}
|
||||
if (testName.includes("inputs.test.ts")) {
|
||||
return 2;
|
||||
}
|
||||
return 3;
|
||||
}
|
||||
|
||||
//#endregion
|
||||
|
@ -1,14 +0,0 @@
|
||||
import { defineWorkspace } from "vitest/config";
|
||||
import { defaultConfig } from "./vite.config";
|
||||
|
||||
export default defineWorkspace([
|
||||
{
|
||||
...defaultConfig,
|
||||
test: {
|
||||
name: "pre",
|
||||
include: ["./test/pre.test.ts"],
|
||||
environment: "jsdom",
|
||||
},
|
||||
},
|
||||
"./vitest.config.ts",
|
||||
]);
|
Loading…
Reference in New Issue
Block a user